summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md10
-rw-r--r--CONTRIBUTING.md15
-rw-r--r--SConstruct44
-rw-r--r--core/config/project_settings.cpp94
-rw-r--r--core/config/project_settings.h13
-rw-r--r--core/core_bind.cpp11
-rw-r--r--core/core_bind.h3
-rw-r--r--core/debugger/script_debugger.cpp4
-rw-r--r--core/debugger/script_debugger.h1
-rw-r--r--core/extension/extension_api_dump.cpp3
-rw-r--r--core/extension/gdextension_interface.cpp75
-rw-r--r--core/extension/gdextension_interface.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/io/file_access.cpp12
-rw-r--r--core/io/file_access.h4
-rw-r--r--core/io/image_loader.cpp4
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/resource.cpp7
-rw-r--r--core/io/resource.h2
-rw-r--r--core/io/resource_format_binary.cpp4
-rw-r--r--core/io/resource_format_binary.h1
-rw-r--r--core/io/resource_loader.cpp7
-rw-r--r--core/io/resource_loader.h1
-rw-r--r--core/io/resource_saver.cpp7
-rw-r--r--core/io/resource_saver.h1
-rw-r--r--core/io/xml_parser.cpp10
-rw-r--r--core/io/xml_parser.h4
-rw-r--r--core/math/basis.cpp25
-rw-r--r--core/math/basis.h4
-rw-r--r--core/math/face3.cpp40
-rw-r--r--core/math/face3.h5
-rw-r--r--core/math/geometry_2d.cpp35
-rw-r--r--core/math/geometry_2d.h1
-rw-r--r--core/math/geometry_3d.cpp145
-rw-r--r--core/math/geometry_3d.h2
-rw-r--r--core/math/plane.h2
-rw-r--r--core/math/transform_2d.cpp6
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/triangle_mesh.cpp196
-rw-r--r--core/math/triangle_mesh.h2
-rw-r--r--core/object/script_language.cpp51
-rw-r--r--core/object/script_language.h1
-rw-r--r--core/os/keyboard.cpp3
-rw-r--r--core/os/keyboard.h5
-rw-r--r--core/os/os.h3
-rw-r--r--core/variant/variant.h1
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_setget.cpp21
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/AnimatedSprite2D.xml1
-rw-r--r--doc/classes/AnimationNode.xml7
-rw-r--r--doc/classes/AnimationNodeOneShot.xml6
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml11
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml3
-rw-r--r--doc/classes/AnimationNodeTransition.xml8
-rw-r--r--doc/classes/AnimationPlayer.xml6
-rw-r--r--doc/classes/Array.xml2
-rw-r--r--doc/classes/ArrayMesh.xml14
-rw-r--r--doc/classes/BackBufferCopy.xml4
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/BoneAttachment3D.xml31
-rw-r--r--doc/classes/Callable.xml2
-rw-r--r--doc/classes/CanvasGroup.xml4
-rw-r--r--doc/classes/CanvasItem.xml21
-rw-r--r--doc/classes/CodeEdit.xml8
-rw-r--r--doc/classes/CollisionObject3D.xml6
-rw-r--r--doc/classes/Control.xml8
-rw-r--r--doc/classes/ConvexPolygonShape3D.xml2
-rw-r--r--doc/classes/DTLSServer.xml4
-rw-r--r--doc/classes/DisplayServer.xml5
-rw-r--r--doc/classes/EditorFileSystem.xml11
-rw-r--r--doc/classes/EditorPlugin.xml21
-rw-r--r--doc/classes/EditorResourceConversionPlugin.xml23
-rw-r--r--doc/classes/EditorSettings.xml6
-rw-r--r--doc/classes/EditorUndoRedoManager.xml2
-rw-r--r--doc/classes/GeometryInstance3D.xml5
-rw-r--r--doc/classes/Image.xml4
-rw-r--r--doc/classes/ImporterMesh.xml10
-rw-r--r--doc/classes/JavaScriptBridge.xml2
-rw-r--r--doc/classes/Mesh.xml7
-rw-r--r--doc/classes/OS.xml12
-rw-r--r--doc/classes/Object.xml1
-rw-r--r--doc/classes/PhysicsServer3DManager.xml2
-rw-r--r--doc/classes/Plane.xml17
-rw-r--r--doc/classes/ProjectSettings.xml29
-rw-r--r--doc/classes/RenderingServer.xml7
-rw-r--r--doc/classes/ResourcePreloader.xml4
-rw-r--r--doc/classes/RichTextLabel.xml1
-rw-r--r--doc/classes/ShaderMaterial.xml3
-rw-r--r--doc/classes/Skeleton2D.xml2
-rw-r--r--doc/classes/Skeleton3D.xml96
-rw-r--r--doc/classes/SkeletonModification2D.xml2
-rw-r--r--doc/classes/SkeletonModification3D.xml66
-rw-r--r--doc/classes/SkeletonModification3DCCDIK.xml136
-rw-r--r--doc/classes/SkeletonModification3DFABRIK.xml161
-rw-r--r--doc/classes/SkeletonModification3DJiggle.xml199
-rw-r--r--doc/classes/SkeletonModification3DLookAt.xml64
-rw-r--r--doc/classes/SkeletonModification3DStackHolder.xml27
-rw-r--r--doc/classes/SkeletonModification3DTwoBoneIK.xml191
-rw-r--r--doc/classes/SkeletonModificationStack3D.xml88
-rw-r--r--doc/classes/SkeletonProfile.xml11
-rw-r--r--doc/classes/SkeletonProfileHumanoid.xml1
-rw-r--r--doc/classes/SpriteFrames.xml21
-rw-r--r--doc/classes/TextServer.xml11
-rw-r--r--doc/classes/TextServerExtension.xml2
-rw-r--r--doc/classes/TileMap.xml14
-rw-r--r--doc/classes/Transform3D.xml1
-rw-r--r--doc/classes/Tree.xml4
-rw-r--r--doc/classes/TreeItem.xml42
-rw-r--r--doc/classes/Tween.xml10
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/Variant.xml4
-rw-r--r--doc/classes/VisualShaderNodeTexture.xml10
-rw-r--r--doc/classes/VisualShaderNodeTextureParameter.xml18
-rw-r--r--doc/classes/Window.xml38
-rw-r--r--doc/classes/bool.xml2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp10
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h3
-rw-r--r--drivers/gles3/shaders/canvas.glsl8
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl3
-rw-r--r--drivers/gles3/shaders/scene.glsl4
-rw-r--r--drivers/gles3/storage/material_storage.cpp22
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp3
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp15
-rw-r--r--drivers/unix/dir_access_unix.cpp4
-rw-r--r--drivers/unix/os_unix.cpp19
-rw-r--r--drivers/unix/os_unix.h4
-rw-r--r--editor/action_map_editor.cpp6
-rw-r--r--editor/animation_bezier_editor.cpp16
-rw-r--r--editor/animation_track_editor.cpp72
-rw-r--r--editor/animation_track_editor_plugins.cpp5
-rw-r--r--editor/array_property_edit.cpp7
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/connections_dialog.cpp7
-rw-r--r--editor/create_dialog.cpp8
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/dictionary_property_edit.cpp5
-rw-r--r--editor/doc_tools.cpp63
-rw-r--r--editor/editor_audio_buses.cpp44
-rw-r--r--editor/editor_autoload_settings.cpp18
-rw-r--r--editor/editor_data.cpp69
-rw-r--r--editor/editor_data.h6
-rw-r--r--editor/editor_file_system.cpp141
-rw-r--r--editor/editor_file_system.h10
-rw-r--r--editor/editor_help.cpp2
-rw-r--r--editor/editor_inspector.cpp81
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_locale_dialog.cpp9
-rw-r--r--editor/editor_node.cpp84
-rw-r--r--editor/editor_node.h5
-rw-r--r--editor/editor_plugin.cpp18
-rw-r--r--editor/editor_plugin.h9
-rw-r--r--editor/editor_properties.cpp20
-rw-r--r--editor/editor_properties_array_dict.cpp16
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_property_name_processor.cpp1
-rw-r--r--editor/editor_resource_picker.cpp5
-rw-r--r--editor/editor_run_native.cpp107
-rw-r--r--editor/editor_run_native.h7
-rw-r--r--editor/editor_settings_dialog.cpp14
-rw-r--r--editor/editor_toaster.cpp49
-rw-r--r--editor/editor_toaster.h2
-rw-r--r--editor/editor_undo_redo_manager.cpp12
-rw-r--r--editor/editor_undo_redo_manager.h11
-rw-r--r--editor/export/editor_export.cpp6
-rw-r--r--editor/export/editor_export_platform.cpp234
-rw-r--r--editor/export/editor_export_platform.h10
-rw-r--r--editor/export/editor_export_platform_pc.h1
-rw-r--r--editor/export/editor_export_plugin.cpp5
-rw-r--r--editor/export/project_export.cpp8
-rw-r--r--editor/fbx_importer_manager.cpp8
-rw-r--r--editor/filesystem_dock.cpp11
-rw-r--r--editor/groups_editor.cpp14
-rw-r--r--editor/history_dock.cpp2
-rw-r--r--editor/history_dock.h2
-rw-r--r--editor/icons/PlayRemote.svg1
-rw-r--r--editor/icons/README.md2
-rw-r--r--editor/import/collada.cpp164
-rw-r--r--editor/import/resource_importer_obj.cpp27
-rw-r--r--editor/import/resource_importer_shader_file.cpp1
-rw-r--r--editor/import/scene_import_settings.cpp26
-rw-r--r--editor/inspector_dock.cpp4
-rw-r--r--editor/localization_editor.cpp19
-rw-r--r--editor/multi_node_edit.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp10
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp14
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp18
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp24
-rw-r--r--editor/plugins/animation_library_editor.cpp28
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp50
-rw-r--r--editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp22
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp29
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp22
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/control_editor_plugin.cpp6
-rw-r--r--editor/plugins/curve_editor_plugin.cpp14
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/gradient_editor.cpp2
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp8
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp44
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp22
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp12
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp16
-rw-r--r--editor/plugins/script_editor_plugin.cpp32
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--editor/plugins/script_text_editor.cpp10
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/shader_editor_plugin.cpp10
-rw-r--r--editor/plugins/shader_editor_plugin.h3
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp35
-rw-r--r--editor/plugins/text_editor.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp17
-rw-r--r--editor/plugins/theme_editor_plugin.cpp48
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp79
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.h2
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp30
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp120
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp65
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp13
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp168
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp56
-rw-r--r--editor/plugins/tiles/tile_set_editor.h1
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp10
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp27
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp142
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h3
-rw-r--r--editor/project_converter_3_to_4.cpp3
-rw-r--r--editor/project_settings_editor.cpp16
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp44
-rw-r--r--editor/scene_tree_editor.cpp12
-rw-r--r--editor/shader_globals_editor.cpp6
-rw-r--r--main/main.cpp20
-rw-r--r--main/performance.cpp4
-rw-r--r--methods.py36
-rw-r--r--misc/hooks/asmessage.applescript59
-rwxr-xr-xmisc/hooks/pre-commit-black19
-rwxr-xr-xmisc/hooks/pre-commit-clang-format19
-rw-r--r--modules/bmp/image_loader_bmp.cpp20
-rw-r--r--modules/csg/editor/csg_gizmos.cpp8
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp65
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_editor.cpp10
-rw-r--r--modules/gdscript/gdscript_parser.cpp74
-rw-r--r--modules/gdscript/tests/README.md2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_name.gd2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd51
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out14
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml8
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp10
-rw-r--r--modules/mono/csharp_script.cpp7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs59
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs217
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs58
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs72
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs37
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs110
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs107
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs54
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs148
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs101
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs32
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp4
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp10
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp8
-rw-r--r--modules/multiplayer/multiplayer_spawner.h2
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp48
-rw-r--r--modules/multiplayer/scene_replication_interface.h7
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_action_editor.h2
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp2
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h2
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h2
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h2
-rw-r--r--modules/openxr/openxr_api.cpp10
-rw-r--r--modules/openxr/openxr_api.h1
-rw-r--r--modules/openxr/register_types.cpp4
-rw-r--r--modules/raycast/SCsub2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp82
-rw-r--r--modules/text_server_adv/text_server_adv.h5
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp33
-rw-r--r--modules/text_server_fb/text_server_fb.cpp59
-rw-r--r--modules/text_server_fb/text_server_fb.h4
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp33
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml4
-rw-r--r--platform/android/README.md2
-rw-r--r--platform/android/display_server_android.cpp13
-rw-r--r--platform/android/export/export_plugin.cpp23
-rw-r--r--platform/android/logo.pngbin968 -> 0 bytes
-rw-r--r--platform/android/logo.svg1
-rw-r--r--platform/android/os_android.cpp16
-rw-r--r--platform/android/run_icon.pngbin324 -> 0 bytes
-rw-r--r--platform/android/run_icon.svg1
-rw-r--r--platform/ios/README.md2
-rw-r--r--platform/ios/display_server_ios.mm25
-rw-r--r--platform/ios/export/export_plugin.cpp23
-rw-r--r--platform/ios/export/export_plugin.h1
-rw-r--r--platform/ios/logo.pngbin1297 -> 0 bytes
-rw-r--r--platform/ios/logo.svg1
-rw-r--r--platform/linuxbsd/README.md2
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp40
-rw-r--r--platform/linuxbsd/detect.py11
-rw-r--r--platform/linuxbsd/export/export.cpp1
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp344
-rw-r--r--platform/linuxbsd/export/export_plugin.h45
-rw-r--r--platform/linuxbsd/logo.pngbin1679 -> 0 bytes
-rw-r--r--platform/linuxbsd/logo.svg1
-rw-r--r--platform/linuxbsd/run_icon.svg1
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp70
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h4
-rw-r--r--platform/macos/README.md2
-rw-r--r--platform/macos/display_server_macos.h1
-rw-r--r--platform/macos/display_server_macos.mm54
-rw-r--r--platform/macos/export/export_plugin.cpp384
-rw-r--r--platform/macos/export/export_plugin.h59
-rw-r--r--platform/macos/logo.pngbin7195 -> 0 bytes
-rw-r--r--platform/macos/logo.svg1
-rw-r--r--platform/macos/run_icon.svg1
-rw-r--r--platform/uwp/README.md2
-rw-r--r--platform/uwp/export/export_plugin.cpp18
-rw-r--r--platform/uwp/logo.pngbin1519 -> 0 bytes
-rw-r--r--platform/uwp/logo.svg1
-rw-r--r--platform/web/README.md2
-rw-r--r--platform/web/display_server_web.cpp6
-rw-r--r--platform/web/export/export_plugin.cpp25
-rw-r--r--platform/web/export/export_plugin.h5
-rw-r--r--platform/web/logo.pngbin1234 -> 0 bytes
-rw-r--r--platform/web/logo.svg1
-rw-r--r--platform/web/os_web.cpp18
-rw-r--r--platform/web/run_icon.pngbin290 -> 0 bytes
-rw-r--r--platform/web/run_icon.svg1
-rw-r--r--platform/windows/README.md2
-rw-r--r--platform/windows/display_server_windows.cpp57
-rw-r--r--platform/windows/display_server_windows.h1
-rw-r--r--platform/windows/export/export.cpp1
-rw-r--r--platform/windows/export/export_plugin.cpp316
-rw-r--r--platform/windows/export/export_plugin.h36
-rw-r--r--platform/windows/logo.pngbin1536 -> 0 bytes
-rw-r--r--platform/windows/logo.svg1
-rw-r--r--platform/windows/os_windows.cpp13
-rw-r--r--platform/windows/os_windows.h3
-rw-r--r--platform/windows/run_icon.svg1
-rw-r--r--scene/2d/path_2d.cpp25
-rw-r--r--scene/2d/path_2d.h5
-rw-r--r--scene/2d/tile_map.cpp65
-rw-r--r--scene/2d/tile_map.h5
-rw-r--r--scene/3d/bone_attachment_3d.cpp52
-rw-r--r--scene/3d/bone_attachment_3d.h8
-rw-r--r--scene/3d/label_3d.cpp2
-rw-r--r--scene/3d/label_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp10
-rw-r--r--scene/3d/skeleton_3d.cpp263
-rw-r--r--scene/3d/skeleton_3d.h55
-rw-r--r--scene/3d/skeleton_ik_3d.cpp23
-rw-r--r--scene/animation/animation_blend_tree.cpp162
-rw-r--r--scene/animation/animation_blend_tree.h42
-rw-r--r--scene/animation/animation_node_state_machine.cpp134
-rw-r--r--scene/animation/animation_node_state_machine.h16
-rw-r--r--scene/animation/animation_player.cpp43
-rw-r--r--scene/animation/animation_player.h7
-rw-r--r--scene/animation/animation_tree.cpp23
-rw-r--r--scene/animation/animation_tree.h4
-rw-r--r--scene/animation/tween.cpp20
-rw-r--r--scene/animation/tween.h2
-rw-r--r--scene/gui/base_button.cpp75
-rw-r--r--scene/gui/base_button.h13
-rw-r--r--scene/gui/code_edit.cpp55
-rw-r--r--scene/gui/code_edit.h1
-rw-r--r--scene/gui/color_picker.cpp6
-rw-r--r--scene/gui/control.cpp25
-rw-r--r--scene/gui/control.h14
-rw-r--r--scene/gui/graph_edit.cpp1
-rw-r--r--scene/gui/item_list.cpp6
-rw-r--r--scene/gui/item_list.h1
-rw-r--r--scene/gui/label.cpp9
-rw-r--r--scene/gui/label.h2
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/tab_container.cpp5
-rw-r--r--scene/gui/text_edit.cpp10
-rw-r--r--scene/gui/texture_rect.cpp10
-rw-r--r--scene/gui/texture_rect.h3
-rw-r--r--scene/gui/tree.cpp100
-rw-r--r--scene/gui/tree.h22
-rw-r--r--scene/main/canvas_item.cpp47
-rw-r--r--scene/main/canvas_item.h12
-rw-r--r--scene/main/scene_tree.cpp1
-rw-r--r--scene/main/viewport.cpp40
-rw-r--r--scene/main/viewport.h3
-rw-r--r--scene/main/window.cpp20
-rw-r--r--scene/main/window.h5
-rw-r--r--scene/register_scene_types.cpp17
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp2
-rw-r--r--scene/resources/environment.cpp12
-rw-r--r--scene/resources/immediate_mesh.cpp17
-rw-r--r--scene/resources/material.cpp12
-rw-r--r--scene/resources/mesh.cpp5
-rw-r--r--scene/resources/primitive_meshes.cpp2
-rw-r--r--scene/resources/primitive_meshes.h2
-rw-r--r--scene/resources/resource_format_text.cpp7
-rw-r--r--scene/resources/resource_format_text.h1
-rw-r--r--scene/resources/skeleton_modification_3d.cpp151
-rw-r--r--scene/resources/skeleton_modification_3d.h79
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp474
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.h114
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.cpp628
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.h124
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.cpp582
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.h138
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp267
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.h89
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.cpp104
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.h59
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.cpp617
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.h118
-rw-r--r--scene/resources/skeleton_modification_stack_3d.cpp224
-rw-r--r--scene/resources/skeleton_modification_stack_3d.h91
-rw-r--r--scene/resources/tile_set.cpp1
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader_nodes.cpp163
-rw-r--r--scene/resources/visual_shader_nodes.h16
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/physics_3d/gjk_epa.cpp6
-rw-r--r--servers/physics_3d/godot_body_pair_3d.cpp14
-rw-r--r--servers/physics_3d/godot_body_pair_3d.h8
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp18
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.h4
-rw-r--r--servers/physics_3d/godot_collision_solver_3d_sat.cpp59
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp2
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h2
-rw-r--r--servers/physics_3d/godot_space_3d.cpp6
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp265
-rw-r--r--servers/rendering/renderer_canvas_cull.h6
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp18
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp16
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp15
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp7
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl5
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp13
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h4
-rw-r--r--servers/rendering/renderer_scene_cull.cpp4
-rw-r--r--servers/rendering/renderer_scene_render.cpp2
-rw-r--r--servers/rendering/renderer_viewport.cpp69
-rw-r--r--servers/rendering/rendering_device_binds.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/shader_compiler.cpp41
-rw-r--r--servers/rendering/shader_compiler.h3
-rw-r--r--servers/rendering/shader_language.cpp6
-rw-r--r--servers/rendering/shader_types.cpp4
-rw-r--r--servers/rendering/storage/render_scene_buffers.cpp4
-rw-r--r--servers/rendering/storage/render_scene_buffers.h4
-rw-r--r--servers/rendering_server.cpp6
-rw-r--r--servers/rendering_server.h9
-rw-r--r--servers/text/text_server_extension.cpp4
-rw-r--r--servers/text/text_server_extension.h4
-rw-r--r--servers/text_server.cpp116
-rw-r--r--servers/text_server.h7
-rw-r--r--tests/core/io/test_xml_parser.h2
-rw-r--r--tests/core/math/test_plane.h4
-rw-r--r--tests/scene/test_arraymesh.h21
-rw-r--r--tests/scene/test_code_edit.h50
-rw-r--r--tests/scene/test_curve_2d.h228
-rw-r--r--tests/scene/test_node.h106
-rw-r--r--tests/scene/test_primitives.h2
-rw-r--r--tests/test_main.cpp1
532 files changed, 6470 insertions, 9465 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f59c0e645d..820a85c3fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,11 +37,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- [New and improved IK in Skeleton2D](https://github.com/godotengine/godot/pull/40347).
- New classes: SkeletonModifier2D, SkeletonModifierStack2D, SkeletonModification2DLookAt, SkeletonModification2DCCDIK, SkeletonModification2DFABRIK, SkeletonModification2DJiggle, SkeletonModification2DTwoBoneIK, PhysicalBone2D, SkeletonModification2DPhysicalBones, SkeletonModification2DStackHolder.
- New `Transform2D.looking_at()` function.
-- [New and improved IK in Skeleton3D](https://github.com/godotengine/godot/pull/39353).
- - New classes: SkeletonModifier3D, SkeletonModifierStack3D, SkeletonModifier3DLookAt, SkeletonModification3DCCDIK, SkeletonModification3DFABRIK, SkeletonModification3DJiggle, SkeletonModification3DTwoBoneIK, SkeletonModification3DStackHolder.
- - The Bone struct now includes a local_pose_override.
+- [Improvements to Skeleton3D](https://github.com/godotengine/godot/pull/39353).
- The Bone struct now keeps track of its children bones, if it has any.
- - Added functions to Skeleton3D for getting the forward vector using the information stored in the rest pose for the bones.
- New `Basis.rotate_to_align()` function.
- Refactored the BoneAttachment3D node.
- Removed the `process_list` functions.
@@ -230,6 +227,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- More information in the [progress report](https://godotengine.org/article/improvements-shaders-visual-shaders-godot-4).
- [Add Billboard mode to visual shaders.](https://github.com/godotengine/godot/pull/49157)
- [The constants `PI`, `TAU` and `E` are now available in the shader language.](https://github.com/godotengine/godot/pull/48837)
+- Uniform hints to control textures (`repeat_enabled`, `repeat_disabled`, `filter_linear`, `filter_nearest`, `hint_screen_texture`, etc.).
#### Miscellaneous
@@ -404,6 +402,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- [Removed support for 16Ɨ MSAA due to driver bugs and low performance.](https://github.com/godotengine/godot/pull/49063)
- For high-quality offline rendering, using supersampling together with 8Ɨ MSAA is a better option anyway.
+#### Shaders
+
+- Removed `SCREEN_TEXTURE` and `DEPTH_TEXTURE` in favour of uniform hints `hint_screen_texture` and `hint_depth_texture`.
+
### Fixed
#### Core
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 21d6e110ce..aea1c8c5ff 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -122,11 +122,12 @@ recommend that you have a look at it to know what's important to take into
account for a PR to be considered for merging.
In addition to the following tips, also take a look at the
-[Engine development guide](https://docs.godotengine.org/en/latest/development/cpp/)
+[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html)
for an introduction to developing on Godot.
-The [Contributing docs](https://docs.godotengine.org/en/latest/community/contributing/index.html)
-also have important information on the PR workflow and the code style we use.
+The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/ways_to_contribute.html)
+also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
+and the [code style](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html) we use.
### Document your changes
@@ -135,10 +136,10 @@ scripting APIs, you **must** update the class reference to document those.
This is to ensure the documentation coverage doesn't decrease as contributions
are merged.
-[Update the documentation template](https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html#updating-the-documentation-template)
+[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html#updating-class-reference-when-working-on-the-engine)
using your compiled binary, then fill in the descriptions.
Follow the style guide described in the
-[Docs writing guidelines](https://docs.godotengine.org/en/latest/community/contributing/docs_writing_guidelines.html).
+[Writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html).
If your pull request modifies parts of the code in a non-obvious way, make sure
to add comments in the code as well. This helps other people understand the
@@ -164,7 +165,7 @@ applicable.
Feel free to contribute standalone pull requests to add new tests or improve
existing tests as well.
-See [Unit testing](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html)
+See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html)
for information on writing tests in Godot's C++ codebase.
### Be nice to the Git history
@@ -186,7 +187,7 @@ Internet).
This [Git style guide](https://github.com/agis-/git-style-guide) has some
good practices to have in mind.
-See our [PR workflow](https://docs.godotengine.org/en/latest/community/contributing/pr_workflow.html)
+See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
documentation for tips on using Git, amending commits and rebasing branches.
### Format your commit messages with readability in mind
diff --git a/SConstruct b/SConstruct
index 1eb6c0adc8..1acbd83e63 100644
--- a/SConstruct
+++ b/SConstruct
@@ -202,7 +202,7 @@ opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all
opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False))
opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False))
-opts.Add("build_feature_profile", "Path to a file containing a feature build profile", "")
+opts.Add("build_profile", "Path to a file containing a feature build profile", "")
opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True))
opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", True))
opts.Add("system_certs_path", "Use this path as SSL certificates default for editor (for package maintainers)", "")
@@ -492,6 +492,25 @@ if selected_platform in platform_list:
env["LINKFLAGS"] = ""
env.Append(LINKFLAGS=str(LINKFLAGS).split())
+ # Feature build profile
+ disabled_classes = []
+ if env["build_profile"] != "":
+ print("Using feature build profile: " + env["build_profile"])
+ import json
+
+ try:
+ ft = json.load(open(env["build_profile"]))
+ if "disabled_classes" in ft:
+ disabled_classes = ft["disabled_classes"]
+ if "disabled_build_options" in ft:
+ dbo = ft["disabled_build_options"]
+ for c in dbo:
+ env[c] = dbo[c]
+ except:
+ print("Error opening feature build profile: " + env["build_profile"])
+ Exit(255)
+ methods.write_disabled_classes(disabled_classes)
+
# Platform specific flags.
# These can sometimes override default options.
flag_list = platform_flags[selected_platform]
@@ -540,6 +559,9 @@ if selected_platform in platform_list:
env.Append(CCFLAGS=["/Od"])
else:
if env["debug_symbols"]:
+ # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
+ # otherwise addr2line doesn't understand them
+ env.Append(CCFLAGS=["-gdwarf-4"])
if env.dev_build:
env.Append(CCFLAGS=["-g3"])
else:
@@ -815,26 +837,6 @@ if selected_platform in platform_list:
env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
- disabled_classes = []
-
- if env["build_feature_profile"] != "":
- print("Using build feature profile: " + env["build_feature_profile"])
- import json
-
- try:
- ft = json.load(open(env["build_feature_profile"]))
- if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
- if "disabled_build_options" in ft:
- dbo = ft["disabled_build_options"]
- for c in dbo:
- env[c] = dbo[c]
- except:
- print("Error opening feature build profile: " + env["build_feature_profile"])
- Exit(255)
-
- methods.write_disabled_classes(disabled_classes)
-
if env["disable_3d"]:
if env.editor_build:
print("Build option 'disable_3d=yes' cannot be used for editor builds, but only for export templates.")
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 0bf7430d84..ed89bc15d3 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -33,6 +33,7 @@
#include "core/core_bind.h" // For Compression enum.
#include "core/core_string_names.h"
#include "core/input/input_map.h"
+#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/file_access_network.h"
@@ -291,31 +292,26 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (!disable_feature_overrides) {
+ { // Feature overrides.
int dot = p_name.operator String().find(".");
if (dot != -1) {
Vector<String> s = p_name.operator String().split(".");
- bool override_valid = false;
for (int i = 1; i < s.size(); i++) {
String feature = s[i].strip_edges();
- if (OS::get_singleton()->has_feature(feature) || custom_features.has(feature)) {
- override_valid = true;
- break;
+ Pair<StringName, StringName> fo(feature, p_name);
+
+ if (!feature_overrides.has(s[0])) {
+ feature_overrides[s[0]] = LocalVector<Pair<StringName, StringName>>();
}
- }
- if (override_valid) {
- feature_overrides[s[0]] = p_name;
+ feature_overrides[s[0]].push_back(fo);
}
}
}
if (props.has(p_name)) {
- if (!props[p_name].overridden) {
- props[p_name].variant = p_value;
- }
-
+ props[p_name].variant = p_value;
} else {
props[p_name] = VariantContainer(p_value, last_order++);
}
@@ -340,16 +336,35 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
_THREAD_SAFE_METHOD_
+ if (!props.has(p_name)) {
+ WARN_PRINT("Property not found: " + String(p_name));
+ return false;
+ }
+ r_ret = props[p_name].variant;
+ return true;
+}
+
+Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const {
+ _THREAD_SAFE_METHOD_
+
StringName name = p_name;
- if (!disable_feature_overrides && feature_overrides.has(name)) {
- name = feature_overrides[name];
+ if (feature_overrides.has(name)) {
+ const LocalVector<Pair<StringName, StringName>> &overrides = feature_overrides[name];
+ for (uint32_t i = 0; i < overrides.size(); i++) {
+ if (OS::get_singleton()->has_feature(overrides[i].first)) { // Custom features are checked in OS.has_feature() already. No need to check twice.
+ if (props.has(overrides[i].second)) {
+ name = overrides[i].second;
+ break;
+ }
+ }
+ }
}
+
if (!props.has(name)) {
WARN_PRINT("Property not found: " + String(name));
- return false;
+ return Variant();
}
- r_ret = props[name].variant;
- return true;
+ return props[name].variant;
}
struct _VCSort {
@@ -1054,23 +1069,6 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p
return ret;
}
-Vector<String> ProjectSettings::get_optimizer_presets() const {
- List<PropertyInfo> pi;
- ProjectSettings::get_singleton()->get_property_list(&pi);
- Vector<String> names;
-
- for (const PropertyInfo &E : pi) {
- if (!E.name.begins_with("optimizer_presets/")) {
- continue;
- }
- names.push_back(E.name.get_slicec('/', 1));
- }
-
- names.sort();
-
- return names;
-}
-
void ProjectSettings::_add_property_info_bind(const Dictionary &p_info) {
ERR_FAIL_COND(!p_info.has("name"));
ERR_FAIL_COND(!p_info.has("type"));
@@ -1101,10 +1099,6 @@ const HashMap<StringName, PropertyInfo> &ProjectSettings::get_custom_property_in
return custom_prop_info;
}
-void ProjectSettings::set_disable_feature_overrides(bool p_disable) {
- disable_feature_overrides = p_disable;
-}
-
bool ProjectSettings::is_using_datapack() const {
return using_datapack;
}
@@ -1138,6 +1132,29 @@ Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_d
}
}
+Array ProjectSettings::get_global_class_list() {
+ Array script_classes;
+
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ if (cf->load(get_project_data_path().path_join("global_script_class_cache.cfg")) == OK) {
+ script_classes = cf->get_value("", "list");
+ } else {
+#ifndef TOOLS_ENABLED
+ // Script classes can't be recreated in exported project, so print an error.
+ ERR_PRINT("Could not load global script cache.");
+#endif
+ }
+ return script_classes;
+}
+
+void ProjectSettings::store_global_class_list(const Array &p_classes) {
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ cf->set_value("", "list", p_classes);
+ cf->save(get_project_data_path().path_join("global_script_class_cache.cfg"));
+}
+
bool ProjectSettings::has_custom_feature(const String &p_feature) const {
return custom_features.has(p_feature);
}
@@ -1169,6 +1186,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting);
ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("get_setting_with_override", "name"), &ProjectSettings::get_setting_with_override);
ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order);
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 2aca1e7691..d1704a7c31 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -34,6 +34,7 @@
#include "core/object/class_db.h"
#include "core/os/thread_safe.h"
#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
#include "core/templates/rb_set.h"
class ProjectSettings : public Object {
@@ -69,7 +70,6 @@ protected:
Variant variant;
Variant initial;
bool hide_from_editor = false;
- bool overridden = false;
bool restart_if_changed = false;
#ifdef DEBUG_METHODS_ENABLED
bool ignore_value_in_docs = false;
@@ -91,12 +91,11 @@ protected:
RBMap<StringName, VariantContainer> props; // NOTE: Key order is used e.g. in the save_custom method.
String resource_path;
HashMap<StringName, PropertyInfo> custom_prop_info;
- bool disable_feature_overrides = false;
bool using_datapack = false;
List<String> input_presets;
HashSet<String> custom_features;
- HashMap<StringName, StringName> feature_overrides;
+ HashMap<StringName, LocalVector<Pair<StringName, StringName>>> feature_overrides;
HashMap<StringName, AutoloadInfo> autoloads;
@@ -142,6 +141,8 @@ public:
void set_setting(const String &p_setting, const Variant &p_value);
Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
+ Array get_global_class_list();
+ void store_global_class_list(const Array &p_classes);
bool has_setting(String p_var) const;
String localize_path(const String &p_path) const;
@@ -177,11 +178,9 @@ public:
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
uint64_t get_last_saved_time() { return last_save_time; }
- Vector<String> get_optimizer_presets() const;
-
List<String> get_input_presets() const { return input_presets; }
- void set_disable_feature_overrides(bool p_disable);
+ Variant get_setting_with_override(const StringName &p_name) const;
bool is_using_datapack() const;
@@ -205,7 +204,7 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
-#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index ab433bd8f1..96e1da9dde 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -322,8 +322,12 @@ String OS::get_environment(const String &p_var) const {
return ::OS::get_singleton()->get_environment(p_var);
}
-bool OS::set_environment(const String &p_var, const String &p_value) const {
- return ::OS::get_singleton()->set_environment(p_var, p_value);
+void OS::set_environment(const String &p_var, const String &p_value) const {
+ ::OS::get_singleton()->set_environment(p_var, p_value);
+}
+
+void OS::unset_environment(const String &p_var) const {
+ ::OS::get_singleton()->unset_environment(p_var);
}
String OS::get_name() const {
@@ -548,9 +552,10 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running);
ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id);
+ ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
ClassDB::bind_method(D_METHOD("get_environment", "variable"), &OS::get_environment);
ClassDB::bind_method(D_METHOD("set_environment", "variable", "value"), &OS::set_environment);
- ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
+ ClassDB::bind_method(D_METHOD("unset_environment", "variable"), &OS::unset_environment);
ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
diff --git a/core/core_bind.h b/core/core_bind.h
index 7ef346d1c4..c0c87fd009 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -162,7 +162,8 @@ public:
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
- bool set_environment(const String &p_var, const String &p_value) const;
+ void set_environment(const String &p_var, const String &p_value) const;
+ void unset_environment(const String &p_var) const;
String get_name() const;
String get_distribution_name() const;
diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp
index 8af1573bff..32725b76c1 100644
--- a/core/debugger/script_debugger.cpp
+++ b/core/debugger/script_debugger.cpp
@@ -73,10 +73,6 @@ bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const
return breakpoints[p_line].has(p_source);
}
-bool ScriptDebugger::is_breakpoint_line(int p_line) const {
- return breakpoints.has(p_line);
-}
-
String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
return p_source;
}
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index c7aa90027b..edce089179 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -64,7 +64,6 @@ public:
void insert_breakpoint(int p_line, const StringName &p_source);
void remove_breakpoint(int p_line, const StringName &p_source);
bool is_breakpoint(int p_line, const StringName &p_source) const;
- bool is_breakpoint_line(int p_line) const;
void clear_breakpoints();
const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 312064a36c..7be14b741d 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -458,6 +458,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
// Global enums and constants.
Array constants;
HashMap<String, List<Pair<String, int64_t>>> enum_list;
+ HashMap<String, bool> enum_is_bitfield;
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
int64_t value = CoreConstants::get_global_constant_value(i);
@@ -466,6 +467,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
bool bitfield = CoreConstants::is_global_constant_bitfield(i);
if (!enum_name.is_empty()) {
enum_list[enum_name].push_back(Pair<String, int64_t>(name, value));
+ enum_is_bitfield[enum_name] = bitfield;
} else {
Dictionary d;
d["name"] = name;
@@ -481,6 +483,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
for (const KeyValue<String, List<Pair<String, int64_t>>> &E : enum_list) {
Dictionary d1;
d1["name"] = E.key;
+ d1["is_bitfield"] = enum_is_bitfield[E.key];
Array values;
for (const Pair<String, int64_t> &F : E.value) {
Dictionary d2;
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index bd4fa61bd5..4df3df160f 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -31,8 +31,11 @@
#include "gdextension_interface.h"
#include "core/config/engine.h"
+#include "core/io/file_access.h"
+#include "core/io/xml_parser.h"
#include "core/object/class_db.h"
#include "core/object/script_language_extension.h"
+#include "core/object/worker_thread_pool.h"
#include "core/os/memory.h"
#include "core/variant/variant.h"
#include "core/version.h"
@@ -678,6 +681,59 @@ static const char32_t *gdextension_string_operator_index_const(GDExtensionConstS
return &self->ptr()[p_index];
}
+static void gdextension_string_operator_plus_eq_string(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b) {
+ String *self = (String *)p_self;
+ const String *b = (const String *)p_b;
+ *self += *b;
+}
+
+static void gdextension_string_operator_plus_eq_char(GDExtensionStringPtr p_self, char32_t p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_cstr(GDExtensionStringPtr p_self, const char *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_wcstr(GDExtensionStringPtr p_self, const wchar_t *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_c32str(GDExtensionStringPtr p_self, const char32_t *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) {
+ XMLParser *xml = (XMLParser *)p_instance;
+ return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size);
+}
+
+static void gdextension_file_access_store_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length) {
+ FileAccess *fa = (FileAccess *)p_instance;
+ fa->store_buffer(p_src, p_length);
+}
+
+static uint64_t gdextension_file_access_get_buffer(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length) {
+ const FileAccess *fa = (FileAccess *)p_instance;
+ return fa->get_buffer(p_dst, p_length);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_group_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, GDExtensionConstStringPtr p_description) {
+ WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+ const String *description = (const String *)p_description;
+ return (int64_t)p->add_native_group_task(p_func, p_userdata, p_elements, p_tasks, p_high_priority, *description);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, bool p_high_priority, GDExtensionConstStringPtr p_description) {
+ WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+ const String *description = (const String *)p_description;
+ return (int64_t)p->add_native_task(p_func, p_userdata, p_high_priority, *description);
+}
+
/* Packed array functions */
static uint8_t *gdextension_packed_byte_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
@@ -1025,6 +1081,25 @@ void gdextension_setup_interface(GDExtensionInterface *p_interface) {
gde_interface.string_to_wide_chars = gdextension_string_to_wide_chars;
gde_interface.string_operator_index = gdextension_string_operator_index;
gde_interface.string_operator_index_const = gdextension_string_operator_index_const;
+ gde_interface.string_operator_plus_eq_string = gdextension_string_operator_plus_eq_string;
+ gde_interface.string_operator_plus_eq_char = gdextension_string_operator_plus_eq_char;
+ gde_interface.string_operator_plus_eq_cstr = gdextension_string_operator_plus_eq_cstr;
+ gde_interface.string_operator_plus_eq_wcstr = gdextension_string_operator_plus_eq_wcstr;
+ gde_interface.string_operator_plus_eq_c32str = gdextension_string_operator_plus_eq_c32str;
+
+ /* XMLParser extra utilities */
+
+ gde_interface.xml_parser_open_buffer = gdextension_xml_parser_open_buffer;
+
+ /* FileAccess extra utilities */
+
+ gde_interface.file_access_store_buffer = gdextension_file_access_store_buffer;
+ gde_interface.file_access_get_buffer = gdextension_file_access_get_buffer;
+
+ /* WorkerThreadPool extra utilities */
+
+ gde_interface.worker_thread_pool_add_native_group_task = gdextension_worker_thread_pool_add_native_group_task;
+ gde_interface.worker_thread_pool_add_native_task = gdextension_worker_thread_pool_add_native_task;
/* Packed array functions */
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 190298ee8a..a16eef2fcf 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -503,6 +503,26 @@ typedef struct {
char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index);
const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index);
+ void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b);
+ void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b);
+ void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b);
+ void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b);
+ void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b);
+
+ /* XMLParser extra utilities */
+
+ GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size);
+
+ /* FileAccess extra utilities */
+
+ void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length);
+ uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length);
+
+ /* WorkerThreadPool extra utilities */
+
+ int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, GDExtensionConstStringPtr p_description);
+ int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, bool p_high_priority, GDExtensionConstStringPtr p_description);
+
/* Packed array functions */
uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index a7729c9af2..76e199e0ff 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -45,7 +45,7 @@ def make_default_controller_mappings(target, source, env):
platform_mappings[current_platform][guid] = line
platform_variables = {
- "Linux": "#if X11_ENABLED",
+ "Linux": "#if LINUXBSD_ENABLED",
"Windows": "#ifdef WINDOWS_ENABLED",
"Mac OS X": "#ifdef MACOS_ENABLED",
"Android": "#if defined(__ANDROID__)",
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 77d1bdcc5c..cacbcb28a4 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -292,7 +292,7 @@ real_t FileAccess::get_real() const {
Variant FileAccess::get_var(bool p_allow_objects) const {
uint32_t len = get_32();
- Vector<uint8_t> buff = _get_buffer(len);
+ Vector<uint8_t> buff = get_buffer(len);
ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
const uint8_t *r = buff.ptr();
@@ -469,7 +469,7 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
-Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
@@ -663,7 +663,7 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
}
-void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
uint64_t len = p_buffer.size();
if (len == 0) {
return;
@@ -687,7 +687,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
store_32(len);
- _store_buffer(buff);
+ store_buffer(buff);
}
Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
@@ -829,7 +829,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t>(FileAccess::*)(int64_t) const) & FileAccess::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
@@ -847,7 +847,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
- ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+ ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer);
ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 3116ed521f..3e51ba11ed 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -127,7 +127,7 @@ public:
Variant get_var(bool p_allow_objects = false) const;
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
- Vector<uint8_t> _get_buffer(int64_t p_length) const;
+ Vector<uint8_t> get_buffer(int64_t p_length) const;
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
@@ -162,7 +162,7 @@ public:
virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
- void _store_buffer(const Vector<uint8_t> &p_buffer);
+ void store_buffer(const Vector<uint8_t> &p_buffer);
void store_var(const Variant &p_var, bool p_full_objects = false);
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 17fb199811..c6452f1033 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -135,10 +135,6 @@ void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.erase(p_loader);
}
-const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() {
- return loader;
-}
-
void ImageLoader::cleanup() {
while (loader.size()) {
remove_image_format_loader(loader[0]);
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index 1473f24186..ac51f13376 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -98,8 +98,6 @@ public:
static void add_image_format_loader(Ref<ImageFormatLoader> p_loader);
static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader);
- static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders();
-
static void cleanup();
};
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 2d6f09725f..6d3575b9fa 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -385,10 +385,6 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
ResourceCache::lock.unlock();
}
-bool Resource::is_translation_remapped() const {
- return remapped_list.in_list();
-}
-
#ifdef TOOLS_ENABLED
//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
void Resource::set_id_for_path(const String &p_path, const String &p_id) {
@@ -481,9 +477,6 @@ void ResourceCache::clear() {
resources.clear();
}
-void ResourceCache::reload_externals() {
-}
-
bool ResourceCache::has(const String &p_path) {
lock.lock();
diff --git a/core/io/resource.h b/core/io/resource.h
index 22ce5cef43..5135664f36 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -136,7 +136,6 @@ public:
#endif
void set_as_translation_remapped(bool p_remapped);
- bool is_translation_remapped() const;
virtual RID get_rid() const; // some resources may offer conversion to RID
@@ -164,7 +163,6 @@ class ResourceCache {
friend void register_core_types();
public:
- static void reload_externals();
static bool has(const String &p_path);
static Ref<Resource> get_ref(const String &p_path);
static void get_cached_resources(List<Ref<Resource>> *p_resources);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 45e1301930..03beb25b03 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -661,10 +661,6 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
return OK; //never reach anyway
}
-void ResourceLoaderBinary::set_local_path(const String &p_local_path) {
- res_path = p_local_path;
-}
-
Ref<Resource> ResourceLoaderBinary::get_resource() {
return resource;
}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 2e8988005f..9dd208e3cd 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -92,7 +92,6 @@ class ResourceLoaderBinary {
HashMap<String, Ref<Resource>> dependency_cache;
public:
- void set_local_path(const String &p_local_path);
Ref<Resource> get_resource();
Error load();
void set_translation_remapped(bool p_remapped);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 946c31cf0d..68b9f8b6f7 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -1011,13 +1011,6 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
return true;
}
-void ResourceLoader::remove_custom_resource_format_loader(String script_path) {
- Ref<ResourceFormatLoader> custom_loader = _find_custom_resource_format_loader(script_path);
- if (custom_loader.is_valid()) {
- remove_resource_format_loader(custom_loader);
- }
-}
-
void ResourceLoader::set_create_missing_resources_if_class_unavailable(bool p_enable) {
create_missing_resources_if_class_unavailable = p_enable;
}
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 41ba0dc6e6..e427a2f5fc 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -225,7 +225,6 @@ public:
static ResourceLoaderImport import;
static bool add_custom_resource_format_loader(String script_path);
- static void remove_custom_resource_format_loader(String script_path);
static void add_custom_loaders();
static void remove_custom_loaders();
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 9809b9a48f..b8201cc6b9 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -250,13 +250,6 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
return true;
}
-void ResourceSaver::remove_custom_resource_format_saver(String script_path) {
- Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path);
- if (custom_saver.is_valid()) {
- remove_resource_format_saver(custom_saver);
- }
-}
-
void ResourceSaver::add_custom_savers() {
// Custom resource savers exploits global class names
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 2043947963..9e88b2086b 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -101,7 +101,6 @@ public:
static void set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback);
static bool add_custom_resource_format_saver(String script_path);
- static void remove_custom_resource_format_saver(String script_path);
static void add_custom_savers();
static void remove_custom_savers();
};
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 09836419be..5c0a017bfc 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -354,10 +354,10 @@ void XMLParser::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_offset"), &XMLParser::get_node_offset);
ClassDB::bind_method(D_METHOD("get_attribute_count"), &XMLParser::get_attribute_count);
ClassDB::bind_method(D_METHOD("get_attribute_name", "idx"), &XMLParser::get_attribute_name);
- ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), (String(XMLParser::*)(int) const) & XMLParser::get_attribute_value);
+ ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), &XMLParser::get_attribute_value);
ClassDB::bind_method(D_METHOD("has_attribute", "name"), &XMLParser::has_attribute);
- ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), (String(XMLParser::*)(const String &) const) & XMLParser::get_attribute_value);
- ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_attribute_value_safe);
+ ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), &XMLParser::get_named_attribute_value);
+ ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_named_attribute_value_safe);
ClassDB::bind_method(D_METHOD("is_empty"), &XMLParser::is_empty);
ClassDB::bind_method(D_METHOD("get_current_line"), &XMLParser::get_current_line);
ClassDB::bind_method(D_METHOD("skip_section"), &XMLParser::skip_section);
@@ -422,7 +422,7 @@ bool XMLParser::has_attribute(const String &p_name) const {
return false;
}
-String XMLParser::get_attribute_value(const String &p_name) const {
+String XMLParser::get_named_attribute_value(const String &p_name) const {
int idx = -1;
for (int i = 0; i < attributes.size(); i++) {
if (attributes[i].name == p_name) {
@@ -436,7 +436,7 @@ String XMLParser::get_attribute_value(const String &p_name) const {
return attributes[idx].value;
}
-String XMLParser::get_attribute_value_safe(const String &p_name) const {
+String XMLParser::get_named_attribute_value_safe(const String &p_name) const {
int idx = -1;
for (int i = 0; i < attributes.size(); i++) {
if (attributes[i].name == p_name) {
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index b4ae5c93b6..b96478c7a5 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -109,8 +109,8 @@ public:
String get_attribute_name(int p_idx) const;
String get_attribute_value(int p_idx) const;
bool has_attribute(const String &p_name) const;
- String get_attribute_value(const String &p_name) const;
- String get_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
+ String get_named_attribute_value(const String &p_name) const;
+ String get_named_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
bool is_empty() const;
int get_current_line() const;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 39e383fb49..234a4ddb79 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -36,23 +36,6 @@
#define cofac(row1, col1, row2, col2) \
(rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
-void Basis::from_z(const Vector3 &p_z) {
- if (Math::abs(p_z.z) > (real_t)Math_SQRT12) {
- // choose p in y-z plane
- real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2];
- real_t k = 1.0f / Math::sqrt(a);
- rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k);
- rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]);
- } else {
- // choose p in x-y plane
- real_t a = p_z.x * p_z.x + p_z.y * p_z.y;
- real_t k = 1.0f / Math::sqrt(a);
- rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0);
- rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k);
- }
- rows[2] = p_z;
-}
-
void Basis::invert() {
real_t co[3] = {
cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)
@@ -271,14 +254,6 @@ float Basis::get_uniform_scale() const {
return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
}
-void Basis::make_scale_uniform() {
- float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
- for (int i = 0; i < 3; i++) {
- rows[i].normalize();
- rows[i] *= l;
- }
-}
-
Basis Basis::scaled_local(const Vector3 &p_scale) const {
return (*this) * Basis::from_scale(p_scale);
}
diff --git a/core/math/basis.h b/core/math/basis.h
index b3197dbc84..bbc1d40469 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -56,8 +56,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ real_t determinant() const;
- void from_z(const Vector3 &p_z);
-
void rotate(const Vector3 &p_axis, real_t p_angle);
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
@@ -101,8 +99,6 @@ struct _NO_DISCARD_ Basis {
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
-
- void make_scale_uniform();
float get_uniform_scale() const;
Vector3 get_scale() const;
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index e53bbf872b..1dff0ee4a6 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -120,36 +120,6 @@ bool Face3::is_degenerate() const {
return (normal.length_squared() < (real_t)CMP_EPSILON2);
}
-Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const {
- int over = 0, under = 0;
-
- Plane plane = get_plane(p_clock_dir);
-
- for (int i = 0; i < 3; i++) {
- const Vector3 &v = p_face.vertex[i];
-
- if (plane.has_point(v)) { //coplanar, don't bother
- continue;
- }
-
- if (plane.is_point_over(v)) {
- over++;
- } else {
- under++;
- }
- }
-
- if (over > 0 && under == 0) {
- return SIDE_OVER;
- } else if (under > 0 && over == 0) {
- return SIDE_UNDER;
- } else if (under == 0 && over == 0) {
- return SIDE_COPLANAR;
- } else {
- return SIDE_SPANNING;
- }
-}
-
Vector3 Face3::get_random_point_inside() const {
real_t a = Math::random(0.0, 1.0);
real_t b = Math::random(0.0, 1.0);
@@ -164,20 +134,10 @@ Plane Face3::get_plane(ClockDirection p_dir) const {
return Plane(vertex[0], vertex[1], vertex[2], p_dir);
}
-Vector3 Face3::get_median_point() const {
- return (vertex[0] + vertex[1] + vertex[2]) / 3.0f;
-}
-
real_t Face3::get_area() const {
return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5f;
}
-ClockDirection Face3::get_clock_dir() const {
- Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]);
- //printf("normal is %g,%g,%g x %g,%g,%g- wtfu is %g\n",tofloat(normal.x),tofloat(normal.y),tofloat(normal.z),tofloat(vertex[0].x),tofloat(vertex[0].y),tofloat(vertex[0].z),tofloat( normal.dot( vertex[0] ) ) );
- return (normal.dot(vertex[0]) >= 0) ? CLOCKWISE : COUNTERCLOCKWISE;
-}
-
bool Face3::intersects_aabb(const AABB &p_aabb) const {
/** TEST PLANE **/
if (!p_aabb.intersects_plane(get_plane())) {
diff --git a/core/math/face3.h b/core/math/face3.h
index 3d87de03dc..3dd47d0226 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -57,19 +57,14 @@ struct _NO_DISCARD_ Face3 {
Plane get_plane(ClockDirection p_dir = CLOCKWISE) const;
Vector3 get_random_point_inside() const;
- Side get_side_of(const Face3 &p_face, ClockDirection p_clock_dir = CLOCKWISE) const;
-
bool is_degenerate() const;
real_t get_area() const;
- Vector3 get_median_point() const;
Vector3 get_closest_point_to(const Vector3 &p_point) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const;
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const;
- ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity
-
void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const;
void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index a0b76d31cb..74cb92539a 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -320,41 +320,6 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
return polypaths;
}
-Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) {
- Vector<stbrp_node> nodes;
- nodes.resize(p_atlas_size.width);
-
- stbrp_context context;
- stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
-
- Vector<stbrp_rect> rects;
- rects.resize(p_sizes.size());
-
- for (int i = 0; i < p_sizes.size(); i++) {
- rects.write[i].id = 0;
- rects.write[i].w = p_sizes[i].width;
- rects.write[i].h = p_sizes[i].height;
- rects.write[i].x = 0;
- rects.write[i].y = 0;
- rects.write[i].was_packed = 0;
- }
-
- int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size());
- if (res == 0) { //pack failed
- return Vector<Point2i>();
- }
-
- Vector<Point2i> ret;
- ret.resize(p_sizes.size());
-
- for (int i = 0; i < p_sizes.size(); i++) {
- Point2i r(rects[i].x, rects[i].y);
- ret.write[i] = r;
- }
-
- return ret;
-}
-
Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
Vector<stbrp_node> nodes;
nodes.resize(p_atlas_size.width);
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index b55aecf85e..0e5702e0af 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -464,7 +464,6 @@ public:
static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon);
static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
- static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size);
static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size);
private:
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 3ac78e0709..51523ea296 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -198,149 +198,6 @@ struct _FaceClassify {
_FaceClassify() {}
};
-static bool _connect_faces(_FaceClassify *p_faces, int len, int p_group) {
- // Connect faces, error will occur if an edge is shared between more than 2 faces.
- // Clear connections.
-
- bool error = false;
-
- for (int i = 0; i < len; i++) {
- for (int j = 0; j < 3; j++) {
- p_faces[i].links[j].clear();
- }
- }
-
- for (int i = 0; i < len; i++) {
- if (p_faces[i].group != p_group) {
- continue;
- }
- for (int j = i + 1; j < len; j++) {
- if (p_faces[j].group != p_group) {
- continue;
- }
-
- for (int k = 0; k < 3; k++) {
- Vector3 vi1 = p_faces[i].face.vertex[k];
- Vector3 vi2 = p_faces[i].face.vertex[(k + 1) % 3];
-
- for (int l = 0; l < 3; l++) {
- Vector3 vj2 = p_faces[j].face.vertex[l];
- Vector3 vj1 = p_faces[j].face.vertex[(l + 1) % 3];
-
- if (vi1.distance_to(vj1) < 0.00001f &&
- vi2.distance_to(vj2) < 0.00001f) {
- if (p_faces[i].links[k].face != -1) {
- ERR_PRINT("already linked\n");
- error = true;
- break;
- }
- if (p_faces[j].links[l].face != -1) {
- ERR_PRINT("already linked\n");
- error = true;
- break;
- }
-
- p_faces[i].links[k].face = j;
- p_faces[i].links[k].edge = l;
- p_faces[j].links[l].face = i;
- p_faces[j].links[l].edge = k;
- }
- }
- if (error) {
- break;
- }
- }
- if (error) {
- break;
- }
- }
- if (error) {
- break;
- }
- }
-
- for (int i = 0; i < len; i++) {
- p_faces[i].valid = true;
- for (int j = 0; j < 3; j++) {
- if (p_faces[i].links[j].face == -1) {
- p_faces[i].valid = false;
- }
- }
- }
- return error;
-}
-
-static bool _group_face(_FaceClassify *p_faces, int len, int p_index, int p_group) {
- if (p_faces[p_index].group >= 0) {
- return false;
- }
-
- p_faces[p_index].group = p_group;
-
- for (int i = 0; i < 3; i++) {
- ERR_FAIL_INDEX_V(p_faces[p_index].links[i].face, len, true);
- _group_face(p_faces, len, p_faces[p_index].links[i].face, p_group);
- }
-
- return true;
-}
-
-Vector<Vector<Face3>> Geometry3D::separate_objects(Vector<Face3> p_array) {
- Vector<Vector<Face3>> objects;
-
- int len = p_array.size();
-
- const Face3 *arrayptr = p_array.ptr();
-
- Vector<_FaceClassify> fc;
-
- fc.resize(len);
-
- _FaceClassify *_fcptr = fc.ptrw();
-
- for (int i = 0; i < len; i++) {
- _fcptr[i].face = arrayptr[i];
- }
-
- bool error = _connect_faces(_fcptr, len, -1);
-
- ERR_FAIL_COND_V_MSG(error, Vector<Vector<Face3>>(), "Invalid geometry.");
-
- // Group connected faces in separate objects.
-
- int group = 0;
- for (int i = 0; i < len; i++) {
- if (!_fcptr[i].valid) {
- continue;
- }
- if (_group_face(_fcptr, len, i, group)) {
- group++;
- }
- }
-
- // Group connected faces in separate objects.
-
- for (int i = 0; i < len; i++) {
- _fcptr[i].face = arrayptr[i];
- }
-
- if (group >= 0) {
- objects.resize(group);
- Vector<Face3> *group_faces = objects.ptrw();
-
- for (int i = 0; i < len; i++) {
- if (!_fcptr[i].valid) {
- continue;
- }
- if (_fcptr[i].group >= 0 && _fcptr[i].group < group) {
- group_faces[_fcptr[i].group].push_back(_fcptr[i].face);
- }
- }
- }
-
- return objects;
-}
-
/*** GEOMETRY WRAPPER ***/
enum _CellFlags {
@@ -748,7 +605,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector3 right = p.normal.cross(ref).normalized();
Vector3 up = p.normal.cross(right).normalized();
- Vector3 center = p.center();
+ Vector3 center = p.get_center();
// make a quad clockwise
LocalVector<Vector3> vertices = {
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 6759db5766..99c554fe05 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -532,8 +532,6 @@ public:
return clipped;
}
- static Vector<Vector<Face3>> separate_objects(Vector<Face3> p_array);
-
// Create a "wrap" that encloses the given geometry.
static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = nullptr);
diff --git a/core/math/plane.h b/core/math/plane.h
index 3bc7c54b9d..8159f25342 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -47,7 +47,7 @@ struct _NO_DISCARD_ Plane {
/* Plane-Point operations */
- _FORCE_INLINE_ Vector3 center() const { return normal * d; }
+ _FORCE_INLINE_ Vector3 get_center() const { return normal * d; }
Vector3 get_any_perpendicular_normal() const;
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 6a7ee32230..910995d717 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -221,12 +221,6 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
return t;
}
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
- Transform2D copy = *this;
- copy.scale_basis(p_scale);
- return copy;
-}
-
Transform2D Transform2D::scaled(const Size2 &p_scale) const {
// Equivalent to left multiplication
Transform2D copy = *this;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 2a0917c63f..4a17a9db37 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -85,7 +85,6 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
- Transform2D basis_scaled(const Size2 &p_scale) const;
Transform2D scaled(const Size2 &p_scale) const;
Transform2D scaled_local(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 4b6921d38b..0da1b8c7ad 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -182,90 +182,6 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces, const Vector<int32_t>
valid = true;
}
-Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const {
- uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
-
- enum {
- TEST_AABB_BIT = 0,
- VISIT_LEFT_BIT = 1,
- VISIT_RIGHT_BIT = 2,
- VISIT_DONE_BIT = 3,
- VISITED_BIT_SHIFT = 29,
- NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
- VISITED_BIT_MASK = ~NODE_IDX_MASK,
-
- };
-
- int n_count = 0;
- Vector3 n;
-
- int level = 0;
-
- const Triangle *triangleptr = triangles.ptr();
- // const Vector3 *verticesr = vertices.ptr();
- const BVH *bvhptr = bvh.ptr();
-
- int pos = bvh.size() - 1;
-
- stack[0] = pos;
- while (true) {
- uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &b = bvhptr[node];
- bool done = false;
-
- switch (stack[level] >> VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
- 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];
- n += s.normal;
- n_count++;
-
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
- } else {
- stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
- }
- }
- continue;
- }
- case VISIT_LEFT_BIT: {
- stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.left | TEST_AABB_BIT;
- continue;
- }
- case VISIT_RIGHT_BIT: {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.right | TEST_AABB_BIT;
- continue;
- }
- case VISIT_DONE_BIT: {
- if (level == 0) {
- done = true;
- break;
- } else {
- level--;
- }
- continue;
- }
- }
-
- if (done) {
- break;
- }
- }
-
- if (n_count > 0) {
- n /= n_count;
- }
-
- return n;
-}
-
bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const {
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
@@ -468,118 +384,6 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
return inters;
}
-bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
- uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
-
- //p_fully_inside = true;
-
- enum {
- TEST_AABB_BIT = 0,
- VISIT_LEFT_BIT = 1,
- VISIT_RIGHT_BIT = 2,
- VISIT_DONE_BIT = 3,
- VISITED_BIT_SHIFT = 29,
- NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
- VISITED_BIT_MASK = ~NODE_IDX_MASK,
-
- };
-
- int level = 0;
-
- const Triangle *triangleptr = triangles.ptr();
- const Vector3 *vertexptr = vertices.ptr();
- const BVH *bvhptr = bvh.ptr();
-
- int pos = bvh.size() - 1;
-
- stack[0] = pos;
- while (true) {
- uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &b = bvhptr[node];
- bool done = false;
-
- switch (stack[level] >> VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
- 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];
-
- for (int j = 0; j < 3; ++j) {
- const Vector3 &point = vertexptr[s.indices[j]];
- const Vector3 &next_point = vertexptr[s.indices[(j + 1) % 3]];
- Vector3 res;
- bool over = true;
- for (int i = 0; i < p_plane_count; i++) {
- const Plane &p = p_planes[i];
-
- if (p.intersects_segment(point, next_point, &res)) {
- bool inisde = true;
- for (int k = 0; k < p_plane_count; k++) {
- if (k == i) {
- continue;
- }
- const Plane &pp = p_planes[k];
- if (pp.is_point_over(res)) {
- inisde = false;
- break;
- }
- }
- if (inisde) {
- return true;
- }
- }
-
- if (p.is_point_over(point)) {
- over = false;
- break;
- }
- }
- if (over) {
- return true;
- }
- }
-
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
- } else {
- stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
- }
- }
- continue;
- }
- case VISIT_LEFT_BIT: {
- stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.left | TEST_AABB_BIT;
- continue;
- }
- case VISIT_RIGHT_BIT: {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.right | TEST_AABB_BIT;
- continue;
- }
- case VISIT_DONE_BIT: {
- if (level == 0) {
- done = true;
- break;
- } else {
- level--;
- }
- continue;
- }
- }
-
- if (done) {
- break;
- }
- }
-
- return false;
-}
-
bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale) const {
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index 728fd600d5..24fc12dda9 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -84,9 +84,7 @@ public:
bool is_valid() const;
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const;
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const;
- bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
- Vector3 get_area_normal(const AABB &p_aabb) const;
Vector<Face3> get_faces() const;
const Vector<Triangle> &get_triangles() const { return triangles; }
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 7be3a6c688..66ef418e42 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -186,6 +186,7 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
void ScriptServer::init_languages() {
{ // Load global classes.
global_classes_clear();
+#ifndef DISABLE_DEPRECATED
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
Array script_classes = GLOBAL_GET("_global_script_classes");
@@ -196,6 +197,17 @@ void ScriptServer::init_languages() {
}
add_global_class(c["class"], c["base"], c["language"], c["path"]);
}
+ ProjectSettings::get_singleton()->clear("_global_script_classes");
+ }
+#endif
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
+ continue;
+ }
+ add_global_class(c["class"], c["base"], c["language"], c["path"]);
}
}
@@ -251,6 +263,15 @@ void ScriptServer::remove_global_class(const StringName &p_class) {
global_classes.erase(p_class);
}
+void ScriptServer::remove_global_class_by_path(const String &p_path) {
+ for (const KeyValue<StringName, GlobalScriptClass> &kv : global_classes) {
+ if (kv.value.path == p_path) {
+ global_classes.erase(kv.key);
+ return;
+ }
+ }
+}
+
bool ScriptServer::is_global_class(const StringName &p_class) {
return global_classes.has(p_class);
}
@@ -291,6 +312,17 @@ void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
}
void ScriptServer::save_global_classes() {
+ Dictionary class_icons;
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d = script_classes[i];
+ if (!d.has("name") || !d.has("icon")) {
+ continue;
+ }
+ class_icons[d["name"]] = d["icon"];
+ }
+
List<StringName> gc;
get_global_class_list(&gc);
Array gcarr;
@@ -300,25 +332,10 @@ void ScriptServer::save_global_classes() {
d["language"] = global_classes[E].language;
d["path"] = global_classes[E].path;
d["base"] = global_classes[E].base;
+ d["icon"] = class_icons.get(E, "");
gcarr.push_back(d);
}
-
- Array old;
- if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = GLOBAL_GET("_global_script_classes");
- }
- if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
- return;
- }
-
- if (gcarr.is_empty()) {
- if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- ProjectSettings::get_singleton()->clear("_global_script_classes");
- }
- } else {
- ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
- }
- ProjectSettings::get_singleton()->save();
+ ProjectSettings::get_singleton()->store_global_class_list(gcarr);
}
////////////////////
diff --git a/core/object/script_language.h b/core/object/script_language.h
index ff678bcd25..02d1880dc2 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -80,6 +80,7 @@ public:
static void global_classes_clear();
static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path);
static void remove_global_class(const StringName &p_class);
+ static void remove_global_class_by_path(const String &p_path);
static bool is_global_class(const StringName &p_class);
static StringName get_global_class_language(const StringName &p_class);
static String get_global_class_path(const String &p_class);
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index e0231b818f..5183b77cb1 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -63,12 +63,15 @@ static const _KeyCodeText _keycodes[] = {
{Key::CTRL ,"Ctrl"},
#if defined(MACOS_ENABLED)
{Key::META ,"Command"},
+ {Key::CMD_OR_CTRL ,"Command"},
{Key::ALT ,"Option"},
#elif defined(WINDOWS_ENABLED)
{Key::META ,"Windows"},
+ {Key::CMD_OR_CTRL ,"Ctrl"},
{Key::ALT ,"Alt"},
#else
{Key::META ,"Meta"},
+ {Key::CMD_OR_CTRL ,"Ctrl"},
{Key::ALT ,"Alt"},
#endif
{Key::CAPSLOCK ,"CapsLock"},
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 389baee915..c78fa2a631 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -65,6 +65,11 @@ enum class Key {
SHIFT = SPECIAL | 0x15,
CTRL = SPECIAL | 0x16,
META = SPECIAL | 0x17,
+#if defined(MACOS_ENABLED)
+ CMD_OR_CTRL = META,
+#else
+ CMD_OR_CTRL = CTRL,
+#endif
ALT = SPECIAL | 0x18,
CAPSLOCK = SPECIAL | 0x19,
NUMLOCK = SPECIAL | 0x1A,
diff --git a/core/os/os.h b/core/os/os.h
index b80efa47b7..4818e9281a 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -167,7 +167,8 @@ public:
virtual bool has_environment(const String &p_var) const = 0;
virtual String get_environment(const String &p_var) const = 0;
- virtual bool set_environment(const String &p_var, const String &p_value) const = 0;
+ virtual void set_environment(const String &p_var, const String &p_value) const = 0;
+ virtual void unset_environment(const String &p_var) const = 0;
virtual String get_name() const = 0;
virtual String get_distribution_name() const = 0;
diff --git a/core/variant/variant.h b/core/variant/variant.h
index fff59c43a6..b9294de77d 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -655,6 +655,7 @@ public:
static bool has_indexing(Variant::Type p_type);
static Variant::Type get_indexed_element_type(Variant::Type p_type);
+ static uint32_t get_indexed_element_usage(Variant::Type p_type);
typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob);
typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 05fb62ff12..2cc0b3a8d7 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1923,7 +1923,7 @@ static void _register_variant_builtin_methods() {
/* Plane */
bind_method(Plane, normalized, sarray(), varray());
- bind_method(Plane, center, sarray(), varray());
+ bind_method(Plane, get_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());
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index b8d4495702..ba37e15f31 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -389,6 +389,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.write[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -460,6 +461,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.write[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -515,6 +517,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -564,6 +567,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v m_accessor[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -613,6 +617,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.m_set(index, PtrToArg<m_elem_type>::convert(member)); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -683,6 +688,7 @@ struct VariantIndexedSetGet_Array {
v.set(index, PtrToArg<Variant>::convert(member));
}
static Variant::Type get_index_type() { return Variant::NIL; }
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_NIL_IS_VARIANT; }
static uint64_t get_indexed_size(const Variant *base) { return 0; }
};
@@ -768,6 +774,7 @@ struct VariantIndexedSetGet_String {
}
}
static Variant::Type get_index_type() { return Variant::STRING; }
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; }
static uint64_t get_indexed_size(const Variant *base) { return VariantInternal::get_string(base)->length(); }
};
@@ -812,6 +819,7 @@ struct VariantIndexedSetGet_String {
v[index] = PtrToArg<Variant>::convert(member); \
} \
static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -852,7 +860,8 @@ struct VariantIndexedSetterGetterInfo {
uint64_t (*get_indexed_size)(const Variant *base) = nullptr;
- Variant::Type index_type;
+ Variant::Type index_type = Variant::NIL;
+ uint32_t index_usage = PROPERTY_USAGE_DEFAULT;
bool valid = false;
};
@@ -872,6 +881,7 @@ static void register_indexed_member(Variant::Type p_type) {
sgi.ptr_getter = T::ptr_get;
sgi.index_type = T::get_index_type();
+ sgi.index_usage = T::get_index_usage();
sgi.get_indexed_size = T::get_indexed_size;
sgi.valid = true;
@@ -920,6 +930,11 @@ Variant::Type Variant::get_indexed_element_type(Variant::Type p_type) {
return variant_indexed_setters_getters[p_type].index_type;
}
+uint32_t Variant::get_indexed_element_usage(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, PROPERTY_USAGE_DEFAULT);
+ return variant_indexed_setters_getters[p_type].index_usage;
+}
+
Variant::ValidatedIndexedSetter Variant::get_member_validated_indexed_setter(Variant::Type p_type) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
return variant_indexed_setters_getters[p_type].validated_setter;
@@ -1253,7 +1268,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
return _data._int > 0;
} break;
case FLOAT: {
- r_iter = 0;
+ r_iter = 0.0;
return _data._float > 0.0;
} break;
case VECTOR2: {
@@ -1457,7 +1472,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
return true;
} break;
case FLOAT: {
- int64_t idx = r_iter;
+ double idx = r_iter;
idx++;
if (idx >= _data._float) {
return false;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 41836650cd..7e7cb07cef 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -494,7 +494,7 @@
<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.
+ Returns whether [param x] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity.
</description>
</method>
<method name="is_inf">
@@ -529,7 +529,7 @@
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns [code]true[/code] if [param x] is zero or almost zero.
+ Returns [code]true[/code] if [param x] is zero or almost zero. The comparison is done using a tolerance calculation with a small internal epsilon.
This function is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index e20fb71c7e..cd9c0cee98 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -7,7 +7,6 @@
[AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
To pause the current animation, set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
- [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
<link title="2D Sprite animation">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index a33ec2f6dc..6e3345b675 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -49,6 +49,13 @@
When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node.
</description>
</method>
+ <method name="_is_parameter_read_only" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="parameter" type="StringName" />
+ <description>
+ When inheriting from [AnimationRootNode], implement this virtual method to return whether the [param parameter] is read-only. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
+ </description>
+ </method>
<method name="_process" qualifiers="virtual const">
<return type="float" />
<param index="0" name="time" type="float" />
diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml
index 14abc34992..9e8193868c 100644
--- a/doc/classes/AnimationNodeOneShot.xml
+++ b/doc/classes/AnimationNodeOneShot.xml
@@ -28,6 +28,12 @@
</member>
</members>
<constants>
+ <constant name="ONE_SHOT_REQUEST_NONE" value="0" enum="OneShotRequest">
+ </constant>
+ <constant name="ONE_SHOT_REQUEST_FIRE" value="1" enum="OneShotRequest">
+ </constant>
+ <constant name="ONE_SHOT_REQUEST_ABORT" value="2" enum="OneShotRequest">
+ </constant>
<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">
</constant>
<constant name="MIX_MODE_ADD" value="1" enum="MixMode">
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index 8f53ef0dcf..7e01be12c4 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -50,11 +50,19 @@
Returns [code]true[/code] if an animation is playing.
</description>
</method>
+ <method name="next">
+ <return type="void" />
+ <description>
+ If there is a next path by travel or auto advance, immediately transitions from the current state to the next state.
+ </description>
+ </method>
<method name="start">
<return type="void" />
<param index="0" name="node" type="StringName" />
+ <param index="1" name="reset" type="bool" default="true" />
<description>
Starts playing the given animation.
+ If [param reset] is [code]true[/code], the animation is played from the beginning.
</description>
</method>
<method name="stop">
@@ -66,8 +74,11 @@
<method name="travel">
<return type="void" />
<param index="0" name="to_node" type="StringName" />
+ <param index="1" name="reset_on_teleport" type="bool" default="true" />
<description>
Transitions from the current state to another one, following the shortest path.
+ If the path does not connect from the current state, the animation will play after the state teleports.
+ If [param reset_on_teleport] is [code]true[/code], the animation is played from the beginning when the travel cause a teleportation.
</description>
</method>
</methods>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 814b2d0052..eee25fad7c 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -28,6 +28,9 @@
<member name="priority" type="int" setter="set_priority" getter="get_priority" default="1">
Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO].
</member>
+ <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true">
+ If [code]true[/code], the destination animation is played back from the beginning when switched.
+ </member>
<member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0">
The transition type.
</member>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index f6e2fc5eb2..bca94a568a 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -12,6 +12,12 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
+ <method name="find_input_caption" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="caption" type="String" />
+ <description>
+ </description>
+ </method>
<method name="get_input_caption" qualifiers="const">
<return type="String" />
<param index="0" name="input" type="int" />
@@ -43,7 +49,7 @@
<member name="enabled_inputs" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
The number of enabled input ports for this node.
</member>
- <member name="from_start" type="bool" setter="set_from_start" getter="is_from_start" default="true">
+ <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true">
If [code]true[/code], the destination animation is played back from the beginning when switched.
</member>
<member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index ca0cbf0ca1..304caeef43 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -208,9 +208,11 @@
</method>
<method name="stop">
<return type="void" />
+ <param index="0" name="keep_state" type="bool" default="false" />
<description>
- Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code].
- See also [method pause].
+ Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code]. See also [method pause].
+ If [param keep_state] is [code]true[/code], the animation state is not updated visually.
+ [b]Note:[/b] The method / audio / animation playback tracks will not be processed by this method.
</description>
</method>
</methods>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 21ccf79fe2..ce4d7693d8 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -679,7 +679,7 @@
</description>
</operator>
<operator name="operator []">
- <return type="void" />
+ <return type="Variant" />
<param index="0" name="index" type="int" />
<description>
Returns a reference to the element of type [Variant] at the specified location. Arrays start at index 0. [param index] can be a zero or positive value to start from the beginning, or a negative value to start from the end. Out-of-bounds array access causes a run-time error, which will result in an error being printed and the project execution pausing if run from the editor.
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index f7764d5e32..7b86afcc4c 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -65,11 +65,15 @@
<param index="1" name="arrays" type="Array" />
<param index="2" name="blend_shapes" type="Array[]" default="[]" />
<param index="3" name="lods" type="Dictionary" default="{}" />
- <param index="4" name="compress_flags" type="int" enum="Mesh.ArrayFormat" default="0" />
- <description>
- Creates a new surface.
- Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ <param index="4" name="flags" type="int" enum="Mesh.ArrayFormat" default="0" />
+ <description>
+ Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
+ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
+ [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
</method>
<method name="clear_blend_shapes">
diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml
index b2c5a1756f..be4a649b50 100644
--- a/doc/classes/BackBufferCopy.xml
+++ b/doc/classes/BackBufferCopy.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BackBufferCopy" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts through the [code]texture(SCREEN_TEXTURE, ...)[/code] function.
+ Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts using the screen texture (i.e. a uniform sampler with ``hint_screen_texture``).
</brief_description>
<description>
- Node for back-buffering the currently-displayed screen. The region defined in the [BackBufferCopy] node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer.
+ Node for back-buffering the currently-displayed screen. The region defined in the [BackBufferCopy] node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the screen texture in your shader scripts to access the buffer.
[b]Note:[/b] Since this node inherits from [Node2D] (and not [Control]), anchors and margins won't apply to child [Control]-derived nodes. This can be problematic when resizing the window. To avoid this, add [Control]-derived nodes as [i]siblings[/i] to the [BackBufferCopy] node instead of adding them as children.
</description>
<tutorials>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index aedb8f4420..68f62d1c00 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -70,7 +70,7 @@
[Shortcut] associated to the button.
</member>
<member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback" default="true">
- 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.
+ If [code]true[/code], the button will highlight for a short amount of time when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate without any visual feedback.
</member>
<member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled" default="true">
If [code]true[/code], the button will add information about its shortcut in the tooltip.
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index f29525038e..dd01de3607 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -16,19 +16,6 @@
Returns the [NodePath] to the external [Skeleton3D] node, if one has been set.
</description>
</method>
- <method name="get_override_mode" qualifiers="const" is_deprecated="true">
- <return type="int" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Returns the override mode for the BoneAttachment3D node (0=global / 1=local).
- </description>
- </method>
- <method name="get_override_pose" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the BoneAttachment3D node is overriding the bone pose of the bone it's attached to.
- </description>
- </method>
<method name="get_use_external_skeleton" qualifiers="const">
<return type="bool" />
<description>
@@ -49,21 +36,6 @@
Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code].
</description>
</method>
- <method name="set_override_mode" is_deprecated="true">
- <return type="void" />
- <param index="0" name="override_mode" type="int" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Sets the override mode for the BoneAttachment3D node (0=global / 1=local). The override mode defines which of the bone poses the BoneAttachment3D node will override.
- </description>
- </method>
- <method name="set_override_pose">
- <return type="void" />
- <param index="0" name="override_pose" type="bool" />
- <description>
- Sets whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone.
- </description>
- </method>
<method name="set_use_external_skeleton">
<return type="void" />
<param index="0" name="use_external_skeleton" type="bool" />
@@ -79,5 +51,8 @@
<member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
The name of the attached bone.
</member>
+ <member name="override_pose" type="bool" setter="set_override_pose" getter="get_override_pose" default="false">
+ Whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone. When set to [code]false[/code], the BoneAttachment3D will always be set to the bone's transform.
+ </member>
</members>
</class>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index d1fdaef29c..79e65f3472 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -14,7 +14,7 @@
func test():
var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ".
- callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(Node.gd)::print_args".
+ callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(node.gd)::print_args".
callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript]
[csharp]
diff --git a/doc/classes/CanvasGroup.xml b/doc/classes/CanvasGroup.xml
index 37827defec..6eeff8fef3 100644
--- a/doc/classes/CanvasGroup.xml
+++ b/doc/classes/CanvasGroup.xml
@@ -9,8 +9,10 @@
[codeblock]
shader_type canvas_item;
+ uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a &gt; 0.0001) {
c.rgb /= c.a;
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 5171e0acbe..5279574d5a 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -45,7 +45,8 @@
<param index="6" name="width" type="float" default="1.0" />
<param index="7" name="antialiased" type="bool" default="false" />
<description>
- Draws a unfilled arc between the given angles. The larger the value of [param point_count], the smoother the curve. See also [method draw_circle].
+ Draws an unfilled arc between the given angles. The larger the value of [param point_count], the smoother the curve. See also [method draw_circle].
+ The arc is drawn from [param start_angle] towards the value of [param end_angle] so in clockwise direction if [code]start_angle &lt; end_angle[/code] and counter-clockwise otherwise. Passing the same angles but in reversed order will produce the same arc. If absolute difference of [param start_angle] and [param end_angle] is greater than [constant @GDScript.TAU] radians, then a full circle arc is drawn (i.e. arc will not overlap itself).
</description>
</method>
<method name="draw_char" qualifiers="const">
@@ -95,10 +96,12 @@
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="2" name="color" type="Color" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<param index="4" name="dash" type="float" default="2.0" />
+ <param index="5" name="aligned" type="bool" default="true" />
<description>
Draws a dashed line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline].
+ If [param width] is negative, then a two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the line parts will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_end_animation">
@@ -129,10 +132,11 @@
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="2" name="color" type="Color" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<param index="4" name="antialiased" type="bool" default="false" />
<description>
Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. See also [method draw_multiline] and [method draw_polyline].
+ If [param width] is negative, then a two-point primitive will be drawn instead of a four-point one. This means that when the CanvasItem is scaled, the line will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_mesh">
@@ -164,18 +168,20 @@
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="color" type="Color" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<description>
Draws multiple disconnected lines with a uniform [param color]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_multiline_colors">
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="colors" type="PackedColorArray" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<description>
Draws multiple disconnected lines with a uniform [param width] and segment-by-segment coloring. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_multiline_string" qualifiers="const">
@@ -259,7 +265,6 @@
<param index="1" name="colors" type="PackedColorArray" />
<param index="2" name="uvs" type="PackedVector2Array" />
<param index="3" name="texture" type="Texture2D" default="null" />
- <param index="4" name="width" type="float" default="1.0" />
<description>
Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. If 0 points or more than 4 points are specified, nothing will be drawn and an error message will be printed. See also [method draw_line], [method draw_polyline], [method draw_polygon], and [method draw_rect].
</description>
@@ -269,10 +274,12 @@
<param index="0" name="rect" type="Rect2" />
<param index="1" name="color" type="Color" />
<param index="2" name="filled" type="bool" default="true" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<description>
Draws a rectangle. If [param filled] is [code]true[/code], the rectangle will be filled with the [param color] specified. If [param filled] is [code]false[/code], the rectangle will be drawn as a stroke with the [param color] and [param width] specified.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
[b]Note:[/b] [param width] is only effective if [param filled] is [code]false[/code].
+ [b]Note:[/b] Unfilled rectangles drawn with a negative [param width] may not display perfectly. For example, corners may be missing or brighter due to overlapping lines (for a translucent [param color]).
</description>
</method>
<method name="draw_set_transform">
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 3ceb8967a0..df40d2a4cf 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -132,12 +132,6 @@
Perform an indent as if the user activated the "ui_text_indent" action.
</description>
</method>
- <method name="do_unindent">
- <return type="void" />
- <description>
- Perform an unindent as if the user activated the "ui_text_unindent" action.
- </description>
- </method>
<method name="fold_all_lines">
<return type="void" />
<description>
@@ -423,7 +417,7 @@
<method name="unindent_lines">
<return type="void" />
<description>
- Unindents selected lines, or in the case of no selection the caret line by one.
+ Unindents selected lines, or in the case of no selection the caret line by one. Same as performing "ui_text_unindent" action.
</description>
</method>
<method name="update_code_completion_options">
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index c302963b92..31b5842930 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -216,13 +216,13 @@
<signal name="mouse_entered">
<description>
Emitted when the mouse pointer enters any of this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
- [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question.
+ [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question.
</description>
</signal>
<signal name="mouse_exited">
<description>
Emitted when the mouse pointer exits all this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
- [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question.
+ [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question.
</description>
</signal>
</signals>
@@ -232,7 +232,7 @@
Automatically re-added to the physics simulation when the [Node] is processed again.
</constant>
<constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode">
- When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody3D] can't be affected by forces or other bodies while static.
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area3D]. [PhysicsBody3D] can't be affected by forces or other bodies while static.
Automatically set [PhysicsBody3D] back to its original mode when the [Node] is processed again.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode">
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 08964cf21d..7082eff97d 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -180,14 +180,14 @@
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
- var tooltip = preload("res://SomeTooltipScene.tscn").instantiate()
+ var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
tooltip.get_node("Label").text = for_text
return tooltip
[/gdscript]
[csharp]
public override Godot.Control _MakeCustomTooltip(String forText)
{
- Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://SomeTooltipScene.tscn").Instantiate();
+ Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate();
tooltip.GetNode&lt;Label&gt;("Label").Text = forText;
return tooltip;
}
@@ -196,12 +196,12 @@
</description>
</method>
<method name="_structured_text_parser" qualifiers="virtual const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="args" type="Array" />
<param index="1" name="text" type="String" />
<description>
User defined BiDi algorithm override function.
- Returns an [Array] of [Vector2i] text ranges, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
+ Returns an [Array] of [Vector3i] text ranges and text base directions, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
</description>
</method>
<method name="accept_event">
diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml
index 32dc8f673b..66d2280280 100644
--- a/doc/classes/ConvexPolygonShape3D.xml
+++ b/doc/classes/ConvexPolygonShape3D.xml
@@ -4,7 +4,7 @@
Convex polygon shape resource for 3D physics.
</brief_description>
<description>
- 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape2D]s can be manually drawn in the editor using the [CollisionPolygon3D] node.
+ 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape3D]s can be manually drawn in the editor using the [CollisionPolygon3D] node.
[b]Convex decomposition:[/b] Concave objects' collisions can be represented accurately using [i]several[/i] [ConvexPolygonShape3D]s. This allows dynamic physics bodies to have complex concave collisions (at a performance cost). This is available in the editor by selecting the [MeshInstance3D], going to the [b]Mesh[/b] menu and choosing [b]Create Multiple Convex Collision Siblings[/b]. Alternatively, [method MeshInstance3D.create_multiple_convex_collisions] can be called in a script to perform this decomposition at run-time.
[b]Performance:[/b] [ConvexPolygonShape3D] is faster to check collisions against compared to [ConcavePolygonShape3D], but it is slower than primitive collision shapes such as [SphereShape3D] or [BoxShape3D]. Its use should generally be limited to medium-sized objects that cannot have their collision accurately represented by a primitive shape.
</description>
diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml
index 9af8be99ef..457513b8aa 100644
--- a/doc/classes/DTLSServer.xml
+++ b/doc/classes/DTLSServer.xml
@@ -8,7 +8,7 @@
Below a small example of how to use it:
[codeblocks]
[gdscript]
- # ServerNode.gd
+ # server_node.gd
extends Node
var dtls := DTLSServer.new()
@@ -86,7 +86,7 @@
[/codeblocks]
[codeblocks]
[gdscript]
- # ClientNode.gd
+ # client_node.gd
extends Node
var dtls := PacketPeerDTLS.new()
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 5da6cf8102..832adb6e98 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1694,7 +1694,10 @@
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">
+ <constant name="WINDOW_FLAG_MOUSE_PASSTHROUGH" value="7" enum="WindowFlags">
+ All mouse events are passed to the underlying window of the same application.
+ </constant>
+ <constant name="WINDOW_FLAG_MAX" value="8" enum="WindowFlags">
Max value of the [enum WindowFlags].
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index e8df6ae7fe..5f33c68a7d 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -71,12 +71,6 @@
This will not import the file. To reimport, call [method reimport_files] or [method scan] methods.
</description>
</method>
- <method name="update_script_classes">
- <return type="void" />
- <description>
- Scans the script files and updates the list of custom class names.
- </description>
- </method>
</methods>
<signals>
<signal name="filesystem_changed">
@@ -96,6 +90,11 @@
Emitted if at least one resource is reloaded when the filesystem is scanned.
</description>
</signal>
+ <signal name="script_classes_updated">
+ <description>
+ Emitted when the list of global script classes gets updated.
+ </description>
+ </signal>
<signal name="sources_changed">
<param index="0" name="exist" type="bool" />
<description>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index b44c1d7ffa..370be8e9f3 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -143,7 +143,7 @@
[gdscript]
func _forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
- overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white)
+ overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
@@ -347,7 +347,7 @@
[codeblock]
func _set_state(data):
zoom = data.get("zoom", 1.0)
- preferred_color = data.get("my_color", Color.white)
+ preferred_color = data.get("my_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -359,7 +359,7 @@
[codeblock]
func _set_window_layout(configuration):
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
- $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.white)
+ $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -467,6 +467,14 @@
See [method add_inspector_plugin] for an example of how to register a plugin.
</description>
</method>
+ <method name="add_resource_conversion_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceConversionPlugin" />
+ <description>
+ Registers a new [EditorResourceConversionPlugin]. Resource conversion plugins are used to add custom resource converters to the editor inspector.
+ See [EditorResourceConversionPlugin] for an example of how to create a resource conversion plugin.
+ </description>
+ </method>
<method name="add_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
@@ -632,6 +640,13 @@
Removes a gizmo plugin registered by [method add_node_3d_gizmo_plugin].
</description>
</method>
+ <method name="remove_resource_conversion_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceConversionPlugin" />
+ <description>
+ Removes a resource conversion plugin registered by [method add_resource_conversion_plugin].
+ </description>
+ </method>
<method name="remove_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml
index c40bb1d91e..6bdfbbe40c 100644
--- a/doc/classes/EditorResourceConversionPlugin.xml
+++ b/doc/classes/EditorResourceConversionPlugin.xml
@@ -1,8 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Plugin for adding custom converters from one resource format to another in the editor resource picker context menu; for example, converting a [StandardMaterial3D] to a [ShaderMaterial].
</brief_description>
<description>
+ [EditorResourceConversionPlugin] is invoked when the context menu is brought up for a resource in the editor inspector. Relevant conversion plugins will appear as menu options to convert the given resource to a target type.
+ Below shows an example of a basic plugin that will convert an [ImageTexture] to a [PortableCompressedTexture2D].
+ [codeblocks]
+ [gdscript]
+ extends EditorResourceConversionPlugin
+
+ func _handles(resource : Resource):
+ return resource is ImageTexture
+
+ func _converts_to():
+ return "PortableCompressedTexture2D"
+
+ func _convert(itex : Resource):
+ var ptex = PortableCompressedTexture2D.new()
+ ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
+ return ptex
+ [/gdscript]
+ [/codeblocks]
+ To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.
</description>
<tutorials>
</tutorials>
@@ -11,17 +31,20 @@
<return type="Resource" />
<param index="0" name="resource" type="Resource" />
<description>
+ Takes an input [Resource] and converts it to the type given in [method _converts_to]. The returned [Resource] is the result of the conversion, and the input [Resource] remains unchanged.
</description>
</method>
<method name="_converts_to" qualifiers="virtual const">
<return type="String" />
<description>
+ Returns the class name of the target type of [Resource] that this plugin converts source resources to.
</description>
</method>
<method name="_handles" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="resource" type="Resource" />
<description>
+ Called to determine whether a particular [Resource] can be converted to the target resource type by this plugin.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 98f4789163..fca87f6a56 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -499,7 +499,7 @@
</member>
<member name="interface/editor/editor_language" type="String" setter="" getter="">
The language to use for the editor interface.
- Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
+ Translations are provided by the community. If you spot a mistake, [url=$DOCS_URL/contributing/documentation/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
</member>
<member name="interface/editor/expand_to_title" type="bool" setter="" getter="">
Expanding main editor window content to the title, if supported by [DisplayServer]. See [constant DisplayServer.WINDOW_FLAG_EXTEND_TO_TITLE].
@@ -741,7 +741,7 @@
</member>
<member name="text_editor/behavior/indent/type" type="int" setter="" getter="">
The indentation style to use (tabs or spaces).
- [b]Note:[/b] The [url=https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
+ [b]Note:[/b] The [url=$DOCS_URL/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
</member>
<member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter="">
If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor.
@@ -782,7 +782,7 @@
If [code]true[/code], the code completion tooltip will appear below the current line unless there is no space on screen below the current line. If [code]false[/code], the code completion tooltip will appear above the current line.
</member>
<member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter="">
- If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
+ If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
</member>
<member name="text_editor/help/class_reference_examples" type="int" setter="" getter="">
Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help.
diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
index cd96e740e8..4d6938e6aa 100644
--- a/doc/classes/EditorUndoRedoManager.xml
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorUndoRedoManager" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorUndoRedoManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manages undo history of scenes opened in the editor.
</brief_description>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 1ae4718536..127c5daf95 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -21,7 +21,10 @@
<param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
<description>
- Set the value of a shader parameter for this instance only.
+ Set the value of a shader uniform for this instance only ([url=$DOCS_URL/tutorials/shaders/shader_reference/shading_language.html#per-instance-uniforms]per-instance uniform[/url]). See also [method ShaderMaterial.set_shader_parameter] to assign a uniform on all instances using the same [ShaderMaterial].
+ [b]Note:[/b] For a shader uniform to be assignable on a per-instance basis, it [i]must[/i] be defined with [code]instance uniform ...[/code] rather than [code]uniform ...[/code] in the shader code.
+ [b]Note:[/b] [param name] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
+ [b]Note:[/b] Per-instance shader uniforms are currently only available in 3D, so there is no 2D equivalent of this method.
</description>
</method>
</methods>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index ed1b40488e..051e087611 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -489,7 +489,7 @@
var img = Image.new()
img.create(img_width, img_height, false, Image.FORMAT_RGBA8)
- img.set_pixel(1, 2, Color.red) # Sets the color at (1, 2) to red.
+ img.set_pixel(1, 2, Color.RED) # Sets the color at (1, 2) to red.
[/gdscript]
[csharp]
int imgWidth = 10;
@@ -517,7 +517,7 @@
var img = Image.new()
img.create(img_width, img_height, false, Image.FORMAT_RGBA8)
- img.set_pixelv(Vector2i(1, 2), Color.red) # Sets the color at (1, 2) to red.
+ img.set_pixelv(Vector2i(1, 2), Color.RED) # Sets the color at (1, 2) to red.
[/gdscript]
[csharp]
int imgWidth = 10;
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index b80857a7bf..10479dfcfe 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -27,9 +27,13 @@
<param index="5" name="name" type="String" default="&quot;&quot;" />
<param index="6" name="flags" type="int" default="0" />
<description>
- Creates a new surface, analogous to [method ArrayMesh.add_surface_from_arrays].
- Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
+ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
+ [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
</method>
<method name="clear">
diff --git a/doc/classes/JavaScriptBridge.xml b/doc/classes/JavaScriptBridge.xml
index 340c296eef..f79c11b334 100644
--- a/doc/classes/JavaScriptBridge.xml
+++ b/doc/classes/JavaScriptBridge.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The JavaScriptBridge singleton is implemented only in the Web export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs.
- [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
+ [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/contributing/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
</description>
<tutorials>
<link title="Exporting for the Web: Calling JavaScript from script">$DOCS_URL/tutorials/export/exporting_for_web.html#calling-javascript-from-script</link>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index 94e80ffb2b..1c1f48588f 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -227,10 +227,10 @@
Contains custom color channel 3. [PackedByteArray] if [code](format &gt;&gt; [constant ARRAY_FORMAT_CUSTOM3_SHIFT]) &amp; [constant ARRAY_FORMAT_CUSTOM_MASK])[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise.
</constant>
<constant name="ARRAY_BONES" value="10" enum="ArrayType">
- [PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element is a group of 4 numbers.
+ [PackedFloat32Array] or [PackedInt32Array] of bone indices. Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag.
</constant>
<constant name="ARRAY_WEIGHTS" value="11" enum="ArrayType">
- [PackedFloat32Array] of bone weights. Each element in groups of 4 floats.
+ [PackedFloat32Array] or [PackedFloat64Array] of bone weights in the range [code]0.0[/code] to [code]1.0[/code] (inclusive). Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag.
</constant>
<constant name="ARRAY_INDEX" value="12" enum="ArrayType">
[PackedInt32Array] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices.
@@ -341,6 +341,9 @@
<constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true">
Flag used to mark that the mesh contains up to 8 bone influences per vertex. This flag indicates that [constant ARRAY_BONES] and [constant ARRAY_WEIGHTS] elements will have double length.
</constant>
+ <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true">
+ Flag used to mark that the mesh intentionally contains no vertex array.
+ </constant>
<constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode">
Blend shapes are normalized.
</constant>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 6dab7b4ebe..1bc81ffb42 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -592,12 +592,12 @@
</description>
</method>
<method name="set_environment" qualifiers="const">
- <return type="bool" />
+ <return type="void" />
<param index="0" name="variable" type="String" />
<param index="1" name="value" type="String" />
<description>
Sets the value of the environment variable [param variable] to [param value]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
- [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows.
+ [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character. On Windows, there is a 32767 characters limit for the combined length of [param variable], [param value], and the [code]=[/code] and null terminator characters that will be registered in the environment block.
</description>
</method>
<method name="set_restart_on_exit">
@@ -637,6 +637,14 @@
[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows.
</description>
</method>
+ <method name="unset_environment" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="variable" type="String" />
+ <description>
+ Removes the environment [param variable] from the current environment, if it exists. The environment variable will be removed for the Godot process and any process executed with [method execute] after running [method unset_environment]. The removal of the environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
+ [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character.
+ </description>
+ </method>
</methods>
<members>
<member name="low_processor_usage_mode" type="bool" setter="set_low_processor_usage_mode" getter="is_in_low_processor_usage_mode" default="false">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index e015bec134..a9e17f4666 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -24,6 +24,7 @@
[b]Note:[/b] The [code]script[/code] is not exposed like most properties. To set or get an object's [Script] in code, use [method set_script] and [method get_script], respectively.
</description>
<tutorials>
+ <link title="Object class introduction">$DOCS_URL/contributing/development/core_and_modules/object_class.html</link>
<link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link>
<link title="Object notifications">$DOCS_URL/tutorials/best_practices/godot_notifications.html</link>
</tutorials>
diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml
index 3ec03fede4..4d789ceb3f 100644
--- a/doc/classes/PhysicsServer3DManager.xml
+++ b/doc/classes/PhysicsServer3DManager.xml
@@ -15,7 +15,7 @@
<param index="0" name="name" type="String" />
<param index="1" name="create_callback" type="Callable" />
<description>
- Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
+ Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer3D] object.
</description>
</method>
<method name="set_default_server">
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index fbe8afa8d1..aa09081e3e 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -38,6 +38,7 @@
<param index="0" name="normal" type="Vector3" />
<description>
Creates a plane from the normal vector. The plane will intersect the origin.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -46,6 +47,7 @@
<param index="1" name="d" type="float" />
<description>
Creates a plane from the normal vector and the plane's distance from the origin.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -54,6 +56,7 @@
<param index="1" name="point" type="Vector3" />
<description>
Creates a plane from the normal vector and a point on the plane.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -67,12 +70,6 @@
</constructor>
</constructors>
<methods>
- <method name="center" qualifiers="const">
- <return type="Vector3" />
- <description>
- Returns the center of the plane.
- </description>
- </method>
<method name="distance_to" qualifiers="const">
<return type="float" />
<param index="0" name="point" type="Vector3" />
@@ -80,6 +77,12 @@
Returns the shortest distance from the plane to the position [param point]. If the point is above the plane, the distance will be positive. If below, the distance will be negative.
</description>
</method>
+ <method name="get_center" qualifiers="const">
+ <return type="Vector3" />
+ <description>
+ Returns the center of the plane.
+ </description>
+ </method>
<method name="has_point" qualifiers="const">
<return type="bool" />
<param index="0" name="point" type="Vector3" />
@@ -152,7 +155,7 @@
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is [code]d[/code], while the [code](a, b, c)[/code] coordinates are represented by the [member normal] property.
</member>
<member name="normal" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The normal of the plane, which must be normalized.
+ The normal of the plane, which must be a unit vector.
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is the vector [code](a, b, c)[/code], where [code]d[/code] is the [member d] property.
</member>
<member name="x" type="float" setter="" getter="" default="0.0">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index cfcfca9880..de41edc305 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -84,6 +84,25 @@
GD.Print(ProjectSettings.GetSetting("application/config/custom_description", "No description specified."));
[/csharp]
[/codeblocks]
+ [b]Note:[/b] This method doesn't take potential feature overrides into account automatically. Use [method get_setting_with_override] to handle seamlessly.
+ </description>
+ </method>
+ <method name="get_setting_with_override" qualifiers="const">
+ <return type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <description>
+ Similar to [method get_setting], but applies feature tag overrides if any exists and is valid.
+ [b]Example:[/b]
+ If the following setting override exists "application/config/name.windows", and the following code is executed:
+ [codeblocks]
+ [gdscript]
+ print(ProjectSettings.get_setting_with_override("application/config/name"))
+ [/gdscript]
+ [csharp]
+ GD.Print(ProjectSettings.GetSettingWithOverride("application/config/name"));
+ [/csharp]
+ [/codeblocks]
+ Then the overridden setting will be returned instead if the project is running on the [i]Windows[/i] operating system.
</description>
</method>
<method name="globalize_path" qualifiers="const">
@@ -633,6 +652,13 @@
See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported.
</member>
+ <member name="dotnet/project/assembly_name" type="String" setter="" getter="" default="&quot;&quot;">
+ Name of the .NET assembly. This name is used as the name of the [code].csproj[/code] and [code].sln[/code] files. By default, it's set to the name of the project ([member application/config/name]) allowing to change it in the future without affecting the .NET assembly.
+ </member>
+ <member name="dotnet/project/solution_directory" type="String" setter="" getter="" default="&quot;&quot;">
+ Directory that contains the [code].sln[/code] file. By default, the [code].sln[/code] files is in the root of the project directory, next to the [code]project.godot[/code] and [code].csproj[/code] files.
+ Changing this value allows setting up a multi-project scenario where there are multiple [code].csproj[/code]. Keep in mind that the Godot project is considered one of the C# projects in the workspace and it's root directory should contain the [code]project.godot[/code] and [code].csproj[/code] next to each other.
+ </member>
<member name="editor/movie_writer/disable_vsync" type="bool" setter="" getter="" default="false">
If [code]true[/code], requests V-Sync to be disabled when writing a movie (similar to setting [member display/window/vsync/vsync_mode] to [b]Disabled[/b]). This can speed up video writing if the hardware is fast enough to render, encode and save the video at a framerate higher than the monitor's refresh rate.
[b]Note:[/b] [member editor/movie_writer/disable_vsync] has no effect if the operating system or graphics driver forces V-Sync with no way for applications to disable it.
@@ -741,6 +767,9 @@
<member name="gui/theme/lcd_subpixel_layout" type="int" setter="" getter="" default="1">
LCD subpixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout].
</member>
+ <member name="gui/timers/button_shortcut_feedback_highlight_time" type="float" setter="" getter="" default="0.2">
+ When [member BaseButton.shortcut_feedback] is enabled, this is the time the [BaseButton] will remain highlighted after a shortcut.
+ </member>
<member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="" default="2000">
Timer setting for incremental search in [Tree], [ItemList], etc. controls (in milliseconds).
</member>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 7675a37cbd..3d7fb0d445 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -217,7 +217,7 @@
<param index="1" name="from" type="Vector2" />
<param index="2" name="to" type="Vector2" />
<param index="3" name="color" type="Color" />
- <param index="4" name="width" type="float" default="1.0" />
+ <param index="4" name="width" type="float" default="-1.0" />
<param index="5" name="antialiased" type="bool" default="false" />
<description>
</description>
@@ -303,7 +303,6 @@
<param index="2" name="colors" type="PackedColorArray" />
<param index="3" name="uvs" type="PackedVector2Array" />
<param index="4" name="texture" type="RID" />
- <param index="5" name="width" type="float" default="1.0" />
<description>
</description>
</method>
@@ -3337,7 +3336,7 @@
<param index="0" name="viewport" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
- If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
+ If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the screen_texture. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
</description>
</method>
<method name="viewport_set_scaling_3d_mode">
@@ -3811,6 +3810,8 @@
</constant>
<constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true">
</constant>
+ <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true">
+ </constant>
<constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType">
Primitive to draw consists of points.
</constant>
diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml
index 17904697e6..5c0079f408 100644
--- a/doc/classes/ResourcePreloader.xml
+++ b/doc/classes/ResourcePreloader.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ResourcePreloader" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Resource Preloader Node.
+ Preloads a list of resources inside a scene.
</brief_description>
<description>
- This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader.
+ This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader. You can add the resources using the ResourcePreloader tab when the node is selected.
GDScript has a simplified [method @GDScript.preload] built-in method which can be used in most situations, leaving the use of [ResourcePreloader] for more advanced scenarios.
</description>
<tutorials>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index dd291a425d..5550bf0955 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -283,6 +283,7 @@
<return type="void" />
<param index="0" name="font_size" type="int" />
<description>
+ Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration.
</description>
</method>
<method name="push_hint">
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 1af7ac4fc5..a2346822e5 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -23,7 +23,8 @@
<param index="1" name="value" type="Variant" />
<description>
Changes the value set for this material of a uniform in the shader.
- [b]Note:[/b] [param param] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] [param param] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
+ [b]Note:[/b] Changes to the shader uniform will be effective on all instances using this [ShaderMaterial]. To prevent this, use per-instance uniforms with [method GeometryInstance3D.set_instance_shader_parameter] or duplicate the [ShaderMaterial] resource using [method Resource.duplicate]. Per-instance uniforms allow for better shader reuse and are therefore faster, so they should be preferred over duplicating the [ShaderMaterial] when possible.
</description>
</method>
</methods>
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index 808f93b491..39bdc5c796 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -16,7 +16,7 @@
<param index="0" name="delta" type="float" />
<param index="1" name="execution_mode" type="int" />
<description>
- Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned.
+ Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton2D has one assigned.
</description>
</method>
<method name="get_bone">
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 3bd0e04b92..70986ba06a 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -7,6 +7,7 @@
Skeleton3D provides a hierarchical interface for managing bones, including pose, rest and animation (see [Animation]). It can also use ragdoll physics.
The overall transform of a bone with respect to the skeleton is determined by the following hierarchical order: rest pose, custom pose and pose.
Note that "global pose" below refers to the overall transform of the bone with respect to skeleton, so it not the actual global/world transform of the bone.
+ To setup different types of inverse kinematics, consider using [SkeletonIK3D], or add a custom IK implementation in [method Node._process] as a child node.
</description>
<tutorials>
<link title="3D Inverse Kinematics Demo">https://godotengine.org/asset-library/asset/523</link>
@@ -32,26 +33,11 @@
Removes the global pose override on all bones in the skeleton.
</description>
</method>
- <method name="clear_bones_local_pose_override" is_deprecated="true">
- <return type="void" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Removes the local pose override on all bones in the skeleton.
- </description>
- </method>
<method name="create_skin_from_rest_transforms">
<return type="Skin" />
<description>
</description>
</method>
- <method name="execute_modifications" is_deprecated="true">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <param index="1" name="execution_mode" type="int" />
- <description>
- Executes all the modifications on the [SkeletonModificationStack3D], if the Skeleton3D has one assigned.
- </description>
- </method>
<method name="find_bone" qualifiers="const">
<return type="int" />
<param index="0" name="name" type="String" />
@@ -113,13 +99,6 @@
Returns the global rest transform for [param bone_idx].
</description>
</method>
- <method name="get_bone_local_pose_override" qualifiers="const">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Returns the local pose override transform for [param bone_idx].
- </description>
- </method>
<method name="get_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="bone_idx" type="int" />
@@ -167,43 +146,18 @@
Returns the rest transform for a bone [param bone_idx].
</description>
</method>
- <method name="get_modification_stack" is_deprecated="true">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the modification stack attached to this skeleton, if one exists.
- </description>
- </method>
<method name="get_parentless_bones" qualifiers="const">
<return type="PackedInt32Array" />
<description>
Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton.
</description>
</method>
- <method name="global_pose_to_local_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="global_pose" type="Transform3D" />
- <description>
- Takes the passed-in global pose and converts it to local pose transform.
- This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override].
- </description>
- </method>
- <method name="global_pose_to_world_transform" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="global_pose" type="Transform3D" />
- <description>
- Deprecated. Use [Node3D] apis instead.
- Takes the passed-in global pose and converts it to a world transform.
- This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example.
- </description>
- </method>
- <method name="global_pose_z_forward_to_bone_forward" is_deprecated="true">
- <return type="Basis" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="basis" type="Basis" />
+ <method name="get_version" qualifiers="const">
+ <return type="int" />
<description>
- Rotates the given [Basis] so that the forward axis of the Basis is facing in the forward direction of the bone at [param bone_idx].
- This is helper function to make using [method Transform3D.looking_at] easier with bone poses.
+ Returns the number of times the bone hierarchy has changed within this skeleton, including renames.
+ The Skeleton version is not serialized: only use within a single instance of Skeleton3D.
+ Use for invalidating caches in IK solvers and other nodes which process bones.
</description>
</method>
<method name="is_bone_enabled" qualifiers="const">
@@ -213,15 +167,6 @@
Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
- <method name="local_pose_to_global_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="local_pose" type="Transform3D" />
- <description>
- Converts the passed-in local pose to a global pose relative to the inputted bone, [param bone_idx].
- This could be used to convert [method get_bone_pose] for use with the [method set_bone_global_pose_override] function.
- </description>
- </method>
<method name="localize_rests">
<return type="void" />
<description>
@@ -298,19 +243,6 @@
[b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform
</description>
</method>
- <method name="set_bone_local_pose_override" is_deprecated="true">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="pose" type="Transform3D" />
- <param index="2" name="amount" type="float" />
- <param index="3" name="persistent" type="bool" default="false" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Sets the local pose transform, [param pose], for the bone at [param bone_idx].
- [param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
- [b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose.
- </description>
- </method>
<method name="set_bone_name">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -356,13 +288,6 @@
Sets the rest transform for bone [param bone_idx].
</description>
</method>
- <method name="set_modification_stack" is_deprecated="true">
- <return type="void" />
- <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets the modification stack for this skeleton to the passed-in modification stack, [param modification_stack].
- </description>
- </method>
<method name="unparent_bone_and_rest">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -370,15 +295,6 @@
Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
- <method name="world_transform_to_global_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="world_transform" type="Transform3D" />
- <description>
- Deprecated. Use [Node3D] apis instead.
- Takes the passed-in global transform and converts it to a global pose.
- This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example.
- </description>
- </method>
</methods>
<members>
<member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index 77aaf0213b..3a78f13bff 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -56,7 +56,7 @@
<method name="get_modification_stack">
<return type="SkeletonModificationStack2D" />
<description>
- Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on.
+ Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton2D the modification is operating on.
</description>
</method>
<method name="set_editor_draw_gizmo">
diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml
deleted file mode 100644
index 25431ea96f..0000000000
--- a/doc/classes/SkeletonModification3D.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A resource that operates on bones in a [Skeleton3D].
- </brief_description>
- <description>
- This resource provides an interface that can be expanded so code that operates on bones in a [Skeleton3D] can be mixed and matched together to create complex interactions.
- This is used to provide Godot with a flexible and powerful Inverse Kinematics solution that can be adapted for many different uses.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="_execute" qualifiers="virtual">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <description>
- Executes the given modification. This is where the modification performs whatever function it is designed to do.
- </description>
- </method>
- <method name="_setup_modification" qualifiers="virtual">
- <return type="void" />
- <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets up the modification so it can be executed. This function should be called automatically by the [SkeletonModificationStack3D] containing this modification.
- If you need to initialize a modification before use, this is the place to do it!
- </description>
- </method>
- <method name="clamp_angle">
- <return type="float" />
- <param index="0" name="angle" type="float" />
- <param index="1" name="min" type="float" />
- <param index="2" name="max" type="float" />
- <param index="3" name="invert" type="bool" />
- <description>
- Takes a angle and clamps it so it is within the passed-in [param min] and [param max] range. [param invert] will inversely clamp the angle, clamping it to the range outside of the given bounds.
- </description>
- </method>
- <method name="get_is_setup" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether this modification has been successfully setup or not.
- </description>
- </method>
- <method name="get_modification_stack">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the [SkeletonModificationStack3D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on.
- </description>
- </method>
- <method name="set_is_setup">
- <return type="void" />
- <param index="0" name="is_setup" type="bool" />
- <description>
- Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack3D] the modification is bound to should handle setting the modification up.
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="true">
- When true, the modification's [method _execute] function will be called by the [SkeletonModificationStack3D].
- </member>
- <member name="execution_mode" type="int" setter="set_execution_mode" getter="get_execution_mode" default="0">
- The execution mode for the modification. This tells the modification stack when to execute the modification. Some modifications have settings that are only available in certain execution modes.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml
deleted file mode 100644
index 90b2e78449..0000000000
--- a/doc/classes/SkeletonModification3DCCDIK.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that uses CCDIK to manipulate a series of bones to reach a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm called Cyclic Coordinate Descent Inverse Kinematics, or CCDIK, to manipulate a chain of bones in a Skeleton so it reaches a defined target.
- CCDIK works by rotating a set of bones, typically called a "bone chain", on a single axis. Each bone is rotated to face the target from the tip (by default), which over a chain of bones allow it to rotate properly to reach the target. Because the bones only rotate on a single axis, CCDIK [i]can[/i] look more robotic than other IK solvers.
- [b]Note:[/b] The CCDIK modifier has [code]ccdik_joints[/code], which are the data objects that hold the data for each joint in the CCDIK chain. This is different from a bone! CCDIK joints hold the data needed for each bone in the bone chain used by CCDIK.
- CCDIK also fully supports angle constraints, allowing for more control over how a solution is met.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_ccdik_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_ccdik_axis" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the integer representing the joint axis of the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_angle_max" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_angle_min" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_invert" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_invert] for details.
- </description>
- </method>
- <method name="get_ccdik_joint_enable_joint_constraint" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Enables angle constraints to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_ccdik_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_index" type="int" />
- <description>
- Sets the bone index, [param bone_index], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the CCDIK joint based on data provided by the linked skeleton.
- </description>
- </method>
- <method name="set_ccdik_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the CCDIK joint based on data provided by the linked skeleton.
- </description>
- </method>
- <method name="set_ccdik_joint_ccdik_axis">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="axis" type="int" />
- <description>
- Sets the joint axis of the CCDIK joint at [param joint_idx] to the passed-in joint axis, [param axis].
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_angle_max">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="max_angle" type="float" />
- <description>
- Sets the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_angle_min">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="min_angle" type="float" />
- <description>
- Sets the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_invert">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="invert" type="bool" />
- <description>
- Sets whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint.
- An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
- </description>
- </method>
- <method name="set_ccdik_joint_enable_joint_constraint">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="enable" type="bool" />
- <description>
- Sets whether joint constraints are enabled for the CCDIK joint at [param joint_idx].
- </description>
- </method>
- </methods>
- <members>
- <member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0">
- The number of CCDIK joints in the CCDIK modification.
- </member>
- <member name="high_quality_solve" type="bool" setter="set_use_high_quality_solve" getter="get_use_high_quality_solve" default="true">
- When true, the CCDIK algorithm will perform a higher quality solve that returns more natural results. A high quality solve requires more computation power to solve though, and therefore can be disabled to save performance.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to.
- </member>
- <member name="tip_nodepath" type="NodePath" setter="set_tip_node" getter="get_tip_node" default="NodePath(&quot;&quot;)">
- The end position of the CCDIK chain. Typically, this should be a child of a [BoneAttachment3D] node attached to the final bone in the CCDIK chain, where the child node is offset so it is at the end of the final bone.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml
deleted file mode 100644
index a2bec2b559..0000000000
--- a/doc/classes/SkeletonModification3DFABRIK.xml
+++ /dev/null
@@ -1,161 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that uses FABRIK to manipulate a series of bones to reach a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm called Forward And Backward Reaching Inverse Kinematics, or FABRIK, to rotate a bone chain so that it reaches a target.
- FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other.
- Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification3DCCDIK], though FABRIK currently does not support joint constraints.
- [b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from a bone! FABRIK joints hold the data needed for each bone in the bone chain used by FABRIK.
- To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="fabrik_joint_auto_calculate_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Will attempt to automatically calculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_auto_calculate_length" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether this modification will attempt to autocalculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_length" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the length of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_magnet" qualifiers="const">
- <return type="Vector3" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the magnet vector of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_tip_node" qualifiers="const">
- <return type="NodePath" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the [Node3D]-based node placed at the tip of the FABRIK joint at [param joint_idx], if one has been set.
- </description>
- </method>
- <method name="get_fabrik_joint_use_target_basis" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean indicating whether the FABRIK joint uses the target's [Basis] for its rotation.
- [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
- </description>
- </method>
- <method name="get_fabrik_joint_use_tip_node" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Sets the [Node3D]-based node that will be used as the tip of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_fabrik_joint_auto_calculate_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="auto_calculate_length" type="bool" />
- <description>
- When [code]true[/code], this modification will attempt to automatically calculate the length of the bone for the FABRIK joint at [param joint_idx]. It does this by either using the tip node assigned, if there is one assigned, or the distance the of the bone's children, if the bone has any. If the bone has no children and no tip node is assigned, then the modification [b]cannot[/b] autocalculate the joint's length. In this case, the joint length should be entered manually or a tip node assigned.
- </description>
- </method>
- <method name="set_fabrik_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_index" type="int" />
- <description>
- Sets the bone index, [param bone_index], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_fabrik_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_fabrik_joint_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="length" type="float" />
- <description>
- Sets the joint length, [param length], of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_fabrik_joint_magnet">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="magnet_position" type="Vector3" />
- <description>
- Sets the magenet position to [param magnet_position] for the joint at [param joint_idx]. The magnet position is used to nudge the joint in that direction when solving, which gives some control over how that joint will bend when being solved.
- </description>
- </method>
- <method name="set_fabrik_joint_tip_node">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="tip_node" type="NodePath" />
- <description>
- Sets the nodepath of the FARIK joint at [param joint_idx] to [param tip_node]. The tip node is used to calculate the length of the FABRIK joint when set to automatically calculate joint length.
- [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the bone that this FABRIK joint operates on, with the child node being offset so it is at the end of the bone.
- </description>
- </method>
- <method name="set_fabrik_joint_use_target_basis">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_target_basis" type="bool" />
- <description>
- Sets whether the FABRIK joint at [param joint_idx] uses the target's [Basis] for its rotation.
- [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
- </description>
- </method>
- <method name="set_fabrik_joint_use_tip_node">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_tip_node" type="bool" />
- <description>
- Sets whether the tip node should be used when autocalculating the joint length for the FABRIK joint at [param joint_idx]. This will only work if there is a node assigned to the tip nodepath for this joint.
- </description>
- </method>
- </methods>
- <members>
- <member name="chain_max_iterations" type="int" setter="set_chain_max_iterations" getter="get_chain_max_iterations" default="10">
- The number of times FABRIK will try to solve each time the [code]execute[/code] function is called. Setting this value to a lower number will be result in better performance, but this can also result in harsher movements and slower solves.
- </member>
- <member name="chain_tolerance" type="float" setter="set_chain_tolerance" getter="get_chain_tolerance" default="0.01">
- The minimum distance the target has to be from the tip of the final bone in the bone chain. Setting this value to a higher number allows for greater performance, but less accurate solves.
- </member>
- <member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0">
- The amount of FABRIK joints in the FABRIK modification.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml
deleted file mode 100644
index 304f08bb20..0000000000
--- a/doc/classes/SkeletonModification3DJiggle.xml
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that jiggles bones as they move towards a target.
- </brief_description>
- <description>
- This modification moves a series of bones, typically called a bone chain, towards a target. What makes this modification special is that it calculates the velocity and acceleration for each bone in the bone chain, and runs a very light physics-like calculation using the inputted values. This allows the bones to overshoot the target and "jiggle" around. It can be configured to act more like a spring, or sway around like cloth might.
- This modification is useful for adding additional motion to things like hair, the edges of clothing, and more. It has several settings to that allow control over how the joint moves when the target moves.
- [b]Note:[/b] The Jiggle modifier has [code]jiggle_joints[/code], which are the data objects that hold the data for each joint in the Jiggle chain. This is different from a bone! Jiggle joints hold the data needed for each bone in the bone chain used by the Jiggle modification.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_collision_mask" qualifiers="const">
- <return type="int" />
- <description>
- Returns the collision mask that the Jiggle modifier will take into account when performing physics calculations.
- </description>
- </method>
- <method name="get_jiggle_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_damping" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of dampening of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_gravity" qualifiers="const">
- <return type="Vector3" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a [Vector3] representign the amount of gravity the Jiggle joint at [param joint_idx] is influenced by.
- </description>
- </method>
- <method name="get_jiggle_joint_mass" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of mass of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_override" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether the joint at [param joint_idx] is overriding the default jiggle joint data defined in the modification.
- </description>
- </method>
- <method name="get_jiggle_joint_roll" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of roll/twist applied to the bone that the Jiggle joint is applied to.
- </description>
- </method>
- <method name="get_jiggle_joint_stiffness" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the stiffness of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_use_gravity" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether the joint at [param joint_idx] is using gravity or not.
- </description>
- </method>
- <method name="get_use_colliders" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the Jiggle modifier is taking physics colliders into account when solving.
- </description>
- </method>
- <method name="set_collision_mask">
- <return type="void" />
- <param index="0" name="mask" type="int" />
- <description>
- Sets the collision mask that the Jiggle modifier takes into account when performing physics calculations.
- </description>
- </method>
- <method name="set_jiggle_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_jiggle_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="name" type="String" />
- <description>
- Sets the bone name, [param name], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_jiggle_joint_damping">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="damping" type="float" />
- <description>
- Sets the amount of dampening of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_gravity">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="gravity" type="Vector3" />
- <description>
- Sets the gravity vector of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_mass">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="mass" type="float" />
- <description>
- Sets the of mass of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_override">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="override" type="bool" />
- <description>
- Sets whether the Jiggle joint at [param joint_idx] should override the default Jiggle joint settings. Setting this to true will make the joint use its own settings rather than the default ones attached to the modification.
- </description>
- </method>
- <method name="set_jiggle_joint_roll">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist on the bone the Jiggle joint is attached to.
- </description>
- </method>
- <method name="set_jiggle_joint_stiffness">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="stiffness" type="float" />
- <description>
- Sets the of stiffness of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_use_gravity">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_gravity" type="bool" />
- <description>
- Sets whether the Jiggle joint at [param joint_idx] should use gravity.
- </description>
- </method>
- <method name="set_use_colliders">
- <return type="void" />
- <param index="0" name="use_colliders" type="bool" />
- <description>
- When [code]true[/code], the Jiggle modifier will use raycasting to prevent the Jiggle joints from rotating themselves into collision objects when solving.
- </description>
- </method>
- </methods>
- <members>
- <member name="damping" type="float" setter="set_damping" getter="get_damping" default="0.75">
- The default amount of dampening applied to the Jiggle joints, if they are not overridden. Higher values lead to more of the calculated velocity being applied.
- </member>
- <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3(0, -6, 0)">
- The default amount of gravity applied to the Jiggle joints, if they are not overridden.
- </member>
- <member name="jiggle_data_chain_length" type="int" setter="set_jiggle_data_chain_length" getter="get_jiggle_data_chain_length" default="0">
- The amount of Jiggle joints in the Jiggle modification.
- </member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" default="0.75">
- The default amount of mass assigned to the Jiggle joints, if they are not overridden. Higher values lead to faster movements and more overshooting.
- </member>
- <member name="stiffness" type="float" setter="set_stiffness" getter="get_stiffness" default="3.0">
- The default amount of stiffness assigned to the Jiggle joints, if they are not overridden. Higher values act more like springs, quickly moving into the correct position.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the Jiggle modification. This node is what the Jiggle chain will attempt to rotate the bone chain to.
- </member>
- <member name="use_gravity" type="bool" setter="set_use_gravity" getter="get_use_gravity" default="false">
- Whether the gravity vector, [member gravity], should be applied to the Jiggle joints, assuming they are not overriding the default settings.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml
deleted file mode 100644
index aeed953ca9..0000000000
--- a/doc/classes/SkeletonModification3DLookAt.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that rotates a bone to look at a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] rotates a bone to look a target. This is extremely helpful for moving character's heads to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_additional_rotation" qualifiers="const">
- <return type="Vector3" />
- <description>
- Returns the amount of extra rotation that is applied to the bone after the LookAt modification executes.
- </description>
- </method>
- <method name="get_lock_rotation_plane" qualifiers="const">
- <return type="int" />
- <description>
- Returns the plane that the LookAt modification is limiting rotation to.
- </description>
- </method>
- <method name="get_lock_rotation_to_plane" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the LookAt modification is limiting rotation to a single plane in 3D space.
- </description>
- </method>
- <method name="set_additional_rotation">
- <return type="void" />
- <param index="0" name="additional_rotation" type="Vector3" />
- <description>
- Sets the amount of extra rotation to be applied after the LookAt modification executes. This allows you to adjust the finished result.
- </description>
- </method>
- <method name="set_lock_rotation_plane">
- <return type="void" />
- <param index="0" name="plane" type="int" />
- <description>
- </description>
- </method>
- <method name="set_lock_rotation_to_plane">
- <return type="void" />
- <param index="0" name="lock_to_plane" type="bool" />
- <description>
- When [code]true[/code], the LookAt modification will limit its rotation to a single plane in 3D space. The plane used can be configured using the [code]set_lock_rotation_plane[/code] function.
- </description>
- </method>
- </methods>
- <members>
- <member name="bone_index" type="int" setter="set_bone_index" getter="get_bone_index" default="-2">
- The bone index of the bone that should be operated on by this modification.
- When possible, this will also update the [member bone_name] based on data provided by the [Skeleton3D].
- </member>
- <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
- The name of the bone that should be operated on by this modification.
- When possible, this will also update the [member bone_index] based on data provided by the [Skeleton3D].
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the modification.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml
deleted file mode 100644
index 9448e2c783..0000000000
--- a/doc/classes/SkeletonModification3DStackHolder.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that holds and executes a [SkeletonModificationStack3D].
- </brief_description>
- <description>
- This [SkeletonModification3D] holds a reference to a [SkeletonModificationStack3D], allowing you to use multiple modification stacks on a single [Skeleton3D].
- [b]Note:[/b] The modifications in the held [SkeletonModificationStack3D] will only be executed if their execution mode matches the execution mode of the SkeletonModification3DStackHolder.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_held_modification_stack" qualifiers="const">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the [SkeletonModificationStack3D] that this modification is holding.
- </description>
- </method>
- <method name="set_held_modification_stack">
- <return type="void" />
- <param index="0" name="held_modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets the [SkeletonModificationStack3D] that this modification is holding. This modification stack will then be executed when this modification is executed.
- </description>
- </method>
- </methods>
-</class>
diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml
deleted file mode 100644
index 0e7ffd5c80..0000000000
--- a/doc/classes/SkeletonModification3DTwoBoneIK.xml
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that moves two bones to reach the target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm typically called TwoBoneIK. This algorithm works by leveraging the law of cosigns and the lengths of the bones to figure out what rotation the bones currently have, and what rotation they need to make a complete triangle, where the first bone, the second bone, and the target form the three vertices of the triangle. Because the algorithm works by making a triangle, it can only operate on two bones.
- TwoBoneIK is great for arms, legs, and really any joints that can be represented by just two bones that bend to reach a target. This solver is more lightweight than [SkeletonModification3DFABRIK], but gives similar, natural looking results.
- A [Node3D]-based node can be used to define the pole, or bend direction, allowing control over which direction the joint takes when bending to reach the target when the target is within reach.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_auto_calculate_joint_length" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to autocalculate the lengths of the two bones.
- </description>
- </method>
- <method name="get_joint_one_bone_idx" qualifiers="const">
- <return type="int" />
- <description>
- Returns the bone index of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_bone_name" qualifiers="const">
- <return type="String" />
- <description>
- Returns the name of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_length" qualifiers="const">
- <return type="float" />
- <description>
- Returns the length of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_roll" qualifiers="const">
- <return type="float" />
- <description>
- Returns the amount of roll/twist applied to the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_bone_idx" qualifiers="const">
- <return type="int" />
- <description>
- Returns the bone index of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_bone_name" qualifiers="const">
- <return type="String" />
- <description>
- Returns the name of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_length" qualifiers="const">
- <return type="float" />
- <description>
- Returns the length of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_roll" qualifiers="const">
- <return type="float" />
- <description>
- Returns the amount of roll/twist applied to the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_pole_node" qualifiers="const">
- <return type="NodePath" />
- <description>
- Returns the node that is being used as the pole node for the TwoBoneIK modification, if a pole node has been set.
- </description>
- </method>
- <method name="get_tip_node" qualifiers="const">
- <return type="NodePath" />
- <description>
- Returns the node that is being used to calculate the tip position of the second bone in the TwoBoneIK modification, if a tip node has been set.
- </description>
- </method>
- <method name="get_use_pole_node" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to use the pole node to figure out which direction to bend, if a pole node has been set.
- </description>
- </method>
- <method name="get_use_tip_node" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to use the tip node to figure out the length and position of the tip of the second bone.
- </description>
- </method>
- <method name="set_auto_calculate_joint_length">
- <return type="void" />
- <param index="0" name="auto_calculate_joint_length" type="bool" />
- <description>
- If true, the TwoBoneIK modification will attempt to autocalculate the lengths of the bones being used. The first bone will be calculated by using the distance from the origin of the first bone to the origin of the second bone.
- The second bone will be calculated either using the tip node if that setting is enabled, or by using the distances of the second bone's children. If the tip node is not enabled and the bone has no children, then the length cannot be autocalculated. In this case, the length will either have to be manually inputted or a tip node used to calculate the length.
- </description>
- </method>
- <method name="set_joint_one_bone_idx">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the first bone. When possible, this will also update the [code]bone_name[/code] of the first bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_one_bone_name">
- <return type="void" />
- <param index="0" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the first bone. When possible, this will also update the [code]bone_index[/code] of the first bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_one_length">
- <return type="void" />
- <param index="0" name="bone_length" type="float" />
- <description>
- Sets the length of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_one_roll">
- <return type="void" />
- <param index="0" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist applied to the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_two_bone_idx">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the second bone. When possible, this will also update the [code]bone_name[/code] of the second bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_two_bone_name">
- <return type="void" />
- <param index="0" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the second bone. When possible, this will also update the [code]bone_index[/code] of the second bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_two_length">
- <return type="void" />
- <param index="0" name="bone_length" type="float" />
- <description>
- Sets the length of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_two_roll">
- <return type="void" />
- <param index="0" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist applied to the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_pole_node">
- <return type="void" />
- <param index="0" name="pole_nodepath" type="NodePath" />
- <description>
- Sets the node to be used as the for the pole of the TwoBoneIK. When a node is set and the modification is set to use the pole node, the TwoBoneIK modification will bend the nodes in the direction towards this node when the bones need to bend.
- </description>
- </method>
- <method name="set_tip_node">
- <return type="void" />
- <param index="0" name="tip_nodepath" type="NodePath" />
- <description>
- Sets the node to be used as the tip for the second bone. This is used to calculate the length and position of the end of the second bone in the TwoBoneIK modification.
- [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the second bone, with the child node being offset so it is at the end of the bone.
- </description>
- </method>
- <method name="set_use_pole_node">
- <return type="void" />
- <param index="0" name="use_pole_node" type="bool" />
- <description>
- When [code]true[/code], the TwoBoneIK modification will bend the bones towards the pole node, if one has been set. This gives control over the direction the TwoBoneIK solver will bend, which is helpful for joints like elbows that only bend in certain directions.
- </description>
- </method>
- <method name="set_use_tip_node">
- <return type="void" />
- <param index="0" name="use_tip_node" type="bool" />
- <description>
- When [code]true[/code], the TwoBoneIK modification will use the tip node to calculate the distance and position of the end/tip of the second bone. This is the most stable solution for knowing the tip position and length of the second bone.
- </description>
- </method>
- </methods>
- <members>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the TwoBoneIK modification. This node is what the modification will attempt to rotate the bones to reach.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml
deleted file mode 100644
index 9eaeeefd8e..0000000000
--- a/doc/classes/SkeletonModificationStack3D.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A resource that holds a stack of [SkeletonModification3D]s.
- </brief_description>
- <description>
- This resource is used by the Skeleton and holds a stack of [SkeletonModification3D]s. The SkeletonModificationStack3D controls the order of the modifications, which controls how they are applied. Modification order is especially important for full-body IK setups, as you need to execute the modifications in the correct order to get the desired results. For example, you want to execute a modification on the spine [i]before[/i] the arms on a humanoid skeleton.
- Additionally, the SkeletonModificationStack3D also controls how strongly the modifications are applied to the [Skeleton3D] node.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_modification">
- <return type="void" />
- <param index="0" name="modification" type="SkeletonModification3D" />
- <description>
- Adds the passed-in [SkeletonModification3D] to the stack.
- </description>
- </method>
- <method name="delete_modification">
- <return type="void" />
- <param index="0" name="mod_idx" type="int" />
- <description>
- Deletes the [SkeletonModification3D] at the index position [param mod_idx], if it exists.
- </description>
- </method>
- <method name="enable_all_modifications">
- <return type="void" />
- <param index="0" name="enabled" type="bool" />
- <description>
- Enables all [SkeletonModification3D]s in the stack.
- </description>
- </method>
- <method name="execute">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <param index="1" name="execution_mode" type="int" />
- <description>
- Executes all of the [SkeletonModification3D]s in the stack that use the same execution mode as the passed-in [param execution_mode], starting from index [code]0[/code] to [member modification_count].
- [b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results.
- </description>
- </method>
- <method name="get_is_setup" qualifiers="const">
- <return type="bool" />
- <description>
- Returns a boolean that indicates whether the modification stack is setup and can execute.
- </description>
- </method>
- <method name="get_modification" qualifiers="const">
- <return type="SkeletonModification3D" />
- <param index="0" name="mod_idx" type="int" />
- <description>
- Returns the [SkeletonModification3D] at the passed-in index, [param mod_idx].
- </description>
- </method>
- <method name="get_skeleton" qualifiers="const">
- <return type="Skeleton3D" />
- <description>
- Returns the [Skeleton3D] node that the SkeletonModificationStack3D is bound to.
- </description>
- </method>
- <method name="set_modification">
- <return type="void" />
- <param index="0" name="mod_idx" type="int" />
- <param index="1" name="modification" type="SkeletonModification3D" />
- <description>
- Sets the modification at [param mod_idx] to the passed-in modification, [param modification].
- </description>
- </method>
- <method name="setup">
- <return type="void" />
- <description>
- Sets up the modification stack so it can execute. This function should be called by [Skeleton3D] and shouldn't be called unless you know what you are doing.
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="false">
- When true, the modification's in the stack will be called. This is handled automatically through the [Skeleton3D] node.
- </member>
- <member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0">
- The number of modifications in the stack.
- </member>
- <member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
- The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the skeleton bone poses.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 57bdd52d9e..6fb311bcee 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
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].
+ [b]Note:[/b] These parameters need to be set only when creating a custom profile. In [SkeletonProfileHumanoid], they are defined internally as read-only values.
</description>
<tutorials>
<link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
@@ -160,16 +161,18 @@
</methods>
<members>
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" default="0">
+ The amount of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 56 bones.
+ The size of elements in [BoneMap] updates when changing this property in it's assigned [SkeletonProfile].
</member>
<member name="group_size" type="int" setter="set_group_size" getter="get_group_size" default="0">
+ The amount of groups of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 4 groups.
+ This property exists to separate the bone list into several sections in the editor.
</member>
<member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&amp;&quot;&quot;">
- A name of bone that will be used as the root bone in [AnimationTree].
- [b]Note:[/b] In most cases, it is the bone of the parent of the hips that exists at the world origin in the humanoid model.
+ A bone name that will be used as the root bone in [AnimationTree]. This should be the bone of the parent of hips that exists at the world origin.
</member>
<member name="scale_base_bone" type="StringName" setter="set_scale_base_bone" getter="get_scale_base_bone" default="&amp;&quot;&quot;">
- A name of bone which height will be used as the coefficient for normalization.
- [b]Note:[/b] In most cases, it is hips in the humanoid model.
+ A bone name which will use model's height as the coefficient for normalization. For example, [SkeletonProfileHumanoid] defines it as [code]Hips[/code].
</member>
</members>
<signals>
diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml
index 0dbd66d8d6..7445272ccc 100644
--- a/doc/classes/SkeletonProfileHumanoid.xml
+++ b/doc/classes/SkeletonProfileHumanoid.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A humanoid [SkeletonProfile] preset.
</brief_description>
<description>
A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only.
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 87b823bd2a..195f3598d5 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -5,7 +5,6 @@
</brief_description>
<description>
Sprite frame library for an [AnimatedSprite2D] or [AnimatedSprite3D] node. Contains frames and animation data for playback.
- [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
</tutorials>
@@ -14,7 +13,7 @@
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Adds a new animation to the library.
+ Adds a new [param anim] animation to the library.
</description>
</method>
<method name="add_frame">
@@ -24,20 +23,20 @@
<param index="2" name="duration" type="float" default="1.0" />
<param index="3" name="at_position" type="int" default="-1" />
<description>
- Adds a frame to the given animation.
+ Adds a frame to the [param anim] animation. If [param at_position] is [code]-1[/code], the frame will be added to the end of the animation.
</description>
</method>
<method name="clear">
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Removes all frames from the given animation.
+ Removes all frames from the [param anim] animation.
</description>
</method>
<method name="clear_all">
<return type="void" />
<description>
- Removes all animations. A "default" animation will be created.
+ Removes all animations. An empty [code]default[/code] animation will be created.
</description>
</method>
<method name="get_animation_loop" qualifiers="const">
@@ -91,14 +90,14 @@
<return type="bool" />
<param index="0" name="anim" type="StringName" />
<description>
- If [code]true[/code], the named animation exists.
+ Returns [code]true[/code] if the [param anim] animation exists.
</description>
</method>
<method name="remove_animation">
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Removes the given animation.
+ Removes the [param anim] animation.
</description>
</method>
<method name="remove_frame">
@@ -106,7 +105,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="idx" type="int" />
<description>
- Removes the animation's selected frame.
+ Removes the [param anim] animation's frame [param idx].
</description>
</method>
<method name="rename_animation">
@@ -114,7 +113,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="newname" type="StringName" />
<description>
- Changes the animation's name to [param newname].
+ Changes the [param anim] animation's name to [param newname].
</description>
</method>
<method name="set_animation_loop">
@@ -122,7 +121,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="loop" type="bool" />
<description>
- If [code]true[/code], the animation will loop.
+ If [param loop] is [code]true[/code], the [param anim] animation will loop when it reaches the end, or the start if it is played in reverse.
</description>
</method>
<method name="set_animation_speed">
@@ -140,7 +139,7 @@
<param index="2" name="texture" type="Texture2D" />
<param index="3" name="duration" type="float" default="1.0" />
<description>
- Sets the texture and the duration of the frame [param idx] in the [param anim] animation.
+ Sets the [param texture] and the [param duration] of the frame [param idx] in the [param anim] animation.
</description>
</method>
</methods>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index d2c6dee373..711fb89217 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1042,7 +1042,7 @@
</description>
</method>
<method name="parse_structured_text" qualifiers="const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
<param index="1" name="args" type="Array" />
<param index="2" name="text" type="String" />
@@ -1634,6 +1634,9 @@
<constant name="DIRECTION_RTL" value="2" enum="Direction">
Text is written from right to left.
</constant>
+ <constant name="DIRECTION_INHERITED" value="3" enum="Direction">
+ Text writing direction is the same as base string writing direction. Used for BiDi override only.
+ </constant>
<constant name="ORIENTATION_HORIZONTAL" value="0" enum="Orientation">
Text is written horizontally.
</constant>
@@ -1881,7 +1884,7 @@
Font have fixed-width characters.
</constant>
<constant name="STRUCTURED_TEXT_DEFAULT" value="0" enum="StructuredTextParser">
- Use default behavior. Same as [constant STRUCTURED_TEXT_NONE] unless specified otherwise in the control description.
+ Use default Unicode BiDi algorithm.
</constant>
<constant name="STRUCTURED_TEXT_URI" value="1" enum="StructuredTextParser">
BiDi override for URI.
@@ -1896,8 +1899,8 @@
BiDi override for lists.
Structured text options: list separator [code]String[/code].
</constant>
- <constant name="STRUCTURED_TEXT_NONE" value="5" enum="StructuredTextParser">
- Use default Unicode BiDi algorithm.
+ <constant name="STRUCTURED_TEXT_GDSCRIPT" value="5" enum="StructuredTextParser">
+ BiDi override for GDScript.
</constant>
<constant name="STRUCTURED_TEXT_CUSTOM" value="6" enum="StructuredTextParser">
User defined structured text BiDi override function.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index e144b09eb6..f4b306cf96 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -896,7 +896,7 @@
</description>
</method>
<method name="_parse_structured_text" qualifiers="virtual const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
<param index="1" name="args" type="Array" />
<param index="2" name="text" type="String" />
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 8176901ff7..f67b84f96f 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -185,7 +185,19 @@
<return type="Vector2i[]" />
<param index="0" name="layer" type="int" />
<description>
- Returns a [Vector2] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ </description>
+ </method>
+ <method name="get_used_cells_by_id" qualifiers="const">
+ <return type="Vector2i[]" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="source_id" type="int" default="-1" />
+ <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="3" name="alternative_tile" type="int" default="-1" />
+ <description>
+ Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param source_id]).
+ If a parameter has it's value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default value, this method returns the same result as [method get_used_cells].
+ A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
</description>
</method>
<method name="get_used_rect">
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index b3145ea022..90c10e3664 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -41,6 +41,7 @@
<return type="Transform3D" />
<param index="0" name="from" type="Projection" />
<description>
+ Constructs a Transform3D from a [Projection] by trimming the last row of the projection matrix ([code]from.x.w[/code], [code]from.y.w[/code], [code]from.z.w[/code], and [code]from.w.w[/code] are not copied over).
</description>
</constructor>
<constructor name="Transform3D">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index bfabd2d97d..ff5a665bfd 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -45,11 +45,11 @@
<method name="create_item">
<return type="TreeItem" />
<param index="0" name="parent" type="TreeItem" default="null" />
- <param index="1" name="idx" type="int" default="-1" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
Creates an item in the tree and adds it as a child of [param parent], which can be either a valid [TreeItem] or [code]null[/code].
If [param parent] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty.
- The new item will be the [param idx]th child of parent, or it will be the last child if there are not enough siblings.
+ The new item will be the [param index]-th child of parent, or it will be the last child if there are not enough siblings.
</description>
</method>
<method name="deselect_all">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index ec6b166e57..91248092d9 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -18,7 +18,7 @@
<param index="3" name="disabled" type="bool" default="false" />
<param index="4" name="tooltip_text" type="String" default="&quot;&quot;" />
<description>
- Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
+ Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
</description>
</method>
<method name="call_recursive" qualifiers="vararg">
@@ -44,10 +44,10 @@
</method>
<method name="create_child">
<return type="TreeItem" />
- <param index="0" name="idx" type="int" default="-1" />
+ <param index="0" name="index" type="int" default="-1" />
<description>
Creates an item and adds it as a child.
- The new item will be inserted as position [param idx] (the default value [code]-1[/code] means the last position), or it will be the last child if [param idx] is higher than the child count.
+ The new item will be inserted as position [param index] (the default value [code]-1[/code] means the last position), or it will be the last child if [param index] is higher than the child count.
</description>
</method>
<method name="deselect">
@@ -60,17 +60,17 @@
<method name="erase_button">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Removes the button at index [param button_idx] in column [param column].
+ Removes the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button" qualifiers="const">
<return type="Texture2D" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the [Texture2D] of the button at index [param button_idx] in column [param column].
+ Returns the [Texture2D] of the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button_by_id" qualifiers="const">
@@ -91,17 +91,17 @@
<method name="get_button_id" qualifiers="const">
<return type="int" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the ID for the button at index [param button_idx] in column [param column].
+ Returns the ID for the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button_tooltip_text" qualifiers="const">
<return type="String" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the tooltip text for the button at index [param button_idx] in column [param column].
+ Returns the tooltip text for the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_cell_mode" qualifiers="const">
@@ -113,9 +113,9 @@
</method>
<method name="get_child">
<return type="TreeItem" />
- <param index="0" name="idx" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item.
+ Returns a child item by its [param index] (see [method get_child_count]). This method is often used for iterating all children of an item.
Negative indices access the children from the last one.
</description>
</method>
@@ -332,9 +332,9 @@
<method name="is_button_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns [code]true[/code] if the button at index [param button_idx] for the given [param column] is disabled.
+ Returns [code]true[/code] if the button at index [param button_index] for the given [param column] is disabled.
</description>
</method>
<method name="is_checked" qualifiers="const">
@@ -419,28 +419,28 @@
<method name="set_button">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<param index="2" name="button" type="Texture2D" />
<description>
- Sets the given column's button [Texture2D] at index [param button_idx] to [param button].
+ Sets the given column's button [Texture2D] at index [param button_index] 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="1" name="button_index" 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].
+ Sets the given column's button color at index [param button_index] to [param color].
</description>
</method>
<method name="set_button_disabled">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<param index="2" name="disabled" type="bool" />
<description>
- If [code]true[/code], disables the button at index [param button_idx] in the given [param column].
+ If [code]true[/code], disables the button at index [param button_index] in the given [param column].
</description>
</method>
<method name="set_cell_mode">
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index eef35049e5..fc0dd9f05d 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -11,7 +11,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_property($Sprite, "modulate", Color.red, 1)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -27,7 +27,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1).set_trans(Tween.TRANS_SINE)
tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -42,7 +42,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC)
- tween.tween_property($Sprite, "modulate", Color.red, 1)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -288,8 +288,8 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2)
- tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2)
+ tween.tween_callback($Sprite.set_modulate.bind(Color.RED)).set_delay(2)
+ tween.tween_callback($Sprite.set_modulate.bind(Color.BLUE)).set_delay(2)
[/gdscript]
[csharp]
Tween tween = GetTree().CreateTween();
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 7258efbdda..42baf7728d 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -17,7 +17,7 @@
func undo_something():
pass # Put here the code that reverts what's done by "do_something()".
- func _on_MyButton_pressed():
+ func _on_my_button_pressed():
var node = get_node("MyNode2D")
undo_redo.create_action("Move the node")
undo_redo.add_do_method(self, "do_something")
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 6b384d6a77..5416468ab6 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -38,7 +38,7 @@
# To get the name of the underlying Object type, you need the `get_class()` method.
print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string.
# Note also that there is not yet any way to get a script's `class_name` string easily.
- # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes".
+ # To fetch that value, you can parse the [code]res://.godot/global_script_class_cache.cfg[/code] file with the [ConfigFile] API.
# Open your project.godot file to see it up close.
[/gdscript]
[csharp]
@@ -70,6 +70,6 @@
Modifications to a container will modify all references to it. A [Mutex] should be created to lock it if multi-threaded access is desired.
</description>
<tutorials>
- <link title="Variant class">$DOCS_URL/development/cpp/variant_class.html</link>
+ <link title="Variant class introduction">$DOCS_URL/contributing/development/core_and_modules/variant_class.html</link>
</tutorials>
</class>
diff --git a/doc/classes/VisualShaderNodeTexture.xml b/doc/classes/VisualShaderNodeTexture.xml
index 72a7fadf1a..38fa98b21e 100644
--- a/doc/classes/VisualShaderNodeTexture.xml
+++ b/doc/classes/VisualShaderNodeTexture.xml
@@ -33,12 +33,18 @@
Use the texture from this shader's normal map built-in.
</constant>
<constant name="SOURCE_DEPTH" value="4" enum="Source">
- Use the depth texture available for this shader.
+ Use the depth texture captured during the depth prepass. Only available when the depth prepass is used (i.e. in spatial shaders and in the forward_plus or gl_compatibility renderers).
</constant>
<constant name="SOURCE_PORT" value="5" enum="Source">
Use the texture provided in the input port for this function.
</constant>
- <constant name="SOURCE_MAX" value="6" enum="Source">
+ <constant name="SOURCE_3D_NORMAL" value="6" enum="Source">
+ Use the normal buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer).
+ </constant>
+ <constant name="SOURCE_ROUGHNESS" value="7" enum="Source">
+ Use the roughness buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer).
+ </constant>
+ <constant name="SOURCE_MAX" value="8" enum="Source">
Represents the size of the [enum Source] enum.
</constant>
<constant name="TYPE_DATA" value="0" enum="TextureType">
diff --git a/doc/classes/VisualShaderNodeTextureParameter.xml b/doc/classes/VisualShaderNodeTextureParameter.xml
index 333226dc58..8a08bea659 100644
--- a/doc/classes/VisualShaderNodeTextureParameter.xml
+++ b/doc/classes/VisualShaderNodeTextureParameter.xml
@@ -18,6 +18,9 @@
<member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="VisualShaderNodeTextureParameter.TextureRepeat" default="0">
Sets the texture repeating mode. See [enum TextureRepeat] for options.
</member>
+ <member name="texture_source" type="int" setter="set_texture_source" getter="get_texture_source" enum="VisualShaderNodeTextureParameter.TextureSource" default="0">
+ Sets the texture source mode. Used for reading from the screen, depth, or normal_roughness texture. see [enum TextureSource] for options.
+ </member>
<member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureParameter.TextureType" default="0">
Defines the type of data provided by the source texture. See [enum TextureType] for options.
</member>
@@ -88,5 +91,20 @@
<constant name="REPEAT_MAX" value="3" enum="TextureRepeat">
Represents the size of the [enum TextureRepeat] enum.
</constant>
+ <constant name="SOURCE_NONE" value="0" enum="TextureSource">
+ The texture source is not specified in the shader.
+ </constant>
+ <constant name="SOURCE_SCREEN" value="1" enum="TextureSource">
+ The texture source is the screen texture which captures all opaque objects drawn this frame.
+ </constant>
+ <constant name="SOURCE_DEPTH" value="2" enum="TextureSource">
+ The texture source is the depth texture from the depth prepass.
+ </constant>
+ <constant name="SOURCE_NORMAL_ROUGHNESS" value="3" enum="TextureSource">
+ The texture source is the normal-roughness buffer from the depth prepass.
+ </constant>
+ <constant name="SOURCE_MAX" value="4" enum="TextureSource">
+ Represents the size of the [enum TextureSource] enum.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 4cd6cf41da..da31e6761e 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -527,6 +527,39 @@
Set's the window's current mode.
[b]Note:[/b] Fullscreen mode is not exclusive full screen on Windows and Linux.
</member>
+ <member name="mouse_passthrough" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], all mouse event as passed to the underlying window of the same application. See also [member mouse_passthrough_polygon].
+ [b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
+ </member>
+ <member name="mouse_passthrough_polygon" type="PackedVector2Array" setter="set_mouse_passthrough_polygon" getter="get_mouse_passthrough_polygon" default="PackedVector2Array()">
+ Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through.
+ Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior).
+ [codeblocks]
+ [gdscript]
+ # Set region, using Path2D node.
+ $Window.mouse_passthrough_polygon = $Path2D.curve.get_baked_points()
+
+ # Set region, using Polygon2D node.
+ $Window.mouse_passthrough_polygon = $Polygon2D.polygon
+
+ # Reset region to default.
+ $Window.mouse_passthrough_polygon = []
+ [/gdscript]
+ [csharp]
+ // Set region, using Path2D node.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = GetNode&lt;Path2D&gt;("Path2D").Curve.GetBakedPoints();
+
+ // Set region, using Polygon2D node.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = GetNode&lt;Polygon2D&gt;("Polygon2D").Polygon;
+
+ // Reset region to default.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = new Vector2[] {};
+ [/csharp]
+ [/codeblocks]
+ [b]Note:[/b] This property is ignored if [member mouse_passthrough] is set to [code]true[/code].
+ [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 property is implemented on Linux (X11), macOS and Windows.
+ </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).
</member>
@@ -695,7 +728,10 @@
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">
+ <constant name="FLAG_MOUSE_PASSTHROUGH" value="7" enum="Flags">
+ All mouse events are passed to the underlying window of the same application.
+ </constant>
+ <constant name="FLAG_MAX" value="8" enum="Flags">
Max value of the [enum Flags].
</constant>
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index d0ef664281..e1a98f0ea4 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -60,7 +60,7 @@
_can_shoot = false
_cool_down.start()
- func _on_CoolDownTimer_timeout():
+ func _on_cool_down_timer_timeout():
_can_shoot = true
[/gdscript]
[csharp]
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 2887b6b44f..fb338b9849 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -905,10 +905,12 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
@@ -2652,8 +2654,10 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a > 0.0001) {
c.rgb /= c.a;
@@ -2677,8 +2681,10 @@ void fragment() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
COLOR.rgb = c.rgb;
}
)");
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index db9203b249..916e12057c 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -75,6 +75,9 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
+
+ FLAGS_FLIP_H = (1 << 30),
+ FLAGS_FLIP_V = (1 << 31),
};
enum {
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 9a90f33674..1631c65385 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -277,7 +277,7 @@ flat in uvec4 varying_G;
uniform sampler2D atlas_texture; //texunit:-2
uniform sampler2D shadow_atlas_texture; //texunit:-3
#endif // DISABLE_LIGHTING
-uniform sampler2D screen_texture; //texunit:-4
+uniform sampler2D color_buffer; //texunit:-4
uniform sampler2D sdf_texture; //texunit:-5
uniform sampler2D normal_texture; //texunit:-6
uniform sampler2D specular_texture; //texunit:-7
@@ -579,6 +579,12 @@ void main() {
if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index f65558f042..d53c0fcb26 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -27,6 +27,9 @@
#define FLAGS_USE_MSDF uint(1 << 28)
#define FLAGS_USE_LCD uint(1 << 29)
+#define FLAGS_FLIP_H uint(1 << 30)
+#define FLAGS_FLIP_V uint(1 << 31)
+
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 1b922fa726..951155e287 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -564,10 +564,10 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#ifdef USE_MULTIVIEW
uniform highp sampler2DArray depth_buffer; // texunit:-6
-uniform highp sampler2DArray screen_texture; // texunit:-5
+uniform highp sampler2DArray color_buffer; // texunit:-5
#else
uniform highp sampler2D depth_buffer; // texunit:-6
-uniform highp sampler2D screen_texture; // texunit:-5
+uniform highp sampler2D color_buffer; // texunit:-5
#endif
uniform highp mat4 world_transform;
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index e54fad1551..50e5c868d3 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1515,7 +1515,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "screen_texture";
actions.renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
@@ -1536,7 +1535,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
@@ -1617,9 +1615,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- //actions.renames["SCREEN_TEXTURE"] = "color_buffer"; //Not implemented in 3D yet.
- //actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; // Not implemented in 3D yet.
- //actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; // Not implemented in 3D yet
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -1684,7 +1679,6 @@ MaterialStorage::MaterialStorage() {
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
@@ -2765,6 +2759,14 @@ void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
ERR_FAIL_COND(!material);
+ // Need to clear texture arrays to prevent spin locking of their RID's.
+ // This happens when the app is being closed.
+ for (KeyValue<StringName, Variant> &E : material->params) {
+ if (E.value.get_type() == Variant::ARRAY) {
+ Array(E.value).clear();
+ }
+ }
+
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
@@ -2952,7 +2954,6 @@ void CanvasShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
actions.usage_flag_pointers["TIME"] = &uses_time;
@@ -2966,6 +2967,7 @@ void CanvasShaderData::set_code(const String &p_code) {
blend_mode = BlendMode(blend_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
#if 0
print_line("**compiling shader:");
@@ -3301,9 +3303,6 @@ void SceneShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
- actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
- actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
actions.usage_flag_pointers["DISCARD"] = &uses_discard;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
@@ -3356,6 +3355,9 @@ void SceneShaderData::set_code(const String &p_code) {
vertex_input_mask |= uses_bones << 9;
vertex_input_mask |= uses_weights << 10;
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 65c4ca6131..19bf57df94 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -37,13 +37,14 @@ 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) {
+void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, 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();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
width = p_target_size.x;
height = p_target_size.y;
+ //scaling_3d_mode = p_scaling_3d_mode
//fsr_sharpness = p_fsr_sharpness;
//texture_mipmap_bias = p_texture_mipmap_bias;
render_target = p_render_target;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index 52a7737910..d07a0812f6 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -81,7 +81,7 @@ public:
private:
public:
virtual ~RenderSceneBuffersGLES3();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, 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) override;
virtual void set_fsr_sharpness(float p_fsr_sharpness) override{};
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{};
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 489c328f64..8818ab2118 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -567,23 +567,29 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
}
} break;
case Image::FORMAT_ETC2_RA_AS_RG: {
+#ifndef WEB_ENABLED
if (config->etc2_supported) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC;
r_gl_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = true;
- } else {
+ } else
+#endif
+ {
need_decompress = true;
}
decompress_ra_to_rg = true;
} break;
case Image::FORMAT_DXT5_RA_AS_RG: {
+#ifndef WEB_ENABLED
if (config->s3tc_supported) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
r_gl_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = true;
- } else {
+ } else
+#endif
+ {
need_decompress = true;
}
decompress_ra_to_rg = true;
@@ -1137,6 +1143,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+#ifndef WEB_ENABLED
switch (texture->format) {
#ifdef GLES_OVER_GL
case Image::FORMAT_L8: {
@@ -1151,7 +1158,8 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
} break;
-#endif
+#endif // GLES3_OVER_GL
+
case Image::FORMAT_ETC2_RA_AS_RG:
case Image::FORMAT_DXT5_RA_AS_RG: {
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
@@ -1172,6 +1180,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
} break;
}
+#endif // WEB_ENABLED
int mipmaps = img->has_mipmaps() ? img->get_mipmap_count() + 1 : 1;
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 557060c907..a162f46103 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -189,7 +189,7 @@ void DirAccessUnix::list_dir_end() {
_cisdir = false;
}
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
static bool _filter_drive(struct mntent *mnt) {
// Ignore devices that don't point to /dev
if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) {
@@ -213,7 +213,7 @@ static void _get_drives(List<String> *list) {
// Add root.
list->push_back("/");
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
// Check /etc/mtab for the list of mounted partitions.
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab) {
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index c37b3d9c87..178f01b185 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -411,10 +411,6 @@ bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
return true;
}
-bool OS_Unix::has_environment(const String &p_var) const {
- return getenv(p_var.utf8().get_data()) != nullptr;
-}
-
String OS_Unix::get_locale() const {
if (!has_environment("LANG")) {
return "en";
@@ -487,6 +483,10 @@ Error OS_Unix::set_cwd(const String &p_cwd) {
return OK;
}
+bool OS_Unix::has_environment(const String &p_var) const {
+ return getenv(p_var.utf8().get_data()) != nullptr;
+}
+
String OS_Unix::get_environment(const String &p_var) const {
if (getenv(p_var.utf8().get_data())) {
return getenv(p_var.utf8().get_data());
@@ -494,8 +494,15 @@ String OS_Unix::get_environment(const String &p_var) const {
return "";
}
-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;
+void OS_Unix::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1);
+ ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var));
+}
+
+void OS_Unix::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ unsetenv(p_var.utf8().get_data());
}
String OS_Unix::get_user_data_dir() const {
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 416311307c..03429622ae 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -81,7 +81,9 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
+
virtual String get_locale() const override;
virtual void initialize_debugging() override;
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 712b11d7d7..cb8d98932d 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -354,10 +354,6 @@ void ActionMapEditor::_notification(int p_what) {
}
void ActionMapEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ActionMapEditor::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name")));
ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action")));
ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name")));
@@ -578,7 +574,7 @@ ActionMapEditor::ActionMapEditor() {
action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
main_vbox->add_child(action_tree);
- action_tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(action_tree, ActionMapEditor);
// Adding event dialog
event_config_dialog = memnew(InputEventConfigurationDialog);
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index d4ab907e78..639f5e6de5 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -788,7 +788,7 @@ void AnimationBezierTrackEdit::_clear_selection() {
}
void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Update Selected Key Handles"));
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
const IntPair track_key_pair = E->get();
@@ -985,7 +985,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (I.value.has_point(mb->get_position())) {
if (I.key == REMOVE_ICON) {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Remove Bezier Track");
undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
@@ -1172,7 +1172,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
time += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
@@ -1270,7 +1270,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_selection) {
//combit it
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Bezier Points"));
List<AnimMoveRestore> to_restore;
@@ -1471,7 +1471,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Bezier Points"));
if (moving_handle == -1) {
real_t ratio = timeline->get_zoom_scale() * v_zoom;
@@ -1543,7 +1543,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
time += 0.001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
@@ -1591,7 +1591,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Duplicate Keys"));
List<Pair<int, real_t>> new_selection_values;
@@ -1637,7 +1637,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
void AnimationBezierTrackEdit::delete_selection() {
if (selection.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Delete Keys"));
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 89bb1f5ae6..857a9a664a 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -107,7 +107,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
float val = p_value;
float prev_val = animation->track_get_key_transition(track, key);
setting = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
@@ -119,7 +119,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
return true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -704,7 +704,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
float val = p_value;
float prev_val = animation->track_get_key_transition(track, key);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!setting) {
setting = true;
undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS);
@@ -714,7 +714,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
update_obj = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -925,7 +925,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (setting) {
if (update_obj) {
undo_redo->add_do_method(this, "_update_obj", animation);
@@ -1252,7 +1252,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
}
editing = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Length"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(animation.ptr(), "set_length", p_new_len);
undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
@@ -1265,7 +1265,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
void AnimationTimelineEdit::_anim_loop_pressed() {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop"));
switch (animation->get_loop_mode()) {
case Animation::LOOP_NONE: {
@@ -2392,7 +2392,7 @@ void AnimationTrackEdit::_zoom_changed() {
}
void AnimationTrackEdit::_path_submitted(const String &p_text) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Track Path"));
undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text);
undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
@@ -2630,7 +2630,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (!read_only) {
if (check_rect.has_point(pos)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Track Enabled"));
undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
@@ -3020,7 +3020,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_CALL_MODE_DISCRETE:
case MENU_CALL_MODE_CAPTURE: {
Animation::UpdateMode update_mode = Animation::UpdateMode(p_index);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Update Mode"));
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode);
undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track));
@@ -3034,7 +3034,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_INTERPOLATION_LINEAR_ANGLE:
case MENU_INTERPOLATION_CUBIC_ANGLE: {
Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track));
@@ -3044,7 +3044,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_LOOP_WRAP:
case MENU_LOOP_CLAMP: {
bool loop_wrap = p_index == MENU_LOOP_WRAP;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track));
@@ -3438,7 +3438,7 @@ void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Anim
}
int idx = p_track;
if (idx >= 0 && idx < p_from_animation->get_track_count()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Anim Track"), UndoRedo::MERGE_DISABLE, p_from_animation.ptr());
// Remove corresponding reset tracks if they are no longer needed.
@@ -3639,7 +3639,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
}
void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_beziers) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Insert Key"));
Ref<Animation> reset_anim;
@@ -3968,7 +3968,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
Ref<Animation> reset_anim;
reset_anim.instantiate();
reset_anim->set_length(ANIM_MIN_LENGTH);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(al.ptr(), "add_animation", SceneStringNames::get_singleton()->RESET, reset_anim);
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
undo_redo->add_undo_method(al.ptr(), "remove_animation", SceneStringNames::get_singleton()->RESET);
@@ -3978,7 +3978,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
}
void AnimationTrackEditor::_confirm_insert_list() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Insert Key"));
bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed();
@@ -4148,7 +4148,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (create_normal_track) {
if (p_create_beziers) {
bool valid;
@@ -4600,7 +4600,7 @@ void AnimationTrackEditor::_update_scroll(double) {
}
void AnimationTrackEditor::_update_step(double p_new_step) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Step"));
float step_value = p_new_step;
if (timeline->is_using_fps()) {
@@ -4627,7 +4627,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
}
_clear_selection(true);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rearrange Tracks"));
undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track);
// Take into account that the position of the tracks that come after the one removed will change.
@@ -4671,7 +4671,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
case Animation::TYPE_METHOD: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4700,7 +4700,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4719,7 +4719,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4744,7 +4744,7 @@ void AnimationTrackEditor::_add_track(int p_type) {
void AnimationTrackEditor::_new_track_property_selected(String p_name) {
String full_path = String(adding_track_path) + ":" + p_name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (adding_track_type == Animation::TYPE_VALUE) {
Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
{
@@ -4835,7 +4835,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
p_ofs += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(p_track)) {
case Animation::TYPE_POSITION_3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
@@ -4991,7 +4991,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
}
d["args"] = params;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Method Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
@@ -5178,7 +5178,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t
}
void AnimationTrackEditor::_move_selection_commit() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Move Keys"));
List<_AnimMoveRestore> to_restore;
@@ -5430,7 +5430,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
int start_track = transpose ? _get_track_selected() : top_track;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Duplicate Keys"));
List<Pair<int, float>> new_selection_values;
@@ -5660,7 +5660,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
int base_track = animation->get_track_count();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Tracks"));
for (int i = 0; i < track_clipboard.size(); i++) {
undo_redo->add_do_method(animation.ptr(), "add_track", track_clipboard[i].track_type);
@@ -5730,7 +5730,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
float s = scale->get_value();
ERR_FAIL_COND_MSG(s == 0, "Can't scale to 0.");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Scale Keys"));
List<_AnimMoveRestore> to_restore;
@@ -5810,7 +5810,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
ease_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
case EDIT_EASE_CONFIRM: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Make Easing Keys"));
Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id());
@@ -5917,7 +5917,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
_anim_duplicate_keys(true);
} break;
case EDIT_ADD_RESET_KEY: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Add RESET Keys"));
Ref<Animation> reset = _create_and_get_reset_animation();
@@ -5978,7 +5978,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
if (selection.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Delete Keys"));
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
@@ -6009,7 +6009,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
bake_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
case EDIT_BAKE_ANIMATION_CONFIRM: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Bake Animation as Linear keys."));
int track_len = animation->get_track_count();
@@ -6130,7 +6130,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value());
_redraw_tracks();
_update_key_edit();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
@@ -6200,7 +6200,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
_update_tracks();
@@ -6801,7 +6801,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() {
}
int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
if (existing != -1) {
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 0926a63f88..ba73a63245 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -31,7 +31,6 @@
#include "animation_track_editor_plugins.h"
#include "editor/audio_stream_preview.h"
-#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
@@ -1018,7 +1017,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
ofs += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Audio Track Clip"));
undo_redo->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream);
undo_redo->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
@@ -1125,7 +1124,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (len_resizing_rel == 0 || len_resizing_index < 0) {
len_resizing = false;
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
index b2e12e2409..dd27b61df9 100644
--- a/editor/array_property_edit.cpp
+++ b/editor/array_property_edit.cpp
@@ -31,7 +31,6 @@
#include "array_property_edit.h"
#include "core/io/marshalls.h"
-#include "editor/editor_node.h"
#include "editor/editor_undo_redo_manager.h"
#define ITEMS_PER_PAGE 100
@@ -88,7 +87,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Resize Array"));
ur->add_do_method(this, "_set_size", newsize);
ur->add_undo_method(this, "_set_size", size);
@@ -135,7 +134,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Callable::CallError ce;
Variant new_value;
Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Array Value Type"));
ur->add_do_method(this, "_set_value", idx, new_value);
@@ -151,7 +150,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Variant arr = get_array();
Variant value = arr.get(idx);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Array Value"));
ur->add_do_method(this, "_set_value", idx, p_value);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index ba7e7f2877..644735a4d8 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -143,6 +143,7 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) {
}
bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) {
+ text_editor->remove_secondary_carets();
String text = get_search_text();
Point2i pos = text_editor->search(text, p_flags, p_from_line, p_from_col);
@@ -178,6 +179,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
}
void FindReplaceBar::_replace() {
+ text_editor->remove_secondary_carets();
bool selection_enabled = text_editor->has_selection(0);
Point2i selection_begin, selection_end;
if (selection_enabled) {
@@ -225,6 +227,7 @@ void FindReplaceBar::_replace() {
}
void FindReplaceBar::_replace_all() {
+ text_editor->remove_secondary_carets();
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(0), text_editor->get_caret_column(0));
@@ -2083,6 +2086,7 @@ CodeTextEditor::CodeTextEditor() {
text_editor = memnew(CodeEdit);
add_child(text_editor);
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ text_editor->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_GDSCRIPT);
int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 78987ee6ef..6f4736dca7 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -685,7 +685,7 @@ void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) {
}
Callable callable = p_cd.get_callable();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(p_cd.signal), String(p_cd.method)));
undo_redo->add_do_method(source, "connect", p_cd.signal, callable, p_cd.flags);
undo_redo->add_undo_method(source, "disconnect", p_cd.signal, callable);
@@ -706,7 +706,7 @@ void ConnectionsDock::_disconnect(TreeItem &p_item) {
ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... Bugcheck.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), cd.signal, cd.method));
Callable callable = cd.get_callable();
@@ -733,7 +733,7 @@ void ConnectionsDock::_disconnect_all() {
TreeItem *child = item->get_first_child();
String signal_name = item->get_metadata(0).operator Dictionary()["name"];
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signal_name));
while (child) {
@@ -1196,6 +1196,7 @@ ConnectionsDock::ConnectionsDock() {
tree->set_columns(1);
tree->set_select_mode(Tree::SELECT_ROW);
tree->set_hide_root(true);
+ tree->set_column_clip_content(0, true);
vbc->add_child(tree);
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->set_allow_rmb_select(true);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 98fcde17c4..0814d5b5ca 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -724,12 +724,6 @@ void CreateDialog::_load_favorites_and_history() {
}
void CreateDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list);
-
- ClassDB::bind_method("_get_drag_data_fw", &CreateDialog::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &CreateDialog::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &CreateDialog::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("create"));
ADD_SIGNAL(MethodInfo("favorites_updated"));
}
@@ -759,7 +753,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);
- favorites->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(favorites, CreateDialog);
fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
VBoxContainer *rec_vb = memnew(VBoxContainer);
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index d685db40d9..fc806ded5e 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -213,7 +213,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
}
EditorNode *editor = EditorNode::get_singleton();
- Error err = platform_string == "android" ? editor->run_play_native(device, idx) : editor->run_play_native(-1, idx);
+ Error err = platform_string == "android" ? editor->run_play_native(device * 10000 + idx) : editor->run_play_native(idx);
if (err) {
if (err == ERR_INVALID_PARAMETER && platform_string == "android") {
return prepare_error_response(p_params, DAP::ErrorType::MISSING_DEVICE);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index e4afbde89f..a368cacf56 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -275,7 +275,7 @@ void EditorDebuggerNode::stop(bool p_force) {
});
_break_state_changed();
breakpoints.clear();
- EditorNode::get_undo_redo()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY);
set_process(false);
}
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index 0d191cabe8..ad59a1c169 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "dictionary_property_edit.h"
-#include "editor/editor_node.h"
#include "editor/editor_undo_redo_manager.h"
void DictionaryPropertyEdit::_notif_change() {
@@ -119,7 +118,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
int index = pn.substr(0, slash).to_int();
if (type == "key" && index < keys.size()) {
const Variant &key = keys[index];
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Dictionary Key"));
ur->add_do_method(this, "_set_key", key, p_value);
@@ -131,7 +130,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
const Variant &key = keys[index];
if (dict.has(key)) {
Variant value = dict[key];
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Dictionary Value"));
ur->add_do_method(this, "_set_value", key, p_value);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 85adc312f2..5bdef32c60 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -750,6 +750,7 @@ void DocTools::generate(bool p_basic_types) {
MethodInfo mi;
mi.name = "operator []";
mi.return_val.type = Variant::get_indexed_element_type(Variant::Type(i));
+ mi.return_val.usage = Variant::get_indexed_element_usage(Variant::Type(i));
PropertyInfo arg;
arg.name = "index";
arg.type = Variant::INT;
@@ -1021,15 +1022,15 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
if (parser->get_node_name() == element) {
DocData::MethodDoc method;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- method.name = parser->get_attribute_value("name");
+ method.name = parser->get_named_attribute_value("name");
if (parser->has_attribute("qualifiers")) {
- method.qualifiers = parser->get_attribute_value("qualifiers");
+ method.qualifiers = parser->get_named_attribute_value("qualifiers");
}
if (parser->has_attribute("is_deprecated")) {
- method.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ method.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- method.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ method.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1037,21 +1038,21 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
String name = parser->get_node_name();
if (name == "return") {
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- method.return_type = parser->get_attribute_value("type");
+ method.return_type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
- method.return_enum = parser->get_attribute_value("enum");
+ method.return_enum = parser->get_named_attribute_value("enum");
}
} else if (name == "returns_error") {
ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
- method.errors_returned.push_back(parser->get_attribute_value("number").to_int());
+ method.errors_returned.push_back(parser->get_named_attribute_value("number").to_int());
} else if (name == "param") {
DocData::ArgumentDoc argument;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- argument.name = parser->get_attribute_value("name");
+ argument.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- argument.type = parser->get_attribute_value("type");
+ argument.type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
- argument.enumeration = parser->get_attribute_value("enum");
+ argument.enumeration = parser->get_named_attribute_value("enum");
}
method.arguments.push_back(argument);
@@ -1153,21 +1154,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT);
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- String name = parser->get_attribute_value("name");
+ String name = parser->get_named_attribute_value("name");
class_list[name] = DocData::ClassDoc();
DocData::ClassDoc &c = class_list[name];
c.name = name;
if (parser->has_attribute("inherits")) {
- c.inherits = parser->get_attribute_value("inherits");
+ c.inherits = parser->get_named_attribute_value("inherits");
}
if (parser->has_attribute("is_deprecated")) {
- c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ c.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1193,7 +1194,7 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (name3 == "link") {
DocData::TutorialDoc tutorial;
if (parser->has_attribute("title")) {
- tutorial.title = parser->get_attribute_value("title");
+ tutorial.title = parser->get_named_attribute_value("title");
}
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1231,23 +1232,23 @@ Error DocTools::_load(Ref<XMLParser> parser) {
DocData::PropertyDoc prop2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
+ prop2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
+ prop2.type = parser->get_named_attribute_value("type");
if (parser->has_attribute("setter")) {
- prop2.setter = parser->get_attribute_value("setter");
+ prop2.setter = parser->get_named_attribute_value("setter");
}
if (parser->has_attribute("getter")) {
- prop2.getter = parser->get_attribute_value("getter");
+ prop2.getter = parser->get_named_attribute_value("getter");
}
if (parser->has_attribute("enum")) {
- prop2.enumeration = parser->get_attribute_value("enum");
+ prop2.enumeration = parser->get_named_attribute_value("enum");
}
if (parser->has_attribute("is_deprecated")) {
- prop2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ prop2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- prop2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ prop2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
@@ -1274,11 +1275,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
DocData::ThemeItemDoc prop2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
+ prop2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
+ prop2.type = parser->get_named_attribute_value("type");
ERR_FAIL_COND_V(!parser->has_attribute("data_type"), ERR_FILE_CORRUPT);
- prop2.data_type = parser->get_attribute_value("data_type");
+ prop2.data_type = parser->get_named_attribute_value("data_type");
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1303,21 +1304,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (name3 == "constant") {
DocData::ConstantDoc constant2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- constant2.name = parser->get_attribute_value("name");
+ constant2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT);
- constant2.value = parser->get_attribute_value("value");
+ constant2.value = parser->get_named_attribute_value("value");
constant2.is_value_valid = true;
if (parser->has_attribute("enum")) {
- constant2.enumeration = parser->get_attribute_value("enum");
+ constant2.enumeration = parser->get_named_attribute_value("enum");
}
if (parser->has_attribute("is_bitfield")) {
- constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
+ constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
}
if (parser->has_attribute("is_deprecated")) {
- constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ constant2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ constant2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 7ef99d56ab..f4cefc606b 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -282,7 +282,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
}
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
ur->create_action(TTR("Rename Audio Bus"));
@@ -323,7 +323,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));
@@ -417,7 +417,7 @@ void EditorAudioBus::_hide_value_preview() {
void EditorAudioBus::_solo_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Solo"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));
@@ -431,7 +431,7 @@ void EditorAudioBus::_solo_toggled() {
void EditorAudioBus::_mute_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Mute"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));
@@ -445,7 +445,7 @@ void EditorAudioBus::_mute_toggled() {
void EditorAudioBus::_bypass_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
@@ -459,7 +459,7 @@ void EditorAudioBus::_bypass_toggled() {
void EditorAudioBus::_send_selected(int p_which) {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));
@@ -509,7 +509,7 @@ void EditorAudioBus::_effect_edited() {
int index = effect->get_metadata(0);
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
@@ -536,7 +536,7 @@ void EditorAudioBus::_effect_add(int p_which) {
afxr->set_name(effect_options->get_item_text(p_which));
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Audio Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);
ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));
@@ -690,7 +690,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data,
bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Move Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);
@@ -732,7 +732,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) {
int index = item->get_metadata(0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Delete Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);
ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);
@@ -765,10 +765,6 @@ void EditorAudioBus::_bind_methods() {
ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);
ClassDB::bind_method("update_send", &EditorAudioBus::update_send);
- ClassDB::bind_method("_get_drag_data_fw", &EditorAudioBus::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &EditorAudioBus::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &EditorAudioBus::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("duplicate_request"));
ADD_SIGNAL(MethodInfo("delete_request"));
ADD_SIGNAL(MethodInfo("vol_reset_request"));
@@ -903,7 +899,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));
effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
- effects->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus);
effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));
effects->set_allow_rmb_select(true);
effects->set_focus_mode(FOCUS_CLICK);
@@ -1065,7 +1061,7 @@ void EditorAudioBuses::_notification(int p_what) {
}
void EditorAudioBuses::_add_bus() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
@@ -1097,7 +1093,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Delete Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);
@@ -1119,7 +1115,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
void EditorAudioBuses::_duplicate_bus(int p_which) {
int add_at_pos = p_which + 1;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Duplicate Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");
@@ -1142,7 +1138,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
int index = bus->get_index();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Reset Bus Volume"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
@@ -1162,7 +1158,7 @@ void EditorAudioBuses::_request_drop_end() {
}
void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Move Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);
@@ -1221,7 +1217,7 @@ void EditorAudioBuses::_load_default_layout() {
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
@@ -1237,7 +1233,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
} else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
@@ -1257,7 +1253,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
edited_path = p_string;
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
}
@@ -1356,7 +1352,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
file->set_text(p_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 4001b849ff..f843733f2c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -194,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() {
TreeItem *ti = tree->get_edited();
int column = tree->get_edited_column();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (column == 0) {
String name = ti->get_text(0);
@@ -289,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
String name = "autoload/" + ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_button) {
case BUTTON_OPEN: {
@@ -717,7 +717,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &
orders.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rearrange Autoloads"));
@@ -760,7 +760,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
name = "autoload/" + name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Autoload"));
// Singleton autoloads are represented with a leading "*" in their path.
@@ -786,7 +786,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
void EditorAutoloadSettings::autoload_remove(const String &p_name) {
String name = "autoload/" + p_name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
int order = ProjectSettings::get_singleton()->get_order(name);
@@ -808,12 +808,6 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) {
}
void EditorAutoloadSettings::_bind_methods() {
- ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open);
-
- ClassDB::bind_method("_get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &EditorAutoloadSettings::drop_data_fw);
-
ClassDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload);
ClassDB::bind_method("autoload_add", &EditorAutoloadSettings::autoload_add);
ClassDB::bind_method("autoload_remove", &EditorAutoloadSettings::autoload_remove);
@@ -935,7 +929,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
tree->set_select_mode(Tree::SELECT_MULTI);
tree->set_allow_reselect(true);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, EditorAutoloadSettings);
tree->set_columns(4);
tree->set_column_titles_visible(true);
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index c5fe89e35d..3059ce445c 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -122,12 +122,6 @@ int EditorSelectionHistory::get_history_pos() {
return current_elem_idx;
}
-bool EditorSelectionHistory::is_history_obj_inspector_only(int p_obj) const {
- ERR_FAIL_INDEX_V(p_obj, history.size(), false);
- ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), false);
- return history[p_obj].path[history[p_obj].level].inspector_only;
-}
-
ObjectID EditorSelectionHistory::get_history_obj(int p_obj) const {
ERR_FAIL_INDEX_V(p_obj, history.size(), ObjectID());
ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), ObjectID());
@@ -351,18 +345,6 @@ void EditorData::apply_changes_in_editors() {
}
}
-void EditorData::save_editor_global_states() {
- for (int i = 0; i < editor_plugins.size(); i++) {
- editor_plugins[i]->save_global_state();
- }
-}
-
-void EditorData::restore_editor_global_states() {
- for (int i = 0; i < editor_plugins.size(); i++) {
- editor_plugins[i]->restore_global_state();
- }
-}
-
void EditorData::paste_object_params(Object *p_object) {
ERR_FAIL_NULL(p_object);
undo_redo_manager->create_action(TTR("Paste Params"));
@@ -390,7 +372,7 @@ void EditorData::set_scene_as_saved(int p_idx) {
}
ERR_FAIL_INDEX(p_idx, edited_scene.size());
- get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id);
+ undo_redo_manager->set_history_as_saved(edited_scene[p_idx].history_id);
}
bool EditorData::is_scene_changed(int p_idx) {
@@ -399,7 +381,7 @@ bool EditorData::is_scene_changed(int p_idx) {
}
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false);
- uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
+ uint64_t current_scene_version = undo_redo_manager->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version;
edited_scene.write[p_idx].last_checked_version = current_scene_version;
return is_changed;
@@ -425,10 +407,6 @@ int EditorData::get_scene_history_id(int p_idx) const {
return edited_scene[p_idx].history_id;
}
-Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() {
- return undo_redo_manager;
-}
-
void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
undo_redo_callbacks.push_back(p_callable);
}
@@ -998,6 +976,8 @@ void EditorData::script_class_set_name(const String &p_path, const StringName &p
}
void EditorData::script_class_save_icon_paths() {
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+
Dictionary d;
for (const KeyValue<StringName, String> &E : _script_class_icon_paths) {
if (ScriptServer::is_global_class(E.key)) {
@@ -1005,27 +985,20 @@ void EditorData::script_class_save_icon_paths() {
}
}
- Dictionary old;
- if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- old = GLOBAL_GET("_global_script_class_icons");
- }
- if ((!old.is_empty() || d.is_empty()) && d.hash() == old.hash()) {
- return;
- }
-
- if (d.is_empty()) {
- if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- ProjectSettings::get_singleton()->clear("_global_script_class_icons");
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d2 = script_classes[i];
+ if (!d2.has("class")) {
+ continue;
}
- } else {
- ProjectSettings::get_singleton()->set("_global_script_class_icons", d);
+ d2["icon"] = d.get(d2["class"], "");
}
- ProjectSettings::get_singleton()->save();
+ ProjectSettings::get_singleton()->store_global_class_list(script_classes);
}
void EditorData::script_class_load_icon_paths() {
script_class_clear_icon_paths();
+#ifndef DISABLE_DEPRECATED
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
Dictionary d = GLOBAL_GET("_global_script_class_icons");
List<Variant> keys;
@@ -1038,15 +1011,33 @@ void EditorData::script_class_load_icon_paths() {
String path = ScriptServer::get_global_class_path(name);
script_class_set_name(path, name);
}
+ ProjectSettings::get_singleton()->clear("_global_script_class_icons");
+ }
+#endif
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d = script_classes[i];
+ if (!d.has("class") || !d.has("path") || !d.has("icon")) {
+ continue;
+ }
+
+ String name = d["class"];
+ _script_class_icon_paths[name] = d["icon"];
+ script_class_set_name(d["path"], name);
}
}
EditorData::EditorData() {
current_edited_scene = -1;
- undo_redo_manager.instantiate();
+ undo_redo_manager = memnew(EditorUndoRedoManager);
script_class_load_icon_paths();
}
+EditorData::~EditorData() {
+ memdelete(undo_redo_manager);
+}
+
///////////////////////////////////////////////////////////////////////////////
void EditorSelection::_node_removed(Node *p_node) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 385bcad1f9..6a89b3572c 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -80,7 +80,6 @@ public:
// Gets an object from the history. The most recent object would be the object with p_obj = get_history_len() - 1.
ObjectID get_history_obj(int p_obj) const;
- bool is_history_obj_inspector_only(int p_obj) const;
bool next();
bool previous();
@@ -133,7 +132,7 @@ private:
HashMap<String, Vector<CustomType>> custom_types;
List<PropertyData> clipboard;
- Ref<EditorUndoRedoManager> undo_redo_manager;
+ EditorUndoRedoManager *undo_redo_manager;
Vector<Callable> undo_redo_callbacks;
HashMap<StringName, Callable> move_element_functions;
@@ -168,7 +167,6 @@ public:
int get_editor_plugin_count() const;
EditorPlugin *get_editor_plugin(int p_idx);
- Ref<EditorUndoRedoManager> &get_undo_redo();
void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value)
void remove_undo_redo_inspector_hook_callback(Callable p_callable);
const Vector<Callable> get_undo_redo_inspector_hook_callback();
@@ -178,7 +176,6 @@ public:
Callable get_move_array_element_function(const StringName &p_class) const;
void save_editor_global_states();
- void restore_editor_global_states();
void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
Variant instantiate_custom_type(const String &p_type, const String &p_inherits);
@@ -245,6 +242,7 @@ public:
void script_class_load_icon_paths();
EditorData();
+ ~EditorData();
};
/**
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 4efc7c3055..a9b4c08698 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -602,10 +602,19 @@ bool EditorFileSystem::_update_scan_actions() {
fs_changed = true;
+ if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
+ _queue_update_script_class(ia.dir->get_file_path(idx));
+ }
+
} break;
case ItemAction::ACTION_FILE_REMOVE: {
int idx = ia.dir->find_file_index(ia.file);
ERR_CONTINUE(idx == -1);
+
+ if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
+ _queue_update_script_class(ia.dir->get_file_path(idx));
+ }
+
_delete_internal_files(ia.dir->files[idx]->file);
memdelete(ia.dir->files[idx]);
ia.dir->files.remove_at(idx);
@@ -640,6 +649,10 @@ bool EditorFileSystem::_update_scan_actions() {
ERR_CONTINUE(idx == -1);
String full_path = ia.dir->get_file_path(idx);
+ if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
+ _queue_update_script_class(full_path);
+ }
+
reloads.push_back(full_path);
} break;
@@ -708,9 +721,9 @@ void EditorFileSystem::scan() {
new_filesystem = nullptr;
_update_scan_actions();
scanning = false;
+ _update_pending_script_classes();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
} else {
ERR_FAIL_COND(thread.is_started());
@@ -911,6 +924,10 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
fi->modified_time = mt;
fi->import_modified_time = 0;
fi->import_valid = true;
+
+ if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
+ _queue_update_script_class(path);
+ }
}
}
@@ -922,20 +939,6 @@ 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> scr = ResourceLoader::load(path);
- if (scr == nullptr) {
- continue;
- }
- Vector<DocData::ClassDoc> docs = scr->get_documentation();
- for (int j = 0; j < docs.size(); j++) {
- EditorHelp::get_doc_data()->add_doc(docs[j]);
- }
- }
- }
-
p_dir->files.push_back(fi);
p_progress.update(idx, total);
}
@@ -1176,7 +1179,9 @@ void EditorFileSystem::scan_changes() {
sp.low = 0;
scan_total = 0;
_scan_fs_changes(filesystem, sp);
- if (_update_scan_actions()) {
+ bool changed = _update_scan_actions();
+ _update_pending_script_classes();
+ if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
}
@@ -1225,11 +1230,12 @@ void EditorFileSystem::_notification(int p_what) {
set_process(false);
thread_sources.wait_to_finish();
- if (_update_scan_actions()) {
+ bool changed = _update_scan_actions();
+ _update_pending_script_classes();
+ if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
}
} else if (!scanning && thread.is_started()) {
@@ -1242,9 +1248,9 @@ void EditorFileSystem::_notification(int p_what) {
new_filesystem = nullptr;
thread.wait_to_finish();
_update_scan_actions();
+ _update_pending_script_classes();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
}
@@ -1491,42 +1497,63 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St
return String();
}
-void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
- int filecount = p_dir->files.size();
- const EditorFileSystemDirectory::FileInfo *const *files = p_dir->files.ptr();
- for (int i = 0; i < filecount; i++) {
- if (files[i]->script_class_name.is_empty()) {
+void EditorFileSystem::_update_script_classes() {
+ update_script_mutex.lock();
+
+ for (const String &path : update_script_paths) {
+ ScriptServer::remove_global_class_by_path(path); // First remove, just in case it changed
+
+ int index = -1;
+ EditorFileSystemDirectory *efd = find_file(path, &index);
+
+ if (!efd || index < 0) {
+ // The file was removed
continue;
}
- String lang;
- for (int j = 0; j < ScriptServer::get_language_count(); j++) {
- if (ScriptServer::get_language(j)->handles_global_class_type(files[i]->type)) {
- lang = ScriptServer::get_language(j)->get_name();
+ if (!efd->files[index]->script_class_name.is_empty()) {
+ String lang;
+ for (int j = 0; j < ScriptServer::get_language_count(); j++) {
+ if (ScriptServer::get_language(j)->handles_global_class_type(efd->files[index]->type)) {
+ lang = ScriptServer::get_language(j)->get_name();
+ }
}
+ if (lang.is_empty()) {
+ continue; // No lang found that can handle this global class
+ }
+
+ ScriptServer::add_global_class(efd->files[index]->script_class_name, efd->files[index]->script_class_extends, lang, path);
+ EditorNode::get_editor_data().script_class_set_icon_path(efd->files[index]->script_class_name, efd->files[index]->script_class_icon_path);
+ EditorNode::get_editor_data().script_class_set_name(efd->files[index]->file, efd->files[index]->script_class_name);
}
- ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i));
- EditorNode::get_editor_data().script_class_set_icon_path(files[i]->script_class_name, files[i]->script_class_icon_path);
- EditorNode::get_editor_data().script_class_set_name(files[i]->file, files[i]->script_class_name);
}
- for (int i = 0; i < p_dir->get_subdir_count(); i++) {
- _scan_script_classes(p_dir->get_subdir(i));
- }
-}
-void EditorFileSystem::update_script_classes() {
- if (!update_script_classes_queued.is_set()) {
- return;
- }
+ // Parse documentation second, as it requires the class names to be correct and registered
+ for (const String &path : update_script_paths) {
+ int index = -1;
+ EditorFileSystemDirectory *efd = find_file(path, &index);
- update_script_classes_queued.clear();
- ScriptServer::global_classes_clear();
- if (get_filesystem()) {
- _scan_script_classes(get_filesystem());
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptLanguage *lang = ScriptServer::get_language(i);
+ if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) {
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_null()) {
+ continue;
+ }
+ Vector<DocData::ClassDoc> docs = scr->get_documentation();
+ for (int j = 0; j < docs.size(); j++) {
+ EditorHelp::get_doc_data()->add_doc(docs[j]);
+ }
+ }
+ }
}
+ update_script_paths.clear();
+ update_script_mutex.unlock();
+
ScriptServer::save_global_classes();
EditorNode::get_editor_data().script_class_save_icon_paths();
+ emit_signal("script_classes_updated");
// Rescan custom loaders and savers.
// Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update.
@@ -1537,13 +1564,16 @@ void EditorFileSystem::update_script_classes() {
ResourceSaver::add_custom_savers();
}
-void EditorFileSystem::_queue_update_script_classes() {
- if (update_script_classes_queued.is_set()) {
- return;
+void EditorFileSystem::_update_pending_script_classes() {
+ if (!update_script_paths.is_empty()) {
+ _update_script_classes();
}
+}
- update_script_classes_queued.set();
- call_deferred(SNAME("update_script_classes"));
+void EditorFileSystem::_queue_update_script_class(const String &p_path) {
+ update_script_mutex.lock();
+ update_script_paths.insert(p_path);
+ update_script_mutex.unlock();
}
void EditorFileSystem::update_file(const String &p_file) {
@@ -1565,12 +1595,16 @@ void EditorFileSystem::update_file(const String &p_file) {
ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid);
}
}
+ if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
+ _queue_update_script_class(p_file);
+ }
+
memdelete(fs->files[cpos]);
fs->files.remove_at(cpos);
}
+ _update_pending_script_classes();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
- _queue_update_script_classes();
return;
}
@@ -1630,8 +1664,12 @@ void EditorFileSystem::update_file(const String &p_file) {
// Update preview
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
+ if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
+ _queue_update_script_class(p_file);
+ }
+
+ _update_pending_script_classes();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
- _queue_update_script_classes();
}
HashSet<String> EditorFileSystem::get_valid_extensions() const {
@@ -2413,10 +2451,10 @@ void EditorFileSystem::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_file", "path"), &EditorFileSystem::update_file);
ClassDB::bind_method(D_METHOD("get_filesystem_path", "path"), &EditorFileSystem::get_filesystem_path);
ClassDB::bind_method(D_METHOD("get_file_type", "path"), &EditorFileSystem::get_file_type);
- ClassDB::bind_method(D_METHOD("update_script_classes"), &EditorFileSystem::update_script_classes);
ClassDB::bind_method(D_METHOD("reimport_files", "files"), &EditorFileSystem::reimport_files);
ADD_SIGNAL(MethodInfo("filesystem_changed"));
+ ADD_SIGNAL(MethodInfo("script_classes_updated"));
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources")));
ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources")));
@@ -2472,7 +2510,6 @@ EditorFileSystem::EditorFileSystem() {
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
scan_total = 0;
- update_script_classes_queued.clear();
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_file_system.h b/editor/editor_file_system.h
index 2985134093..03b1fb4a49 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -257,9 +257,11 @@ class EditorFileSystem : public Node {
}
};
- void _scan_script_classes(EditorFileSystemDirectory *p_dir);
- SafeFlag update_script_classes_queued;
- void _queue_update_script_classes();
+ Mutex update_script_mutex;
+ HashSet<String> update_script_paths;
+ void _queue_update_script_class(const String &p_path);
+ void _update_script_classes();
+ void _update_pending_script_classes();
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
@@ -312,8 +314,6 @@ public:
void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params);
- void update_script_classes();
-
bool is_group_file(const String &p_path) const;
void move_group_file(const String &p_path, const String &p_new_path);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 5baa58873e..9b1a5e028b 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -41,7 +41,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/line_edit.h"
-#define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL)
+#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL)
DocTools *EditorHelp::doc = nullptr;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 12aa44891d..035bd96f4d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1361,38 +1361,22 @@ void EditorInspectorSection::_notification(int p_what) {
} break;
case NOTIFICATION_DRAG_BEGIN: {
- Dictionary dd = get_viewport()->gui_get_drag_data();
-
- // Only allow dropping if the section contains properties which can take the dragged data.
- bool children_can_drop = false;
- for (int child_idx = 0; child_idx < vbox->get_child_count(); child_idx++) {
- Control *editor_property = Object::cast_to<Control>(vbox->get_child(child_idx));
-
- // Test can_drop_data and can_drop_data_fw, since can_drop_data only works if set up with forwarding or if script attached.
- if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("_can_drop_data_fw", Point2(), dd, this))) {
- children_can_drop = true;
- break;
- }
- }
-
- dropping = children_can_drop;
- queue_redraw();
+ dropping_for_unfold = true;
} break;
case NOTIFICATION_DRAG_END: {
- dropping = false;
- queue_redraw();
+ dropping_for_unfold = false;
} break;
case NOTIFICATION_MOUSE_ENTER: {
- if (dropping) {
+ if (dropping || dropping_for_unfold) {
dropping_unfold_timer->start();
}
queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
- if (dropping) {
+ if (dropping || dropping_for_unfold) {
dropping_unfold_timer->stop();
}
queue_redraw();
@@ -1696,13 +1680,13 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
} else {
action_name = vformat("Move element %d to position %d in property array with prefix %s.", p_element_index, p_to_pos, array_element_prefix);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(action_name);
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos };
+ Variant args[] = { undo_redo, object, array_element_prefix, p_element_index, p_to_pos };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1840,14 +1824,14 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
}
void EditorInspectorArray::_clear_array() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat("Clear property array with prefix %s.", array_element_prefix));
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
for (int i = count - 1; i >= 0; i--) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1893,7 +1877,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat("Resize property array with prefix %s.", array_element_prefix));
if (p_size > count) {
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
@@ -1901,7 +1885,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, -1, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1920,7 +1904,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -2065,7 +2049,7 @@ void EditorInspectorArray::_setup() {
ae.panel = memnew(PanelContainer);
ae.panel->set_focus_mode(FOCUS_ALL);
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
- ae.panel->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(ae.panel, EditorInspectorArray);
ae.panel->set_meta("index", begin_array_index + i);
ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
@@ -2236,10 +2220,6 @@ void EditorInspectorArray::_notification(int p_what) {
}
void EditorInspectorArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorInspectorArray::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorInspectorArray::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorInspectorArray::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("page_change_request"));
}
@@ -3568,8 +3548,8 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ if (bool(object->call("_dont_undo_redo"))) {
object->set(p_name, p_value);
if (p_refresh_all) {
_edit_request_change(object, "");
@@ -3689,7 +3669,7 @@ void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array
}
names += p_paths[i];
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS);
for (int i = 0; i < p_paths.size(); i++) {
_edit_set(p_paths[i], p_values[i], false, "");
@@ -3724,7 +3704,7 @@ void EditorInspector::_property_deleted(const String &p_path) {
if (p_path.begins_with("metadata/")) {
String name = p_path.replace_first("metadata/", "");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove metadata %s"), name));
undo_redo->add_do_method(object, "remove_meta", name);
undo_redo->add_undo_method(object, "set_meta", name, object->get_meta(name));
@@ -3790,26 +3770,17 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
Node *node = Object::cast_to<Node>(object);
ERR_FAIL_COND(!node);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (undo_redo.is_valid()) {
- undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
- undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
- undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
- if (editor_property_map.has(p_path)) {
- for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- undo_redo->add_do_method(E->get(), "_update_editor_property_status");
- undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
- }
- }
- undo_redo->commit_action();
- } else {
- node->set_property_pinned(p_path, p_pinned);
- if (editor_property_map.has(p_path)) {
- for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- E->get()->update_editor_property_status();
- }
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
+ undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
+ undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
+ if (editor_property_map.has(p_path)) {
+ for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
+ undo_redo->add_do_method(E->get(), "_update_editor_property_status");
+ undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
}
}
+ undo_redo->commit_action();
}
void EditorInspector::_property_selected(const String &p_path, int p_focusable) {
@@ -3988,7 +3959,7 @@ void EditorInspector::_add_meta_confirm() {
Variant defval;
Callable::CallError ce;
Variant::construct(Variant::Type(add_meta_type->get_selected_id()), defval, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add metadata %s"), name));
undo_redo->add_do_method(object, "set_meta", name, defval);
undo_redo->add_undo_method(object, "remove_meta", name);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index af8d1e6806..699a88e657 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -276,6 +276,7 @@ class EditorInspectorSection : public Container {
Timer *dropping_unfold_timer = nullptr;
bool dropping = false;
+ bool dropping_for_unfold = false;
HashSet<StringName> revertable_properties;
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index d57b3b66cc..5a372412fa 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -31,7 +31,6 @@
#include "editor_locale_dialog.h"
#include "core/config/project_settings.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_button.h"
@@ -141,7 +140,7 @@ void EditorLocaleDialog::_filter_lang_option_changed() {
f_lang_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Language Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", f_lang_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", prev);
@@ -175,7 +174,7 @@ void EditorLocaleDialog::_filter_script_option_changed() {
f_script_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Script Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", f_script_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", prev);
@@ -209,7 +208,7 @@ void EditorLocaleDialog::_filter_cnt_option_changed() {
f_cnt_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Country Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", f_cnt_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", prev);
@@ -224,7 +223,7 @@ void EditorLocaleDialog::_filter_mode_changed(int p_mode) {
prev = GLOBAL_GET("internationalization/locale/locale_filter_mode");
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Filter Mode"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", f_mode);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", prev);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ae9261864f..b0278030f9 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -288,7 +288,7 @@ void EditorNode::_update_scene_tabs() {
icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node");
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
@@ -533,8 +533,8 @@ void EditorNode::_notification(int p_what) {
opening_prev = false;
}
- bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
- bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
+ bool global_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ bool scene_or_global_unsaved = global_unsaved || EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
if (unsaved_cache != scene_or_global_unsaved) {
unsaved_cache = scene_or_global_unsaved;
_update_title();
@@ -584,10 +584,11 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);
- Window *window = static_cast<Window *>(get_tree()->get_root());
+ Window *window = get_window();
if (window) {
// Handle macOS fullscreen and extend-to-title changes.
window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
+ window->set_theme(theme);
}
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
@@ -633,6 +634,10 @@ void EditorNode::_notification(int p_what) {
set_addon_plugin_enabled(addons[i], true);
}
_initializing_plugins = false;
+
+ if (!pending_addons.is_empty()) {
+ EditorFileSystem::get_singleton()->connect("script_classes_updated", callable_mp(this, &EditorNode::_enable_pending_addons));
+ }
}
RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true);
@@ -695,6 +700,7 @@ void EditorNode::_notification(int p_what) {
theme_base->set_theme(theme);
gui_base->set_theme(theme);
+ get_window()->set_theme(theme);
gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles")));
scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles")));
@@ -1128,7 +1134,7 @@ void EditorNode::_version_button_pressed() {
}
void EditorNode::_update_undo_redo_allowed() {
- Ref<EditorUndoRedoManager> undo_redo = get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo());
file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo());
}
@@ -1680,7 +1686,7 @@ int EditorNode::_save_external_resources() {
saved++;
}
- get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
return saved;
}
@@ -1857,7 +1863,7 @@ void EditorNode::_mark_unsaved_scenes() {
String path = node->get_scene_file_path();
if (!path.is_empty() && !FileAccess::exists(path)) {
// Mark scene tab as unsaved if the file is gone.
- get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
+ EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
}
}
@@ -2744,9 +2750,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo()->get_current_action_name();
- int id = editor_data.get_undo_redo()->get_current_action_history_id();
- if (!editor_data.get_undo_redo()->undo()) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ String action = undo_redo->get_current_action_name();
+ int id = undo_redo->get_current_action_history_id();
+ if (!undo_redo->undo()) {
log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR);
} else if (!action.is_empty()) {
switch (id) {
@@ -2763,18 +2770,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
} break;
case EDIT_REDO: {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- if (!editor_data.get_undo_redo()->redo()) {
+ if (!undo_redo->redo()) {
log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo()->get_current_action_name();
+ String action = undo_redo->get_current_action_name();
if (action.is_empty()) {
break;
}
- switch (editor_data.get_undo_redo()->get_current_action_history_id()) {
+ switch (undo_redo->get_current_action_history_id()) {
case EditorUndoRedoManager::GLOBAL_HISTORY:
log->add_message(vformat(TTR("Global Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
break;
@@ -2817,7 +2825,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
ERR_PRINT("Failed to load scene");
}
editor_data.move_edited_scene_to_index(cur_idx);
- get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
scene_tabs->set_current_tab(cur_idx);
} break;
@@ -2909,7 +2917,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
- if (_next_unsaved_scene(!save_each) == -1 && !get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) {
+ if (_next_unsaved_scene(!save_each) == -1 && !EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) {
_discard_changes();
break;
} else {
@@ -3148,7 +3156,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
if (!editor_data.get_edited_scene_root(i)) {
continue;
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (unsaved) {
String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
if (p_valid_filename && scene_filename.length() == 0) {
@@ -3469,6 +3477,12 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Errors in the script cause the base_type to be an empty StringName.
if (scr->get_instance_base_type() == StringName()) {
+ if (_initializing_plugins) {
+ // However, if it happens during initialization, waiting for file scan might help.
+ pending_addons.push_back(p_addon);
+ return;
+ }
+
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;
@@ -3657,7 +3671,7 @@ void EditorNode::set_current_scene(int p_idx) {
editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx));
}
- get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx));
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(p_idx));
}
changing_scene = true;
@@ -3724,7 +3738,7 @@ int EditorNode::new_scene() {
// Remove placeholder empty 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));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (!unsaved && editor_data.get_scene_path(i).is_empty() && editor_data.get_edited_scene_root(i) == nullptr) {
editor_data.remove_scene(i);
idx--;
@@ -3949,10 +3963,6 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) {
SceneTreeDock::get_singleton()->instantiate_scenes(p_files);
}
-Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() {
- return singleton->editor_data.get_undo_redo();
-}
-
void EditorNode::_inherit_request(String p_file) {
current_menu_option = FILE_NEW_INHERITED_SCENE;
_dialog_action(p_file);
@@ -4378,6 +4388,13 @@ void EditorNode::_build_icon_type_cache() {
}
}
+void EditorNode::_enable_pending_addons() {
+ for (uint32_t i = 0; i < pending_addons.size(); i++) {
+ set_addon_plugin_enabled(pending_addons[i], true);
+ }
+ pending_addons.clear();
+}
+
void EditorNode::_file_dialog_register(FileDialog *p_dialog) {
singleton->file_dialogs.insert(p_dialog);
}
@@ -5065,8 +5082,8 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
return true;
}
-Error EditorNode::run_play_native(int p_idx, int p_platform) {
- return run_native->run_native(p_idx, p_platform);
+Error EditorNode::run_play_native(int p_id) {
+ return run_native->run_native(p_id);
}
void EditorNode::run_play() {
@@ -5222,7 +5239,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
return;
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
if (unsaved) {
save_confirmation->set_ok_button_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene"));
@@ -5721,7 +5738,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
- editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
}
return;
}
@@ -5737,7 +5754,7 @@ void EditorNode::reload_scene(const String &p_path) {
// Adjust index so tab is back a the previous position.
editor_data.move_edited_scene_to_index(scene_idx);
- get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
// Recover the tab.
scene_tabs->set_current_tab(current_tab);
@@ -6055,8 +6072,8 @@ EditorNode::EditorNode() {
singleton = this;
- get_undo_redo()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
- get_undo_redo()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
+ EditorUndoRedoManager::get_singleton()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
+ EditorUndoRedoManager::get_singleton()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
TranslationServer::get_singleton()->set_enabled(false);
// Load settings.
@@ -7051,8 +7068,8 @@ EditorNode::EditorNode() {
right_r_vsplit->hide();
// Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize.
- left_r_hsplit->set_split_offset(70 * EDSCALE);
- main_hsplit->set_split_offset(-70 * EDSCALE);
+ left_r_hsplit->set_split_offset(270 * EDSCALE);
+ main_hsplit->set_split_offset(-270 * EDSCALE);
// Define corresponding default layout.
@@ -7067,8 +7084,8 @@ EditorNode::EditorNode() {
default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0);
}
default_layout->set_value(docks_section, "dock_hsplit_1", 0);
- default_layout->set_value(docks_section, "dock_hsplit_2", 70 * EDSCALE);
- default_layout->set_value(docks_section, "dock_hsplit_3", -70 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_2", 270 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_3", -270 * EDSCALE);
default_layout->set_value(docks_section, "dock_hsplit_4", 0);
_update_layouts_menu();
@@ -7383,7 +7400,6 @@ EditorNode::EditorNode() {
_update_recent_scenes();
- editor_data.restore_editor_global_states();
set_process_shortcut_input(true);
load_errors = memnew(RichTextLabel);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index ae951808d5..fb2544c141 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -292,6 +292,7 @@ private:
Vector<EditorPlugin *> editor_plugins;
bool _initializing_plugins = false;
HashMap<String, EditorPlugin *> addon_name_to_plugin;
+ LocalVector<String> pending_addons;
PanelContainer *scene_root_parent = nullptr;
Control *theme_base = nullptr;
@@ -535,6 +536,7 @@ private:
static void _resource_loaded(Ref<Resource> p_resource, const String &p_path);
void _build_icon_type_cache();
+ void _enable_pending_addons();
void _dialog_action(String p_file);
@@ -729,7 +731,6 @@ public:
static EditorLog *get_log() { return singleton->log; }
static EditorData &get_editor_data() { return singleton->editor_data; }
static EditorFolding &get_editor_folding() { return singleton->editor_folding; }
- static Ref<EditorUndoRedoManager> &get_undo_redo();
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -914,7 +915,7 @@ public:
bool ensure_main_scene(bool p_from_native);
- Error run_play_native(int p_idx, int p_platform);
+ Error run_play_native(int p_id);
void run_play();
void run_play_current();
void run_play_custom(const String &p_custom);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index a5d1ddb2fa..7f02148dfc 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -45,6 +45,7 @@
#include "editor/inspector_dock.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/editor_debugger_plugin.h"
+#include "editor/plugins/editor_resource_conversion_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/project_settings_editor.h"
@@ -711,9 +712,6 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
return false;
}
-void EditorPlugin::restore_global_state() {}
-void EditorPlugin::save_global_state() {}
-
void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) {
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(p_callable);
}
@@ -856,6 +854,14 @@ void EditorPlugin::remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plu
EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_plugin);
}
+void EditorPlugin::add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
+ EditorNode::get_singleton()->add_resource_conversion_plugin(p_plugin);
+}
+
+void EditorPlugin::remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
+ EditorNode::get_singleton()->remove_resource_conversion_plugin(p_plugin);
+}
+
void EditorPlugin::_editor_project_settings_changed() {
emit_signal(SNAME("project_settings_changed"));
}
@@ -911,6 +917,8 @@ void EditorPlugin::_bind_methods() {
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("add_resource_conversion_plugin", "plugin"), &EditorPlugin::add_resource_conversion_plugin);
+ ClassDB::bind_method(D_METHOD("remove_resource_conversion_plugin", "plugin"), &EditorPlugin::remove_resource_conversion_plugin);
ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled);
ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled);
@@ -977,8 +985,8 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_CUSTOM);
}
-Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() {
- return EditorNode::get_undo_redo();
+EditorUndoRedoManager *EditorPlugin::get_undo_redo() {
+ return EditorUndoRedoManager::get_singleton();
}
EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS];
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 33081e867a..a5a17acdf1 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -48,6 +48,7 @@ class EditorInspector;
class EditorInspectorPlugin;
class EditorNode3DGizmoPlugin;
class EditorPaths;
+class EditorResourceConversionPlugin;
class EditorResourcePreview;
class EditorSceneFormatImporter;
class EditorScenePostImportPlugin;
@@ -148,7 +149,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- Ref<EditorUndoRedoManager> get_undo_redo();
+ EditorUndoRedoManager *get_undo_redo();
void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
void remove_custom_type(const String &p_type);
@@ -277,9 +278,6 @@ public:
void make_bottom_panel_item_visible(Control *p_item);
void hide_bottom_panel();
- virtual void restore_global_state();
- virtual void save_global_state();
-
void add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
void remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
@@ -307,6 +305,9 @@ public:
void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
+ void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
+ void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
+
void enable_plugin();
void disable_plugin();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 8ef394a59f..46f52ec4af 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -342,12 +342,17 @@ void EditorPropertyTextEnum::_notification(int p_what) {
}
EditorPropertyTextEnum::EditorPropertyTextEnum() {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ add_child(hb);
+
default_layout = memnew(HBoxContainer);
- add_child(default_layout);
+ default_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_child(default_layout);
edit_custom_layout = memnew(HBoxContainer);
+ edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL);
edit_custom_layout->hide();
- add_child(edit_custom_layout);
+ hb->add_child(edit_custom_layout);
option_button = memnew(OptionButton);
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -561,15 +566,13 @@ bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant
}
void EditorPropertyPath::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_drop_data_fw);
}
EditorPropertyPath::EditorPropertyPath() {
HBoxContainer *path_hb = memnew(HBoxContainer);
add_child(path_hb);
path = memnew(LineEdit);
- path->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(path, EditorPropertyPath);
path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
path_hb->add_child(path);
path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
@@ -3673,8 +3676,6 @@ void EditorPropertyNodePath::_notification(int p_what) {
}
void EditorPropertyNodePath::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::drop_data_fw);
}
EditorPropertyNodePath::EditorPropertyNodePath() {
@@ -3686,7 +3687,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
assign->set_h_size_flags(SIZE_EXPAND_FILL);
assign->set_clip_text(true);
assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign));
- assign->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath);
hbc->add_child(assign);
clear = memnew(Button);
@@ -3805,6 +3806,8 @@ static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &res
return true;
}
}
+
+ resources_found.erase(r.ptr());
} break;
default: {
}
@@ -4584,6 +4587,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
return editor;
} else {
EditorPropertyDictionary *editor = memnew(EditorPropertyDictionary);
+ editor->setup(p_hint);
return editor;
}
} break;
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index ed667aa7c8..28c0b047d8 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -702,8 +702,6 @@ void EditorPropertyArray::_reorder_button_up() {
}
void EditorPropertyArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorPropertyArray::drop_data_fw);
}
EditorPropertyArray::EditorPropertyArray() {
@@ -715,7 +713,7 @@ EditorPropertyArray::EditorPropertyArray() {
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
edit->set_toggle_mode(true);
- edit->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(edit, EditorPropertyArray);
edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));
add_child(edit);
add_focusable(edit);
@@ -818,6 +816,10 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) {
update_property();
}
+void EditorPropertyDictionary::setup(PropertyHint p_hint) {
+ property_hint = p_hint;
+}
+
void EditorPropertyDictionary::update_property() {
Variant updated_val = get_edited_object()->get(get_edited_property());
@@ -929,7 +931,13 @@ void EditorPropertyDictionary::update_property() {
prop = editor;
} break;
case Variant::STRING: {
- prop = memnew(EditorPropertyText);
+ if (i != amount && property_hint == PROPERTY_HINT_MULTILINE_TEXT) {
+ // If this is NOT the new key field and there's a multiline hint,
+ // show the field as multiline
+ prop = memnew(EditorPropertyMultilineText);
+ } else {
+ prop = memnew(EditorPropertyText);
+ }
} break;
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 96fc2dce24..73a16e3687 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -154,6 +154,7 @@ class EditorPropertyDictionary : public EditorProperty {
EditorSpinSlider *size_sliderv = nullptr;
Button *button_add_item = nullptr;
EditorPaginator *paginator = nullptr;
+ PropertyHint property_hint;
void _page_changed(int p_page);
void _edit_pressed();
@@ -169,6 +170,7 @@ protected:
void _notification(int p_what);
public:
+ void setup(PropertyHint p_hint);
virtual void update_property() override;
EditorPropertyDictionary();
};
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 195457c239..18ba19f5f6 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -211,6 +211,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["rmb"] = "RMB";
capitalize_string_remaps["rpc"] = "RPC";
capitalize_string_remaps["s3tc"] = "S3TC";
+ capitalize_string_remaps["scp"] = "SCP";
capitalize_string_remaps["sdf"] = "SDF";
capitalize_string_remaps["sdfgi"] = "SDFGI";
capitalize_string_remaps["sdk"] = "SDK";
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 81b2fff97a..a1c913aadd 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -772,9 +772,6 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
void EditorResourcePicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_resource_preview"), &EditorResourcePicker::_update_resource_preview);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw);
ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &EditorResourcePicker::set_base_type);
ClassDB::bind_method(D_METHOD("get_base_type"), &EditorResourcePicker::get_base_type);
@@ -950,7 +947,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
assign_button->set_flat(true);
assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
assign_button->set_clip_text(true);
- assign_button->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(assign_button, EditorResourcePicker);
add_child(assign_button);
assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));
assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw));
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index b0eb4c3d55..0628dc7116 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -37,56 +37,38 @@
void EditorRunNative::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i);
- if (eep.is_null()) {
- continue;
- }
- Ref<ImageTexture> icon = eep->get_run_icon();
- if (!icon.is_null()) {
- Ref<Image> im = icon->get_image();
- im = im->duplicate();
- im->clear_mipmaps();
- if (!im->is_empty()) {
- im->resize(16 * EDSCALE, 16 * EDSCALE);
- Ref<ImageTexture> small_icon = ImageTexture::create_from_image(im);
- MenuButton *mb = memnew(MenuButton);
- mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native).bind(i));
- mb->connect("pressed", callable_mp(this, &EditorRunNative::run_native).bind(-1, i));
- mb->set_icon(small_icon);
- add_child(mb);
- menus[i] = mb;
- }
- }
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons")));
} break;
-
case NOTIFICATION_PROCESS: {
bool changed = EditorExport::get_singleton()->poll_export_platforms() || first;
if (changed) {
- for (KeyValue<int, MenuButton *> &E : menus) {
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(E.key);
- MenuButton *mb = E.value;
- int dc = eep->get_options_count();
-
- if (dc == 0) {
- mb->hide();
- } else {
- mb->get_popup()->clear();
- mb->show();
- if (dc == 1) {
- mb->set_tooltip_text(eep->get_option_tooltip(0));
- } else {
- mb->set_tooltip_text(eep->get_options_tooltip());
- for (int i = 0; i < dc; i++) {
- mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i));
- mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i));
- }
+ PopupMenu *popup = remote_debug->get_popup();
+ popup->clear();
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
+ Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i);
+ if (eep.is_null()) {
+ continue;
+ }
+ int dc = MIN(eep->get_options_count(), 9000);
+ if (dc > 0) {
+ popup->add_icon_item(eep->get_run_icon(), eep->get_name(), -1);
+ popup->set_item_disabled(-1, true);
+ for (int j = 0; j < dc; j++) {
+ popup->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j);
+ popup->set_item_tooltip(-1, eep->get_option_tooltip(j));
+ popup->set_item_indent(-1, 2);
}
}
}
+ if (popup->get_item_count() == 0) {
+ remote_debug->set_disabled(true);
+ remote_debug->set_tooltip_text(TTR("No Remote Debug export presets configured."));
+ } else {
+ remote_debug->set_disabled(false);
+ remote_debug->set_tooltip_text(TTR("Remote Debug"));
+ }
first = false;
}
@@ -94,25 +76,22 @@ void EditorRunNative::_notification(int p_what) {
}
}
-Error EditorRunNative::run_native(int p_idx, int p_platform) {
- if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
- resume_idx = p_idx;
- resume_platform = p_platform;
+Error EditorRunNative::run_native(int p_id) {
+ if (p_id < 0) {
return OK;
}
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(p_platform);
- ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE);
+ int platform = p_id / 10000;
+ int idx = p_id % 10000;
- if (p_idx == -1) {
- if (eep->get_options_count() == 1) {
- menus[p_platform]->get_popup()->hide();
- p_idx = 0;
- } else {
- return ERR_INVALID_PARAMETER;
- }
+ if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
+ resume_id = p_id;
+ return OK;
}
+ Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(platform);
+ ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE);
+
Ref<EditorExportPreset> preset;
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
@@ -151,16 +130,18 @@ Error EditorRunNative::run_native(int p_idx, int p_platform) {
}
eep->clear_messages();
- Error err = eep->run(preset, p_idx, flags);
+ Error err = eep->run(preset, idx, flags);
result_dialog_log->clear();
if (eep->fill_log_messages(result_dialog_log, err)) {
- result_dialog->popup_centered_ratio(0.5);
+ if (eep->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_ERROR) {
+ result_dialog->popup_centered_ratio(0.5);
+ }
}
return err;
}
void EditorRunNative::resume_run_native() {
- run_native(resume_idx, resume_platform);
+ run_native(resume_id);
}
void EditorRunNative::_bind_methods() {
@@ -172,6 +153,14 @@ bool EditorRunNative::is_deploy_debug_remote_enabled() const {
}
EditorRunNative::EditorRunNative() {
+ remote_debug = memnew(MenuButton);
+ remote_debug->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native));
+ remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons")));
+ remote_debug->set_tooltip_text(TTR("Remote Debug"));
+ remote_debug->set_disabled(true);
+
+ add_child(remote_debug);
+
result_dialog = memnew(AcceptDialog);
result_dialog->set_title(TTR("Project Run"));
result_dialog_log = memnew(RichTextLabel);
@@ -182,6 +171,4 @@ EditorRunNative::EditorRunNative() {
result_dialog->hide();
set_process(true);
- resume_idx = 0;
- resume_platform = 0;
}
diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h
index a87e27de97..2a5431e54b 100644
--- a/editor/editor_run_native.h
+++ b/editor/editor_run_native.h
@@ -42,18 +42,17 @@ class EditorRunNative : public HBoxContainer {
RichTextLabel *result_dialog_log = nullptr;
AcceptDialog *result_dialog = nullptr;
- HashMap<int, MenuButton *> menus;
+ MenuButton *remote_debug = nullptr;
bool first = true;
- int resume_idx;
- int resume_platform;
+ int resume_id = -1;
protected:
static void _bind_methods();
void _notification(int p_what);
public:
- Error run_native(int p_idx, int p_platform);
+ Error run_native(int p_id);
bool is_deploy_debug_remote_enabled() const;
void resume_run_native();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 2881302775..ad614b1769 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -132,7 +132,7 @@ void EditorSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
@@ -161,7 +161,7 @@ void EditorSettingsDialog::_notification(int p_what) {
void EditorSettingsDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
@@ -232,7 +232,7 @@ void EditorSettingsDialog::_event_config_confirmed() {
void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Array &p_events) {
Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(p_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Built-in Action") + " '" + p_name + "'");
undo_redo->add_do_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides");
undo_redo->add_undo_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides");
@@ -248,7 +248,7 @@ void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Ar
void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const Array &p_events) {
Ref<Shortcut> current_sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Shortcut") + " '" + p_path + "'");
undo_redo->add_do_method(current_sc.ptr(), "set_events", p_events);
undo_redo->add_undo_method(current_sc.ptr(), "set_events", current_sc->get_events());
@@ -694,10 +694,6 @@ void EditorSettingsDialog::_editor_restart_close() {
void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed);
-
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorSettingsDialog::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorSettingsDialog::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorSettingsDialog::drop_data_fw);
}
EditorSettingsDialog::EditorSettingsDialog() {
@@ -793,7 +789,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked));
tab_shortcuts->add_child(shortcuts);
- shortcuts->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(shortcuts, EditorSettingsDialog);
// Adding event dialog
shortcut_editor = memnew(InputEventConfigurationDialog);
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index dd5d68a08e..558423df78 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -90,11 +90,12 @@ void EditorToaster::_notification(int p_what) {
}
// Hide element if it is not visible anymore.
- if (modulate_fade.a <= 0) {
- if (element.key->is_visible()) {
- element.key->hide();
- needs_update = true;
- }
+ if (modulate_fade.a <= 0 && element.key->is_visible()) {
+ element.key->hide();
+ needs_update = true;
+ } else if (modulate_fade.a >= 0 && !element.key->is_visible()) {
+ element.key->show();
+ needs_update = true;
}
}
@@ -419,12 +420,21 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
// Create a new message if needed.
if (control == nullptr) {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->add_theme_constant_override("separation", 0);
+
Label *label = memnew(Label);
+ hb->add_child(label);
- control = popup(label, p_severity, default_message_duration, p_tooltip);
+ Label *count_label = memnew(Label);
+ hb->add_child(count_label);
+
+ control = popup(hb, p_severity, default_message_duration, p_tooltip);
toasts[control].message = p_message;
toasts[control].tooltip = p_tooltip;
toasts[control].count = 1;
+ toasts[control].message_label = label;
+ toasts[control].message_count_label = count_label;
} else {
if (toasts[control].popped) {
toasts[control].count += 1;
@@ -441,14 +451,31 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
main_button->queue_redraw();
}
- // Retrieve the label back then update the text.
- Label *label = Object::cast_to<Label>(control->get_child(0)->get_child(0));
- ERR_FAIL_COND(!label);
+ // Retrieve the label back, then update the text.
+ Label *message_label = toasts[control].message_label;
+ ERR_FAIL_COND(!message_label);
+ message_label->set_text(p_message);
+ message_label->set_text_overrun_behavior(TextServer::OVERRUN_NO_TRIMMING);
+ message_label->set_custom_minimum_size(Size2());
+
+ Size2i size = message_label->get_combined_minimum_size();
+ int limit_width = get_viewport_rect().size.x / 2; // Limit label size to half the viewport size.
+ if (size.x > limit_width) {
+ message_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ message_label->set_custom_minimum_size(Size2(limit_width, 0));
+ }
+
+ // Retrieve the count label back, then update the text.
+ Label *message_count_label = toasts[control].message_count_label;
if (toasts[control].count == 1) {
- label->set_text(p_message);
+ message_count_label->hide();
} else {
- label->set_text(vformat("%s (%d)", p_message, toasts[control].count));
+ message_count_label->set_text(vformat("(%d)", toasts[control].count));
+ message_count_label->show();
}
+
+ vbox_container->reset_size();
+
is_processing_error = false;
}
diff --git a/editor/editor_toaster.h b/editor/editor_toaster.h
index acd2a8fbf3..6b834f8288 100644
--- a/editor/editor_toaster.h
+++ b/editor/editor_toaster.h
@@ -79,6 +79,8 @@ private:
String message;
String tooltip;
int count = 0;
+ Label *message_label = nullptr;
+ Label *message_count_label = nullptr;
};
HashMap<Control *, Toast> toasts;
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 2ef52bd85a..f65f905b25 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -39,6 +39,8 @@
#include "editor/editor_node.h"
#include "scene/main/node.h"
+EditorUndoRedoManager *EditorUndoRedoManager::singleton = nullptr;
+
EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) {
if (!history_map.has(p_idx)) {
History history;
@@ -503,6 +505,16 @@ void EditorUndoRedoManager::_bind_methods() {
BIND_ENUM_CONSTANT(INVALID_HISTORY);
}
+EditorUndoRedoManager *EditorUndoRedoManager::get_singleton() {
+ return singleton;
+}
+
+EditorUndoRedoManager::EditorUndoRedoManager() {
+ if (!singleton) {
+ singleton = this;
+ }
+}
+
EditorUndoRedoManager::~EditorUndoRedoManager() {
for (const KeyValue<int, History> &E : history_map) {
discard_history(E.key, false);
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
index 960d17d410..10daeae807 100644
--- a/editor/editor_undo_redo_manager.h
+++ b/editor/editor_undo_redo_manager.h
@@ -32,11 +32,13 @@
#define EDITOR_UNDO_REDO_MANAGER_H
#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
+#include "core/object/object.h"
#include "core/object/undo_redo.h"
-class EditorUndoRedoManager : public RefCounted {
- GDCLASS(EditorUndoRedoManager, RefCounted);
+class EditorUndoRedoManager : public Object {
+ GDCLASS(EditorUndoRedoManager, Object);
+
+ static EditorUndoRedoManager *singleton;
public:
enum SpecialHistory {
@@ -132,6 +134,9 @@ public:
int get_current_action_history_id();
void discard_history(int p_idx, bool p_erase_from_map = true);
+
+ static EditorUndoRedoManager *get_singleton();
+ EditorUndoRedoManager();
~EditorUndoRedoManager();
};
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index f48cabf207..cc96107f97 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -170,6 +170,12 @@ void EditorExport::_notification(int p_what) {
case NOTIFICATION_PROCESS: {
update_export_presets();
} break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ for (int i = 0; i < export_platforms.size(); i++) {
+ export_platforms.write[i]->cleanup();
+ }
+ } break;
}
}
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index ef6c835b38..cacd181ad8 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -786,6 +786,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
HashSet<String> paths;
Vector<String> path_remaps;
+ paths.insert(ProjectSettings::get_singleton()->get_project_data_path().path_join("global_script_class_cache.cfg"));
if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) {
//find stuff
_export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
@@ -1322,6 +1323,121 @@ Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObj
return OK;
}
+void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
+ String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder);
+
+ Ref<DirAccess> da = DirAccess::open(dir);
+ da->list_dir_begin();
+ String f = da->get_next();
+ while (!f.is_empty()) {
+ if (f == "." || f == "..") {
+ f = da->get_next();
+ continue;
+ }
+ if (da->is_link(f)) {
+ OS::DateTime dt = OS::get_singleton()->get_datetime();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_year = dt.year;
+ zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mday = dt.day;
+ zipfi.tmz_date.tm_hour = dt.hour;
+ zipfi.tmz_date.tm_min = dt.minute;
+ zipfi.tmz_date.tm_sec = dt.second;
+ zipfi.dosDate = 0;
+ // 0120000: symbolic link type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = 0120644;
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.path_join(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ String target = da->read_link(f);
+ zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
+ zipCloseFileInZip(p_zip);
+ } 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 = is_executable(dir.path_join(f));
+
+ OS::DateTime dt = OS::get_singleton()->get_datetime();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_year = dt.year;
+ zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mday = dt.day;
+ zipfi.tmz_date.tm_hour = dt.hour;
+ zipfi.tmz_date.tm_min = dt.minute;
+ zipfi.tmz_date.tm_sec = dt.second;
+ zipfi.dosDate = 0;
+ // 0100000: regular file type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = (_is_executable ? 0100755 : 0100644);
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.path_join(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
+ if (fa.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f)));
+ return;
+ }
+ const int bufsize = 16384;
+ uint8_t buf[bufsize];
+
+ while (true) {
+ uint64_t got = fa->get_buffer(buf, bufsize);
+ if (got == 0) {
+ break;
+ }
+ zipWriteInFileInZip(p_zip, buf, got);
+ }
+
+ zipCloseFileInZip(p_zip);
+ }
+ f = da->get_next();
+ }
+ da->list_dir_end();
+}
+
Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
EditorProgress ep("savepack", TTR("Packing"), 102, true);
@@ -1642,5 +1758,123 @@ bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, S
return valid;
}
+Error EditorExportPlatform::ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out, int p_port_fwd) const {
+ String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh");
+ if (ssh_path.is_empty()) {
+ ssh_path = "ssh";
+ }
+
+ List<String> args;
+ args.push_back("-p");
+ args.push_back(p_port);
+ for (const String &E : p_ssh_args) {
+ args.push_back(E);
+ }
+ if (p_port_fwd > 0) {
+ args.push_back("-R");
+ args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd));
+ }
+ args.push_back(p_host);
+ args.push_back(p_cmd_args);
+
+ String out;
+ int exit_code = -1;
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ Error err = OS::get_singleton()->execute(ssh_path, args, &out, &exit_code, true);
+ if (out.is_empty()) {
+ print_verbose(vformat("Exit code: %d", exit_code));
+ } else {
+ print_verbose(vformat("Exit code: %d, Output: %s", exit_code, out.replace("\r\n", "\n")));
+ }
+ if (r_out) {
+ *r_out = out.replace("\r\n", "\n").get_slice("\n", 0);
+ }
+ if (err != OK) {
+ return err;
+ } else if (exit_code != 0) {
+ if (!out.is_empty()) {
+ print_line(out);
+ }
+ return FAILED;
+ }
+ return OK;
+}
+
+Error EditorExportPlatform::ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid, int p_port_fwd) const {
+ String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh");
+ if (ssh_path.is_empty()) {
+ ssh_path = "ssh";
+ }
+
+ List<String> args;
+ args.push_back("-p");
+ args.push_back(p_port);
+ for (const String &E : p_ssh_args) {
+ args.push_back(E);
+ }
+ if (p_port_fwd > 0) {
+ args.push_back("-R");
+ args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd));
+ }
+ args.push_back(p_host);
+ args.push_back(p_cmd_args);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ return OS::get_singleton()->create_process(ssh_path, args, r_pid);
+}
+
+Error EditorExportPlatform::ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const {
+ String scp_path = EditorSettings::get_singleton()->get("export/ssh/scp");
+ if (scp_path.is_empty()) {
+ scp_path = "scp";
+ }
+
+ List<String> args;
+ args.push_back("-P");
+ args.push_back(p_port);
+ for (const String &E : p_scp_args) {
+ args.push_back(E);
+ }
+ args.push_back(p_src_file);
+ args.push_back(vformat("%s:%s", p_host, p_dst_file));
+
+ String out;
+ int exit_code = -1;
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", scp_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ Error err = OS::get_singleton()->execute(scp_path, args, &out, &exit_code, true);
+ if (err != OK) {
+ return err;
+ } else if (exit_code != 0) {
+ if (!out.is_empty()) {
+ print_line(out);
+ }
+ return FAILED;
+ }
+ return OK;
+}
+
EditorExportPlatform::EditorExportPlatform() {
}
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index d3d8a8f186..1fb35759ac 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -35,6 +35,7 @@ class EditorFileSystemDirectory;
struct EditorProgress;
#include "core/io/dir_access.h"
+#include "core/io/zip_io.h"
#include "editor_export_preset.h"
#include "editor_export_shared_object.h"
#include "scene/gui/rich_text_label.h"
@@ -92,7 +93,6 @@ private:
void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths);
void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths);
- void gen_debug_flags(Vector<String> &r_flags, int p_flags);
static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
@@ -126,6 +126,13 @@ protected:
bool exists_export_template(String template_file_name, String *err) const;
String find_export_template(String template_file_name, String *err = nullptr) const;
void gen_export_flags(Vector<String> &r_flags, int p_flags);
+ void gen_debug_flags(Vector<String> &r_flags, int p_flags);
+
+ virtual void zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
+
+ Error ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out = nullptr, int p_port_fwd = -1) const;
+ Error ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid = nullptr, int p_port_fwd = -1) const;
+ Error ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const;
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const = 0;
@@ -215,6 +222,7 @@ public:
DEBUG_FLAG_VIEW_NAVIGATION = 16,
};
+ virtual void cleanup() {}
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { return OK; }
virtual Ref<Texture2D> get_run_icon() const { return get_logo(); }
diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h
index c71a62ee5c..8c24f2fc68 100644
--- a/editor/export/editor_export_platform_pc.h
+++ b/editor/export/editor_export_platform_pc.h
@@ -62,7 +62,6 @@ public:
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { return OK; };
virtual Error export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
- void set_extension(const String &p_extension, const String &p_feature_key = "default");
void set_name(const String &p_name);
void set_os_name(const String &p_name);
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index f34ebfa541..784dbc116a 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -34,6 +34,7 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "editor/editor_paths.h"
+#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform.h"
#include "scene/resources/resource_format_text.h"
@@ -226,4 +227,8 @@ void EditorExportPlugin::_bind_methods() {
}
EditorExportPlugin::EditorExportPlugin() {
+ GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false);
+
+ EDITOR_DEF("export/ssh/ssh", "");
+ EDITOR_DEF("export/ssh/scp", "");
}
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index df5d2dcd29..e099acca00 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -480,7 +480,7 @@ void ProjectExportDialog::_enc_filters_changed(const String &p_filters) {
}
void ProjectExportDialog::_open_key_help_link() {
- OS::get_singleton()->shell_open(vformat("%s/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
+ OS::get_singleton()->shell_open(vformat("%s/contributing/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
}
void ProjectExportDialog::_enc_pck_changed(bool p_pressed) {
@@ -979,9 +979,6 @@ void ProjectExportDialog::_export_all(bool p_debug) {
}
void ProjectExportDialog::_bind_methods() {
- ClassDB::bind_method("_get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ProjectExportDialog::drop_data_fw);
ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path);
ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path);
@@ -1022,8 +1019,7 @@ ProjectExportDialog::ProjectExportDialog() {
preset_vb->add_child(mc);
mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
presets = memnew(ItemList);
- // TODO: Must reimplement drag forwarding.
- //presets->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(presets, ProjectExportDialog);
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
duplicate_preset = memnew(Button);
diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp
index dfea2e706a..2a005034a5 100644
--- a/editor/fbx_importer_manager.cpp
+++ b/editor/fbx_importer_manager.cpp
@@ -144,12 +144,8 @@ FBXImporterManager::FBXImporterManager() {
browse_dialog = memnew(EditorFileDialog);
browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
-#if defined(X11_ENABLED)
- browse_dialog->add_filter("FBX2glTF-linux-x86_64");
-#elif defined(OSX_ENABLED)
- browse_dialog->add_filter("FBX2glTF-macos-x86_64");
-#elif defined(WINDOWS_ENABLED)
- browse_dialog->add_filter("FBX2glTF-windows-x86_64");
+#ifdef WINDOWS_ENABLED
+ browse_dialog->add_filter("*.exe");
#endif
browse_dialog->connect("file_selected", callable_mp(this, &FBXImporterManager::_select_file));
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6eed3e3e61..7ba60bfaad 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2051,7 +2051,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- ScriptEditor::get_singleton()->open_text_file_create_dialog(fpath);
+ String dir = ProjectSettings::get_singleton()->globalize_path(fpath);
+ ScriptEditor::get_singleton()->open_text_file_create_dialog(dir);
} break;
}
}
@@ -3020,9 +3021,6 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw);
ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path);
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
@@ -3122,10 +3120,11 @@ FileSystemDock::FileSystemDock() {
tree = memnew(Tree);
tree->set_hide_root(true);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, FileSystemDock);
tree->set_allow_rmb_select(true);
tree->set_select_mode(Tree::SELECT_MULTI);
tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
+ tree->set_column_clip_content(0, true);
split_box->add_child(tree);
tree->connect("item_activated", callable_mp(this, &FileSystemDock::_tree_activate_file));
@@ -3159,7 +3158,7 @@ FileSystemDock::FileSystemDock() {
files = memnew(ItemList);
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_select_mode(ItemList::SELECT_MULTI);
- files->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(files, FileSystemDock);
files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));
files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index 3ee7d5ddd8..7f0417ea29 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -130,7 +130,7 @@ void GroupDialog::_add_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add to Group"));
while (selected) {
@@ -160,7 +160,7 @@ void GroupDialog::_removed_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove from Group"));
while (selected) {
@@ -248,7 +248,7 @@ void GroupDialog::_group_renamed() {
renamed_group->set_text(0, name); // Spaces trimmed.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Group"));
List<Node *> nodes;
@@ -325,7 +325,7 @@ void GroupDialog::_modify_group_pressed(Object *p_item, int p_column, int p_id,
case DELETE_GROUP: {
String name = ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Group"));
List<Node *> nodes;
@@ -597,7 +597,7 @@ void GroupsEditor::_add_group(const String &p_group) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add to Group"));
undo_redo->add_do_method(node, "add_to_group", name, true);
@@ -652,7 +652,7 @@ void GroupsEditor::_group_renamed() {
ti->set_text(0, name); // Spaces trimmed.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Group"));
undo_redo->add_do_method(node, "remove_from_group", selected_group);
@@ -688,7 +688,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu
switch (p_id) {
case DELETE_GROUP: {
const String name = ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove from Group"));
undo_redo->add_do_method(node, "remove_from_group", name);
diff --git a/editor/history_dock.cpp b/editor/history_dock.cpp
index f9fe1093b8..41ca519400 100644
--- a/editor/history_dock.cpp
+++ b/editor/history_dock.cpp
@@ -221,7 +221,7 @@ void HistoryDock::_notification(int p_notification) {
HistoryDock::HistoryDock() {
set_name("History");
- ur_manager = EditorNode::get_undo_redo();
+ ur_manager = EditorUndoRedoManager::get_singleton();
ur_manager->connect("history_changed", callable_mp(this, &HistoryDock::on_history_changed));
ur_manager->connect("version_changed", callable_mp(this, &HistoryDock::on_version_changed));
diff --git a/editor/history_dock.h b/editor/history_dock.h
index 81d1d02b79..d507f19b07 100644
--- a/editor/history_dock.h
+++ b/editor/history_dock.h
@@ -40,7 +40,7 @@ class EditorUndoRedoManager;
class HistoryDock : public VBoxContainer {
GDCLASS(HistoryDock, VBoxContainer);
- Ref<EditorUndoRedoManager> ur_manager;
+ EditorUndoRedoManager *ur_manager;
ItemList *action_list = nullptr;
CheckBox *current_scene_checkbox = nullptr;
diff --git a/editor/icons/PlayRemote.svg b/editor/icons/PlayRemote.svg
new file mode 100644
index 0000000000..ea2195294f
--- /dev/null
+++ b/editor/icons/PlayRemote.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path d="m12.998 2.548-9.996.005a2.006 2.006 0 0 0-2.006 2v4.61c0 1.107.898 2.003 2.006 2.003h3.996v.9h-1.68v.381H3.001v2h2.315v.38h5.366v-.38H13v-2.004h-2.315v-.378H9.004v-.9h3.994a2.006 2.006 0 0 0 2.006-2.003v-4.61c0-1.106-.9-2.003-2.006-2.003zm-7.496 1.31 5 3-5 3z" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/editor/icons/README.md b/editor/icons/README.md
index 3159565180..d191000985 100644
--- a/editor/icons/README.md
+++ b/editor/icons/README.md
@@ -3,5 +3,5 @@
This folder contains all the icons used by Godot editor (except for platform
icons which are located in their respective platform folder).
-See [Editor icons](https://docs.godotengine.org/en/latest/development/editor/creating_icons.html)
+See [Editor icons](https://docs.godotengine.org/en/latest/contributing/development/editor/creating_icons.html)
in the documentation for details on creating icons for the Godot editor.
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index fcd706627d..a8d746fde6 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -262,7 +262,7 @@ void Collada::_parse_asset(XMLParser &parser) {
COLLADA_PRINT("up axis: " + parser.get_node_data());
} else if (name == "unit") {
- state.unit_scale = parser.get_attribute_value("meter").to_float();
+ state.unit_scale = parser.get_named_attribute_value("meter").to_float();
COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
}
@@ -273,7 +273,7 @@ void Collada::_parse_asset(XMLParser &parser) {
}
void Collada::_parse_image(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
if (!parser.is_empty()) {
@@ -286,7 +286,7 @@ void Collada::_parse_image(XMLParser &parser) {
if (state.version < State::Version(1, 4, 0)) {
/* <1.4 */
- String path = parser.get_attribute_value("source").strip_edges();
+ String path = parser.get_named_attribute_value("source").strip_edges();
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
@@ -337,9 +337,9 @@ void Collada::_parse_material(XMLParser &parser) {
Material material;
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.has_attribute("name")) {
- material.name = parser.get_attribute_value("name");
+ material.name = parser.get_named_attribute_value("name");
}
if (state.version < State::Version(1, 4, 0)) {
@@ -348,7 +348,7 @@ void Collada::_parse_material(XMLParser &parser) {
} else {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
- material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
+ material.instance_effect = _uri_to_id(parser.get_named_attribute_value("url"));
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material") {
break; //end of <asset>
}
@@ -549,7 +549,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
_parse_effect_material(parser, effect, id); // try again
} else if (parser.get_node_name() == "newparam") {
- String name = parser.get_attribute_value("sid");
+ String name = parser.get_named_attribute_value("sid");
Variant value = _parse_param(parser);
effect.params[name] = value;
COLLADA_PRINT("param: " + name + " value:" + String(value));
@@ -591,7 +591,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
}
} else if (parser.get_node_name() == "texture") {
- String sampler = parser.get_attribute_value("texture");
+ String sampler = parser.get_named_attribute_value("texture");
if (!effect.params.has(sampler)) {
ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
} else {
@@ -609,7 +609,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
} else if (what == "emission") {
effect.emission.texture = uri;
} else if (what == "bump") {
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
}
@@ -654,7 +654,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "texture") {
- String sampler = parser.get_attribute_value("texture");
+ String sampler = parser.get_named_attribute_value("texture");
if (!effect.params.has(sampler)) {
ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
} else {
@@ -665,7 +665,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
} else {
String uri = effect.params[surface];
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
}
@@ -703,11 +703,11 @@ void Collada::_parse_effect(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
Effect effect;
if (parser.has_attribute("name")) {
- effect.name = parser.get_attribute_value("name");
+ effect.name = parser.get_named_attribute_value("name");
}
_parse_effect_material(parser, effect, id);
@@ -724,7 +724,7 @@ void Collada::_parse_camera(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
state.camera_data_map[id] = CameraData();
CameraData &camera = state.camera_data_map[id];
@@ -780,7 +780,7 @@ void Collada::_parse_light(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
state.light_data_map[id] = LightData();
LightData &light = state.light_data_map[id];
@@ -848,7 +848,7 @@ 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();
+ String closed = parser.get_named_attribute_value_safe("closed").to_lower();
curvedata.closed = closed == "true" || closed == "1";
COLLADA_PRINT("curve name: " + p_name);
@@ -865,7 +865,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
curvedata.sources[id] = CurveData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -888,15 +888,15 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
} else if (section == "accessor") { // child of source (below a technique tag)
if (curvedata.sources.has(current_source)) {
- curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ curvedata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
}
} else if (section == "control_vertices") {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
curvedata.control_vertices[semantic] = source;
@@ -945,7 +945,7 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
meshdata.sources[id] = MeshData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -961,19 +961,19 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
} else if (section == "accessor") { // child of source (below a technique tag)
if (meshdata.sources.has(current_source)) {
- meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ meshdata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
}
} else if (section == "vertices") {
MeshData::Vertices vert;
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
int last_ref = 0;
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
if (semantic == "TEXCOORD") {
semantic = "TEXCOORD" + itos(last_ref++);
@@ -998,22 +998,22 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
MeshData::Primitives prim;
if (parser.has_attribute("material")) {
- prim.material = parser.get_attribute_value("material");
+ prim.material = parser.get_named_attribute_value("material");
}
- prim.count = parser.get_attribute_value("count").to_int();
+ prim.count = parser.get_named_attribute_value("count").to_int();
prim.vertex_size = 0;
int last_ref = 0;
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
if (semantic == "TEXCOORD") {
semantic = "TEXCOORD" + itos(last_ref++);
}
- int offset = parser.get_attribute_value("offset").to_int();
+ int offset = parser.get_named_attribute_value("offset").to_int();
MeshData::Primitives::SourceRef sref;
sref.source = source;
@@ -1074,7 +1074,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
state.skin_controller_data_map[p_id] = SkinControllerData();
SkinControllerData &skindata = state.skin_controller_data_map[p_id];
- skindata.base = _uri_to_id(parser.get_attribute_value("source"));
+ skindata.base = _uri_to_id(parser.get_named_attribute_value("source"));
String current_source;
@@ -1091,7 +1091,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
} else if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
skindata.sources[id] = SkinControllerData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -1125,7 +1125,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
if (skindata.sources.has(current_source)) {
int stride = 1;
if (parser.has_attribute("stride")) {
- stride = parser.get_attribute_value("stride").to_int();
+ stride = parser.get_named_attribute_value("stride").to_int();
}
skindata.sources[current_source].stride = stride;
@@ -1138,8 +1138,8 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
joint.sources[semantic] = source;
@@ -1155,15 +1155,15 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
} else if (section == "vertex_weights") {
SkinControllerData::Weights weights;
- weights.count = parser.get_attribute_value("count").to_int();
+ weights.count = parser.get_named_attribute_value("count").to_int();
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
- int offset = parser.get_attribute_value("offset").to_int();
+ int offset = parser.get_named_attribute_value("offset").to_int();
SkinControllerData::Weights::SourceRef sref;
sref.source = source;
@@ -1228,8 +1228,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
state.morph_controller_data_map[p_id] = MorphControllerData();
MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
- morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
- morphdata.mode = parser.get_attribute_value("method");
+ morphdata.mesh = _uri_to_id(parser.get_named_attribute_value("source"));
+ morphdata.mode = parser.get_named_attribute_value("method");
String current_source;
while (parser.read() == OK) {
@@ -1237,7 +1237,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
morphdata.sources[id] = MorphControllerData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -1261,7 +1261,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
if (morphdata.sources.has(current_source)) {
int stride = 1;
if (parser.has_attribute("stride")) {
- stride = parser.get_attribute_value("stride").to_int();
+ stride = parser.get_named_attribute_value("stride").to_int();
}
morphdata.sources[current_source].stride = stride;
@@ -1272,8 +1272,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
morphdata.targets[semantic] = source;
@@ -1295,7 +1295,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
}
void Collada::_parse_controller(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.is_empty()) {
return;
@@ -1320,7 +1320,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
String type = parser.get_node_name();
NodeGeometry *geom = memnew(NodeGeometry);
geom->controller = type == "instance_controller";
- geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
+ geom->source = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (parser.is_empty()) { //nothing else to parse...
return geom;
@@ -1329,8 +1329,8 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "instance_material") {
- String symbol = parser.get_attribute_value("symbol");
- String target = _uri_to_id(parser.get_attribute_value("target"));
+ String symbol = parser.get_named_attribute_value("symbol");
+ String target = _uri_to_id(parser.get_named_attribute_value("target"));
NodeGeometry::Material mat;
mat.target = target;
@@ -1370,7 +1370,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
NodeCamera *cam = memnew(NodeCamera);
- cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
+ cam->camera = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1391,7 +1391,7 @@ Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
NodeLight *cam = memnew(NodeLight);
- cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
+ cam->light = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1437,7 +1437,7 @@ Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
String name;
- String id = parser.get_attribute_value_safe("id");
+ String id = parser.get_named_attribute_value_safe("id");
bool found_name = false;
@@ -1455,25 +1455,25 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
Node *node = nullptr;
- name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
+ name = parser.has_attribute("name") ? parser.get_named_attribute_value_safe("name") : parser.get_named_attribute_value_safe("id");
if (name.is_empty()) {
name = id;
} else {
found_name = true;
}
- if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
+ if ((parser.has_attribute("type") && parser.get_named_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
// handle a bone
NodeJoint *joint = memnew(NodeJoint);
if (parser.has_attribute("sid")) { //bones may not have sid
- joint->sid = parser.get_attribute_value("sid");
+ joint->sid = parser.get_named_attribute_value("sid");
//state.bone_map[joint->sid]=joint;
} else if (state.idref_joints.has(name)) {
joint->sid = name; //kind of a cheat but..
} else if (parser.has_attribute("name")) {
- joint->sid = parser.get_attribute_value_safe("name");
+ joint->sid = parser.get_named_attribute_value_safe("name");
}
if (!joint->sid.is_empty()) {
@@ -1490,7 +1490,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
if (section == "translate") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_TRANSLATE;
@@ -1501,7 +1501,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "rotate") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_ROTATE;
@@ -1513,7 +1513,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "scale") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_SCALE;
@@ -1527,7 +1527,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "matrix") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_MATRIX;
@@ -1544,7 +1544,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "visibility") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_VISIBILITY;
@@ -1609,7 +1609,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
}
void Collada::_parse_visual_scene(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.is_empty()) {
return;
@@ -1619,7 +1619,7 @@ void Collada::_parse_visual_scene(XMLParser &parser) {
VisualScene &vscene = state.visual_scene_map[id];
if (parser.has_attribute("name")) {
- vscene.name = parser.get_attribute_value("name");
+ vscene.name = parser.get_named_attribute_value("name");
}
while (parser.read() == OK) {
@@ -1656,7 +1656,7 @@ void Collada::_parse_animation(XMLParser &parser) {
String id = "";
if (parser.has_attribute("id")) {
- id = parser.get_attribute_value("id");
+ id = parser.get_named_attribute_value("id");
}
String current_source;
@@ -1668,7 +1668,7 @@ void Collada::_parse_animation(XMLParser &parser) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
String name = parser.get_node_name();
if (name == "source") {
- current_source = parser.get_attribute_value("id");
+ current_source = parser.get_named_attribute_value("id");
source_param_names[current_source] = Vector<String>();
source_param_types[current_source] = Vector<String>();
@@ -1683,32 +1683,32 @@ void Collada::_parse_animation(XMLParser &parser) {
}
} else if (name == "accessor") {
if (!current_source.is_empty() && parser.has_attribute("stride")) {
- source_strides[current_source] = parser.get_attribute_value("stride").to_int();
+ source_strides[current_source] = parser.get_named_attribute_value("stride").to_int();
}
} else if (name == "sampler") {
- current_sampler = parser.get_attribute_value("id");
+ current_sampler = parser.get_named_attribute_value("id");
samplers[current_sampler] = HashMap<String, String>();
} else if (name == "param") {
if (parser.has_attribute("name")) {
- source_param_names[current_source].push_back(parser.get_attribute_value("name"));
+ source_param_names[current_source].push_back(parser.get_named_attribute_value("name"));
} else {
source_param_names[current_source].push_back("");
}
if (parser.has_attribute("type")) {
- source_param_types[current_source].push_back(parser.get_attribute_value("type"));
+ source_param_types[current_source].push_back(parser.get_named_attribute_value("type"));
} else {
source_param_types[current_source].push_back("");
}
} else if (name == "input") {
if (!current_sampler.is_empty()) {
- samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
+ samplers[current_sampler][parser.get_named_attribute_value("semantic")] = parser.get_named_attribute_value("source");
}
} else if (name == "channel") {
- channel_sources.push_back(parser.get_attribute_value("source"));
- channel_targets.push_back(parser.get_attribute_value("target"));
+ channel_sources.push_back(parser.get_named_attribute_value("source"));
+ channel_targets.push_back(parser.get_named_attribute_value("target"));
}
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation") {
@@ -1857,22 +1857,22 @@ void Collada::_parse_animation_clip(XMLParser &parser) {
AnimationClip clip;
if (parser.has_attribute("name")) {
- clip.name = parser.get_attribute_value("name");
+ clip.name = parser.get_named_attribute_value("name");
} else if (parser.has_attribute("id")) {
- clip.name = parser.get_attribute_value("id");
+ clip.name = parser.get_named_attribute_value("id");
}
if (parser.has_attribute("start")) {
- clip.begin = parser.get_attribute_value("start").to_float();
+ clip.begin = parser.get_named_attribute_value("start").to_float();
}
if (parser.has_attribute("end")) {
- clip.end = parser.get_attribute_value("end").to_float();
+ clip.end = parser.get_named_attribute_value("end").to_float();
}
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
String name = parser.get_node_name();
if (name == "instance_animation") {
- String url = _uri_to_id(parser.get_attribute_value("url"));
+ String url = _uri_to_id(parser.get_named_attribute_value("url"));
clip.tracks.push_back(url);
}
@@ -1894,9 +1894,9 @@ void Collada::_parse_scene(XMLParser &parser) {
String name = parser.get_node_name();
if (name == "instance_visual_scene") {
- state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
+ state.root_visual_scene = _uri_to_id(parser.get_named_attribute_value("url"));
} else if (name == "instance_physics_scene") {
- state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
+ state.root_physics_scene = _uri_to_id(parser.get_named_attribute_value("url"));
}
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene") {
@@ -1925,8 +1925,8 @@ void Collada::_parse_library(XMLParser &parser) {
} else if (name == "light") {
_parse_light(parser);
} else if (name == "geometry") {
- String id = parser.get_attribute_value("id");
- String name2 = parser.get_attribute_value_safe("name");
+ String id = parser.get_named_attribute_value("id");
+ String name2 = parser.get_named_attribute_value_safe("name");
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "mesh") {
@@ -2346,7 +2346,7 @@ Error Collada::load(const String &p_path, int p_flags) {
{
//version
- String version = parser.get_attribute_value("version");
+ String version = parser.get_named_attribute_value("version");
state.version.major = version.get_slice(".", 0).to_int();
state.version.minor = version.get_slice(".", 1).to_int();
state.version.rev = version.get_slice(".", 2).to_int();
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index f1fd1d5a03..3dd01754a3 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -206,6 +206,20 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
+ // Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree)
+ // This should only match, if it's indeed a COFF file header
+ // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
+ const int first_bytes = f->get_16();
+ static const Vector<int> coff_header_machines{
+ 0x0, // IMAGE_FILE_MACHINE_UNKNOWN
+ 0x8664, // IMAGE_FILE_MACHINE_AMD64
+ 0x1c0, // IMAGE_FILE_MACHINE_ARM
+ 0x14c, // IMAGE_FILE_MACHINE_I386
+ 0x200, // IMAGE_FILE_MACHINE_IA64
+ };
+ ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path));
+ f->seek(0);
+
Ref<ArrayMesh> mesh;
mesh.instantiate();
@@ -218,7 +232,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Vector<Vector3> normals;
Vector<Vector2> uvs;
Vector<Color> colors;
- String name;
+ const String default_name = "Mesh";
+ String name = default_name;
HashMap<String, HashMap<String, Ref<StandardMaterial3D>>> material_map;
@@ -395,9 +410,12 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
if (l.begins_with("o ") || f->eof_reached()) {
if (!p_single_mesh) {
- mesh->set_name(name);
- r_meshes.push_back(mesh);
- mesh.instantiate();
+ if (mesh->get_surface_count() > 0) {
+ mesh->set_name(name);
+ r_meshes.push_back(mesh);
+ mesh.instantiate();
+ }
+ name = default_name;
current_group = "";
current_material = "";
}
@@ -460,6 +478,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co
for (const Ref<Mesh> &m : meshes) {
Ref<ImporterMesh> mesh;
mesh.instantiate();
+ mesh->set_name(m->get_name());
for (int i = 0; i < m->get_surface_count(); i++) {
mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i));
}
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index 7187e85df0..ba48fc9029 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -91,6 +91,7 @@ static String _include_function(const String &p_path, void *userpointer) {
Error ResourceImporterShaderFile::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
/* STEP 1, Read shader code */
+ ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders.");
Error err;
Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err);
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index f6ec7da158..044f7475c2 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -703,15 +703,17 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
}
MeshData &md = mesh_map[p_id];
- if (p_from != mesh_tree) {
- md.mesh_node->uncollapse_tree();
- md.mesh_node->select(0);
- mesh_tree->ensure_cursor_is_visible();
- }
- if (p_from != scene_tree) {
- md.scene_node->uncollapse_tree();
- md.scene_node->select(0);
- scene_tree->ensure_cursor_is_visible();
+ if (md.mesh_node != nullptr) {
+ if (p_from != mesh_tree) {
+ md.mesh_node->uncollapse_tree();
+ md.mesh_node->select(0);
+ mesh_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != scene_tree) {
+ md.scene_node->uncollapse_tree();
+ md.scene_node->select(0);
+ scene_tree->ensure_cursor_is_visible();
+ }
}
mesh_preview->set_mesh(md.mesh);
@@ -1234,6 +1236,12 @@ SceneImportSettings::SceneImportSettings() {
action_menu = memnew(MenuButton);
action_menu->set_text(TTR("Actions..."));
+ // Style the MenuButton like a regular Button to make it more noticeable.
+ action_menu->set_flat(false);
+ action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
+ action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
+ action_menu->add_theme_style_override("pressed", get_theme_stylebox("pressed", "Button"));
+ action_menu->set_focus_mode(Control::FOCUS_ALL);
menu_hb->add_child(action_menu);
action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 4cd8976e80..b28373e308 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -186,8 +186,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
- int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id;
- editor_data->get_undo_redo()->clear_history(true, history_id);
+ int history_id = EditorUndoRedoManager::get_singleton()->get_history_for_object(current).id;
+ EditorUndoRedoManager::get_singleton()->clear_history(true, history_id);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(current);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 6fa980a8e5..5503645930 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -33,7 +33,6 @@
#include "core/config/project_settings.h"
#include "core/string/translation.h"
#include "editor/editor_file_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_translation_parser.h"
#include "editor/editor_undo_redo_manager.h"
@@ -81,7 +80,7 @@ void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translations"));
@@ -112,7 +111,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
translations.remove_at(idx);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translations"));
@@ -143,7 +142,7 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths)
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Path(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", prev);
@@ -175,7 +174,7 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_
}
remaps[key] = r;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -239,7 +238,7 @@ void LocalizationEditor::_translation_res_option_changed() {
updating_translations = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -273,7 +272,7 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
remaps.erase(key);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -313,7 +312,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
r.remove_at(idx);
remaps[key] = r;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -332,7 +331,7 @@ void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translations_pot_files"));
@@ -359,7 +358,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button,
pot_translations.remove_at(idx);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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", GLOBAL_GET("internationalization/locale/translations_pot_files"));
diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp
index dbbcd57742..2a55ac949f 100644
--- a/editor/multi_node_edit.cpp
+++ b/editor/multi_node_edit.cpp
@@ -55,7 +55,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
node_path_target = es->get_node(p_value);
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS);
for (const NodePath &E : nodes) {
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 8e94ae871b..7c23e19564 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -91,7 +91,7 @@ void AbstractPolygon2DEditor::_set_polygon(int p_idx, const Variant &p_polygon)
void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Node2D *node = _get_node();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(node, "set_polygon", p_polygon);
undo_redo->add_undo_method(node, "set_polygon", p_previous);
}
@@ -101,7 +101,7 @@ Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const {
}
void AbstractPolygon2DEditor::_commit_action() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
@@ -205,7 +205,7 @@ void AbstractPolygon2DEditor::_wip_close() {
if (_is_line()) {
_set_polygon(0, wip);
} else if (wip.size() >= (_is_line() ? 2 : 3)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Polygon"));
_action_add_polygon(wip);
if (_has_uv()) {
@@ -257,7 +257,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return false;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_event;
if (!_has_resource()) {
@@ -619,7 +619,7 @@ void AbstractPolygon2DEditor::_bind_methods() {
}
void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Vector<Vector2> vertices = _get_polygon(p_vertex.polygon);
if (vertices.size() > (_is_line() ? 2 : 3)) {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 85cca23e64..33aebe5883 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -157,7 +157,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -351,7 +351,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Config"));
undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
@@ -375,7 +375,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text());
undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label());
@@ -431,7 +431,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -450,7 +450,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
anim->set_animation(animations_to_add[p_index]);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -524,7 +524,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
if (selected_point != -1) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove BlendSpace1D Point"));
undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);
@@ -544,7 +544,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index c22f0a9f15..7f8137f8d5 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -228,7 +228,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Triangle"));
undo_redo->add_do_method(blend_space.ptr(), "add_triangle", making_triangle[0], making_triangle[1], making_triangle[2]);
undo_redo->add_undo_method(blend_space.ptr(), "remove_triangle", blend_space->get_triangle_count());
@@ -254,7 +254,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (!read_only) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -362,7 +362,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -381,7 +381,7 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
anim->set_animation(animations_to_add[p_index]);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -676,7 +676,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace2D Config"));
undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value()));
undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
@@ -702,7 +702,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text());
undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label());
@@ -715,7 +715,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
}
void AnimationNodeBlendSpace2DEditor::_erase_selected() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (selected_point != -1) {
updating = true;
undo_redo->create_action(TTR("Remove BlendSpace2D Point"));
@@ -778,7 +778,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
return;
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value()));
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -856,7 +856,7 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() {
}
void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Auto Triangles"));
undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed());
undo_redo->add_undo_method(blend_space.ptr(), "set_auto_triangles", blend_space->get_auto_triangles());
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f680993026..f5f9ec11b3 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -103,7 +103,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
return;
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
@@ -187,7 +187,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
- prop->set_read_only(read_only);
+ prop->set_read_only(read_only || (F.usage & PROPERTY_USAGE_READ_ONLY));
prop->set_object_and_property(tree, base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -363,7 +363,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
name = base_name + " " + itos(base);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node to BlendTree"));
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
@@ -432,7 +432,7 @@ void AnimationNodeBlendTreeEditor::_popup_hide() {
void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Moved"));
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
@@ -454,7 +454,7 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Connected"));
undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
@@ -471,7 +471,7 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from,
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
@@ -487,7 +487,7 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node);
ERR_FAIL_COND(!anim.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Animation"));
undo_redo->add_do_method(anim.ptr(), "set_animation", option);
undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation());
@@ -501,7 +501,7 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -546,7 +546,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Node(s)"));
for (const StringName &F : to_erase) {
@@ -580,7 +580,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) {
void AnimationNodeBlendTreeEditor::_filter_toggled() {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Filter On/Off"));
undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_enabled", filter_enabled->is_pressed());
undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_enabled", _filter_edit->is_filter_enabled());
@@ -598,7 +598,7 @@ void AnimationNodeBlendTreeEditor::_filter_edited() {
bool filtered = edited->is_checked(0);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Filter"));
undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", edited_path, filtered);
undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", edited_path, _filter_edit->is_path_filtered(edited_path));
@@ -981,7 +981,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
String base_path = AnimationTreeEditor::get_singleton()->get_base_path();
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Renamed"));
undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index 9decbef51b..bf7e419fe4 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -94,7 +94,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
void AnimationLibraryEditor::_add_library_confirm() {
if (adding_animation) {
String anim_name = add_library_name->get_text();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
ERR_FAIL_COND(!al.is_valid());
@@ -111,7 +111,7 @@ void AnimationLibraryEditor::_add_library_confirm() {
} else {
String lib_name = add_library_name->get_text();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<AnimationLibrary> al;
al.instantiate();
@@ -211,7 +211,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
ald->add_animation(animation_name, animation);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_do_method(player, "add_animation_library", lib_name, ald);
@@ -280,7 +280,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<Animation> animd = anim->duplicate();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd);
@@ -328,7 +328,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name));
undo_redo->add_do_method(player, "add_animation_library", name, al);
@@ -366,7 +366,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -382,7 +382,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
EditorNode::get_singleton()->save_resource_in_path(al, p_path);
if (al->get_path() != prev_path) { // Save successful.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library));
undo_redo->add_do_method(al.ptr(), "set_path", al->get_path());
@@ -403,7 +403,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
String prev_path = anim->get_path();
EditorNode::get_singleton()->save_resource_in_path(anim, p_path);
if (anim->get_path() != prev_path) { // Save successful.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation));
undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path());
@@ -421,7 +421,7 @@ void AnimationLibraryEditor::_item_renamed() {
String text = ti->get_text(0);
String old_text = ti->get_metadata(0);
bool restore_text = false;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
restore_text = true;
@@ -535,7 +535,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
name = base_name + " (" + itos(attempt) + ")";
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -554,14 +554,14 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_popup->add_separator();
file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY);
Rect2 pos = tree->get_item_rect(p_item, 1, 0);
- Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
file_popup->popup(Rect2(popup_pos, Size2()));
file_dialog_animation = StringName();
file_dialog_library = lib_name;
} break;
case LIB_BUTTON_DELETE: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
@@ -594,7 +594,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_popup->add_separator();
file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION);
Rect2 pos = tree->get_item_rect(p_item, 1, 0);
- Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
file_popup->popup(Rect2(popup_pos, Size2()));
file_dialog_animation = anim_name;
@@ -602,7 +602,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
} break;
case ANIM_BUTTON_DELETE: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 10f2ce25d9..caee7514d0 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -94,6 +94,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
// Need the last frame after it stopped.
frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
+ stop->set_icon(stop_icon);
}
last_active = player->is_playing();
@@ -119,8 +120,15 @@ void AnimationPlayerEditor::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
- autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
+ stop_icon = get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ pause_icon = get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"));
+ if (player && player->is_playing()) {
+ stop->set_icon(pause_icon);
+ } else {
+ stop->set_icon(stop_icon);
+ }
+ autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
play->set_icon(get_theme_icon(SNAME("PlayStart"), SNAME("EditorIcons")));
play_from->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
play_bw->set_icon(get_theme_icon(SNAME("PlayStartBackwards"), SNAME("EditorIcons")));
@@ -137,7 +145,6 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_reset_img->blit_rect(reset_img, Rect2i(Point2i(), icon_size), Point2i(icon_size.x, 0));
autoplay_reset_icon = ImageTexture::create_from_image(autoplay_reset_img);
}
- stop->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
onion_toggle->set_icon(get_theme_icon(SNAME("Onion"), SNAME("EditorIcons")));
onion_skinning->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
@@ -170,7 +177,7 @@ void AnimationPlayerEditor::_autoplay_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
String current = animation->get_item_text(animation->get_selected());
if (player->get_autoplay() == current) {
//unset
@@ -204,7 +211,7 @@ void AnimationPlayerEditor::_play_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_play_from_pressed() {
@@ -221,7 +228,7 @@ void AnimationPlayerEditor::_play_from_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
String AnimationPlayerEditor::_get_current() const {
@@ -242,7 +249,7 @@ void AnimationPlayerEditor::_play_bw_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_play_bw_from_pressed() {
@@ -259,7 +266,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_stop_pressed() {
@@ -267,9 +274,16 @@ void AnimationPlayerEditor::_stop_pressed() {
return;
}
- player->pause();
- play->set_pressed(false);
- stop->set_pressed(true);
+ if (player->is_playing()) {
+ player->pause();
+ } else {
+ String current = _get_current();
+ player->stop();
+ player->set_assigned_animation(current);
+ frame->set_value(0);
+ track_editor->set_anim_pos(0);
+ }
+ stop->set_icon(stop_icon);
}
void AnimationPlayerEditor::_animation_selected(int p_which) {
@@ -388,7 +402,7 @@ void AnimationPlayerEditor::_animation_remove_confirmed() {
if (current.contains("/")) {
current = current.get_slice("/", 1);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Animation"));
if (player->get_autoplay() == current) {
undo_redo->add_do_method(player, "set_autoplay", "");
@@ -464,7 +478,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (name_dialog_op) {
case TOOL_RENAME_ANIM: {
String current = animation->get_item_text(animation->get_selected());
@@ -599,7 +613,7 @@ void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) {
String current = animation->get_item_text(animation->get_selected());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Blend Next Changed"));
undo_redo->add_do_method(player, "animation_set_next", current, blend_editor.next->get_item_text(p_idx));
undo_redo->add_undo_method(player, "animation_set_next", current, player->animation_get_next(current));
@@ -686,7 +700,7 @@ void AnimationPlayerEditor::_blend_edited() {
float blend_time = selected->get_range(1);
float prev_blend_time = player->get_blend_time(current, to);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Blend Time"));
undo_redo->add_do_method(player, "set_blend_time", current, to, blend_time);
undo_redo->add_undo_method(player, "set_blend_time", current, to, prev_blend_time);
@@ -798,12 +812,9 @@ void AnimationPlayerEditor::_update_animation() {
updating = true;
if (player->is_playing()) {
- play->set_pressed(true);
- stop->set_pressed(false);
-
+ stop->set_icon(pause_icon);
} else {
- play->set_pressed(false);
- stop->set_pressed(true);
+ stop->set_icon(stop_icon);
}
scale->set_text(String::num(player->get_speed_scale(), 2));
@@ -1663,7 +1674,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
stop = memnew(Button);
stop->set_flat(true);
- stop->set_toggle_mode(true);
hb->add_child(stop);
stop->set_tooltip_text(TTR("Stop animation playback. (S)"));
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 6c690c812c..327200506f 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -101,6 +101,8 @@ class AnimationPlayerEditor : public VBoxContainer {
OptionButton *library = nullptr;
Label *name_title = nullptr;
+ Ref<Texture2D> stop_icon;
+ Ref<Texture2D> pause_icon;
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
Ref<ImageTexture> autoplay_reset_icon;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 0de5064a00..a675495429 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -246,7 +246,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node"));
for (int i = 0; i < node_rects.size(); i++) {
@@ -543,7 +543,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Group");
// Move selected nodes to the new state machine
@@ -658,7 +658,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
Vector<TransitionUR> transitions_ur;
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Ungroup");
// Move all child nodes to current state machine
@@ -935,7 +935,7 @@ void AnimationNodeStateMachineEditor::_stop_connecting() {
void AnimationNodeStateMachineEditor::_delete_selected() {
TreeItem *item = delete_tree->get_next_selected(nullptr);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
while (item) {
if (!updating) {
updating = true;
@@ -963,7 +963,7 @@ void AnimationNodeStateMachineEditor::_delete_all() {
selected_multi_transition = TransitionLine();
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Transition(s) Removed");
_erase_selected(true);
for (int i = 0; i < multi_transitions.size(); i++) {
@@ -1043,7 +1043,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
@@ -1070,7 +1070,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
@@ -1100,7 +1100,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
tr->set_advance_mode(auto_advance->is_pressed() ? AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_AUTO : AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_ENABLED);
tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!p_nested_action) {
updating = true;
undo_redo->create_action(TTR("Add Transition"));
@@ -1778,7 +1778,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Renamed"));
undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name);
@@ -1813,7 +1813,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
if (!p_nested_action) {
updating = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Removed"));
for (int i = 0; i < node_rects.size(); i++) {
@@ -1882,7 +1882,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
if (!p_nested_action) {
updating = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Transition Removed"));
undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to);
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 9f2cfc8d9c..eab5eb0404 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -705,6 +705,12 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = {
"testing",
};
+const char *EditorAssetLibrary::support_text[SUPPORT_MAX] = {
+ TTRC("Official"),
+ TTRC("Community"),
+ TTRC("Testing"),
+};
+
void EditorAssetLibrary::_select_author(int p_id) {
// Open author window.
}
@@ -1242,15 +1248,28 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
library_vb->add_child(asset_bottom_page);
if (result.is_empty()) {
+ String support_list;
+ for (int i = 0; i < SUPPORT_MAX; i++) {
+ if (support->get_popup()->is_item_checked(i)) {
+ if (!support_list.is_empty()) {
+ support_list += ", ";
+ }
+ support_list += TTRGET(support_text[i]);
+ }
+ }
+ if (support_list.is_empty()) {
+ support_list = "-";
+ }
+
if (!filter->get_text().is_empty()) {
library_info->set_text(
- vformat(TTR("No results for \"%s\"."), filter->get_text()));
+ vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list));
} else {
// No results, even though the user didn't search for anything specific.
// This is typically because the version number changed recently
// and no assets compatible with the new version have been published yet.
library_info->set_text(
- vformat(TTR("No results compatible with %s %s."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH)));
+ vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list));
}
library_info->show();
} else {
@@ -1510,9 +1529,9 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(support);
support->set_text(TTR("Support"));
support->get_popup()->set_hide_on_checkable_item_selection(false);
- support->get_popup()->add_check_item(TTR("Official"), SUPPORT_OFFICIAL);
- support->get_popup()->add_check_item(TTR("Community"), SUPPORT_COMMUNITY);
- support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_OFFICIAL]), SUPPORT_OFFICIAL);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_COMMUNITY]), SUPPORT_COMMUNITY);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_TESTING]), SUPPORT_TESTING);
support->get_popup()->set_item_checked(SUPPORT_OFFICIAL, true);
support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, true);
support->get_popup()->connect("id_pressed", callable_mp(this, &EditorAssetLibrary::_support_toggled));
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 0667f474da..8c74da0e2a 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -234,6 +234,7 @@ class EditorAssetLibrary : public PanelContainer {
static const char *sort_key[SORT_MAX];
static const char *sort_text[SORT_MAX];
static const char *support_key[SUPPORT_MAX];
+ static const char *support_text[SUPPORT_MAX];
///MainListing
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index acd3271f97..bb3b8a124e 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_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
if (!randomizer) {
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index bd7b7ff1cb..4c14755b03 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -868,7 +868,7 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(action_name);
for (CanvasItem *ci : modified_canvas_items) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
@@ -933,7 +933,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node(s) to Position"));
for (Node *node : nodes_to_move) {
CanvasItem *ci = Object::cast_to<CanvasItem>(node);
@@ -1022,7 +1022,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
}
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> b = p_event;
Ref<InputEventMouseMotion> m = p_event;
@@ -1850,7 +1850,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *ci = selection[0];
@@ -1897,7 +1897,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->is_shift_pressed();
- bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_ctrl = m->is_ctrl_pressed();
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
@@ -1989,7 +1989,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
- if ((b->is_alt_pressed() && !b->is_ctrl_pressed()) || tool == TOOL_MOVE) {
+ if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
drag_selection.clear();
@@ -3418,7 +3418,7 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
if (_is_node_movable(ci)) {
@@ -4263,7 +4263,7 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
}
void CanvasItemEditor::_popup_callback(int p_op) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
last_option = MenuOption(p_op);
switch (p_op) {
case SHOW_ORIGIN: {
@@ -5570,7 +5570,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
String name = path.get_file().get_basename();
child->set_name(Node::adjust_name_casing(name));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<Texture2D> texture = ResourceCache::get_ref(path);
if (parent) {
@@ -5649,7 +5649,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
undo_redo->add_do_reference(instantiated_scene);
@@ -5690,7 +5690,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 078198e64b..723082c293 100644
--- a/editor/plugins/cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_2d_editor_plugin.cpp
@@ -77,7 +77,7 @@ bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
} else if (pressed) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set target_position"));
undo_redo->add_do_property(node, "target_position", target_position);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index bed4658976..c2d5885e43 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -219,7 +219,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
}
void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Handle"));
switch (shape_type) {
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index ad3e861b79..470b90aa7f 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -721,7 +721,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
LayoutPreset preset = (LayoutPreset)p_preset;
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction"));
for (Node *E : selection) {
@@ -742,7 +742,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
void ControlEditorToolbar::_anchors_to_current_ratio() {
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)"));
for (Node *E : selection) {
@@ -793,7 +793,7 @@ void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) {
void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) {
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_vertical) {
undo_redo->create_action(TTR("Change Vertical Size Flags"));
} else {
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index b0bcda946e..20710bac19 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -140,7 +140,7 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) {
_dragging = false;
if (_has_undo_data) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
undo_redo->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
undo_redo->add_undo_method(*_curve_ref, "_set_data", _undo_data);
@@ -301,7 +301,7 @@ void CurveEditor::on_preset_item_selected(int preset_id) {
break;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Load Curve Preset"));
undo_redo->add_do_method(&curve, "_set_data", curve.get_data());
undo_redo->add_undo_method(&curve, "_set_data", previous_data);
@@ -433,7 +433,7 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const {
void CurveEditor::add_point(Vector2 pos) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Curve Point"));
Vector2 point_pos = get_world_pos(pos);
@@ -455,7 +455,7 @@ void CurveEditor::add_point(Vector2 pos) {
void CurveEditor::remove_point(int index) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Curve Point"));
Curve::Point p = _curve_ref->get_point(index);
@@ -477,7 +477,7 @@ void CurveEditor::remove_point(int index) {
void CurveEditor::toggle_linear(TangentIndex tangent) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Curve Linear Tangent"));
if (tangent == TANGENT_NONE) {
@@ -621,8 +621,8 @@ struct CanvasItemPlotCurve {
color2(p_color2) {}
void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) {
- // FIXME: Using a line width greater than 1 breaks curve rendering
- ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1);
+ // FIXME: Using a quad line breaks curve rendering.
+ ci.draw_line(pos0, pos1, in_definition ? color1 : color2, -1);
}
};
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 1a51224198..04b2a9337e 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -113,7 +113,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
cpu_particles->set_process_mode(particles->get_process_mode());
cpu_particles->set_z_index(particles->get_z_index());
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to CPUParticles2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -161,7 +161,7 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
particles->set_emitting(false);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Generate Visibility Rect"));
undo_redo->add_do_method(particles, "set_visibility_rect", rect);
undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 19ac553708..65f66c2661 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -274,7 +274,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
cpu_particles->set_visible(node->is_visible());
cpu_particles->set_process_mode(node->get_process_mode());
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to CPUParticles3D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -324,7 +324,7 @@ void GPUParticles3DEditor::_generate_aabb() {
node->set_emitting(false);
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 68aafd6fa8..3676c2c222 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -99,7 +99,7 @@ void GradientEditor::_gradient_changed() {
void GradientEditor::_ramp_changed() {
editing = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets());
undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors());
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index e03353a67b..7bd159a5b8 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -55,7 +55,7 @@ void GradientTexture2DEditorRect::_update_fill_position() {
String property_name = handle == HANDLE_FILL_FROM ? "fill_from" : "fill_to";
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set %s"), property_name), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(texture.ptr(), property_name, percent);
undo_redo->add_undo_property(texture.ptr(), property_name, handle == HANDLE_FILL_FROM ? texture->get_fill_from() : texture->get_fill_to());
@@ -188,7 +188,7 @@ GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
///////////////////////
void GradientTexture2DEditor::_reverse_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Swap GradientTexture2D Fill Points"));
undo_redo->add_do_property(texture.ptr(), "fill_from", texture->get_fill_to());
undo_redo->add_do_property(texture.ptr(), "fill_to", texture->get_fill_from());
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index bee1206b90..429add4540 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -84,7 +84,7 @@ void LightOccluder2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) co
void LightOccluder2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Ref<OccluderPolygon2D> occluder = _ensure_occluder();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(occluder.ptr(), "set_polygon", p_polygon);
undo_redo->add_undo_method(occluder.ptr(), "set_polygon", p_previous);
}
@@ -98,7 +98,7 @@ void LightOccluder2DEditor::_create_resource() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Occluder Polygon"));
undo_redo->add_do_method(node, "set_occluder_polygon", Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D)));
undo_redo->add_undo_method(node, "set_occluder_polygon", Variant(Ref<RefCounted>()));
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index f2c487dd14..0185617c36 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -55,7 +55,7 @@ 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();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(_node, "set_points", p_polygon);
undo_redo->add_undo_method(_node, "set_points", p_previous);
}
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index bb2bac7c04..36c143ca8d 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -291,8 +291,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
}
void EditorInspectorPluginMaterial::_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());
+ EditorUndoRedoManager *undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo);
// For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot,
// set the respective metallic or roughness factor to 1.0 as a convenience feature
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 6cc551d367..e8976667dd 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -65,7 +65,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -152,7 +152,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Trimesh Static Shape"));
@@ -182,7 +182,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (simplify) {
ur->create_action(TTR("Create Simplified Convex Shape"));
@@ -222,7 +222,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Multiple Convex Shapes"));
@@ -259,7 +259,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Navigation Mesh"));
ur->add_do_method(node, "add_child", nmi, true);
@@ -275,7 +275,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
outline_dialog->popup_centered(Vector2(200, 90));
} break;
case MENU_OPTION_CREATE_DEBUG_TANGENTS: {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Debug Tangents"));
MeshInstance3D *tangents = node->create_debug_tangents_node();
@@ -334,7 +334,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Unwrap UV2"));
ur->add_do_method(node, "set_mesh", unwrapped_mesh);
@@ -460,7 +460,7 @@ void MeshInstance3DEditor::_debug_uv_draw() {
debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), get_theme_color(SNAME("dark_color_3"), SNAME("Editor")));
debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
// Use a translucent color to allow overlapping triangles to be visible.
- debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5), Math::round(EDSCALE));
+ debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5));
}
void MeshInstance3DEditor::_create_outline_mesh() {
@@ -493,7 +493,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
mi->set_mesh(mesho);
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Outline"));
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp
index 53f9ff019f..21a1d839f0 100644
--- a/editor/plugins/navigation_link_2d_editor_plugin.cpp
+++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp
@@ -85,7 +85,7 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
end_grabbed = false;
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (start_grabbed) {
undo_redo->create_action(TTR("Set start_location"));
undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index cbc225a7ff..957a520d8a 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -76,7 +76,7 @@ void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon)
void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count());
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -85,7 +85,7 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx);
undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx);
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -94,7 +94,7 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous);
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -110,7 +110,7 @@ void NavigationPolygonEditor::_create_resource() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Navigation Polygon"));
undo_redo->add_do_method(node, "set_navigation_polygon", Ref<NavigationPolygon>(memnew(NavigationPolygon)));
undo_redo->add_undo_method(node, "set_navigation_polygon", Variant(Ref<RefCounted>()));
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 74db91a309..bb71c27bff 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -1337,13 +1337,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
} else if (p_id == 0) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore);
ur->commit_action();
} else if (p_id == 1) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1562,7 +1562,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
player->set_emission_angle(p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
ur->add_undo_method(player, "set_emission_angle", p_restore);
@@ -1823,7 +1823,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("fov", p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Camera FOV"));
ur->add_do_property(camera, "fov", camera->get_fov());
ur->add_undo_property(camera, "fov", p_restore);
@@ -1834,7 +1834,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("size", p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Camera Size"));
ur->add_do_property(camera, "size", camera->get_size());
ur->add_undo_property(camera, "size", p_restore);
@@ -2160,7 +2160,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(so.ptr(), "set_radius", so->get_radius());
ur->add_undo_method(so.ptr(), "set_radius", p_restore);
@@ -2174,7 +2174,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(bo.ptr(), "set_size", bo->get_size());
ur->add_undo_method(bo.ptr(), "set_size", p_restore);
@@ -2188,7 +2188,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(qo.ptr(), "set_size", qo->get_size());
ur->add_undo_method(qo.ptr(), "set_size", p_restore);
@@ -2902,7 +2902,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Notifier AABB"));
ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
ur->add_undo_method(notifier, "set_aabb", p_restore);
@@ -3093,7 +3093,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Particles AABB"));
ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
@@ -3259,7 +3259,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Radius"));
ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
ur->add_undo_method(sn, "set_radius", p_restore);
@@ -3272,7 +3272,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
@@ -3531,7 +3531,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
@@ -3683,7 +3683,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Decal Extents"));
ur->add_do_method(decal, "set_extents", decal->get_extents());
ur->add_undo_method(decal, "set_extents", restore);
@@ -3823,7 +3823,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_undo_method(probe, "set_extents", restore);
@@ -4438,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
@@ -4452,7 +4452,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(ss.ptr(), "set_size", ss->get_size());
ur->add_undo_method(ss.ptr(), "set_size", p_restore);
@@ -4469,7 +4469,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Capsule Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4494,7 +4494,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4519,7 +4519,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Separation Ray Shape Length"));
ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
ur->add_undo_method(ss.ptr(), "set_length", p_restore);
@@ -5184,7 +5184,7 @@ void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Start Location"));
ur->add_do_method(link, "set_start_location", link->get_start_location());
@@ -5946,7 +5946,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Fog Volume Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4fe1a6c034..dea07ab50c 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3104,7 +3104,7 @@ void Node3DEditorViewport::_draw() {
}
void Node3DEditorViewport::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case VIEW_TOP: {
cursor.y_rot = 0;
@@ -3894,8 +3894,6 @@ Dictionary Node3DEditorViewport::get_state() const {
void Node3DEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Node3DEditorViewport::drop_data_fw);
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
@@ -4257,7 +4255,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
undo_redo->add_do_reference(instantiated_scene);
@@ -4286,7 +4284,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
}
void Node3DEditorViewport::_perform_drop_data() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (spatial_editor->get_preview_material_target().is_valid()) {
GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
@@ -4496,7 +4494,7 @@ void Node3DEditorViewport::commit_transform() {
TTRC("Translate"),
TTRC("Scale"),
};
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(_transform_name[_edit.mode]);
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4921,7 +4919,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
c->add_child(viewport);
surface = memnew(Control);
- surface->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(surface, Node3DEditorViewport);
add_child(surface);
surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
surface->set_clip_contents(true);
@@ -6014,7 +6012,7 @@ void Node3DEditor::_xform_dialog_action() {
t.basis.rotate(rotate);
t.origin = translate;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("XForm Dialog"));
const List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -6126,7 +6124,7 @@ void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) {
}
void Node3DEditor::_menu_item_pressed(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case MENU_TOOL_SELECT:
case MENU_TOOL_MOVE:
@@ -7312,7 +7310,7 @@ void Node3DEditor::_snap_selected_nodes_to_floor() {
}
if (snapped_to_floor) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Snap Nodes to Floor"));
// Perform snapping if at least one node can be snapped
@@ -7382,7 +7380,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
ERR_FAIL_COND(!base);
Node *new_sun = preview_sun->duplicate();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Preview Sun to Scene"));
undo_redo->add_do_method(base, "add_child", new_sun, true);
// Move to the beginning of the scene tree since more "global" nodes
@@ -7416,7 +7414,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true));
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Preview Environment to Scene"));
undo_redo->add_do_method(base, "add_child", new_env, true);
// Move to the beginning of the scene tree since more "global" nodes
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index b78ffb7612..63f6643ba3 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -120,7 +120,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point deletion.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
@@ -155,7 +155,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Point to Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
@@ -191,7 +191,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
insertion_point = curve->get_point_count() - 2;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Split Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
@@ -215,7 +215,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && action != ACTION_NONE) {
Ref<Curve2D> curve = node->get_curve();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
switch (action) {
case ACTION_NONE:
@@ -491,7 +491,7 @@ void Path2DEditor::_mode_selected(int p_mode) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin);
undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count());
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 917b8245a3..75cd04bee8 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -174,7 +174,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (!p_secondary) {
if (p_cancel) {
@@ -409,7 +409,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
}
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (closest_seg != -1) {
//subdivide
@@ -451,21 +451,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
// Find the offset and point index of the place to break up.
// Also check for the control points.
if (dist_to_p < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Path Point"));
ur->add_do_method(c.ptr(), "remove_point", i);
ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_out < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Out-Control Point"));
ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_in < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove In-Control Point"));
ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
@@ -544,7 +544,7 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Close Curve"));
ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 9d8f1a1578..05fc464226 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -156,7 +156,7 @@ void Polygon2DEditor::_sync_bones() {
Array new_bones = node->call("_get_bones");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Sync Bones"));
undo_redo->add_do_method(node, "_set_bones", new_bones);
undo_redo->add_undo_method(node, "_set_bones", prev_bones);
@@ -286,7 +286,7 @@ void Polygon2DEditor::_uv_edit_popup_hide() {
}
void Polygon2DEditor::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case MODE_EDIT_UV: {
if (node->get_texture().is_null()) {
@@ -399,7 +399,7 @@ void Polygon2DEditor::_update_polygon_editing_state() {
void Polygon2DEditor::_commit_action() {
// Makes that undo/redoing actions made outside of the UV editor still affect its polygon.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport");
@@ -467,7 +467,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
mtx.columns[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 8dc0ca9431..9defb4de9b 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -96,7 +96,7 @@ void Polygon3DEditor::_menu_option(int p_option) {
void Polygon3DEditor::_wip_close() {
Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
ERR_FAIL_COND_MSG(!obj, "Edited object is not valid.");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Polygon3D"));
undo_redo->add_undo_method(obj, "set_polygon", obj->call("get_polygon"));
undo_redo->add_do_method(obj, "set_polygon", wip);
@@ -186,7 +186,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed()) {
if (poly.size() < 3) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_undo_method(obj, "set_polygon", poly);
poly.push_back(cpoint);
@@ -265,7 +265,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
poly.write[edited_point] = edited_point_pos;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_do_method(obj, "set_polygon", poly);
undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit);
@@ -294,7 +294,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
}
if (closest_idx >= 0) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
undo_redo->add_undo_method(obj, "set_polygon", poly);
poly.remove_at(closest_idx);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 2a5529e229..dcbff2c756 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -71,7 +71,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths)
name = basename + " " + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, resource);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -116,7 +116,7 @@ void ResourcePreloaderEditor::_item_edited() {
}
Ref<Resource> samp = preloader->get_resource(old_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Resource"));
undo_redo->add_do_method(preloader, "remove_resource", old_name);
undo_redo->add_do_method(preloader, "add_resource", new_name, samp);
@@ -129,7 +129,7 @@ void ResourcePreloaderEditor::_item_edited() {
}
void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Resource"));
undo_redo->add_do_method(preloader, "remove_resource", p_to_remove);
undo_redo->add_undo_method(preloader, "add_resource", p_to_remove, preloader->get_resource(p_to_remove));
@@ -163,7 +163,7 @@ void ResourcePreloaderEditor::_paste_pressed() {
name = basename + " " + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, r);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -322,7 +322,7 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant
name = basename + "_" + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, r);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -342,10 +342,6 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant
void ResourcePreloaderEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library);
ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource);
-
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw);
}
ResourcePreloaderEditor::ResourcePreloaderEditor() {
@@ -379,7 +375,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
tree->set_column_expand(1, true);
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, ResourcePreloaderEditor);
vbc->add_child(tree);
dialog = memnew(AcceptDialog);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index caa42b677c..e515b46b1e 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -439,6 +439,8 @@ void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) {
} else if (current) {
current->goto_line(p_line, true);
}
+
+ _save_history();
}
}
}
@@ -2172,6 +2174,8 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p
p_text_file->set_last_modified_time(FileAccess::get_modified_time(p_path));
}
+ EditorFileSystem::get_singleton()->update_file(p_path);
+
_res_saved_callback(sqscr);
return OK;
}
@@ -2254,11 +2258,14 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
args.push_back(script_path);
}
- Error err = OS::get_singleton()->create_process(path, args);
- if (err == OK) {
- return false;
+ if (!path.is_empty()) {
+ Error err = OS::get_singleton()->create_process(path, args);
+ if (err == OK) {
+ return false;
+ }
}
- WARN_PRINT("Couldn't open external text editor, using internal");
+
+ ERR_PRINT("Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings.");
}
for (int i = 0; i < tab_container->get_tab_count(); i++) {
@@ -2487,7 +2494,6 @@ void ScriptEditor::save_all_scripts() {
}
_update_script_names();
- EditorFileSystem::get_singleton()->update_script_classes();
}
void ScriptEditor::apply_scripts() const {
@@ -2553,9 +2559,9 @@ void ScriptEditor::open_script_create_dialog(const String &p_base_name, const St
}
void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const String &p_base_name) {
- file_dialog->set_current_file(p_base_name);
- file_dialog->set_current_dir(p_base_path);
_menu_option(FILE_NEW_TEXTFILE);
+ file_dialog->set_current_dir(p_base_path);
+ file_dialog->set_current_file(p_base_name);
open_textfile_after_create = false;
}
@@ -3610,10 +3616,6 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter);
ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2);
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
@@ -3669,7 +3671,7 @@ ScriptEditor::ScriptEditor() {
_sort_list_on_update = true;
script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
- script_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(script_list, ScriptEditor);
context_menu = memnew(PopupMenu);
add_child(context_menu);
@@ -4005,12 +4007,6 @@ void ScriptEditorPlugin::apply_changes() {
script_editor->apply_scripts();
}
-void ScriptEditorPlugin::restore_global_state() {
-}
-
-void ScriptEditorPlugin::save_global_state() {
-}
-
void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
script_editor->set_window_layout(p_layout);
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index d4c80c416b..988d07621c 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -542,9 +542,6 @@ public:
virtual void save_external_data() override;
virtual void apply_changes() override;
- virtual void restore_global_state() override;
- virtual void save_global_state() override;
-
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 4d525cc5a9..6bb725f7a0 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1490,14 +1490,6 @@ void ScriptTextEditor::_notification(int p_what) {
}
}
-void ScriptTextEditor::_bind_methods() {
- ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods);
-
- ClassDB::bind_method("_get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ScriptTextEditor::drop_data_fw);
-}
-
Control *ScriptTextEditor::get_edit_menu() {
return edit_hb;
}
@@ -2167,7 +2159,7 @@ ScriptTextEditor::ScriptTextEditor() {
connection_info_dialog = memnew(ConnectionInfoDialog);
- code_editor->get_text_editor()->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(code_editor, ScriptTextEditor);
}
ScriptTextEditor::~ScriptTextEditor() {
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 9db0191128..1d96376748 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -176,7 +176,6 @@ protected:
void _warning_clicked(Variant p_line);
void _notification(int p_what);
- static void _bind_methods();
HashMap<String, Ref<EditorSyntaxHighlighter>> highlighters;
void _change_syntax_highlighter(int p_idx);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index a822584619..87d602ccf1 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -229,7 +229,7 @@ void ShaderEditorPlugin::_close_shader(int p_index) {
memdelete(c);
edited_shaders.remove_at(p_index);
_update_shader_list();
- EditorNode::get_undo_redo()->clear_history(); // To prevent undo on deleted graphs.
+ EditorUndoRedoManager::get_singleton()->clear_history(); // To prevent undo on deleted graphs.
}
void ShaderEditorPlugin::_resource_saved(Object *obj) {
@@ -413,12 +413,6 @@ void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
-void ShaderEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw);
-}
-
ShaderEditorPlugin::ShaderEditorPlugin() {
main_split = memnew(HSplitContainer);
@@ -451,7 +445,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
vb->add_child(shader_list);
shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
- shader_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(shader_list, ShaderEditorPlugin);
main_split->add_child(vb);
vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 8ca4a534ab..408d08ade0 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -92,9 +92,6 @@ class ShaderEditorPlugin : public EditorPlugin {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
-protected:
- static void _bind_methods();
-
public:
virtual String get_name() const override { return "Shader"; }
virtual void edit(Object *p_object) override;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index d90d6b6756..06db696330 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -61,7 +61,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Rest Pose to Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
@@ -77,7 +77,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Rest Pose from Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 956150ec69..3ee9823f3a 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -116,7 +116,7 @@ void BoneTransformEditor::_value_changed(const String &p_property, Variant p_val
return;
}
if (skeleton) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property));
undo_redo->add_do_property(skeleton, p_property, p_value);
@@ -271,7 +271,7 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -338,7 +338,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -358,7 +358,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
}
void Skeleton3DEditor::create_physical_skeleton() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ERR_FAIL_COND(!get_tree());
Node *owner = get_tree()->get_edited_scene_root();
@@ -593,7 +593,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se
Node *node = get_node_or_null(p_skeleton_path);
Skeleton3D *skeleton_node = Object::cast_to<Skeleton3D>(node);
ERR_FAIL_NULL(skeleton_node);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
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_node->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
@@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() {
joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
joint_tree->set_allow_rmb_select(true);
- joint_tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(joint_tree, Skeleton3DEditor);
s_con->add_child(joint_tree);
pose_editor = memnew(BoneTransformEditor(skeleton));
@@ -889,10 +889,6 @@ void Skeleton3DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);
ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone);
ClassDB::bind_method(D_METHOD("_draw_gizmo"), &Skeleton3DEditor::_draw_gizmo);
@@ -1323,7 +1319,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Transform"));
if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
for (int i = 0; i < p_ids.size(); i++) {
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 2a8994d239..0d00bfa8fd 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -344,7 +344,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
mesh_instance->set_mesh(mesh);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to MeshInstance2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false);
ur->add_do_reference(mesh_instance);
@@ -402,7 +402,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() {
polygon_2d_instance->set_polygon(polygon);
polygon_2d_instance->set_polygons(polys);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to Polygon2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false);
ur->add_do_reference(polygon_2d_instance);
@@ -424,7 +424,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() {
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
ur->add_do_reference(collision_polygon_2d_instance);
@@ -457,7 +457,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() {
LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
light_occluder_2d_instance->set_occluder_polygon(polygon);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create LightOccluder2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
ur->add_do_reference(light_occluder_2d_instance);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index f4ec026504..75e1199a6e 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -251,7 +251,7 @@ void SpriteFramesEditor::_sheet_add_frames() {
const Size2i offset = _get_offset();
const Size2i separation = _get_separation();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
@@ -470,7 +470,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
@@ -541,7 +541,7 @@ void SpriteFramesEditor::_paste_pressed() {
return; ///beh should show an error i guess
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Frame"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, frames->get_frame_count(edited_anim));
@@ -584,7 +584,7 @@ void SpriteFramesEditor::_empty_pressed() {
Ref<Texture2D> texture;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Empty"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from);
@@ -608,7 +608,7 @@ void SpriteFramesEditor::_empty2_pressed() {
Ref<Texture2D> texture;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Empty"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from + 1);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from + 1);
@@ -632,7 +632,7 @@ void SpriteFramesEditor::_up_pressed() {
sel = to_move;
sel -= 1;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Frame"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
@@ -658,7 +658,7 @@ void SpriteFramesEditor::_down_pressed() {
sel = to_move;
sel += 1;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Frame"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
@@ -681,7 +681,7 @@ void SpriteFramesEditor::_delete_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Resource"));
undo_redo->add_do_method(frames, "remove_frame", edited_anim, to_delete);
undo_redo->add_undo_method(frames, "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete);
@@ -768,7 +768,7 @@ void SpriteFramesEditor::_animation_name_edited() {
List<Node *> nodes;
_find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Animation"));
undo_redo->add_do_method(frames, "rename_animation", edited_anim, name);
undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim);
@@ -798,7 +798,7 @@ void SpriteFramesEditor::_animation_add() {
List<Node *> nodes;
_find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation"));
undo_redo->add_do_method(frames, "add_animation", name);
undo_redo->add_undo_method(frames, "remove_animation", name);
@@ -831,7 +831,7 @@ void SpriteFramesEditor::_animation_remove() {
}
void SpriteFramesEditor::_animation_remove_confirmed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Animation"));
undo_redo->add_do_method(frames, "remove_animation", edited_anim);
undo_redo->add_undo_method(frames, "add_animation", edited_anim);
@@ -860,7 +860,7 @@ void SpriteFramesEditor::_animation_loop_changed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop"));
undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed());
undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
@@ -874,7 +874,7 @@ void SpriteFramesEditor::_animation_speed_changed(double p_value) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value);
undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
@@ -926,7 +926,7 @@ void SpriteFramesEditor::_frame_duration_changed(double p_value) {
Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, index);
float old_duration = frames->get_frame_duration(edited_anim, index);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Frame Duration"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, index, texture, p_value);
undo_redo->add_undo_method(frames, "set_frame", edited_anim, index, texture, old_duration);
@@ -1206,7 +1206,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
reorder = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (reorder) { //drop is from reordering frames
int from_frame = -1;
float duration = 1.0;
@@ -1247,9 +1247,6 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SpriteFramesEditor::drop_data_fw);
}
SpriteFramesEditor::SpriteFramesEditor() {
@@ -1408,7 +1405,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
frame_list->set_max_columns(0);
frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);
frame_list->set_max_text_lines(2);
- frame_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(frame_list, SpriteFramesEditor);
frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input));
frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected));
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index ad5881c76f..a376699e54 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -649,8 +649,6 @@ TextEditor::TextEditor() {
goto_line_dialog = memnew(GotoLineDialog);
add_child(goto_line_dialog);
-
- code_editor->get_text_editor()->set_drag_forwarding_compat(this);
}
TextEditor::~TextEditor() {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 59f2159167..9bad2f2fbf 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -300,7 +300,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-handle_offset, 0)
};
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
@@ -349,7 +349,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
for (const Rect2 &E : autoslice_cache) {
if (E.has_point(point)) {
rect = E;
- if (Input::get_singleton()->is_key_pressed(Key::CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) {
Rect2 r;
if (atlas_tex.is_valid()) {
r = atlas_tex->get_region();
@@ -824,10 +824,18 @@ void TextureRegionEditor::_update_autoslice() {
void TextureRegionEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &TextureRegionEditor::_node_removed));
+ } break;
+
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &TextureRegionEditor::_node_removed));
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
+
case NOTIFICATION_READY: {
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
@@ -840,11 +848,13 @@ void TextureRegionEditor::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
_update_autoslice();
}
} break;
+
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
// This happens when the user leaves the Editor and returns,
// they could have changed the textures, so the cache is cleared.
@@ -867,7 +877,6 @@ void TextureRegionEditor::_node_removed(Object *p_obj) {
void TextureRegionEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_edit_region"), &TextureRegionEditor::_edit_region);
- ClassDB::bind_method(D_METHOD("_node_removed"), &TextureRegionEditor::_node_removed);
ClassDB::bind_method(D_METHOD("_zoom_on_position"), &TextureRegionEditor::_zoom_on_position);
ClassDB::bind_method(D_METHOD("_update_rect"), &TextureRegionEditor::_update_rect);
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 68c1041a0b..40aac77a99 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -800,7 +800,7 @@ void ThemeItemImportTree::_import_selected() {
ProgressDialog::get_singleton()->end_task("import_theme_items");
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Import Theme Items"));
ur->add_do_method(*edited_theme, "clear");
@@ -1498,7 +1498,7 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu
String item_name = item->get_text(0);
int data_type = item->get_parent()->get_metadata(0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Item"));
ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);
ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type));
@@ -1517,7 +1517,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
const String new_type = edit_add_type_value->get_text().strip_edges();
edit_add_type_value->clear();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Theme Type"));
ur->add_do_method(*edited_theme, "add_type", new_type);
@@ -1529,7 +1529,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
}
void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Theme Item"));
switch (p_data_type) {
@@ -1574,7 +1574,7 @@ void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Type"));
new_snapshot->remove_type(p_theme_type);
@@ -1597,7 +1597,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type,
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Data Type Items From Theme"));
new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);
@@ -1626,7 +1626,7 @@ void ThemeItemEditorDialog::_remove_class_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Class Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1662,7 +1662,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Custom Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1698,7 +1698,7 @@ void ThemeItemEditorDialog::_remove_all_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove All Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1802,7 +1802,7 @@ void ThemeItemEditorDialog::_confirm_edit_theme_item() {
if (item_popup_mode == CREATE_THEME_ITEM) {
_add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
} else if (item_popup_mode == RENAME_THEME_ITEM) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Rename Theme Item"));
ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
@@ -2828,7 +2828,7 @@ void ThemeTypeEditor::_add_default_type_items() {
updating = false;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Override All Default Theme Items"));
ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
@@ -2848,7 +2848,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
}
String item_name = le->get_text().strip_edges();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Theme Item"));
switch (p_data_type) {
@@ -2893,7 +2893,7 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co
}
void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Override Theme Item"));
switch (p_data_type) {
@@ -2932,7 +2932,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
}
void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Item"));
switch (p_data_type) {
@@ -3006,7 +3006,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Rename Theme Item"));
switch (p_data_type) {
@@ -3062,7 +3062,7 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name,
}
void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);
ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));
@@ -3070,7 +3070,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
}
void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Constant Item in Theme"));
ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));
@@ -3078,7 +3078,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name)
}
void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Font Size Item in Theme"));
ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));
@@ -3090,7 +3090,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit)
}
void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Font Item in Theme"));
ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());
@@ -3107,7 +3107,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name)
}
void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Icon Item in Theme"));
ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());
@@ -3124,7 +3124,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n
}
void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Stylebox Item in Theme"));
ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());
@@ -3167,7 +3167,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_
stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Pin Stylebox"));
ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);
@@ -3200,7 +3200,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_
}
void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Unpin Stylebox"));
ur->add_do_method(this, "_unpin_leading_stylebox");
ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);
@@ -3269,7 +3269,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Theme Type Variation"));
if (p_value.is_empty()) {
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index deb1df42d3..eaf72d36ba 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -31,7 +31,6 @@
#include "atlas_merging_dialog.h"
#include "editor/editor_file_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
@@ -56,7 +55,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
new_texture_region_size = new_texture_region_size.max(atlas_source->get_texture_region_size());
}
- // Generate the merged TileSetAtlasSource.
+ // Generate the new texture.
Vector2i atlas_offset;
int line_height = 0;
for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) {
@@ -72,28 +71,6 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
Rect2i new_tile_rect_in_altas = Rect2i(atlas_offset + tile_id, atlas_source->get_tile_size_in_atlas(tile_id));
- // Create tiles and alternatives, then copy their properties.
- for (int alternative_index = 0; alternative_index < atlas_source->get_alternative_tiles_count(tile_id); alternative_index++) {
- int alternative_id = atlas_source->get_alternative_tile_id(tile_id, alternative_index);
- if (alternative_id == 0) {
- merged->create_tile(new_tile_rect_in_altas.position, new_tile_rect_in_altas.size);
- } else {
- merged->create_alternative_tile(new_tile_rect_in_altas.position, alternative_index);
- }
-
- // Copy the properties.
- TileData *original_tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
- List<PropertyInfo> properties;
- original_tile_data->get_property_list(&properties);
- for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- const StringName &property_name = E->get().name;
- merged->set(property_name, original_tile_data->get(property_name));
- }
-
- // Add to the mapping.
- merged_mapping[source_index][tile_id] = new_tile_rect_in_altas.position;
- }
-
// Copy the texture.
for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id, frame);
@@ -103,6 +80,9 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
}
output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2);
}
+
+ // Add to the mapping.
+ merged_mapping[source_index][tile_id] = new_tile_rect_in_altas.position;
}
// Compute the atlas offset.
@@ -115,8 +95,43 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
}
}
- merged->set_name(p_atlas_sources[0]->get_name());
merged->set_texture(ImageTexture::create_from_image(output_image));
+
+ // Copy the tiles to the merged TileSetAtlasSource.
+ for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) {
+ Ref<TileSetAtlasSource> atlas_source = p_atlas_sources[source_index];
+ for (KeyValue<Vector2i, Vector2i> tile_mapping : merged_mapping[source_index]) {
+ // Create tiles and alternatives, then copy their properties.
+ for (int alternative_index = 0; alternative_index < atlas_source->get_alternative_tiles_count(tile_mapping.key); alternative_index++) {
+ int alternative_id = atlas_source->get_alternative_tile_id(tile_mapping.key, alternative_index);
+ if (alternative_id == 0) {
+ merged->create_tile(tile_mapping.value, atlas_source->get_tile_size_in_atlas(tile_mapping.key));
+ } else {
+ merged->create_alternative_tile(tile_mapping.value, alternative_index);
+ }
+
+ // Copy the properties.
+ TileData *src_tile_data = atlas_source->get_tile_data(tile_mapping.key, alternative_id);
+ List<PropertyInfo> properties;
+ src_tile_data->get_property_list(&properties);
+
+ TileData *dst_tile_data = merged->get_tile_data(tile_mapping.value, alternative_id);
+ for (PropertyInfo property : properties) {
+ if (!(property.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+ Variant value = src_tile_data->get(property.name);
+ Variant default_value = ClassDB::class_get_default_property_value("TileData", property.name);
+ if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
+ continue;
+ }
+ dst_tile_data->set(property.name, value);
+ }
+ }
+ }
+ }
+
+ merged->set_name(p_atlas_sources[0]->get_name());
merged->set_texture_region_size(new_texture_region_size);
}
}
@@ -151,10 +166,12 @@ void AtlasMergingDialog::_merge_confirmed(String p_path) {
Ref<ImageTexture> output_image_texture = merged->get_texture();
output_image_texture->get_image()->save_png(p_path);
+ ResourceLoader::import(p_path);
+
Ref<Texture2D> new_texture_resource = ResourceLoader::load(p_path, "Texture2D");
merged->set_texture(new_texture_resource);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Merge TileSetAtlasSource"));
int next_id = tile_set->get_next_source_id();
undo_redo->add_do_method(*tile_set, "add_source", merged, next_id);
@@ -194,7 +211,7 @@ void AtlasMergingDialog::ok_pressed() {
}
void AtlasMergingDialog::cancel_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < commited_actions_count; i++) {
undo_redo->undo();
}
@@ -225,6 +242,14 @@ bool AtlasMergingDialog::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
+void AtlasMergingDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ _update_texture();
+ } break;
+ }
+}
+
void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) {
ERR_FAIL_COND(!p_tile_set.is_valid());
tile_set = p_tile_set;
diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h
index 032541c90e..bf1b56894f 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.h
+++ b/editor/plugins/tiles/atlas_merging_dialog.h
@@ -75,6 +75,8 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _notification(int p_what);
+
public:
void update_tile_set(Ref<TileSet> p_tile_set);
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 3c6ed0f049..0ac375407c 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -454,21 +454,31 @@ void TileAtlasView::set_padding(Side p_side, int p_padding) {
margin_container_paddings[p_side] = p_padding;
}
-Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos) const {
+Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp) const {
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
- if (texture.is_valid()) {
- Vector2i margins = tile_set_atlas_source->get_margins();
- Vector2i separation = tile_set_atlas_source->get_separation();
- Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+ if (!texture.is_valid()) {
+ return TileSetSource::INVALID_ATLAS_COORDS;
+ }
+
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
- // Compute index in atlas
- Vector2 pos = p_pos - margins;
- Vector2i ret = (pos / (texture_region_size + separation)).floor();
+ // Compute index in atlas
+ Vector2 pos = p_pos - margins;
+ Vector2i ret = (pos / (texture_region_size + separation)).floor();
- return ret;
+ // Return invalid value (without clamp).
+ Rect2i rect = Rect2(Vector2i(), tile_set_atlas_source->get_atlas_grid_size());
+ if (!p_clamp && !rect.has_point(ret)) {
+ return TileSetSource::INVALID_ATLAS_COORDS;
}
- return TileSetSource::INVALID_ATLAS_COORDS;
+ // Clamp.
+ ret.x = CLAMP(ret.x, 0, rect.size.x - 1);
+ ret.y = CLAMP(ret.y, 0, rect.size.y - 1);
+
+ return ret;
}
void TileAtlasView::_update_alternative_tiles_rect_cache() {
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 166abca2a3..f719bee704 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -128,7 +128,7 @@ public:
void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
- Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const;
+ Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp = false) const;
void add_control_over_atlas_tiles(Control *p_control, bool scaled = true) {
if (scaled) {
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index fb4787f13c..81aa9bf272 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -265,12 +265,12 @@ void GenericTilePolygonEditor::_zoom_changed() {
}
void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
if (use_undo_redo) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
} else {
// This nice hack allows for discarding undo actions without making code too complex.
- undo_redo.instantiate();
+ undo_redo = memnew(EditorUndoRedoManager);
}
switch (p_item_pressed) {
@@ -361,6 +361,10 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
default:
break;
}
+
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
}
void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) {
@@ -445,12 +449,12 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) {
}
void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) {
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
if (use_undo_redo) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
} else {
// This nice hack allows for discarding undo actions without making code too complex.
- undo_redo.instantiate();
+ undo_redo = memnew(EditorUndoRedoManager);
}
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
@@ -493,11 +497,11 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_ctrl_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_command_or_control_pressed()) {
editor_zoom_widget->set_zoom_by_increments(1);
_zoom_changed();
accept_event();
- } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_ctrl_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_command_or_control_pressed()) {
editor_zoom_widget->set_zoom_by_increments(-1);
_zoom_changed();
accept_event();
@@ -643,6 +647,10 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
base_control->queue_redraw();
+
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -902,7 +910,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s
}
void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E.key.alternative_tile, property), E.value);
@@ -918,8 +926,8 @@ void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_
p_canvas_item->draw_set_transform_matrix(p_transform);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -953,7 +961,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (drag_type == DRAG_TYPE_PAINT) {
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -971,19 +979,19 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- if (picker_button->is_pressed()) {
- Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) {
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
_set_painted_value(p_tile_set_atlas_source, coords, 0);
picker_button->set_pressed(false);
}
- } else if (mb->is_ctrl_pressed()) {
+ } else if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
drag_type = DRAG_TYPE_PAINT_RECT;
drag_modified.clear();
drag_painted_value = _get_painted_value();
@@ -992,7 +1000,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
drag_type = DRAG_TYPE_PAINT;
drag_modified.clear();
drag_painted_value = _get_painted_value();
- Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
TileMapCell cell;
@@ -1007,8 +1015,8 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
} else {
if (drag_type == DRAG_TYPE_PAINT_RECT) {
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
drag_modified.clear();
@@ -1095,7 +1103,7 @@ void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasVie
drag_last_pos = mb->get_position();
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Painting Tiles Property"));
_setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value);
undo_redo->commit_action(false);
@@ -1345,7 +1353,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_
}
void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, occlusion_layer), E.value);
@@ -1524,26 +1532,32 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas
}
void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Array new_array = p_new_value;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ Dictionary new_dict = p_new_value;
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (KeyValue<TileMapCell, Variant> &E : p_previous_values) {
- Array old_array = E.value;
-
Vector2i coords = E.key.get_atlas_coords();
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_array.size());
- for (int i = 0; i < old_array.size(); i++) {
- Dictionary dict = old_array[i];
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]);
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]);
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]);
+
+ Dictionary old_dict = E.value;
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["linear_velocity"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["angular_velocity"]);
+ Array old_polygon_array = old_dict["polygons"];
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_polygon_array.size());
+ for (int i = 0; i < old_polygon_array.size(); i++) {
+ Dictionary polygon_dict = old_polygon_array[i];
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]);
}
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_array.size());
- for (int i = 0; i < new_array.size(); i++) {
- Dictionary dict = new_array[i];
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]);
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]);
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["linear_velocity"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["angular_velocity"]);
+ Array new_polygon_array = new_dict["polygons"];
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_polygon_array.size());
+ for (int i = 0; i < new_polygon_array.size(); i++) {
+ Dictionary polygon_dict = new_polygon_array[i];
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]);
}
}
}
@@ -1804,8 +1818,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
p_canvas_item->draw_set_transform_matrix(p_transform);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -1834,8 +1848,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
int terrain_set = int(painted["terrain_set"]);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -1995,7 +2009,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2029,7 +2043,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
} else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
int terrain_set = Dictionary(drag_painted_value)["terrain_set"];
int terrain = Dictionary(drag_painted_value)["terrain"];
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2083,7 +2097,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
- if (mb->get_button_index() == MouseButton::LEFT && picker_button->is_pressed()) {
+ if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) {
Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2126,7 +2140,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb->get_button_index() == MouseButton::RIGHT) {
terrain_set = -1;
}
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
// Paint terrain set with rect.
drag_type = DRAG_TYPE_PAINT_TERRAIN_SET_RECT;
drag_modified.clear();
@@ -2167,7 +2181,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb->get_button_index() == MouseButton::RIGHT) {
terrain = -1;
}
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
// Paint terrain bits with rect.
drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT;
drag_modified.clear();
@@ -2227,11 +2241,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
}
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) {
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -2318,8 +2332,8 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
int terrain = int(painted["terrain"]);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -2600,7 +2614,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
}
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
undo_redo->create_action(TTR("Painting Tiles Property"));
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
@@ -2747,7 +2761,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla
}
void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, navigation_layer), E.value);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index dd4daa45b7..885d41b8da 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -273,7 +273,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven
if (ED_IS_SHORTCUT("tiles_editor/paste", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
select_last_pattern = true;
int new_pattern_index = tile_set->get_patterns_count();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add TileSet pattern"));
undo_redo->add_do_method(*tile_set, "add_pattern", tile_map_clipboard, new_pattern_index);
undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
@@ -283,7 +283,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
Vector<int> selected = patterns_item_list->get_selected_items();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove TileSet patterns"));
for (int i = 0; i < selected.size(); i++) {
int pattern_index = selected[i];
@@ -515,7 +515,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) {
// Delete selected tiles.
if (!tile_map_selection.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete tiles"));
for (const Vector2i &E : tile_map_selection) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
@@ -547,7 +547,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) {
// Delete selected tiles.
if (!tile_map_selection.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete tiles"));
for (const Vector2i &E : tile_map_selection) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
@@ -646,12 +646,12 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else {
// Check if we are picking a tile.
- if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
drag_type = DRAG_TYPE_PICK;
drag_start_mouse_pos = mpos;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -667,11 +667,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
_fix_invalid_tiles_in_tile_map_selection();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
drag_type = DRAG_TYPE_RECT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -742,7 +742,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the selection.
if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) {
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
- 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))) {
+ if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
// Do nothing
} else {
Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
@@ -812,7 +812,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
@@ -1240,20 +1240,20 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_SELECT: {
undo_redo->create_action(TTR("Change selection"));
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
- if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
tile_map_selection.clear();
}
Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
for (int x = rect.position.x; x <= rect.get_end().x; x++) {
for (int y = rect.position.y; y <= rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
if (tile_map_selection.has(coords)) {
tile_map_selection.erase(coords);
}
@@ -1716,8 +1716,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
// Draw the selection rect.
if (tile_set_dragging_selection) {
- Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
- Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
region.size += Vector2i(1, 1);
@@ -1812,8 +1812,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
tile_set_selection.clear();
}
// Compute the covered area.
- Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
- Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
if (start_tile != TileSetSource::INVALID_ATLAS_COORDS && end_tile != TileSetSource::INVALID_ATLAS_COORDS) {
Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
region.size += Vector2i(1, 1);
@@ -2236,7 +2236,6 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scene_tiles_list = memnew(ItemList);
scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- scene_tiles_list->set_drag_forwarding_compat(this);
scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked));
@@ -2641,7 +2640,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_PICK: {
Vector2i coords = tile_map->local_to_map(mpos);
@@ -2875,7 +2874,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_type = DRAG_TYPE_PICK;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
@@ -2890,14 +2889,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
@@ -2982,7 +2981,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
@@ -3303,12 +3302,16 @@ void TileMapEditorTerrainsPlugin::_update_theme() {
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
_stop_dragging(); // Avoids staying in a wrong drag state.
- tile_map_id = p_tile_map_id;
- tile_map_layer = p_tile_map_layer;
+ if (tile_map_id != p_tile_map_id) {
+ tile_map_id = p_tile_map_id;
- _update_terrains_cache();
- _update_terrains_tree();
- _update_tiles_list();
+ // Clear the selection.
+ _update_terrains_cache();
+ _update_terrains_tree();
+ _update_tiles_list();
+ }
+
+ tile_map_layer = p_tile_map_layer;
}
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
@@ -3485,7 +3488,7 @@ void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) {
}
if (p_id == 0) { // Replace Tile Proxies
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace Tiles with Proxies"));
for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) {
TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index);
@@ -3702,8 +3705,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_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
if (!tile_map) {
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index ef82e748a8..f6aeffa13f 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -30,10 +30,11 @@
#include "tile_proxies_manager_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/popup_menu.h"
#include "scene/gui/separator.h"
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index, Object *p_item_list) {
@@ -55,7 +56,7 @@ void TileProxiesManagerDialog::_menu_id_pressed(int p_id) {
}
void TileProxiesManagerDialog::_delete_selected_bindings() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Tile Proxies"));
Vector<int> source_level_selected = source_level_list->get_selected_items();
@@ -155,7 +156,7 @@ void TileProxiesManagerDialog::_property_changed(const String &p_path, const Var
}
void TileProxiesManagerDialog::_add_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (from.source_id != TileSet::INVALID_SOURCE && to.source_id != TileSet::INVALID_SOURCE) {
Vector2i from_coords = from.get_atlas_coords();
Vector2i to_coords = to.get_atlas_coords();
@@ -196,7 +197,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
}
void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete All Invalid Tile Proxies"));
undo_redo->add_do_method(*tile_set, "cleanup_invalid_tile_proxies");
@@ -224,7 +225,7 @@ void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
}
void TileProxiesManagerDialog::_clear_all_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete All Tile Proxies"));
undo_redo->add_do_method(*tile_set, "clear_tile_proxies");
@@ -305,7 +306,7 @@ void TileProxiesManagerDialog::_unhandled_key_input(Ref<InputEvent> p_event) {
}
void TileProxiesManagerDialog::cancel_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < commited_actions_count; i++) {
undo_redo->undo();
}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 146a53f3dd..32421daa92 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -110,7 +110,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list
p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px"));
p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, ""));
}
@@ -164,7 +164,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
if (p_name == "atlas_coords") {
Vector2i as_vector2i = Vector2i(p_value);
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
+ ERR_FAIL_COND_V_EDMSG(!has_room_for_tile, false, "Cannot move the tile, invalid coordinates or not enough room in the atlas for the tile and its animation frames.");
if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
tiles_set_atlas_source_editor->selection.clear();
@@ -223,7 +223,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
for (TileSelection tile : tiles) {
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_separation(tile.tile), tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot change the number of columns to %s for tile animation. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)));
} else {
tile_set_atlas_source->set_tile_animation_columns(tile.tile, p_value);
}
@@ -234,7 +234,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
for (TileSelection tile : tiles) {
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot change separation between frames of the animation to %s. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)));
} else {
tile_set_atlas_source->set_tile_animation_separation(tile.tile, p_value);
}
@@ -249,11 +249,16 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
return true;
} else if (p_name == "animation_frames_count") {
for (TileSelection tile : tiles) {
- bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), p_value, tile.tile);
+ int frame_count = p_value;
+ if (frame_count == 0) {
+ frame_count = 1;
+ }
+
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), frame_count, tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot add frames to the animation, not enough room in the atlas to layout %s frames.", frame_count));
} else {
- tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, p_value);
+ tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, frame_count);
}
}
notify_property_list_changed();
@@ -1015,44 +1020,13 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Handle the event.
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- if (drag_type == DRAG_TYPE_NONE) {
- if (selection.size() == 1) {
- // Change the cursor depending on the hovered thing.
- TileSelection selected = selection.front()->get();
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
- Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + rect.size * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
- }
- Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
- if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
- }
- }
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
- }
- }
- } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
+ if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
// Create big tile.
new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
@@ -1097,7 +1071,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Move tile.
Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
- coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
selection.clear();
@@ -1243,7 +1216,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
bool can_grow[4];
for (int i = 0; i < 4; i++) {
can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
@@ -1257,7 +1229,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
}
Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
@@ -1266,10 +1237,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
}
}
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
}
@@ -1292,7 +1261,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
} else {
// Start selection dragging.
drag_type = DRAG_TYPE_RECT_SELECT;
@@ -1332,7 +1300,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
}
void TileSetAtlasSourceEditor::_end_dragging() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_CREATE_TILES:
undo_redo->create_action(TTR("Create tiles"));
@@ -1370,8 +1338,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_CREATE_TILES_USING_RECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
undo_redo->create_action(TTR("Create tiles"));
@@ -1387,8 +1355,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_REMOVE_TILES_USING_RECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
List<PropertyInfo> list;
@@ -1438,8 +1406,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
}
break;
case DRAG_TYPE_RECT_SELECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
ERR_FAIL_COND(start_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
ERR_FAIL_COND(new_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
@@ -1509,12 +1477,12 @@ void TileSetAtlasSourceEditor::_end_dragging() {
// We have a tile.
menu_option_coords = selected.tile;
menu_option_alternative = 0;
- base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
} else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
// We don't have a tile, but can create one.
menu_option_coords = hovered_base_tile_coords;
menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
- empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ empty_base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
}
} break;
case DRAG_TYPE_RESIZE_TOP_LEFT:
@@ -1543,7 +1511,67 @@ void TileSetAtlasSourceEditor::_end_dragging() {
drag_modified_tiles.clear();
drag_type = DRAG_TYPE_NONE;
- tile_atlas_control->set_default_cursor_shape(CURSOR_ARROW);
+ // Change mouse accordingly.
+}
+
+Control::CursorShape TileSetAtlasSourceEditor::get_cursor_shape(const Point2 &p_pos) const {
+ Control::CursorShape cursor_shape = get_default_cursor_shape();
+ if (drag_type == DRAG_TYPE_NONE) {
+ if (selection.size() == 1) {
+ // Change the cursor depending on the hovered thing.
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Transform2D xform = tile_atlas_control->get_global_transform().affine_inverse() * get_global_transform();
+ Vector2 mouse_local_pos = xform.xform(p_pos);
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + rect.size * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
+ }
+ }
+ }
+ } else {
+ switch (drag_type) {
+ case DRAG_TYPE_RESIZE_TOP_LEFT:
+ case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
+ cursor_shape = CURSOR_FDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP:
+ case DRAG_TYPE_RESIZE_BOTTOM:
+ cursor_shape = CURSOR_VSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP_RIGHT:
+ case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
+ cursor_shape = CURSOR_BDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_LEFT:
+ case DRAG_TYPE_RESIZE_RIGHT:
+ cursor_shape = CURSOR_HSIZE;
+ break;
+ case DRAG_TYPE_MOVE_TILE:
+ cursor_shape = CURSOR_MOVE;
+ break;
+ default:
+ break;
+ }
+ }
+ return cursor_shape;
}
HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) {
@@ -1563,7 +1591,7 @@ HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_p
}
void TileSetAtlasSourceEditor::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case TILE_DELETE: {
@@ -1747,8 +1775,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
}
} else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
// Draw tiles to be removed.
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
@@ -1777,8 +1805,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
for (int x = area.get_position().x; x < area.get_end().x; x++) {
@@ -1795,8 +1823,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
// Draw the hovered tile.
if (drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT || drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
// Draw the rect.
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
Vector2i margins = tile_set_atlas_source->get_margins();
@@ -1950,7 +1978,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
selected = selection.front()->get();
menu_option_coords = selected.tile;
menu_option_alternative = selected.alternative;
- alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ alternative_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
}
}
@@ -2079,8 +2107,8 @@ 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_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo_man.is_valid());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
@@ -2210,7 +2238,7 @@ void TileSetAtlasSourceEditor::_auto_create_tiles() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
for (int y = 0; y < grid_size.y; y++) {
for (int x = 0; x < grid_size.x; x++) {
@@ -2256,7 +2284,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() {
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove tiles in fully transparent texture regions"));
List<PropertyInfo> list;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 85f780ea26..bcab1296ad 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -277,6 +277,8 @@ public:
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id);
void init_source();
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+
TileSetAtlasSourceEditor();
~TileSetAtlasSourceEditor();
};
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index b44cb18dc7..53c2d4de51 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -67,7 +67,7 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data,
// Actually create the new source.
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(resource);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a new atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
@@ -260,7 +260,7 @@ void TileSetEditor::_source_delete_pressed() {
Ref<TileSetSource> source = tile_set->get_source(to_delete);
// Remove the source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove source"));
undo_redo->add_do_method(*tile_set, "remove_source", to_delete);
undo_redo->add_undo_method(*tile_set, "add_source", source, to_delete);
@@ -279,7 +279,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
// Add a new source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
@@ -294,7 +294,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
Ref<TileSetScenesCollectionSource> scene_collection_source = memnew(TileSetScenesCollectionSource);
// Add a new source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", scene_collection_source, source_id);
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
@@ -369,7 +369,7 @@ void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
Vector<int> selected = patterns_item_list->get_selected_items();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove TileSet patterns"));
for (int i = 0; i < selected.size(); i++) {
int pattern_index = selected[i];
@@ -416,8 +416,8 @@ 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_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited);
if (!ed_tile_set) {
@@ -462,6 +462,35 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
+
+ // Add undo method to adding array element.
+ if (p_array_prefix == "occlusion_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_occlusion_layer", p_to_pos < 0 ? ed_tile_set->get_occlusion_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "physics_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_physics_layer", p_to_pos < 0 ? ed_tile_set->get_physics_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "terrain_set_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_terrain_set", p_to_pos < 0 ? ed_tile_set->get_terrain_sets_count() : 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_man->add_undo_method(ed_tile_set, "remove_terrain", terrain_set, p_to_pos < 0 ? ed_tile_set->get_terrains_count(terrain_set) : p_to_pos);
+ }
+ } else if (p_array_prefix == "navigation_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_navigation_layer", p_to_pos < 0 ? ed_tile_set->get_navigation_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "custom_data_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_custom_data_layer", p_to_pos < 0 ? ed_tile_set->get_custom_data_layers_count() : p_to_pos);
+ }
+ }
+
// Save layers' properties.
List<PropertyInfo> properties;
ed_tile_set->get_property_list(&properties);
@@ -543,7 +572,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
#undef ADD_UNDO
- // Add do method.
+ // Add do method to add/remove array element.
if (p_array_prefix == "occlusion_layer_") {
if (p_from_index < 0) {
undo_redo_man->add_do_method(ed_tile_set, "add_occlusion_layer", p_to_pos);
@@ -597,8 +626,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
#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);
@@ -637,11 +666,6 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
#undef ADD_UNDO
}
-void TileSetEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::_drop_data_fw);
-}
-
void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
if (p_tile_set == tile_set) {
return;
@@ -728,7 +752,7 @@ TileSetEditor::TileSetEditor() {
sources_list->add_user_signal(MethodInfo("sort_request"));
sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
- sources_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(sources_list, TileSetEditor);
split_container_left_side->add_child(sources_list);
HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 33200a0632..e3dff11277 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -97,7 +97,6 @@ private:
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
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 0ff8788626..6251cd18f7 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -237,7 +237,7 @@ void TileSetScenesCollectionSourceEditor::_scenes_list_item_activated(int p_inde
void TileSetScenesCollectionSourceEditor::_source_add_pressed() {
int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", Ref<PackedScene>(), scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
@@ -252,7 +252,7 @@ void TileSetScenesCollectionSourceEditor::_source_delete_pressed() {
ERR_FAIL_COND(selected_indices.size() <= 0);
int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "create_scene_tile", tile_set_scenes_collection_source->get_scene_tile_scene(scene_id), scene_id);
@@ -404,7 +404,7 @@ void TileSetScenesCollectionSourceEditor::_drop_data_fw(const Point2 &p_point, c
Ref<PackedScene> resource = ResourceLoader::load(files[i]);
if (resource.is_valid()) {
int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
@@ -453,8 +453,6 @@ void TileSetScenesCollectionSourceEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_drop_data_fw);
}
TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
@@ -509,7 +507,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scene_tiles_list = memnew(ItemList);
scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
- scene_tiles_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(scene_tiles_list, TileSetScenesCollectionSourceEditor);
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index b40e588e07..19ee0ae98d 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -185,26 +185,34 @@ void TilesEditorPlugin::_notification(int p_what) {
}
void TilesEditorPlugin::make_visible(bool p_visible) {
- is_visible = p_visible;
-
- if (is_visible) {
+ if (p_visible || is_tile_map_selected()) {
// Disable and hide invalid editors.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
tileset_editor_button->set_visible(tile_set.is_valid());
tilemap_editor_button->set_visible(tile_map);
- if (tile_map && !is_editing_tile_set) {
+ if (tile_map && (!is_editing_tile_set || !p_visible)) {
EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
} else {
EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
}
-
+ is_visible = true;
} else {
tileset_editor_button->hide();
tilemap_editor_button->hide();
EditorNode::get_singleton()->hide_bottom_panel();
+ is_visible = false;
}
}
+bool TilesEditorPlugin::is_tile_map_selected() {
+ TypedArray<Node> selection = get_editor_interface()->get_selection()->get_selected_nodes();
+ if (selection.size() == 1 && Object::cast_to<TileMap>(selection[0])) {
+ return true;
+ }
+
+ return false;
+}
+
void TilesEditorPlugin::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_pattern.is_valid());
@@ -362,19 +370,24 @@ void TilesEditorPlugin::edit(Object *p_object) {
} else if (p_object->is_class("TileSet")) {
tile_set = Ref<TileSet>(p_object);
if (tile_map) {
- if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree()) {
+ if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree() || !is_tile_map_selected()) {
tile_map = nullptr;
tile_map_id = ObjectID();
}
}
is_editing_tile_set = true;
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
}
}
// Update the editors.
_update_editors();
+ // If the tileset is being edited, the visibility function must be called
+ // here after _update_editors has been called.
+ if (is_editing_tile_set) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
+ }
+
// Add change listener.
if (tile_map) {
tile_map->connect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed));
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index 5b91584aa3..50073e59c6 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -110,6 +110,8 @@ public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tilemap_editor->forward_canvas_gui_input(p_event); }
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); }
+ bool is_tile_map_selected();
+
// Pattern preview API.
void queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 56dbdb49eb..96b1ad7ee0 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -129,30 +129,32 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio
void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) {
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
- for (const KeyValue<int, Port> &E : links[p_node_id].output_ports) {
+ Link &link = links[p_node_id];
+
+ for (const KeyValue<int, Port> &E : link.output_ports) {
if (E.value.preview_button != nullptr) {
E.value.preview_button->set_pressed(false);
}
}
+ bool is_dirty = link.preview_pos < 0;
- if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) {
- links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box);
- memdelete(links[p_node_id].preview_box);
- links[p_node_id].graph_node->reset_size();
- links[p_node_id].preview_visible = false;
+ if (!is_dirty && link.preview_visible && link.preview_box != nullptr) {
+ link.graph_node->remove_child(link.preview_box);
+ memdelete(link.preview_box);
+ link.preview_box = nullptr;
+ link.graph_node->reset_size();
+ link.preview_visible = false;
}
- if (p_port_id != -1 && links[p_node_id].output_ports[p_port_id].preview_button != nullptr) {
- if (is_dirty()) {
- links[p_node_id].preview_pos = links[p_node_id].graph_node->get_child_count();
+ if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) {
+ if (is_dirty) {
+ link.preview_pos = link.graph_node->get_child_count();
}
VBoxContainer *vbox = memnew(VBoxContainer);
- links[p_node_id].graph_node->add_child(vbox);
- if (links[p_node_id].preview_pos != -1) {
- links[p_node_id].graph_node->move_child(vbox, links[p_node_id].preview_pos);
- }
- links[p_node_id].graph_node->set_slot_draw_stylebox(vbox->get_index(), false);
+ link.graph_node->add_child(vbox);
+ link.graph_node->move_child(vbox, link.preview_pos);
+ link.graph_node->set_slot_draw_stylebox(vbox->get_index(), false);
Control *offset = memnew(Control);
offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
@@ -162,9 +164,9 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id);
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
vbox->add_child(port_preview);
- links[p_node_id].preview_visible = true;
- links[p_node_id].preview_box = vbox;
- links[p_node_id].output_ports[p_port_id].preview_button->set_pressed(true);
+ link.preview_visible = true;
+ link.preview_box = vbox;
+ link.output_ports[p_port_id].preview_button->set_pressed(true);
}
}
}
@@ -329,14 +331,6 @@ void VisualShaderGraphPlugin::clear_links() {
links.clear();
}
-bool VisualShaderGraphPlugin::is_dirty() const {
- return dirty;
-}
-
-void VisualShaderGraphPlugin::make_dirty(bool p_enabled) {
- dirty = p_enabled;
-}
-
void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) {
links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, HashMap<int, InputPort>(), HashMap<int, Port>(), nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } });
}
@@ -426,7 +420,13 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
editor->_update_created_node(node);
if (p_just_update) {
- links[p_id].graph_node = node;
+ Link &link = links[p_id];
+
+ link.graph_node = node;
+ link.preview_box = nullptr;
+ link.preview_pos = -1;
+ link.output_ports.clear();
+ link.input_ports.clear();
} else {
register_link(p_type, p_id, vsnode.ptr(), node);
}
@@ -1861,7 +1861,7 @@ void VisualShaderEditor::_update_parameters(bool p_update_refs) {
}
void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
VisualShader::Type type = VisualShader::Type(i);
@@ -1916,15 +1916,12 @@ void VisualShaderEditor::_update_graph() {
_update_varyings();
graph_plugin->clear_links();
- graph_plugin->make_dirty(true);
graph_plugin->update_theme();
for (int n_i = 0; n_i < nodes.size(); n_i++) {
graph_plugin->add_node(type, nodes[n_i], false);
}
- graph_plugin->make_dirty(false);
-
for (const VisualShader::Connection &E : node_connections) {
int from = E.from_node;
int from_idx = E.from_port;
@@ -1961,7 +1958,7 @@ void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Input Port"));
undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);
undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);
@@ -1977,7 +1974,7 @@ void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_typ
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Output Port"));
undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);
undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);
@@ -1993,7 +1990,7 @@ void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_p
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Input Port Type"));
undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);
undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));
@@ -2009,7 +2006,7 @@ void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Output Port Type"));
undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);
undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));
@@ -2038,7 +2035,7 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Input Port Name"));
undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));
@@ -2065,7 +2062,7 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Output Port Name"));
undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);
@@ -2078,7 +2075,7 @@ void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expa
Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
ERR_FAIL_COND(!node.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_expand) {
undo_redo->create_action(TTR("Expand Output Port"));
} else {
@@ -2176,7 +2173,7 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Input Port"));
List<VisualShader::Connection> conns;
@@ -2226,7 +2223,7 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Output Port"));
List<VisualShader::Connection> conns;
@@ -2293,7 +2290,7 @@ void VisualShaderEditor::_expression_focus_out(Object *code_edit, int p_node) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set VisualShader Expression"));
undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());
undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());
@@ -2357,7 +2354,7 @@ void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, in
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Resize VisualShader Node"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, p_new_size);
undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());
@@ -2374,7 +2371,7 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
if (node->get_output_port_for_preview() == p_port) {
p_port = -1; //toggle it
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));
undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);
undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);
@@ -2420,7 +2417,7 @@ void VisualShaderEditor::_comment_title_popup_hide() {
if (node->get_title() == comment_title_change_edit->get_text()) {
return; // nothing changed - ignored
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Comment Node Title"));
undo_redo->add_do_method(node.ptr(), "set_title", comment_title_change_edit->get_text());
undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());
@@ -2463,7 +2460,7 @@ void VisualShaderEditor::_comment_desc_popup_hide() {
if (node->get_description() == comment_desc_change_edit->get_text()) {
return; // nothing changed - ignored
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Comment Node Description"));
undo_redo->add_do_method(node.ptr(), "set_description", comment_desc_change_edit->get_text());
undo_redo->add_undo_method(node.ptr(), "set_description", node->get_title());
@@ -2484,7 +2481,7 @@ void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Parameter Name"));
undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
@@ -2520,7 +2517,7 @@ void VisualShaderEditor::_port_edited(const StringName &p_property, const Varian
Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);
ERR_FAIL_COND(!vsn.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Input Default Port"));
Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
@@ -2966,7 +2963,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
int id_to_use = visual_shader->get_valid_node_id(type);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_resource_path.is_empty()) {
undo_redo->create_action(TTR("Add Node to Visual Shader"));
} else {
@@ -3133,7 +3130,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));
undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);
@@ -3168,7 +3165,7 @@ void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::Varyin
}
void VisualShaderEditor::_remove_varying(const String &p_name) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));
VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);
@@ -3256,7 +3253,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t
void VisualShaderEditor::_nodes_dragged() {
drag_dirty = false;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node(s) Moved"));
for (const DragOp &E : drag_buffer) {
@@ -3280,7 +3277,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Connected"));
List<VisualShader::Connection> conns;
@@ -3312,7 +3309,7 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
int from = p_from.to_int();
int to = p_to.to_int();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
@@ -3352,7 +3349,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const int &F : p_nodes) {
for (const VisualShader::Connection &E : conns) {
if (E.from_node == F || E.to_node == F) {
@@ -3411,7 +3408,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);
undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);
}
@@ -3446,7 +3443,7 @@ void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_n
void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!p_vice_versa) {
undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
} else {
@@ -3645,7 +3642,7 @@ void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {
List<int> to_erase;
to_erase.push_back(p_node);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete VisualShader Node"));
_delete_nodes(p_type, to_erase);
undo_redo->commit_action();
@@ -3674,7 +3671,7 @@ void VisualShaderEditor::_delete_nodes_request(const TypedArray<StringName> &p_n
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete VisualShader Node(s)"));
_delete_nodes(get_current_shader_type(), to_erase);
undo_redo->commit_action();
@@ -4087,7 +4084,7 @@ void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, Li
}
void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_duplicate) {
undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
} else {
@@ -4206,7 +4203,7 @@ void VisualShaderEditor::_copy_nodes(bool p_cut) {
_dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);
if (p_cut) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Cut VisualShader Node(s)"));
List<int> ids;
@@ -4293,7 +4290,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
bool type_changed = next_input_type != prev_input_type;
- Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));
undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);
@@ -4362,7 +4359,7 @@ 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_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("ParameterRef Name Changed"));
undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
@@ -4406,7 +4403,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
- Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("Varying Name Changed"));
undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
@@ -4477,7 +4474,7 @@ void VisualShaderEditor::_float_constant_selected(int p_which) {
return; // same
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name));
undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value);
undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant());
@@ -4741,7 +4738,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
saved_node_pos_dirty = true;
_add_node(idx, add_options[idx].ops);
} else if (d.has("files")) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));
if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {
@@ -4905,10 +4902,6 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &VisualShaderEditor::drop_data_fw);
-
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
@@ -4922,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_show_zoom_label(true);
add_child(graph);
- graph->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor);
float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
@@ -5153,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() {
members = memnew(Tree);
members_vb->add_child(members);
- members->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor);
members->set_h_size_flags(SIZE_EXPAND_FILL);
members->set_v_size_flags(SIZE_EXPAND_FILL);
members->set_hide_root(true);
@@ -5448,11 +5441,9 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("DepthTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture", "DEPTH_TEXTURE"), { "depth_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FrontFacing", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -5495,7 +5486,6 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("NormalTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture", "NORMAL_TEXTURE"), { "normal_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenPixelSize", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size", "SCREEN_PIXEL_SIZE"), { "screen_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininess", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininessTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE"), { "specular_shininess_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
@@ -5699,7 +5689,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
curve_xyz_node_option_idx = add_options.size();
add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
texture2d_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture2d_array_node_option_idx = add_options.size();
@@ -6172,7 +6162,7 @@ public:
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
updating = true;
undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
@@ -6374,7 +6364,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Visual Shader Mode Changed"));
//do is easy
undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 88f5e3359c..c4f6b4952c 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -95,7 +95,6 @@ private:
Ref<VisualShader> visual_shader;
HashMap<int, Link> links;
List<VisualShader::Connection> connections;
- bool dirty = false;
Color vector_expanded_color[4];
@@ -115,8 +114,6 @@ public:
void clear_links();
void set_shader_type(VisualShader::Type p_type);
bool is_preview_visible(int p_id) const;
- bool is_dirty() const;
- void make_dirty(bool p_enabled);
void update_node(VisualShader::Type p_type, int p_id);
void update_node_deferred(VisualShader::Type p_type, int p_node_id);
void add_node(VisualShader::Type p_type, int p_id, bool p_just_update);
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 8396d50a0e..8ff0e7a454 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -237,7 +237,6 @@ static const char *gdscript_function_renames[][2] = {
{ "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image
{ "can_be_hidden", "_can_be_hidden" }, // EditorNode3DGizmoPlugin
{ "can_drop_data", "_can_drop_data" }, // Control
- { "can_drop_data_fw", "_can_drop_data_fw" }, // ScriptEditor
{ "can_generate_small_preview", "_can_generate_small_preview" }, // EditorResourcePreviewGenerator
{ "can_instance", "can_instantiate" }, // PackedScene, Script
{ "canvas_light_set_scale", "canvas_light_set_texture_scale" }, // RenderingServer
@@ -264,7 +263,6 @@ static const char *gdscript_function_renames[][2] = {
{ "deselect_items", "deselect_all" }, // FileDialog
{ "disable_plugin", "_disable_plugin" }, // EditorPlugin
{ "drop_data", "_drop_data" }, // Control
- { "drop_data_fw", "_drop_data_fw" }, // ScriptEditor
{ "exclude_polygons_2d", "exclude_polygons" }, // Geometry2D
{ "find_node", "find_child" }, // Node
{ "find_scancode_from_string", "find_keycode_from_string" }, // OS
@@ -303,7 +301,6 @@ static const char *gdscript_function_renames[][2] = {
{ "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
{ "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton
{ "get_endian_swap", "is_big_endian" }, // File
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 69c21177f9..560549d249 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -114,7 +114,7 @@ void ProjectSettingsEditor::_add_setting() {
Variant value;
Variant::construct(Variant::Type(type_box->get_selected_id()), value, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Project Setting"));
undo_redo->add_do_property(ps, setting, value);
undo_redo->add_undo_property(ps, setting, ps->has_setting(setting) ? ps->get(setting) : Variant());
@@ -134,7 +134,7 @@ void ProjectSettingsEditor::_delete_setting() {
Variant value = ps->get(setting);
int order = ps->get_order(setting);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Item"));
undo_redo->add_do_method(ps, "clear", setting);
@@ -223,7 +223,7 @@ void ProjectSettingsEditor::_select_type(Variant::Type p_type) {
void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
@@ -345,7 +345,7 @@ void ProjectSettingsEditor::_action_added(const String &p_name) {
action["events"] = Array();
action["deadzone"] = 0.5f;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Input Action"));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name);
@@ -361,7 +361,7 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar
const String property_name = "input/" + p_name;
Dictionary old_val = GLOBAL_GET(property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (old_val["deadzone"] != p_action["deadzone"]) {
// Deadzone Changed
undo_redo->create_action(TTR("Change Action deadzone"));
@@ -398,7 +398,7 @@ void ProjectSettingsEditor::_action_removed(const String &p_name) {
Dictionary old_val = GLOBAL_GET(property_name);
int order = ProjectSettings::get_singleton()->get_order(property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Erase Input Action"));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property_name);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val);
@@ -421,7 +421,7 @@ void ProjectSettingsEditor::_action_renamed(const String &p_old_name, const Stri
int order = ProjectSettings::get_singleton()->get_order(old_property_name);
Dictionary action = GLOBAL_GET(old_property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Input Action Event"));
// Do: clear old, set new
undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", old_property_name);
@@ -451,7 +451,7 @@ void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const
HashMap<String, Variant> action_values;
ProjectSettings::get_singleton()->get_property_list(&props);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Update Input Action Order"));
for (const PropertyInfo &prop : props) {
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index b7b316df64..c3a99e96ef 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -583,7 +583,7 @@ void RenameDialog::rename() {
_iterate_scene(root_node, selected_node_list, &global_count);
if (!to_rename.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Batch Rename"));
// Make sure to iterate reversed so that child nodes will find parents.
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index ac6bceaa55..733f140a56 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -231,7 +231,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Instantiate Scene(s)"));
for (int i = 0; i < instances.size(); i++) {
@@ -275,7 +275,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace with Branch Scene"));
Node *parent = base->get_parent();
@@ -540,7 +540,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
undo_redo->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
@@ -611,7 +611,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break; // one or more nodes can not be moved
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (selection.size() == 1) {
undo_redo->create_action(TTR("Move Node In Parent"));
}
@@ -661,7 +661,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
undo_redo->add_do_method(editor_selection, "clear");
@@ -778,7 +778,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Make node as Root"));
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
@@ -1023,7 +1023,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *node = e->get();
if (node) {
Node *root = EditorNode::get_singleton()->get_edited_scene();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!root) {
break;
}
@@ -1099,7 +1099,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
bool enabling = !first_selected->get()->is_unique_name_in_owner();
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (enabling) {
Vector<Node *> new_unique_nodes;
@@ -1226,7 +1226,7 @@ void SceneTreeDock::_property_selected(int p_idx) {
}
void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set %s"), p_property));
undo_redo->add_do_property(p_node, p_property, p_res);
undo_redo->add_undo_property(p_node, p_property, p_node->get(p_property));
@@ -1234,7 +1234,7 @@ void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<
}
void SceneTreeDock::add_root_node(Node *p_node) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id());
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
undo_redo->add_do_method(scene_tree, "update_tree");
@@ -1385,7 +1385,7 @@ void SceneTreeDock::_notification(int p_what) {
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
if (p_node->get_owner() == p_base && p_node != p_root) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_mode) {
case MODE_BIDI: {
bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
@@ -1619,7 +1619,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
Variant old_variant = p_base->get(propertyname);
Variant updated_variant = old_variant;
if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_property(p_base, propertyname, updated_variant);
undo_redo->add_undo_property(p_base, propertyname, old_variant);
p_base->set(propertyname, updated_variant);
@@ -1666,7 +1666,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
}
HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (found_path) {
if (found_path->value == NodePath()) {
//will be erased
@@ -1833,7 +1833,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
// Sort by tree order, so re-adding is easy.
p_nodes.sort_custom<Node::Comparator>();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Reparent Node"), UndoRedo::MERGE_DISABLE, p_nodes[0]);
HashMap<Node *, NodePath> path_renames;
@@ -1968,7 +1968,7 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
for (Node *E : selected) {
Ref<Script> existing = E->get_script();
@@ -1994,7 +1994,7 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
Ref<Shader> existing = selected_shader_material->get_shader();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Shader"));
undo_redo->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
undo_redo->add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
@@ -2063,7 +2063,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get());
bool entire_scene = false;
@@ -2193,7 +2193,7 @@ void SceneTreeDock::_do_create(Node *p_parent) {
}
child->set_name(new_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action_for_history(TTR("Create Node"), editor_data->get_current_edited_scene_history_id());
if (edited_scene) {
@@ -2262,7 +2262,7 @@ void SceneTreeDock::_create() {
List<Node *> selection = editor_selection->get_selected_node_list();
ERR_FAIL_COND(selection.size() <= 0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
for (Node *n : selection) {
@@ -2396,7 +2396,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
}
//p_remove_old was added to support undo
if (p_remove_old) {
- EditorNode::get_undo_redo()->clear_history();
+ EditorUndoRedoManager::get_singleton()->clear_history();
}
newnode->set_name(newname);
@@ -2618,7 +2618,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
Object *obj = ClassDB::instantiate(scr->get_instance_base_type());
ERR_FAIL_NULL(obj);
@@ -3190,7 +3190,7 @@ List<Node *> SceneTreeDock::paste_nodes() {
owner = paste_parent;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
ur->add_do_method(editor_selection, "clear");
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index b4f1ca5d0b..e0d748c478 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -68,7 +68,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
Node *n = get_node(np);
ERR_FAIL_COND(!n);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_id == BUTTON_SUBSCENE) {
if (n == get_scene_node()) {
if (n && n->get_scene_inherited_state().is_valid()) {
@@ -176,7 +176,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
void SceneTreeEditor::_toggle_visible(Node *p_node) {
if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) {
bool v = bool(p_node->call("is_visible"));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(p_node, "set_visible", !v);
undo_redo->add_undo_method(p_node, "set_visible", v);
}
@@ -1015,7 +1015,7 @@ void SceneTreeEditor::_renamed() {
which->set_metadata(0, n->get_path());
emit_signal(SNAME("node_renamed"));
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Node"));
emit_signal(SNAME("node_prerename"), n, new_name);
undo_redo->add_do_method(this, "_rename_node", n->get_instance_id(), new_name);
@@ -1373,10 +1373,6 @@ void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SceneTreeEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree);
ADD_SIGNAL(MethodInfo("node_selected"));
@@ -1419,7 +1415,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
add_child(tree);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, SceneTreeEditor);
if (p_can_rename) {
tree->set_allow_rmb_select(true);
tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select));
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 4ac0a5b672..800de431eb 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -70,7 +70,7 @@ class ShaderGlobalsEditorInterface : public Object {
GDCLASS(ShaderGlobalsEditorInterface, Object)
void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Shader Global Variable"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);
@@ -399,7 +399,7 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));
@@ -418,7 +418,7 @@ void ShaderGlobalsEditor::_variable_added() {
}
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Shader Global Parameter"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);
diff --git a/main/main.cpp b/main/main.cpp
index 6b04cdc6d6..e5d2ea3922 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1385,7 +1385,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
if (editor) {
packed_data->set_disabled(true);
- globals->set_disable_feature_overrides(true);
Engine::get_singleton()->set_editor_hint(true);
main_args.push_back("--editor");
if (!init_windowed) {
@@ -1678,10 +1677,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
+#ifdef TOOLS_ENABLED
if (editor || project_manager) {
- // The editor and project manager always detect and use hiDPI if needed
+ // The editor and project manager always detect and use hiDPI if needed.
OS::get_singleton()->_allow_hidpi = true;
+ // Disable Vulkan overlays in editor, they cause various issues.
+ OS::get_singleton()->set_environment("DISABLE_MANGOHUD", "1"); // GH-57403.
+ OS::get_singleton()->set_environment("DISABLE_RTSS_LAYER", "1"); // GH-57937.
+ OS::get_singleton()->set_environment("DISABLE_VKBASALT", "1");
+ } else {
+ // Re-allow using Vulkan overlays, disabled while using the editor.
+ OS::get_singleton()->unset_environment("DISABLE_MANGOHUD");
+ OS::get_singleton()->unset_environment("DISABLE_RTSS_LAYER");
+ OS::get_singleton()->unset_environment("DISABLE_VKBASALT");
}
+#endif
if (rtm == -1) {
rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE);
@@ -2115,7 +2125,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#endif
}
-#ifdef TOOLS_ENABLED
+#if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED)
if (OS::get_singleton()->get_bundle_icon_path().is_empty()) {
Ref<Image> icon = memnew(Image(app_icon_png));
DisplayServer::get_singleton()->set_icon(icon);
@@ -3031,11 +3041,13 @@ bool Main::iteration() {
PhysicsServer2D::get_singleton()->flush_queries();
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
+ PhysicsServer3D::get_singleton()->end_sync();
+ PhysicsServer2D::get_singleton()->end_sync();
+
exit = true;
break;
}
- NavigationServer3D::get_singleton()->process(physics_step * time_scale);
uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec();
NavigationServer3D::get_singleton()->process(physics_step * time_scale);
diff --git a/main/performance.cpp b/main/performance.cpp
index 448ddd0e96..e24a3673b9 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -249,6 +249,9 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
+ MONITOR_TYPE_QUANTITY,
+ MONITOR_TYPE_QUANTITY,
+ MONITOR_TYPE_QUANTITY,
};
@@ -313,6 +316,7 @@ uint64_t Performance::get_monitor_modification_time() {
Performance::Performance() {
_process_time = 0;
_physics_process_time = 0;
+ _navigation_process_time = 0;
_monitor_modification_time = 0;
singleton = this;
}
diff --git a/methods.py b/methods.py
index ee88401671..7ede2592ff 100644
--- a/methods.py
+++ b/methods.py
@@ -488,29 +488,29 @@ def use_windows_spawn_fix(self, platform=None):
def save_active_platforms(apnames, ap):
for x in ap:
- names = ["logo"]
- if os.path.isfile(x + "/run_icon.png"):
- names.append("run_icon")
-
- for name in names:
- pngf = open(x + "/" + name + ".png", "rb")
- b = pngf.read(1)
- str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
- str += " static const unsigned char _" + x[9:] + "_" + name + "[]={"
+ svg_names = []
+ if os.path.isfile(x + "/logo.svg"):
+ svg_names.append("logo")
+ if os.path.isfile(x + "/run_icon.svg"):
+ svg_names.append("run_icon")
+
+ for name in svg_names:
+ svgf = open(x + "/" + name + ".svg", "rb")
+ b = svgf.read(1)
+ svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
+ svg_str += " static const char *_" + x[9:] + "_" + name + '_svg = "'
while len(b) == 1:
- str += hex(ord(b))
- b = pngf.read(1)
- if len(b) == 1:
- str += ","
+ svg_str += "\\" + hex(ord(b))[1:]
+ b = svgf.read(1)
- str += "};\n"
+ svg_str += '";\n'
- pngf.close()
+ svgf.close()
# NOTE: It is safe to generate this file here, since this is still executed serially
- wf = x + "/" + name + ".gen.h"
- with open(wf, "w") as pngw:
- pngw.write(str)
+ wf = x + "/" + name + "_svg.gen.h"
+ with open(wf, "w") as svgw:
+ svgw.write(svg_str)
def no_verbose(sys, env):
diff --git a/misc/hooks/asmessage.applescript b/misc/hooks/asmessage.applescript
new file mode 100644
index 0000000000..15ba94dc37
--- /dev/null
+++ b/misc/hooks/asmessage.applescript
@@ -0,0 +1,59 @@
+on run argv
+ set vButtons to { "OK" }
+ set vButtonCodes to { 0 }
+ set vDbutton to "OK"
+ set vText to ""
+ set vTitle to ""
+ set vTimeout to -1
+
+ repeat with i from 1 to length of argv
+ try
+ set vArg to item i of argv
+ if vArg = "-buttons" then
+ set vButtonsAndCodes to my fSplit(item (i + 1) of argv, ",")
+ set vButtons to {}
+ set vButtonCodes to {}
+ repeat with j from 1 to length of vButtonsAndCodes
+ set vBtn to my fSplit(item j of vButtonsAndCodes, ":")
+ copy (item 1 of vBtn) to the end of the vButtons
+ copy (item 2 of vBtn) to the end of the vButtonCodes
+ end repeat
+ else if vArg = "-title" then
+ set vTitle to item (i + 1) of argv
+ else if vArg = "-center" then
+ -- not supported
+ else if vArg = "-default" then
+ set vDbutton to item (i + 1) of argv
+ else if vArg = "-geometry" then
+ -- not supported
+ else if vArg = "-nearmouse" then
+ -- not supported
+ else if vArg = "-timeout" then
+ set vTimeout to item (i + 1) of argv as integer
+ else if vArg = "-file" then
+ set vText to read (item (i + 1) of argv) as string
+ else if vArg = "-text" then
+ set vText to item (i + 1) of argv
+ end if
+ end try
+ end repeat
+
+ set vDlg to display dialog vText buttons vButtons default button vDbutton with title vTitle giving up after vTimeout with icon stop
+ set vRet to button returned of vDlg
+ repeat with i from 1 to length of vButtons
+ set vBtn to item i of vButtons
+ if vBtn = vRet
+ return item i of vButtonCodes
+ end if
+ end repeat
+
+ return 0
+end run
+
+on fSplit(vString, vDelimiter)
+ set oldDelimiters to AppleScript's text item delimiters
+ set AppleScript's text item delimiters to vDelimiter
+ set vArray to every text item of vString
+ set AppleScript's text item delimiters to oldDelimiters
+ return vArray
+end fSplit
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black
index b7335685ae..bbad6a690a 100755
--- a/misc/hooks/pre-commit-black
+++ b/misc/hooks/pre-commit-black
@@ -34,6 +34,9 @@ XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
+# Path to osascript (macOS only)
+OSA=`which osascript 2>/dev/null`
+
##################################################################
# There should be no need to change anything below this line.
@@ -69,6 +72,10 @@ if [ ! -x "$BLACK" ] ; then
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ $OSA "$asmessage" -center -title "Error" --text "Error: black executable not found."
+ exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
@@ -159,6 +166,16 @@ while true; do
else
yn="N"
fi
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"`
+ if [ "$choice" = "100" ] ; then
+ yn="Y"
+ elif [ "$choice" = "200" ] ; then
+ yn="S"
+ else
+ yn="N"
+ fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
@@ -171,7 +188,7 @@ while true; do
yn="N"
fi
else
- printf "Error: zenity, xmessage, or powershell executable not found.\n"
+ printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n"
exit 1
fi
else
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 9570d5120b..fd0213c175 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -47,6 +47,9 @@ XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
+# Path to osascript (macOS only)
+OSA=`which osascript 2>/dev/null`
+
##################################################################
# There should be no need to change anything below this line.
@@ -89,6 +92,10 @@ if [ ! -x "$CLANG_FORMAT" ] ; then
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ $OSA "$asmessage" -center -title "Error" --text "$message"
+ exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
@@ -199,6 +206,16 @@ while true; do
else
yn="N"
fi
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"`
+ if [ "$choice" = "100" ] ; then
+ yn="Y"
+ elif [ "$choice" = "200" ] ; then
+ yn="S"
+ else
+ yn="N"
+ fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
@@ -211,7 +228,7 @@ while true; do
yn="N"
fi
else
- printf "Error: zenity, xmessage, or powershell executable not found.\n"
+ printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n"
exit 1
fi
else
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 3b789a235f..5b451fbf6b 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -58,6 +58,13 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
ERR_FAIL_COND_V_MSG(height % 8 != 0, ERR_UNAVAILABLE,
vformat("1-bpp BMP images must have a height that is a multiple of 8, but the imported BMP is %d pixels tall.", int(height)));
+ } else if (bits_per_pixel == 2) {
+ // Requires bit unpacking...
+ ERR_FAIL_COND_V_MSG(width % 4 != 0, ERR_UNAVAILABLE,
+ vformat("2-bpp BMP images must have a width that is a multiple of 4, but the imported BMP is %d pixels wide.", int(width)));
+ ERR_FAIL_COND_V_MSG(height % 4 != 0, ERR_UNAVAILABLE,
+ vformat("2-bpp BMP images must have a height that is a multiple of 4, but the imported BMP is %d pixels tall.", int(height)));
+
} else if (bits_per_pixel == 4) {
// Requires bit unpacking...
ERR_FAIL_COND_V_MSG(width % 2 != 0, ERR_UNAVAILABLE,
@@ -88,7 +95,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
const uint32_t line_width = (width_bytes + 3) & ~3;
// The actual data traversal is determined by
- // the data width in case of 8/4/1 bit images
+ // the data width in case of 8/4/2/1 bit images
const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes;
const uint8_t *line = p_buffer + (line_width * (height - 1));
const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset;
@@ -114,6 +121,17 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
index += 8;
line_ptr += 1;
} break;
+ case 2: {
+ uint8_t color_index = *line_ptr;
+
+ write_buffer[index + 0] = (color_index >> 6) & 3;
+ write_buffer[index + 1] = (color_index >> 4) & 3;
+ write_buffer[index + 2] = (color_index >> 2) & 3;
+ write_buffer[index + 3] = color_index & 3;
+
+ index += 4;
+ line_ptr += 1;
+ } break;
case 4: {
uint8_t color_index = *line_ptr;
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 61787691a3..2c533cb36d 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -217,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
ur->add_undo_method(s, "set_radius", p_restore);
@@ -231,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(s, "set_size", s->get_size());
ur->add_undo_method(s, "set_size", p_restore);
@@ -249,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
@@ -274,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Torus Inner Radius"));
ur->add_do_method(s, "set_inner_radius", s->get_inner_radius());
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index fd748ea569..3fe741a582 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -553,6 +553,7 @@
@icon("res://path/to/class/icon.svg")
[/codeblock]
[b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported.
+ [b]Note:[/b] As annotations describe their subject, the [code]@icon[/code] annotation must be placed before the class definition and inheritance.
</description>
</annotation>
<annotation name="@onready">
@@ -585,6 +586,7 @@
@tool
extends Node
[/codeblock]
+ [b]Note:[/b] As annotations describe their subject, the [code]@tool[/code] annotation must be placed before the class definition and inheritance.
</description>
</annotation>
<annotation name="@warning_ignore" qualifiers="vararg">
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 0c858a36e7..e04a962dcb 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -889,11 +889,11 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
resolve_function_signature(member.function, p_source);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
+ member.enum_value.identifier->set_datatype(resolving_datatype);
+
if (member.enum_value.custom_value) {
check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.custom_value);
- member.enum_value.identifier->set_datatype(resolving_datatype);
-
const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.enum_value.parent_enum;
reduce_expression(member.enum_value.custom_value);
@@ -1722,21 +1722,52 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
if (list_resolved) {
variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
variable_type.kind = GDScriptParser::DataType::BUILTIN;
- variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else?
- p_for->variable->set_datatype(variable_type);
+ variable_type.builtin_type = Variant::INT;
} else if (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;
- } else if (p_for->list->datatype.is_typed_container_type()) {
- variable_type = p_for->list->datatype.get_typed_container_type();
- variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
- } else {
- // Last resort
- // TODO: Must other cases be handled? Must we mark as unsafe?
- variable_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ GDScriptParser::DataType list_type = p_for->list->get_datatype();
+ if (!list_type.is_hard_type()) {
+ mark_node_unsafe(p_for->list);
+ }
+ if (list_type.is_variant()) {
variable_type.kind = GDScriptParser::DataType::VARIANT;
+ mark_node_unsafe(p_for->list);
+ } else if (list_type.has_container_element_type()) {
+ variable_type = list_type.get_container_element_type();
+ variable_type.type_source = list_type.type_source;
+ } else if (list_type.is_typed_container_type()) {
+ variable_type = list_type.get_typed_container_type();
+ variable_type.type_source = list_type.type_source;
+ } else if (list_type.builtin_type == Variant::INT || list_type.builtin_type == Variant::FLOAT || list_type.builtin_type == Variant::STRING) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = list_type.builtin_type;
+ } else if (list_type.builtin_type == Variant::VECTOR2I || list_type.builtin_type == Variant::VECTOR3I) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = Variant::INT;
+ } else if (list_type.builtin_type == Variant::VECTOR2 || list_type.builtin_type == Variant::VECTOR3) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = Variant::FLOAT;
+ } else if (list_type.builtin_type == Variant::OBJECT) {
+ GDScriptParser::DataType return_type;
+ List<GDScriptParser::DataType> par_types;
+ int default_arg_count = 0;
+ bool is_static = false;
+ bool is_vararg = false;
+ if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ variable_type = return_type;
+ variable_type.type_source = list_type.type_source;
+ } else if (!list_type.is_hard_type()) {
+ variable_type.kind = GDScriptParser::DataType::VARIANT;
+ } else {
+ push_error(vformat(R"(Unable to iterate on object of type "%s".)", list_type.to_string()), p_for->list);
+ }
+ } else if (list_type.builtin_type == Variant::ARRAY || list_type.builtin_type == Variant::DICTIONARY || !list_type.is_hard_type()) {
+ variable_type.kind = GDScriptParser::DataType::VARIANT;
+ } else {
+ push_error(vformat(R"(Unable to iterate on value of type "%s".)", list_type.to_string()), p_for->list);
}
}
if (p_for->variable) {
@@ -2910,8 +2941,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::Ide
p_identifier->set_datatype(p_identifier_datatype);
Error err = OK;
- GDScript *scr = GDScriptCache::get_full_script(p_identifier_datatype.script_path, err).ptr();
- ERR_FAIL_COND_MSG(err != OK, "Error while getting full script.");
+ GDScript *scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err).ptr();
+ ERR_FAIL_COND_MSG(err != OK, vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path));
scr = scr->find_class(p_identifier_datatype.class_type->fqcn);
p_identifier->reduced_value = scr;
p_identifier->is_constant = true;
@@ -3140,7 +3171,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
for (int i = 0; i < current_enum->values.size(); i++) {
const GDScriptParser::EnumNode::Value &element = current_enum->values[i];
if (element.identifier->name == p_identifier->name) {
- StringName enum_name = current_enum->identifier->name ? current_enum->identifier->name : UNNAMED_ENUM;
+ StringName enum_name = current_enum->identifier ? current_enum->identifier->name : UNNAMED_ENUM;
GDScriptParser::DataType type = make_enum_type(enum_name, parser->current_class->fqcn, false);
if (element.parent_enum->identifier) {
type.enum_type = element.parent_enum->identifier->name;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 77c6690d20..d63a1b4536 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -213,7 +213,7 @@ static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScr
}
GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
- if (p_expression->is_constant && !p_expression->get_datatype().is_meta_type) {
+ if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) {
return codegen.add_constant(p_expression->reduced_value);
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 0a1ae46927..3fc0924b4c 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -80,7 +80,7 @@ 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("_CLASS_", p_class_name.to_pascal_case())
.replace("_TS_", _get_indentation());
scr->set_source_code(processed_template);
return scr;
@@ -1275,6 +1275,14 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
}
r_result.insert(option.display, option);
}
+
+ // Global classes
+ List<StringName> global_classes;
+ ScriptServer::get_global_class_list(&global_classes);
+ for (const StringName &E : global_classes) {
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
+ r_result.insert(option.display, option);
+ }
}
static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index bbea6fe857..f5d3306376 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -540,43 +540,28 @@ void GDScriptParser::parse_program() {
head = alloc_node<ClassNode>();
head->fqcn = script_path;
current_class = head;
+ bool can_have_class_or_extends = true;
- // If we happen to parse an annotation before extends or class_name keywords, track it.
- // @tool is allowed, but others should fail.
- AnnotationNode *premature_annotation = nullptr;
-
- if (match(GDScriptTokenizer::Token::ANNOTATION)) {
- // Check for @tool, script-level, or standalone annotation.
+ while (match(GDScriptTokenizer::Token::ANNOTATION)) {
AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
if (annotation != nullptr) {
- if (annotation->name == SNAME("@tool")) {
- // TODO: don't allow @tool anywhere else. (Should all script annotations be the first thing?).
- _is_tool = true;
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after "@tool" annotation.)");
- }
- // @tool annotation has no specific target.
- annotation->apply(this, nullptr);
- } else if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) {
- premature_annotation = annotation;
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after a standalone annotation.)");
- }
+ if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
annotation->apply(this, head);
} else {
- premature_annotation = annotation;
annotation_stack.push_back(annotation);
+ // This annotation must appear after script-level annotations
+ // and class_name/extends (ex: could be @onready or @export),
+ // so we stop looking for script-level stuff.
+ can_have_class_or_extends = false;
+ break;
}
}
}
- for (bool should_break = false; !should_break;) {
+ while (can_have_class_or_extends) {
// Order here doesn't matter, but there should be only one of each at most.
switch (current.type) {
case GDScriptTokenizer::Token::CLASS_NAME:
- if (premature_annotation != nullptr) {
- push_error(R"("class_name" should be used before annotations (except @tool).)");
- }
advance();
if (head->identifier != nullptr) {
push_error(R"("class_name" can only be used once.)");
@@ -585,9 +570,6 @@ void GDScriptParser::parse_program() {
}
break;
case GDScriptTokenizer::Token::EXTENDS:
- if (premature_annotation != nullptr) {
- push_error(R"("extends" should be used before annotations (except @tool).)");
- }
advance();
if (head->extends_used) {
push_error(R"("extends" can only be used once.)");
@@ -597,7 +579,8 @@ void GDScriptParser::parse_program() {
}
break;
default:
- should_break = true;
+ // No tokens are allowed between script annotations and class/extends.
+ can_have_class_or_extends = false;
break;
}
@@ -606,21 +589,6 @@ void GDScriptParser::parse_program() {
}
}
- if (match(GDScriptTokenizer::Token::ANNOTATION)) {
- // Check for a script-level, or standalone annotation.
- AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
- if (annotation != nullptr) {
- if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) {
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after a standalone annotation.)");
- }
- annotation->apply(this, head);
- } else {
- annotation_stack.push_back(annotation);
- }
- }
- }
-
parse_class_body(true);
complete_extents(head);
@@ -3794,6 +3762,26 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.type = Variant::INT;
}
}
+ if (p_annotation->name == SNAME("@export_multiline")) {
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) {
+ DataType inner_type = export_type.get_container_element_type();
+ if (inner_type.builtin_type != Variant::STRING) {
+ push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable);
+ return false;
+ }
+
+ String hint_prefix = itos(inner_type.builtin_type) + "/" + itos(variable->export_info.hint);
+ variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
+ variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
+ variable->export_info.type = Variant::ARRAY;
+
+ return true;
+ } else if (export_type.builtin_type == Variant::DICTIONARY) {
+ variable->export_info.type = Variant::DICTIONARY;
+
+ return true;
+ }
+ }
if (p_annotation->name == SNAME("@export")) {
if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) {
diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md
index 6e54085962..361d586d32 100644
--- a/modules/gdscript/tests/README.md
+++ b/modules/gdscript/tests/README.md
@@ -4,5 +4,5 @@ The `scripts/` folder contains integration tests in the form of GDScript files
and output files.
See the
-[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html#integration-tests-for-gdscript)
+[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html#integration-tests-for-gdscript)
for information about creating and running GDScript integration tests.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd
new file mode 100644
index 0000000000..cf56a0a933
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd
@@ -0,0 +1,6 @@
+const constant_float = 1.0
+
+func test():
+ for x in constant_float:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out
new file mode 100644
index 0000000000..e309831b3e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "float" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd
new file mode 100644
index 0000000000..5ee8ac19e1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd
@@ -0,0 +1,6 @@
+const constant_int = 1
+
+func test():
+ for x in constant_int:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd
new file mode 100644
index 0000000000..b3db4f3b49
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd
@@ -0,0 +1,6 @@
+enum { enum_value = 1 }
+
+func test():
+ for x in enum_value:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd
new file mode 100644
index 0000000000..87c54f7402
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_float := 1.0
+
+ for x in hard_float:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out
new file mode 100644
index 0000000000..e309831b3e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "float" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd
new file mode 100644
index 0000000000..2a43f5a930
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_int := 1
+
+ for x in hard_int:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd
new file mode 100644
index 0000000000..c3920d35b3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd
@@ -0,0 +1,14 @@
+class Iterator:
+ func _iter_init(_count):
+ return true
+ func _iter_next(_count):
+ return false
+ func _iter_get(_count) -> StringName:
+ return &'custom'
+
+func test():
+ var hard_iterator := Iterator.new()
+
+ for x in hard_iterator:
+ if x is int:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out
new file mode 100644
index 0000000000..a48591a3b4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "StringName" so it can't be of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd
new file mode 100644
index 0000000000..b36d87aabe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_string := 'a'
+
+ for x in hard_string:
+ if x is int:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out
new file mode 100644
index 0000000000..92c5ebc599
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "String" so it can't be of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd
new file mode 100644
index 0000000000..060a8bedf9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd
@@ -0,0 +1,3 @@
+func test():
+ for x in true:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out
new file mode 100644
index 0000000000..94cb038885
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Unable to iterate on value of type "bool".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd
new file mode 100644
index 0000000000..6cfc822482
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd
@@ -0,0 +1,4 @@
+func test():
+ for x in 1:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd
new file mode 100644
index 0000000000..f351fc1f7b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd
@@ -0,0 +1,7 @@
+enum {
+ V1,
+ V2 = V1,
+}
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd
new file mode 100644
index 0000000000..7b74be6f2c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd
@@ -0,0 +1,15 @@
+func test():
+ var variant_int: Variant = 1
+ var weak_int = 1
+
+ for x in variant_int:
+ if x is String:
+ print('never')
+ print(x)
+
+ for x in weak_int:
+ if x is String:
+ print('never')
+ print(x)
+
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out
new file mode 100644
index 0000000000..7677671cfd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+0
+0
+ok
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
index 179e454073..0085b3f367 100644
--- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
@@ -1,6 +1,6 @@
-# Error here. `class_name` should be used *before* annotations, not after (except @tool).
-@icon("res://path/to/optional/icon.svg")
+# Error here. Annotations should be used before `class_name`, not after.
class_name HelloWorld
+@icon("res://path/to/optional/icon.svg")
func test():
pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
index 02b33c8692..a598ff8424 100644
--- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-"class_name" should be used before annotations (except @tool).
+Annotation "@icon" is not allowed in this level.
diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd
index 8bd188e247..19009e433d 100644
--- a/modules/gdscript/tests/scripts/parser/features/class_name.gd
+++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd
@@ -1,5 +1,5 @@
-class_name HelloWorld
@icon("res://path/to/optional/icon.svg")
+class_name HelloWorld
func test():
pass
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd
new file mode 100644
index 0000000000..81355e0255
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd
@@ -0,0 +1,51 @@
+const constant_float = 1.0
+const constant_int = 1
+enum { enum_value = 1 }
+
+class Iterator:
+ func _iter_init(_count):
+ return true
+ func _iter_next(_count):
+ return false
+ func _iter_get(_count) -> StringName:
+ return &'custom'
+
+func test():
+ var hard_float := 1.0
+ var hard_int := 1
+ var hard_string := '0'
+ var hard_iterator := Iterator.new()
+
+ var variant_float: Variant = hard_float
+ var variant_int: Variant = hard_int
+ var variant_string: Variant = hard_string
+ var variant_iterator: Variant = hard_iterator
+
+ for i in 1.0:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in 1:
+ print(typeof(i) == TYPE_INT)
+ for i in 'a':
+ print(typeof(i) == TYPE_STRING)
+ for i in Iterator.new():
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ for i in hard_float:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in hard_int:
+ print(typeof(i) == TYPE_INT)
+ for i in hard_string:
+ print(typeof(i) == TYPE_STRING)
+ for i in hard_iterator:
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ for i in variant_float:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in variant_int:
+ print(typeof(i) == TYPE_INT)
+ for i in variant_string:
+ print(typeof(i) == TYPE_STRING)
+ for i in variant_iterator:
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out
new file mode 100644
index 0000000000..b3e82d52ef
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+ok
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index f313f4b28f..d7e8141eb1 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -15,7 +15,7 @@
<param index="2" name="state" type="GLTFState" />
<param index="3" name="flags" type="int" default="0" />
<description>
- Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter.
+ Takes a [PackedByteArray] defining a GLTF and imports the data to the given [GLTFState] object through the [param state] parameter.
[b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty.
</description>
</method>
@@ -26,7 +26,7 @@
<param index="2" name="flags" type="int" default="0" />
<param index="3" name="base_path" type="String" default="&quot;&quot;" />
<description>
- Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter.
+ Takes a path to a GLTF file and imports the data at that file path to the given [GLTFState] object through the [param state] parameter.
[b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty.
</description>
</method>
@@ -36,14 +36,14 @@
<param index="1" name="state" type="GLTFState" />
<param index="2" name="flags" type="int" default="0" />
<description>
- Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter.
+ Takes a Godot Engine scene node and exports it and its descendants to the given [GLTFState] object through the [param state] parameter.
</description>
</method>
<method name="generate_buffer">
<return type="PackedByteArray" />
<param index="0" name="state" type="GLTFState" />
<description>
- Takes a [GLTFState] object through the [param state] parameter and returns a gLTF [PackedByteArray].
+ Takes a [GLTFState] object through the [param state] parameter and returns a GLTF [PackedByteArray].
</description>
</method>
<method name="generate_scene">
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 67bb99de16..183190460e 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -461,7 +461,7 @@ void GridMapEditor::_delete_selection() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Delete Selection"));
for (int i = selection.begin.x; i <= selection.end.x; i++) {
for (int j = selection.begin.y; j <= selection.end.y; j++) {
@@ -482,7 +482,7 @@ void GridMapEditor::_fill_selection() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Fill Selection"));
for (int i = selection.begin.x; i <= selection.end.x; i++) {
for (int j = selection.begin.y; j <= selection.end.y; j++) {
@@ -576,7 +576,7 @@ void GridMapEditor::_do_paste() {
rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
Vector3 ofs = paste_indicator.current - paste_indicator.click;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Paste Selection"));
for (const ClipboardItem &item : clipboard_items) {
@@ -664,7 +664,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
} else {
if ((mb->get_button_index() == MouseButton::RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Paint"));
for (const SetItem &si : set_items) {
undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation);
@@ -686,7 +686,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
}
if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Selection"));
undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);
undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index c45fdda75c..7606465b8a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -113,6 +113,11 @@ void CSharpLanguage::init() {
BindingsGenerator::handle_cmdline_args(cmdline_args);
#endif
+ GLOBAL_DEF("dotnet/project/assembly_name", "");
+#ifdef TOOLS_ENABLED
+ GLOBAL_DEF("dotnet/project/solution_directory", "");
+#endif
+
gdmono = memnew(GDMono);
gdmono->initialize();
@@ -688,7 +693,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
return false; // Already up to date
}
} else {
- String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
+ String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
if (assembly_name.is_empty()) {
assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 745a8b73f8..db96003baf 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
{
+ public override string _GetName() => "C#";
+
private List<string> _tempFolders = new List<string>();
public void RegisterExportSettings()
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index de10c04e31..08147d9f6a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -411,8 +411,6 @@ namespace GodotTools
_editorSettings = editorInterface.GetEditorSettings();
- GodotSharpDirs.RegisterProjectSettings();
-
_errorDialog = new AcceptDialog();
editorBaseControl.AddChild(_errorDialog);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 4e892be55c..7624989092 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -48,12 +48,6 @@ namespace GodotTools.Internals
}
}
- public static void RegisterProjectSettings()
- {
- GlobalDef("dotnet/project/assembly_name", "");
- GlobalDef("dotnet/project/solution_directory", "");
- }
-
public static void DetermineProjectLocation()
{
static string DetermineProjectName()
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index c0d88553ad..03cbfda1bd 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1864,12 +1864,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append("\n" OPEN_BLOCK_L1);
if (getter) {
- p_output.append(INDENT2 "get\n"
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
-
- OPEN_BLOCK_L2 INDENT3);
+ p_output.append(INDENT2 "get\n" OPEN_BLOCK_L2 INDENT3);
p_output.append("return ");
p_output.append(getter->proxy_name + "(");
@@ -1884,21 +1879,11 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index));
}
}
- p_output.append(");\n"
-
- CLOSE_BLOCK_L2
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning restore CS0618\n");
+ p_output.append(");\n" CLOSE_BLOCK_L2);
}
if (setter) {
- p_output.append(INDENT2 "set\n"
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
-
- OPEN_BLOCK_L2 INDENT3);
+ p_output.append(INDENT2 "set\n" OPEN_BLOCK_L2 INDENT3);
p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
@@ -1912,12 +1897,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index) + ", ");
}
}
- p_output.append("value);\n"
-
- CLOSE_BLOCK_L2
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning restore CS0618\n");
+ p_output.append("value);\n" CLOSE_BLOCK_L2);
}
p_output.append(CLOSE_BLOCK_L1);
@@ -3056,12 +3036,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname);
if (accessor) {
- const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value);
-
- // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
- // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
- imethod.is_deprecated = true;
- imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead.";
+ // We only make internal an accessor method if it's in the same class as the property.
+ // It's easier this way, but also we don't know if an accessor method in a different class
+ // could have other purposes, so better leave those untouched.
+ imethod.is_internal = true;
}
if (itype.class_doc) {
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index a2916d4ae8..0e46b63b59 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -437,48 +437,25 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the <see cref="AABB"/> overlaps with <paramref name="with"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
/// <param name="with">The other <see cref="AABB"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>
/// A <see langword="bool"/> for whether or not they are intersecting.
/// </returns>
- public readonly bool Intersects(AABB with, bool includeBorders = false)
+ public readonly bool Intersects(AABB with)
{
- if (includeBorders)
- {
- if (_position.x > with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x < with._position.x)
- return false;
- if (_position.y > with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y < with._position.y)
- return false;
- if (_position.z > with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z < with._position.z)
- return false;
- }
- else
- {
- if (_position.x >= with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x <= with._position.x)
- return false;
- if (_position.y >= with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y <= with._position.y)
- return false;
- if (_position.z >= with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z <= with._position.z)
- return false;
- }
+ if (_position.x >= with._position.x + with._size.x)
+ return false;
+ if (_position.x + _size.x <= with._position.x)
+ return false;
+ if (_position.y >= with._position.y + with._size.y)
+ return false;
+ if (_position.y + _size.y <= with._position.y)
+ return false;
+ if (_position.z >= with._position.z + with._size.z)
+ return false;
+ if (_position.z + _size.z <= with._position.z)
+ return false;
return true;
}
@@ -586,6 +563,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this <see cref="AABB"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
/// Returns a larger <see cref="AABB"/> that contains this <see cref="AABB"/> and <paramref name="with"/>.
/// </summary>
/// <param name="with">The other <see cref="AABB"/>.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 5d390a298d..b57317e1d0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -120,31 +120,6 @@ namespace Godot
}
/// <summary>
- /// The scale of this basis.
- /// </summary>
- /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value>
- public Vector3 Scale
- {
- readonly get
- {
- real_t detSign = Mathf.Sign(Determinant());
- return detSign * new Vector3
- (
- Column0.Length(),
- Column1.Length(),
- Column2.Length()
- );
- }
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- Column0 *= value.x;
- Column1 *= value.y;
- Column2 *= value.z;
- }
- }
-
- /// <summary>
/// Access whole columns in the form of <see cref="Vector3"/>.
/// </summary>
/// <param name="column">Which column vector.</param>
@@ -493,12 +468,6 @@ namespace Godot
}
}
- /// <summary>
- /// Returns the basis's rotation in the form of a quaternion.
- /// See <see cref="GetEuler"/> if you need Euler angles, but keep in
- /// mind that quaternions should generally be preferred to Euler angles.
- /// </summary>
- /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns>
internal readonly Quaternion GetQuaternion()
{
real_t trace = Row0[0] + Row1[1] + Row2[2];
@@ -573,106 +542,18 @@ namespace Godot
}
/// <summary>
- /// Get rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
- /// </summary>
- /// <param name="index">Which row.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns>
- public readonly Vector3 GetRow(int index)
- {
- switch (index)
- {
- case 0:
- return Row0;
- case 1:
- return Row1;
- case 2:
- return Row2;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// Sets rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
+ /// Assuming that the matrix is the combination of a rotation and scaling,
+ /// return the absolute value of scaling factors along each axis.
/// </summary>
- /// <param name="index">Which row.</param>
- /// <param name="value">The vector to set the row to.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- public void SetRow(int index, Vector3 value)
+ public readonly Vector3 GetScale()
{
- switch (index)
- {
- case 0:
- Row0 = value;
- return;
- case 1:
- Row1 = value;
- return;
- case 2:
- Row2 = value;
- return;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// This function considers a discretization of rotations into
- /// 24 points on unit sphere, lying along the vectors (x, y, z) with
- /// each component being either -1, 0, or 1, and returns the index
- /// of the point best representing the orientation of the object.
- /// It is mainly used by the <see cref="GridMap"/> editor.
- ///
- /// For further details, refer to the Godot source code.
- /// </summary>
- /// <returns>The orthogonal index.</returns>
- public readonly int GetOrthogonalIndex()
- {
- var orth = this;
-
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- var row = orth.GetRow(i);
-
- real_t v = row[j];
-
- if (v > 0.5f)
- {
- v = 1.0f;
- }
- else if (v < -0.5f)
- {
- v = -1.0f;
- }
- else
- {
- v = 0f;
- }
-
- row[j] = v;
-
- orth.SetRow(i, row);
- }
- }
-
- for (int i = 0; i < 24; i++)
- {
- if (orth == _orthoBases[i])
- {
- return i;
- }
- }
-
- return 0;
+ real_t detSign = Mathf.Sign(Determinant());
+ return detSign * new Vector3
+ (
+ Column0.Length(),
+ Column1.Length(),
+ Column2.Length()
+ );
}
/// <summary>
@@ -709,6 +590,16 @@ namespace Godot
);
}
+ /// <summary>
+ /// Returns <see langword="true"/> if this basis is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Row0.IsFinite() && Row1.IsFinite() && Row2.IsFinite();
+ }
+
internal readonly Basis Lerp(Basis to, real_t weight)
{
Basis b = this;
@@ -896,7 +787,7 @@ namespace Godot
/// <param name="quaternion">The quaternion to create the basis from.</param>
public Basis(Quaternion quaternion)
{
- real_t s = 2.0f / quaternion.LengthSquared;
+ real_t s = 2.0f / quaternion.LengthSquared();
real_t xs = quaternion.x * s;
real_t ys = quaternion.y * s;
@@ -925,26 +816,26 @@ namespace Godot
public Basis(Vector3 axis, real_t angle)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
- real_t cosine = Mathf.Cos(angle);
- Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
- Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
- Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+
+ Row0.x = axisSq.x + cos * (1.0f - axisSq.x);
+ Row1.y = axisSq.y + cos * (1.0f - axisSq.y);
+ Row2.z = axisSq.z + cos * (1.0f - axisSq.z);
- real_t sine = Mathf.Sin(angle);
- real_t t = 1.0f - cosine;
+ real_t t = 1.0f - cos;
real_t xyzt = axis.x * axis.y * t;
- real_t zyxs = axis.z * sine;
+ real_t zyxs = axis.z * sin;
Row0.y = xyzt - zyxs;
Row1.x = xyzt + zyxs;
xyzt = axis.x * axis.z * t;
- zyxs = axis.y * sine;
+ zyxs = axis.y * sin;
Row0.z = xyzt + zyxs;
Row2.x = xyzt - zyxs;
xyzt = axis.y * axis.z * t;
- zyxs = axis.x * sine;
+ zyxs = axis.x * sin;
Row1.z = xyzt - zyxs;
Row2.y = xyzt + zyxs;
}
@@ -967,8 +858,20 @@ namespace Godot
// We need to assign the struct fields here first so we can't do it that way...
}
- // Arguments are named such that xy is equal to calling x.y
- internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
+ /// <summary>
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>x.y</c>.
+ /// </summary>
+ /// <param name="xx">The X component of the X column vector, accessed via <c>b.x.x</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>b.y.x</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>b.z.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][2]</c>.</param>
+ public Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
{
Row0 = new Vector3(xx, yx, zx);
Row1 = new Vector3(xy, yy, zy);
@@ -982,19 +885,29 @@ namespace Godot
/// <param name="order">The order to compose the Euler angles.</param>
public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.Yxz)
{
- real_t c, s;
-
- c = Mathf.Cos(euler.x);
- s = Mathf.Sin(euler.x);
- Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c));
+ (real_t sin, real_t cos) = Mathf.SinCos(euler.x);
+ Basis xmat = new Basis
+ (
+ new Vector3(1, 0, 0),
+ new Vector3(0, cos, sin),
+ new Vector3(0, -sin, cos)
+ );
- c = Mathf.Cos(euler.y);
- s = Mathf.Sin(euler.y);
- Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c));
+ (sin, cos) = Mathf.SinCos(euler.y);
+ Basis ymat = new Basis
+ (
+ new Vector3(cos, 0, -sin),
+ new Vector3(0, 1, 0),
+ new Vector3(sin, 0, cos)
+ );
- c = Mathf.Cos(euler.z);
- s = Mathf.Sin(euler.z);
- Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1));
+ (sin, cos) = Mathf.SinCos(euler.z);
+ Basis zmat = new Basis
+ (
+ new Vector3(cos, sin, 0),
+ new Vector3(-sin, cos, 0),
+ new Vector3(0, 0, 1)
+ );
switch (order)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 4075a878d2..2effdecf40 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -359,24 +359,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this color and <paramref name="to"/> by color amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination color for interpolation.</param>
- /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting color of the interpolation.</returns>
- public readonly Color Lerp(Color to, Color weight)
- {
- return new Color
- (
- (float)Mathf.Lerp(r, to.r, weight.r),
- (float)Mathf.Lerp(g, to.g, weight.g),
- (float)Mathf.Lerp(b, to.b, weight.b),
- (float)Mathf.Lerp(a, to.a, weight.a)
- );
- }
-
- /// <summary>
/// Returns the color converted to the sRGB color space.
/// This method assumes the original color is in the linear color space.
/// See also <see cref="SrgbToLinear"/> which performs the opposite operation.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 3f9e986f62..b2cb0f5e6b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -440,6 +440,17 @@ namespace Godot
}
/// <summary>
+ /// Returns whether <paramref name="s"/> is a finite value, i.e. it is not
+ /// <see cref="NaN"/>, positive infinite, or negative infinity.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is a finite value.</returns>
+ public static bool IsFinite(real_t s)
+ {
+ return real_t.IsFinite(s);
+ }
+
+ /// <summary>
/// Returns whether <paramref name="s"/> is an infinity value (either positive infinity or negative infinity).
/// </summary>
/// <param name="s">The value to check.</param>
@@ -460,10 +471,11 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if <paramref name="s"/> is approximately zero.
+ /// Returns <see langword="true"/> if <paramref name="s"/> is zero or almost zero.
/// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
///
- /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero.
+ /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with
+ /// one value as zero.
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
index ea05c1547c..72a1868964 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
@@ -83,6 +83,17 @@ namespace Godot
}
/// <summary>
+ /// Returns the sine and cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The sine and cosine of that angle.</returns>
+ public static (real_t Sin, real_t Cos) SinCos(real_t s)
+ {
+ (double sin, double cos) = Math.SinCos(s);
+ return ((real_t)sin, (real_t)cos);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately
/// equal to each other.
/// The comparison is done using the provided tolerance value.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 42c6b0a37e..8a125e3c73 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -15,7 +15,7 @@ namespace Godot
private Vector3 _normal;
/// <summary>
- /// The normal of the plane, which must be normalized.
+ /// The normal of the plane, which must be a unit vector.
/// In the scalar equation of the plane <c>ax + by + cz = d</c>, this is
/// the vector <c>(a, b, c)</c>, where <c>d</c> is the <see cref="D"/> property.
/// </summary>
@@ -85,23 +85,6 @@ namespace Godot
public real_t D { get; set; }
/// <summary>
- /// The center of the plane, the point where the normal line intersects the plane.
- /// </summary>
- /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
- public Vector3 Center
- {
- readonly get
- {
- return _normal * D;
- }
- set
- {
- _normal = value.Normalized();
- D = value.Length();
- }
- }
-
- /// <summary>
/// Returns the shortest distance from this plane to the position <paramref name="point"/>.
/// </summary>
/// <param name="point">The position to use for the calculation.</param>
@@ -112,6 +95,16 @@ namespace Godot
}
/// <summary>
+ /// Returns the center of the plane, the point on the plane closest to the origin.
+ /// The point where the normal line going through the origin intersects the plane.
+ /// </summary>
+ /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
+ public readonly Vector3 GetCenter()
+ {
+ return _normal * D;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if point is inside the plane.
/// Comparison uses a custom minimum tolerance threshold.
/// </summary>
@@ -155,7 +148,7 @@ namespace Godot
/// <param name="from">The start of the ray.</param>
/// <param name="dir">The direction of the ray, normalized.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public readonly Vector3? IntersectRay(Vector3 from, Vector3 dir)
+ public readonly Vector3? IntersectsRay(Vector3 from, Vector3 dir)
{
real_t den = _normal.Dot(dir);
@@ -183,7 +176,7 @@ namespace Godot
/// <param name="begin">The start of the line segment.</param>
/// <param name="end">The end of the line segment.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public readonly Vector3? IntersectSegment(Vector3 begin, Vector3 end)
+ public readonly Vector3? IntersectsSegment(Vector3 begin, Vector3 end)
{
Vector3 segment = begin - end;
real_t den = _normal.Dot(segment);
@@ -205,6 +198,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this plane is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _normal.IsFinite() && Mathf.IsFinite(D);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="point"/> is located above the plane.
/// </summary>
/// <param name="point">The point to check.</param>
@@ -280,10 +283,21 @@ namespace Godot
}
/// <summary>
+ /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector.
+ /// The plane will intersect the origin.
+ /// </summary>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
+ public Plane(Vector3 normal)
+ {
+ _normal = normal;
+ D = 0;
+ }
+
+ /// <summary>
/// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
/// the plane's distance to the origin <paramref name="d"/>.
/// </summary>
- /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param>
public Plane(Vector3 normal, real_t d)
{
@@ -295,7 +309,7 @@ namespace Godot
/// 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="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="point">The point on the plane.</param>
public Plane(Vector3 normal, Vector3 point)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index fd37f8d9e8..f11b3c553a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -381,14 +381,14 @@ namespace Godot
}
real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0);
real_t deltaZ = zFar - zNear;
- real_t sine = Mathf.Sin(radians);
+ (real_t sin, real_t cos) = Mathf.SinCos(radians);
- if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
+ if ((deltaZ == 0) || (sin == 0) || (aspect == 0))
{
return Zero;
}
- real_t cotangent = Mathf.Cos(radians) / sine;
+ real_t cotangent = cos / sin;
Projection proj = Projection.Identity;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index bd0dea0c1c..8e4f9178f7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -97,27 +97,6 @@ namespace Godot
}
/// <summary>
- /// Returns the length (magnitude) of the quaternion.
- /// </summary>
- /// <seealso cref="LengthSquared"/>
- /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
- public readonly real_t Length
- {
- get { return Mathf.Sqrt(LengthSquared); }
- }
-
- /// <summary>
- /// Returns the squared length (squared magnitude) of the quaternion.
- /// This method runs faster than <see cref="Length"/>, so prefer it if
- /// you need to compare quaternions or need the squared length for some formula.
- /// </summary>
- /// <value>Equivalent to <c>Dot(this)</c>.</value>
- public readonly real_t LengthSquared
- {
- get { return Dot(this); }
- }
-
- /// <summary>
/// Returns the angle between this quaternion and <paramref name="to"/>.
/// This is the magnitude of the angle you would need to rotate
/// by to get from one to the other.
@@ -340,12 +319,22 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this quaternion is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w);
+ }
+
+ /// <summary>
/// Returns whether the quaternion is normalized or not.
/// </summary>
/// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns>
public readonly bool IsNormalized()
{
- return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
+ return Mathf.Abs(LengthSquared() - 1) <= Mathf.Epsilon;
}
public readonly Quaternion Log()
@@ -355,12 +344,33 @@ namespace Godot
}
/// <summary>
+ /// Returns the length (magnitude) of the quaternion.
+ /// </summary>
+ /// <seealso cref="LengthSquared"/>
+ /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
+ public readonly real_t Length()
+ {
+ return Mathf.Sqrt(LengthSquared());
+ }
+
+ /// <summary>
+ /// Returns the squared length (squared magnitude) of the quaternion.
+ /// This method runs faster than <see cref="Length"/>, so prefer it if
+ /// you need to compare quaternions or need the squared length for some formula.
+ /// </summary>
+ /// <value>Equivalent to <c>Dot(this)</c>.</value>
+ public readonly real_t LengthSquared()
+ {
+ return Dot(this);
+ }
+
+ /// <summary>
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
/// <returns>The normalized quaternion.</returns>
public readonly Quaternion Normalized()
{
- return this / Length;
+ return this / Length();
}
/// <summary>
@@ -532,14 +542,13 @@ namespace Godot
}
else
{
- real_t sinAngle = Mathf.Sin(angle * 0.5f);
- real_t cosAngle = Mathf.Cos(angle * 0.5f);
- real_t s = sinAngle / d;
+ (real_t sin, real_t cos) = Mathf.SinCos(angle * 0.5f);
+ real_t s = sin / d;
x = axis.x * s;
y = axis.y * s;
z = axis.z * s;
- w = cosAngle;
+ w = cos;
}
}
@@ -583,12 +592,9 @@ namespace Godot
// 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);
+ (real_t sinA1, real_t cosA1) = Mathf.SinCos(halfA1);
+ (real_t sinA2, real_t cosA2) = Mathf.SinCos(halfA2);
+ (real_t sinA3, real_t cosA3) = Mathf.SinCos(halfA3);
return new Quaternion(
(sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3),
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index b0e0e75a34..1a8696d3bc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -101,6 +101,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this <see cref="Rect2"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if this <see cref="Rect2"/> completely encloses another one.
/// </summary>
/// <param name="b">The other <see cref="Rect2"/> that may be enclosed.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index faee81a98a..cf8939a859 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -275,38 +275,19 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the <see cref="Rect2i"/> overlaps with <paramref name="b"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
/// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns>
- public readonly bool Intersects(Rect2i b, bool includeBorders = false)
+ public readonly bool Intersects(Rect2i b)
{
- if (includeBorders)
- {
- if (_position.x > b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x < b._position.x)
- return false;
- if (_position.y > b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y < b._position.y)
- return false;
- }
- else
- {
- if (_position.x >= b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x <= b._position.x)
- return false;
- if (_position.y >= b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y <= b._position.y)
- return false;
- }
+ if (_position.x >= b._position.x + b._size.x)
+ return false;
+ if (_position.x + _size.x <= b._position.x)
+ return false;
+ if (_position.y >= b._position.y + b._size.y)
+ return false;
+ if (_position.y + _size.y <= b._position.y)
+ return false;
return true;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 756f71e5b2..fa060e3a53 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -32,45 +32,6 @@ namespace Godot
public Vector2 origin;
/// <summary>
- /// The rotation of this transformation matrix.
- /// </summary>
- /// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value>
- public real_t Rotation
- {
- readonly get
- {
- return Mathf.Atan2(x.y, x.x);
- }
- set
- {
- Vector2 scale = Scale;
- x.x = y.y = Mathf.Cos(value);
- x.y = y.x = Mathf.Sin(value);
- y.x *= -1;
- Scale = scale;
- }
- }
-
- /// <summary>
- /// The scale of this transformation matrix.
- /// </summary>
- /// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value>
- public Vector2 Scale
- {
- readonly get
- {
- real_t detSign = Mathf.Sign(BasisDeterminant());
- return new Vector2(x.Length(), detSign * y.Length());
- }
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- x *= value.x;
- y *= value.y;
- }
- }
-
- /// <summary>
/// Access whole columns in the form of <see cref="Vector2"/>.
/// The third column is the <see cref="origin"/> vector.
/// </summary>
@@ -203,6 +164,23 @@ namespace Godot
}
/// <summary>
+ /// Returns the transform's rotation (in radians).
+ /// </summary>
+ public readonly real_t GetRotation()
+ {
+ return Mathf.Atan2(x.y, x.x);
+ }
+
+ /// <summary>
+ /// Returns the scale.
+ /// </summary>
+ public readonly Vector2 GetScale()
+ {
+ real_t detSign = Mathf.Sign(BasisDeterminant());
+ return new Vector2(x.Length(), detSign * y.Length());
+ }
+
+ /// <summary>
/// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>.
/// </summary>
/// <param name="transform">The other transform.</param>
@@ -210,15 +188,17 @@ namespace Godot
/// <returns>The interpolated transform.</returns>
public readonly Transform2D InterpolateWith(Transform2D transform, real_t weight)
{
- real_t r1 = Rotation;
- real_t r2 = transform.Rotation;
+ real_t r1 = GetRotation();
+ real_t r2 = transform.GetRotation();
- Vector2 s1 = Scale;
- Vector2 s2 = transform.Scale;
+ Vector2 s1 = GetScale();
+ Vector2 s2 = transform.GetScale();
// Slerp rotation
- var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
- var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2));
+ (real_t sin1, real_t cos1) = Mathf.SinCos(r1);
+ (real_t sin2, real_t cos2) = Mathf.SinCos(r2);
+ var v1 = new Vector2(cos1, sin1);
+ var v2 = new Vector2(cos2, sin2);
real_t dot = v1.Dot(v2);
@@ -235,7 +215,8 @@ namespace Godot
{
real_t angle = weight * Mathf.Acos(dot);
Vector2 v3 = (v2 - (v1 * dot)).Normalized();
- v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle));
+ (real_t sine, real_t cos) = Mathf.SinCos(angle);
+ v = (v1 * sine) + (v3 * cos);
}
// Extract parameters
@@ -271,6 +252,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return x.IsFinite() && y.IsFinite() && origin.IsFinite();
+ }
+
+ /// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
@@ -423,7 +414,7 @@ namespace Godot
/// <summary>
/// Constructs a transformation matrix from the given components.
- /// Arguments are named such that xy is equal to calling x.y
+ /// Arguments are named such that xy is equal to calling <c>x.y</c>.
/// </summary>
/// <param name="xx">The X component of the X column vector, accessed via <c>t.x.x</c> or <c>[0][0]</c>.</param>
/// <param name="xy">The Y component of the X column vector, accessed via <c>t.x.y</c> or <c>[0][1]</c>.</param>
@@ -446,13 +437,34 @@ namespace Godot
/// <param name="origin">The origin vector, or column index 2.</param>
public Transform2D(real_t rotation, Vector2 origin)
{
- x.x = y.y = Mathf.Cos(rotation);
- x.y = y.x = Mathf.Sin(rotation);
+ (real_t sin, real_t cos) = Mathf.SinCos(rotation);
+ x.x = y.y = cos;
+ x.y = y.x = sin;
y.x *= -1;
this.origin = origin;
}
/// <summary>
+ /// Constructs a transformation matrix from a <paramref name="rotation"/> value,
+ /// <paramref name="scale"/> vector, <paramref name="skew"/> value, and
+ /// <paramref name="origin"/> vector.
+ /// </summary>
+ /// <param name="rotation">The rotation of the new transform, in radians.</param>
+ /// <param name="scale">The scale of the new transform.</param>
+ /// <param name="skew">The skew of the new transform, in radians.</param>
+ /// <param name="origin">The origin vector, or column index 2.</param>
+ public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin)
+ {
+ (real_t rotationSin, real_t rotationCos) = Mathf.SinCos(rotation);
+ (real_t rotationSkewSin, real_t rotationSkewCos) = Mathf.SinCos(rotation + skew);
+ x.x = rotationCos * scale.x;
+ y.y = rotationSkewCos * scale.y;
+ y.x = -rotationSkewSin * scale.y;
+ x.y = rotationSin * scale.x;
+ this.origin = origin;
+ }
+
+ /// <summary>
/// Composes these two transformation matrices by multiplying them
/// together. This has the effect of transforming the second transform
/// (the child) by the first transform (the parent).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 39167bd116..6b2475fc59 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -115,16 +115,30 @@ namespace Godot
}
/// <summary>
- /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>.
+ /// Returns a transform interpolated between this transform and another
+ /// <paramref name="transform"/> by a given <paramref name="weight"/>
+ /// (on the range of 0.0 to 1.0).
/// </summary>
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
public readonly Transform3D InterpolateWith(Transform3D transform, real_t weight)
{
- Basis retBasis = basis.Lerp(transform.basis, weight);
- Vector3 retOrigin = origin.Lerp(transform.origin, weight);
- return new Transform3D(retBasis, retOrigin);
+ Vector3 sourceScale = basis.GetScale();
+ Quaternion sourceRotation = basis.GetRotationQuaternion();
+ Vector3 sourceLocation = origin;
+
+ Vector3 destinationScale = transform.basis.GetScale();
+ Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
+ Vector3 destinationLocation = transform.origin;
+
+ var interpolated = new Transform3D();
+ Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
+ Vector3 scale = sourceScale.Lerp(destinationScale, weight);
+ interpolated.basis.SetQuaternionScale(quaternion, scale);
+ interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
+
+ return interpolated;
}
/// <summary>
@@ -140,6 +154,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return basis.IsFinite() && origin.IsFinite();
+ }
+
+ /// <summary>
/// Returns a copy of the transform rotated such that its
/// -Z axis (forward) points towards the <paramref name="target"/> position.
///
@@ -223,34 +247,6 @@ namespace Godot
return new Transform3D(basis * tmpBasis, origin);
}
- /// <summary>
- /// Returns a transform spherically interpolated between this transform and
- /// another <paramref name="transform"/> by <paramref name="weight"/>.
- /// </summary>
- /// <param name="transform">The other transform.</param>
- /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The interpolated transform.</returns>
- public readonly Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight)
- {
- /* not sure if very "efficient" but good enough? */
-
- Vector3 sourceScale = basis.Scale;
- Quaternion sourceRotation = basis.GetRotationQuaternion();
- Vector3 sourceLocation = origin;
-
- Vector3 destinationScale = transform.basis.Scale;
- Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
- Vector3 destinationLocation = transform.origin;
-
- var interpolated = new Transform3D();
- Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
- Vector3 scale = sourceScale.Lerp(destinationScale, weight);
- interpolated.basis.SetQuaternionScale(quaternion, scale);
- interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
-
- return interpolated;
- }
-
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
{
// Make rotation matrix
@@ -346,15 +342,25 @@ namespace Godot
}
/// <summary>
- /// Constructs a transformation matrix from the given <paramref name="quaternion"/>
- /// and <paramref name="origin"/> vector.
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>basis.x.y</c>.
/// </summary>
- /// <param name="quaternion">The <see cref="Quaternion"/> to create the basis from.</param>
- /// <param name="origin">The origin vector, or column index 3.</param>
- public Transform3D(Quaternion quaternion, Vector3 origin)
+ /// <param name="xx">The X component of the X column vector, accessed via <c>t.basis.x.x</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>t.basis.y.x</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>t.basis.z.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][2]</c>.</param>
+ /// <param name="ox">The X component of the origin vector, accessed via <c>t.origin.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="oy">The Y component of the origin vector, accessed via <c>t.origin.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="oz">The Z component of the origin vector, accessed via <c>t.origin.z</c> or <c>[2][2]</c>.</param>
+ public Transform3D(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz, real_t ox, real_t oy, real_t oz)
{
- basis = new Basis(quaternion);
- this.origin = origin;
+ basis = new Basis(xx, yx, zx, xy, yy, zy, xz, yz, zz);
+ origin = new Vector3(ox, oy, oz);
}
/// <summary>
@@ -370,6 +376,29 @@ namespace Godot
}
/// <summary>
+ /// Constructs a transformation matrix from the given <paramref name="projection"/>
+ /// by trimming the last row of the projection matrix (<c>projection.x.w</c>,
+ /// <c>projection.y.w</c>, <c>projection.z.w</c>, and <c>projection.w.w</c>
+ /// are not copied over).
+ /// </summary>
+ /// <param name="projection">The <see cref="Projection"/> to create the transform from.</param>
+ public Transform3D(Projection projection)
+ {
+ basis = new Basis
+ (
+ projection.x.x, projection.y.x, projection.z.x,
+ projection.x.y, projection.y.y, projection.z.y,
+ projection.x.z, projection.y.z, projection.z.z
+ );
+ origin = new Vector3
+ (
+ projection.w.x,
+ projection.w.y,
+ projection.w.z
+ );
+ }
+
+ /// <summary>
/// Composes these two transformation matrices by multiplying them
/// together. This has the effect of transforming the second transform
/// (the child) by the first transform (the parent).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 4c60080ee9..07cb34cadd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -334,6 +334,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -380,24 +390,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">
- /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.
- /// </param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public readonly Vector2 Lerp(Vector2 to, Vector2 weight)
- {
- return new Vector2
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y)
- );
- }
-
- /// <summary>
/// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>.
/// </summary>
/// <param name="length">The length to limit to.</param>
@@ -529,11 +521,12 @@ namespace Godot
/// <returns>The rotated vector.</returns>
public readonly Vector2 Rotated(real_t angle)
{
- real_t sine = Mathf.Sin(angle);
- real_t cosi = Mathf.Cos(angle);
- return new Vector2(
- x * cosi - y * sine,
- x * sine + y * cosi);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2
+ (
+ x * cos - y * sin,
+ x * sin + y * cos
+ );
}
/// <summary>
@@ -683,7 +676,8 @@ namespace Godot
/// <returns>The resulting vector.</returns>
public static Vector2 FromAngle(real_t angle)
{
- return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2(cos, sin);
}
/// <summary>
@@ -989,6 +983,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector2"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index 91be548a21..740fedec66 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -95,38 +95,6 @@ namespace Godot
}
/// <summary>
- /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians.
- ///
- /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when
- /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>.
- /// </summary>
- /// <returns>The angle of this vector, in radians.</returns>
- public readonly real_t Angle()
- {
- return Mathf.Atan2(y, x);
- }
-
- /// <summary>
- /// Returns the angle to the given vector, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public readonly real_t AngleTo(Vector2i to)
- {
- return Mathf.Atan2(Cross(to), Dot(to));
- }
-
- /// <summary>
- /// Returns the angle between the line connecting the two points and the X axis, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public readonly real_t AngleToPoint(Vector2i to)
- {
- return Mathf.Atan2(to.y - y, to.x - x);
- }
-
- /// <summary>
/// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>.
/// </summary>
/// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns>
@@ -153,48 +121,6 @@ namespace Godot
}
/// <summary>
- /// Returns the cross product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector.</param>
- /// <returns>The cross product vector.</returns>
- public readonly int Cross(Vector2i with)
- {
- return x * with.y - y * with.x;
- }
-
- /// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public readonly int DistanceSquaredTo(Vector2i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public readonly real_t DistanceTo(Vector2i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public readonly int Dot(Vector2i with)
- {
- return x * with.x + y * with.y;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
@@ -242,38 +168,6 @@ namespace Godot
}
/// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public readonly Vector2i PosMod(int mod)
- {
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public readonly Vector2i PosMod(Vector2i modv)
- {
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- return v;
- }
-
- /// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
@@ -287,16 +181,6 @@ namespace Godot
return v;
}
- /// <summary>
- /// Returns a perpendicular vector rotated 90 degrees counter-clockwise
- /// compared to the original, with the same length.
- /// </summary>
- /// <returns>The perpendicular vector.</returns>
- public readonly Vector2i Orthogonal()
- {
- return new Vector2i(y, -x);
- }
-
// Constants
private static readonly Vector2i _zero = new Vector2i(0, 0);
private static readonly Vector2i _one = new Vector2i(1, 1);
@@ -467,7 +351,7 @@ namespace Godot
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -490,7 +374,7 @@ namespace Godot
/// with the components of the given <see cref="Vector2i"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector2i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -509,34 +393,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see cref="Vector2i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, Vector2i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index fefdee33a5..b017ba5853 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -331,6 +331,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -386,23 +396,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public readonly Vector3 Lerp(Vector3 to, Vector3 weight)
- {
- return new Vector3
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y),
- Mathf.Lerp(z, to.z, weight.z)
- );
- }
-
- /// <summary>
/// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>.
/// </summary>
/// <param name="length">The length to limit to.</param>
@@ -1060,6 +1053,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector3"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
index e631a9f443..de0c6d27e7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -129,39 +129,6 @@ namespace Godot
}
/// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public readonly int DistanceSquaredTo(Vector3i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <seealso cref="DistanceSquaredTo(Vector3i)"/>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public readonly real_t DistanceTo(Vector3i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public readonly int Dot(Vector3i with)
- {
- return x * with.x + y * with.y + z * with.z;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
@@ -211,40 +178,6 @@ namespace Godot
}
/// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public readonly Vector3i PosMod(int mod)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- v.z = Mathf.PosMod(v.z, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public readonly Vector3i PosMod(Vector3i modv)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- v.z = Mathf.PosMod(v.z, modv.z);
- return v;
- }
-
- /// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
@@ -455,7 +388,7 @@ namespace Godot
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -479,7 +412,7 @@ namespace Godot
/// with the components of the given <see cref="Vector3i"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector3i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -499,36 +432,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see cref="Vector3i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, Vector3i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index 3191e8adc0..0f4528bb40 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -280,6 +280,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -857,6 +867,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z) && Mathf.IsZeroApprox(w);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector4"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
index 8146991fd7..00ecc64856 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
@@ -433,38 +433,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- vec.w &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see cref="Vector4i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, Vector4i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
- vec.w &= andv.w;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 6664dfb2dd..86b0e04206 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -289,7 +289,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
}
#else
static String get_assembly_name() {
- String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
+ String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
if (assembly_name.is_empty()) {
assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
@@ -466,7 +466,7 @@ void GDMono::_init_godot_api_hashes() {
#ifdef TOOLS_ENABLED
bool GDMono::_load_project_assembly() {
- String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
+ String assembly_name = GLOBAL_GET("dotnet/project/assembly_name");
if (assembly_name.is_empty()) {
assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 4ab41cfcb0..66e12a338a 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -142,7 +142,7 @@ void ReplicationEditor::_add_sync_property(String p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add property to synchronizer"));
if (config.is_null()) {
@@ -250,14 +250,12 @@ ReplicationEditor::ReplicationEditor() {
tree->add_child(drop_label);
drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(tree, ReplicationEditor);
}
void ReplicationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_config"), &ReplicationEditor::_update_config);
ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked);
- ClassDB::bind_method("_can_drop_data_fw", &ReplicationEditor::_can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ReplicationEditor::_drop_data_fw);
}
bool ReplicationEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
@@ -357,7 +355,7 @@ void ReplicationEditor::_tree_item_edited() {
int column = tree->get_edited_column();
ERR_FAIL_COND(column < 1 || column > 2);
const NodePath prop = ti->get_metadata(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
bool value = ti->is_checked(column);
String method;
if (column == 1) {
@@ -397,7 +395,7 @@ void ReplicationEditor::_dialog_closed(bool p_confirmed) {
int idx = config->property_get_index(prop);
bool spawn = config->property_get_spawn(prop);
bool sync = config->property_get_sync(prop);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Property"));
undo_redo->add_do_method(config.ptr(), "remove_property", prop);
undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx);
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 7ed69a84d0..0aa54b69f9 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -199,10 +199,6 @@ void MultiplayerSpawner::_notification(int p_what) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E.key));
ERR_CONTINUE(!node);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit));
- // This is unlikely, but might still crash the engine.
- if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) {
- node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready));
- }
get_multiplayer()->object_configuration_remove(node, this);
}
tracked_nodes.clear();
@@ -244,11 +240,11 @@ void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_s
if (!tracked_nodes.has(oid)) {
tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id);
p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
- p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
+ _spawn_notify(p_node->get_instance_id());
}
}
-void MultiplayerSpawner::_node_ready(ObjectID p_id) {
+void MultiplayerSpawner::_spawn_notify(ObjectID p_id) {
get_multiplayer()->object_configuration_add(ObjectDB::get_instance(p_id), this);
}
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index 8d401a6818..8a54140e32 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -77,7 +77,7 @@ private:
void _track(Node *p_node, const Variant &p_argument, int p_scene_id = INVALID_ID);
void _node_added(Node *p_node);
void _node_exit(ObjectID p_id);
- void _node_ready(ObjectID p_id);
+ void _spawn_notify(ObjectID p_id);
Vector<String> _get_spawnable_scenes() const;
void _set_spawnable_scenes(const Vector<String> &p_scenes);
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index e1b7b0c346..233ff76c7d 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -125,6 +125,20 @@ void SceneReplicationInterface::on_reset() {
}
void SceneReplicationInterface::on_network_process() {
+ // Prevent endless stalling in case of unforseen spawn errors.
+ if (spawn_queue.size()) {
+ ERR_PRINT("An error happened during last spawn, this usually means the 'ready' signal was not emitted by the spawned node.");
+ for (const ObjectID &oid : spawn_queue) {
+ Node *node = get_id_as<Node>(oid);
+ ERR_CONTINUE(!node);
+ if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready))) {
+ node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready));
+ }
+ }
+ spawn_queue.clear();
+ }
+
+ // Process timed syncs.
uint64_t msec = OS::get_singleton()->get_ticks_msec();
for (KeyValue<int, PeerInfo> &E : peers_info) {
const HashSet<ObjectID> to_sync = E.value.sync_nodes;
@@ -144,17 +158,39 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) {
// Track node.
const ObjectID oid = node->get_instance_id();
TrackedNode &tobj = _track(oid);
+
+ // Spawn state needs to be callected after "ready", but the spawn order follows "enter_tree".
ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE);
tobj.spawner = spawner->get_instance_id();
- spawned_nodes.insert(oid);
+ spawn_queue.insert(oid);
+ node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT);
+ return OK;
+}
+
+void SceneReplicationInterface::_node_ready(const ObjectID &p_oid) {
+ ERR_FAIL_COND(!spawn_queue.has(p_oid)); // Bug.
- if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
- if (tobj.net_id == 0) {
- tobj.net_id = ++last_net_id;
+ // If we are a nested spawn, we need to wait until the parent is ready.
+ if (p_oid != *(spawn_queue.begin())) {
+ return;
+ }
+
+ for (const ObjectID &oid : spawn_queue) {
+ ERR_CONTINUE(!tracked_nodes.has(oid));
+
+ TrackedNode &tobj = tracked_nodes[oid];
+ MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tobj.spawner);
+ ERR_CONTINUE(!spawner);
+
+ spawned_nodes.insert(oid);
+ if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
+ if (tobj.net_id == 0) {
+ tobj.net_id = ++last_net_id;
+ }
+ _update_spawn_visibility(0, oid);
}
- _update_spawn_visibility(0, oid);
}
- return OK;
+ spawn_queue.clear();
}
Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index a5e610cff6..cf45db2138 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -51,7 +51,6 @@ private:
bool operator==(const ObjectID &p_other) { return id == p_other; }
- _FORCE_INLINE_ MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; }
TrackedNode() {}
TrackedNode(const ObjectID &p_id) { id = p_id; }
TrackedNode(const ObjectID &p_id, uint32_t p_net_id) {
@@ -75,7 +74,10 @@ private:
HashSet<ObjectID> spawned_nodes;
HashSet<ObjectID> sync_nodes;
- // Pending spawn information.
+ // Pending local spawn information (handles spawning nested nodes during ready).
+ HashSet<ObjectID> spawn_queue;
+
+ // Pending remote spawn information.
ObjectID pending_spawn;
int pending_spawn_remote = 0;
const uint8_t *pending_buffer = nullptr;
@@ -89,6 +91,7 @@ private:
TrackedNode &_track(const ObjectID &p_id);
void _untrack(const ObjectID &p_id);
+ void _node_ready(const ObjectID &p_oid);
void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_msec);
Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len);
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
index e3fe06c6f7..586b0b0697 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_action_editor.h"
-#include "editor/editor_node.h"
void OpenXRActionEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionEditor::_do_set_name);
@@ -125,7 +124,7 @@ void OpenXRActionEditor::_on_remove_action() {
}
OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action = p_action;
set_h_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
index 8af5448aed..765b3ef378 100644
--- a/modules/openxr/editor/openxr_action_editor.h
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -43,7 +43,7 @@ class OpenXRActionEditor : public HBoxContainer {
GDCLASS(OpenXRActionEditor, HBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRAction> action;
LineEdit *action_name = nullptr;
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 12c95f8978..ad5a515a01 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -387,7 +387,7 @@ void OpenXRActionMapEditor::_clear_action_map() {
}
OpenXRActionMapEditor::OpenXRActionMapEditor() {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
set_custom_minimum_size(Size2(0.0, 300.0));
top_hb = memnew(HBoxContainer);
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index 47bfda3425..a04bae4a6e 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -48,7 +48,7 @@ class OpenXRActionMapEditor : public VBoxContainer {
GDCLASS(OpenXRActionMapEditor, VBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
String edited_path;
Ref<OpenXRActionMap> action_map;
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 078d83f5f2..bcb0f5f8b1 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_action_set_editor.h"
-#include "editor/editor_node.h"
#include "openxr_action_editor.h"
void OpenXRActionSetEditor::_bind_methods() {
@@ -212,7 +211,7 @@ void OpenXRActionSetEditor::set_focus_on_entry() {
}
OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action_map = p_action_map;
action_set = p_action_set;
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
index 6040f7fb4e..129f800abe 100644
--- a/modules/openxr/editor/openxr_action_set_editor.h
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -44,7 +44,7 @@ class OpenXRActionSetEditor : public HBoxContainer {
GDCLASS(OpenXRActionSetEditor, HBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRActionMap> action_map;
Ref<OpenXRActionSet> action_set;
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index 76b0ae5a3c..6a848dd430 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_interaction_profile_editor.h"
-#include "editor/editor_node.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
@@ -141,7 +140,7 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open
}
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action_map = p_action_map;
interaction_profile = p_interaction_profile;
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index 73dba71cbd..fa25a000a9 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -43,7 +43,7 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
protected:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRInteractionProfile> interaction_profile;
Ref<OpenXRActionMap> action_map;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index d556f475d2..6b8f140923 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -560,6 +560,12 @@ void OpenXRAPI::destroy_instance() {
instance = XR_NULL_HANDLE;
}
enabled_extensions.clear();
+
+ if (graphics_extension != nullptr) {
+ unregister_extension_wrapper(graphics_extension);
+ memdelete(graphics_extension);
+ graphics_extension = nullptr;
+ }
}
bool OpenXRAPI::create_session() {
@@ -1347,6 +1353,10 @@ void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_w
registered_extension_wrappers.push_back(p_extension_wrapper);
}
+void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
+ registered_extension_wrappers.erase(p_extension_wrapper);
+}
+
void OpenXRAPI::register_extension_metadata() {
for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
extension_wrapper->on_register_metadata();
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 5fb8de660e..52a1af5a09 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -312,6 +312,7 @@ public:
void set_xr_interface(OpenXRInterface *p_xr_interface);
static void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
+ static void unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
static void register_extension_metadata();
static void cleanup_extension_wrappers();
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 4e2fe3dab5..1c4d53c43a 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -111,6 +111,10 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
ERR_FAIL_NULL(openxr_api);
if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
+ OS::get_singleton()->alert("OpenXR was requested but failed to start.\n"
+ "Please check if your HMD is connected.\n"
+ "When using Windows MR please note that WMR only has DirectX support, make sure SteamVR is your default OpenXR runtime.\n"
+ "Godot will start in normal mode.\n");
memdelete(openxr_api);
openxr_api = nullptr;
return;
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 37c8a95905..209ebab388 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -96,7 +96,7 @@ if env["builtin_embree"]:
if not env.msvc:
# Flags synced with upstream gnu.cmake.
- if env["arch"] == "arm64" and env["platform"] == "linuxbsd":
+ if env["arch"] == "arm64" and env["platform"] == "linuxbsd" and not env["use_llvm"]:
env_thirdparty.Append(CXXFLAGS=["-flax-vector-conversions"])
env_thirdparty.Append(
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 44a2c76727..79ca4a7024 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -42,7 +42,7 @@
using namespace godot;
-#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#else
// Headers for building as built-in module.
@@ -423,11 +423,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) {
return false;
}
uint64_t len = f->get_length();
-#ifdef GDEXTENSION
PackedByteArray icu_data = f->get_buffer(len);
-#else
- PackedByteArray icu_data = f->_get_buffer(len);
-#endif
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -476,11 +472,7 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
PackedByteArray icu_data;
icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
-#ifdef GDEXTENSION
f->store_buffer(icu_data);
-#else
- f->_store_buffer(icu_data);
-#endif
return true;
#else
@@ -824,29 +816,17 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
// Could not find texture to fit, create one.
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(texsize);
-#else
texsize = next_power_of_2(texsize);
-#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
} else {
texsize = MIN(texsize, 1024);
}
if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mw);
-#else
texsize = next_power_of_2(mw);
-#endif
}
if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mh);
-#else
texsize = next_power_of_2(mh);
-#endif
}
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -949,14 +929,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
return 0;
}
-void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
- int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+ int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
for (int col = 0; col < td->output->width(); ++col) {
- int x = (y % 2) ? td->output->width() - col - 1 : col;
- msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+ int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+ msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
}
@@ -1026,14 +1006,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
td.projection = &projection;
td.distancePixelConversion = &distancePixelConversion;
-#ifdef GDEXTENSION
- for (int i = 0; i < h; i++) {
- _generateMTSDF_threaded(i, &td);
- }
-#else
- WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, SNAME("FontServerRasterizeMSDF"));
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
-#endif
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
@@ -3680,6 +3654,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
sd->hb_buffer = hb_buffer_create();
@@ -3705,6 +3680,7 @@ void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {
void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -3764,8 +3740,12 @@ void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, con
}
sd->bidi_override.clear();
for (int i = 0; i < p_override.size(); i++) {
- if (p_override[i].get_type() == Variant::VECTOR2I) {
- sd->bidi_override.push_back(p_override[i]);
+ if (p_override[i].get_type() == Variant::VECTOR3I) {
+ const Vector3i &r = p_override[i];
+ sd->bidi_override.push_back(r);
+ } else if (p_override[i].get_type() == Variant::VECTOR2I) {
+ const Vector2i &r = p_override[i];
+ sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));
}
}
invalidate(sd, false);
@@ -5570,8 +5550,31 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
}
+ int base_para_direction = UBIDI_DEFAULT_LTR;
+ switch (sd->direction) {
+ case DIRECTION_LTR: {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_LTR;
+ } break;
+ case DIRECTION_RTL: {
+ sd->para_direction = DIRECTION_RTL;
+ base_para_direction = UBIDI_RTL;
+ } break;
+ case DIRECTION_INHERITED:
+ case DIRECTION_AUTO: {
+ UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
+ if (direction != UBIDI_NEUTRAL) {
+ sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
+ base_para_direction = direction;
+ } else {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_DEFAULT_LTR;
+ }
+ } break;
+ }
+
if (sd->bidi_override.is_empty()) {
- sd->bidi_override.push_back(Vector2i(sd->start, sd->end));
+ sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));
}
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
@@ -5587,23 +5590,22 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
- switch (sd->direction) {
+ switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
case DIRECTION_LTR: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
} break;
case DIRECTION_RTL: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
- sd->para_direction = DIRECTION_RTL;
+ } break;
+ case DIRECTION_INHERITED: {
+ ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
} break;
case DIRECTION_AUTO: {
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
if (direction != UBIDI_NEUTRAL) {
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
- sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
} else {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
}
} break;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index e8a3a10ab8..c7fe46d554 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -72,7 +72,6 @@
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
@@ -350,7 +349,7 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const;
_FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data);
- void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+ static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
_FORCE_INLINE_ Vector2i _get_size(const FontAdvanced *p_font_data, int p_size) const {
if (p_font_data->msdf) {
@@ -500,7 +499,7 @@ class TextServerAdvanced : public TextServerExtension {
/* Intermediate data */
Char16String utf16;
Vector<UBiDi *> bidi_iter;
- Vector<Vector2i> bidi_override;
+ Vector<Vector3i> bidi_override;
ScriptIterator *script_iter = nullptr;
hb_buffer_t *hb_buffer = nullptr;
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 9354d3f9b3..1406e3aaa0 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
if (!gl_state.ready) {
Ref<XMLParser> parser;
parser.instantiate();
-#ifdef GDEXTENSION
- PackedByteArray data;
- data.resize(document->svg_document_length);
- memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
- parser->open_buffer(data);
-#else
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
float aspect = 1.0f;
String xml_body;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
const String &gl_name = parser->get_named_attribute_value("id");
-#else
- const String &gl_name = parser->get_attribute_value("id");
-#endif
if (gl_name.begins_with("glyph")) {
int dot_pos = gl_name.find(".");
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
- Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
if (vb.size() == 4) {
aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
continue;
}
-#ifdef GDEXTENSION
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
- xml_body = xml_body + "<" + parser->get_node_name();
- for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
- }
- xml_body = xml_body + ">";
- } else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
- xml_body = xml_body + parser->get_node_data();
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
- xml_body = xml_body + "</" + parser->get_node_name() + ">";
- }
-#else
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
xml_body += vformat("</%s>", parser->get_node_name());
}
-#endif
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
-#ifdef GDEXTENSION
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
- gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 809bfbe41a..b5d7d3a3cf 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -42,7 +42,7 @@
using namespace godot;
-#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#else
// Headers for building as built-in module.
@@ -51,7 +51,6 @@ using namespace godot;
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-#include "core/string/ucaps.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
@@ -248,11 +247,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
// Could not find texture to fit, create one.
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(texsize);
-#else
texsize = next_power_of_2(texsize);
-#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
@@ -260,18 +255,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
texsize = MIN(texsize, 1024);
}
if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mw);
-#else
texsize = next_power_of_2(mw);
-#endif
}
if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mh);
-#else
texsize = next_power_of_2(mh);
-#endif
}
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -374,14 +361,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
return 0;
}
-void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
- int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+ int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
for (int col = 0; col < td->output->width(); ++col) {
- int x = (y % 2) ? td->output->width() - col - 1 : col;
- msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+ int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+ msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
}
@@ -451,14 +438,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
td.projection = &projection;
td.distancePixelConversion = &distancePixelConversion;
-#ifdef GDEXTENSION
- for (int i = 0; i < h; i++) {
- _generateMTSDF_threaded(i, &td);
- }
-#else
- WorkerThreadPool::GroupID group_id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, SNAME("TextServerFBRenderMSDF"));
- WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_id);
-#endif
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF"));
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
@@ -2683,6 +2664,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
sd->direction = p_direction;
@@ -2706,6 +2688,7 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
}
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
if (p_direction == DIRECTION_RTL) {
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
}
@@ -4078,31 +4061,11 @@ double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_sha
}
String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {
- String upper = p_string;
-
- for (int i = 0; i <= upper.length(); i++) {
- const char32_t s = upper[i];
- const char32_t t = _find_upper(s);
- if (s != t) { // avoid copy on write
- upper[i] = t;
- }
- }
-
- return upper;
+ return p_string.to_upper();
}
String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {
- String lower = p_string;
-
- for (int i = 0; i <= lower.length(); i++) {
- const char32_t s = lower[i];
- const char32_t t = _find_lower(s);
- if (s != t) { // avoid copy on write
- lower[i] = t;
- }
- }
-
- return lower;
+ return p_string.to_lower();
}
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index b42f564534..9fb048a581 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,11 +67,11 @@
#include <godot_cpp/classes/image.hpp>
#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/ref.hpp>
+#include <godot_cpp/classes/worker_thread_pool.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
@@ -303,7 +303,7 @@ class TextServerFallback : public TextServerExtension {
_FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const;
_FORCE_INLINE_ void _font_clear_cache(FontFallback *p_font_data);
- void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+ static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
_FORCE_INLINE_ Vector2i _get_size(const FontFallback *p_font_data, int p_size) const {
if (p_font_data->msdf) {
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 9354d3f9b3..1406e3aaa0 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
if (!gl_state.ready) {
Ref<XMLParser> parser;
parser.instantiate();
-#ifdef GDEXTENSION
- PackedByteArray data;
- data.resize(document->svg_document_length);
- memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
- parser->open_buffer(data);
-#else
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
float aspect = 1.0f;
String xml_body;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
const String &gl_name = parser->get_named_attribute_value("id");
-#else
- const String &gl_name = parser->get_attribute_value("id");
-#endif
if (gl_name.begins_with("glyph")) {
int dot_pos = gl_name.find(".");
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
- Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
if (vb.size() == 4) {
aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
continue;
}
-#ifdef GDEXTENSION
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
- xml_body = xml_body + "<" + parser->get_node_name();
- for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
- }
- xml_body = xml_body + ">";
- } else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
- xml_body = xml_body + parser->get_node_data();
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
- xml_body = xml_body + "</" + parser->get_node_name() + ">";
- }
-#else
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
xml_body += vformat("</%s>", parser->get_node_name());
}
-#endif
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
-#ifdef GDEXTENSION
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
- gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index f5964eb4d1..ba1750386f 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -18,7 +18,7 @@
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.pressed.connect(self._on_Button_pressed)
+ $Button.pressed.connect(self._on_button_pressed)
webxr_interface = XRServer.find_interface("WebXR")
if webxr_interface:
@@ -38,7 +38,7 @@
if session_mode == 'immersive-vr':
vr_supported = supported
- func _on_Button_pressed():
+ func _on_button_pressed():
if not vr_supported:
OS.alert("Your browser doesn't support VR")
return
diff --git a/platform/android/README.md b/platform/android/README.md
index f6aabab708..01eb9c03a6 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -5,7 +5,7 @@ using [Gradle](https://gradle.org/) as a build system.
## Documentation
-- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html)
+- [Compiling for Android](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_android.html)
- Instructions on building this platform port from source.
- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 780ad4334e..6b3bdb7fe6 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -466,14 +466,15 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
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, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, 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");
if (p_rendering_driver == "vulkan") {
- OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
- "Please try exporting your game using the gl_compatibility renderer.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required Vulkan version.\n\n"
+ "Please try exporting your game using the 'gl_compatibility' renderer.",
+ "Unable to initialize Vulkan video driver");
} else {
- OS::get_singleton()->alert("Your video card driver does not support OpenGL ES 3.0.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required OpenGL ES 3.0 version.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index a602cc7926..bb1ad3d83b 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -43,10 +43,16 @@
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "main/splash.gen.h"
-#include "platform/android/logo.gen.h"
-#include "platform/android/run_icon.gen.h"
+#include "platform/android/logo_svg.gen.h"
+#include "platform/android/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
#include <string.h>
@@ -3238,8 +3244,17 @@ void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref<
}
EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
- logo = ImageTexture::create_from_image(memnew(Image(_android_logo)));
- run_icon = ImageTexture::create_from_image(memnew(Image(_android_run_icon)));
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
+ logo = ImageTexture::create_from_image(img);
+
+ img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
devices_changed.set();
plugins_changed.set();
diff --git a/platform/android/logo.png b/platform/android/logo.png
deleted file mode 100644
index 9c8be93646..0000000000
--- a/platform/android/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/logo.svg b/platform/android/logo.svg
new file mode 100644
index 0000000000..f154e55d11
--- /dev/null
+++ b/platform/android/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M22.904 20.192a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m-13.808 0a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m14.256-7.525 2.496-4.323a.52.52 0 1 0-.899-.52l-2.528 4.378a15.69 15.69 0 0 0-12.842 0L7.051 7.823a.52.52 0 1 0-.9.521l2.497 4.323C4.361 15 1.43 19.34 1 24.467h30c-.43-5.128-3.361-9.468-7.648-11.8" fill="#56d881"/></svg>
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 376ed89c16..942bf0a904 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -355,20 +355,20 @@ void OS_Android::_load_system_font_config() {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
in_font_node = false;
if (parser->get_node_name() == "familyset") {
- int ver = parser->has_attribute("version") ? parser->get_attribute_value("version").to_int() : 0;
+ int ver = parser->has_attribute("version") ? parser->get_named_attribute_value("version").to_int() : 0;
if (ver < 21) {
ERR_PRINT(vformat("Unsupported font config version %s", ver));
break;
}
} else if (parser->get_node_name() == "alias") {
- String name = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
- String to = parser->has_attribute("to") ? parser->get_attribute_value("to").strip_edges() : String();
+ String name = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+ String to = parser->has_attribute("to") ? parser->get_named_attribute_value("to").strip_edges() : String();
if (!name.is_empty() && !to.is_empty()) {
font_aliases[name] = to;
}
} else if (parser->get_node_name() == "family") {
- fn = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
- String lang_code = parser->has_attribute("lang") ? parser->get_attribute_value("lang").strip_edges() : String();
+ fn = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+ String lang_code = parser->has_attribute("lang") ? parser->get_named_attribute_value("lang").strip_edges() : String();
Vector<String> lang_codes = lang_code.split(",");
for (int i = 0; i < lang_codes.size(); i++) {
Vector<String> lang_code_elements = lang_codes[i].split("-");
@@ -412,9 +412,9 @@ void OS_Android::_load_system_font_config() {
}
} else if (parser->get_node_name() == "font") {
in_font_node = true;
- fb = parser->has_attribute("fallbackFor") ? parser->get_attribute_value("fallbackFor").strip_edges() : String();
- fi.weight = parser->has_attribute("weight") ? parser->get_attribute_value("weight").to_int() : 400;
- fi.italic = parser->has_attribute("style") && parser->get_attribute_value("style").strip_edges() == "italic";
+ fb = parser->has_attribute("fallbackFor") ? parser->get_named_attribute_value("fallbackFor").strip_edges() : String();
+ fi.weight = parser->has_attribute("weight") ? parser->get_named_attribute_value("weight").to_int() : 400;
+ fi.italic = parser->has_attribute("style") && parser->get_named_attribute_value("style").strip_edges() == "italic";
}
}
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
diff --git a/platform/android/run_icon.png b/platform/android/run_icon.png
deleted file mode 100644
index b687c9ac31..0000000000
--- a/platform/android/run_icon.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/run_icon.svg b/platform/android/run_icon.svg
new file mode 100644
index 0000000000..24d930fece
--- /dev/null
+++ b/platform/android/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M11.187 9.936a.577.577 0 1 1 .578-.578.577.577 0 0 1-.578.578m-6.374 0a.577.577 0 1 1 .577-.578.577.577 0 0 1-.577.578m6.581-3.475 1.153-1.996a.24.24 0 1 0-.415-.24l-1.167 2.021a7.244 7.244 0 0 0-5.93 0L3.868 4.225a.24.24 0 1 0-.415.24l1.153 1.996a6.806 6.806 0 0 0-3.532 5.448h13.852a6.807 6.807 0 0 0-3.532-5.448" fill="#56d881" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/platform/ios/README.md b/platform/ios/README.md
index 82c275ad31..0e1d6802cb 100644
--- a/platform/ios/README.md
+++ b/platform/ios/README.md
@@ -8,7 +8,7 @@ project template used for packaging the iOS export templates.
## Documentation
-- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html)
+- [Compiling for iOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_ios.html)
- Instructions on building this platform port from source.
- [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index bea88a7f9b..86ea602a98 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -56,16 +56,9 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
tts = [[TTS_IOS alloc] init];
#if defined(GLES3_ENABLED)
- // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented
- // again,
- // Note that we should be checking "opengl3" as the driver, might never enable this seeing OpenGL is deprecated on iOS
- // We are hardcoding the rendering_driver to "vulkan" down below
-
if (rendering_driver == "opengl3") {
bool gl_initialization_error = false;
- // FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
-
if (RasterizerGLES3::is_viable() == OK) {
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
@@ -74,22 +67,10 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
}
if (gl_initialization_error) {
- OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.", "Unable to initialize video driver");
- // return ERR_UNAVAILABLE;
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required OpenGL ES 3.0 version.\n\n",
+ "Unable to initialize OpenGL video driver");
}
-
- // rendering_server = memnew(RenderingServerDefault);
- // // FIXME: Reimplement threaded rendering
- // if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- // rendering_server = memnew(RenderingServerWrapMT(rendering_server,
- // false));
- // }
- // rendering_server->init();
- // rendering_server->cursor_set_visible(false, 0);
-
- // reset this to what it should be, it will have been set to 0 after
- // rendering_server->init() is called
- // RasterizerStorageGLES3system_fbo = gl_view_base_fb;
}
#endif
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 43eb0f4b1f..87b599bc81 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -32,6 +32,13 @@
#include "core/string/translation.h"
#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "platform/ios/logo_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
// Vulkan and OpenGL ES 3.0 both mandate ETC2 support.
@@ -1565,7 +1572,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
int ret = unzGoToFirstFile(src_pkg_zip);
Vector<uint8_t> project_file_data;
while (ret == UNZ_OK) {
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
bool is_execute = false;
#endif
@@ -1598,7 +1605,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
continue; //ignore!
}
found_library = true;
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
is_execute = true;
#endif
file = file.replace(library_to_use, binary_name + ".xcframework");
@@ -1641,7 +1648,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
f->store_buffer(data.ptr(), data.size());
}
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
if (is_execute) {
// we need execute rights on this file
chmod(file.utf8().get_data(), 0755);
@@ -1926,7 +1933,15 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorEx
}
EditorExportPlatformIOS::EditorExportPlatformIOS() {
- logo = ImageTexture::create_from_image(memnew(Image(_ios_logo)));
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
+ logo = ImageTexture::create_from_image(img);
+#endif
+
plugins_changed.set();
#ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index deadec4b43..628dae2e6f 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -43,7 +43,6 @@
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform.h"
#include "main/splash.gen.h"
-#include "platform/ios/logo.gen.h"
#include "string.h"
#include "godot_plugin_config.h"
diff --git a/platform/ios/logo.png b/platform/ios/logo.png
deleted file mode 100644
index 966d8aa70a..0000000000
--- a/platform/ios/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/logo.svg b/platform/ios/logo.svg
new file mode 100644
index 0000000000..47a72bcf49
--- /dev/null
+++ b/platform/ios/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M1 23.27h2.504V12.61H1zm1.247-12.057c.784 0 1.398-.603 1.398-1.358 0-.764-.614-1.367-1.398-1.367-.774 0-1.388.603-1.388 1.367 0 .755.614 1.358 1.388 1.358zm9.594-2.695c-4.233 0-6.888 2.886-6.888 7.502s2.654 7.492 6.888 7.492c4.224 0 6.88-2.876 6.88-7.492s-2.656-7.502-6.88-7.502zm0 2.212c2.585 0 4.234 2.052 4.234 5.29 0 3.228-1.649 5.28-4.234 5.28-2.594 0-4.233-2.052-4.233-5.28 0-3.238 1.639-5.29 4.233-5.29zm7.936 8.458c.11 2.675 2.303 4.324 5.641 4.324 3.51 0 5.723-1.73 5.723-4.485 0-2.162-1.247-3.379-4.194-4.053l-1.67-.382c-1.78-.422-2.513-.985-2.513-1.95 0-1.208 1.106-2.012 2.745-2.012 1.66 0 2.796.814 2.916 2.172H30.9c-.06-2.554-2.172-4.284-5.37-4.284-3.158 0-5.4 1.74-5.4 4.314 0 2.072 1.267 3.36 3.942 3.973l1.88.442c1.83.433 2.575 1.036 2.575 2.082 0 1.207-1.217 2.072-2.967 2.072-1.77 0-3.107-.875-3.268-2.213h-2.514z" fill="#bfbfbf"/></svg>
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
index efa8682062..c4f287cc6c 100644
--- a/platform/linuxbsd/README.md
+++ b/platform/linuxbsd/README.md
@@ -7,7 +7,7 @@ used by this platform.
## Documentation
-- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html)
+- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_linuxbsd.html)
- Instructions on building this platform port from source.
- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index add69c436f..8d03e3d31c 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -44,6 +44,7 @@
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
+#include <link.h>
#include <signal.h>
#include <stdlib.h>
@@ -79,7 +80,27 @@ static void handle_crash(int sig) {
}
print_error(vformat("Dumping the backtrace. %s", msg));
char **strings = backtrace_symbols(bt_buffer, size);
+ // PIE executable relocation, zero for non-PIE executables
+ uintptr_t relocation = _r_debug.r_map->l_addr;
if (strings) {
+ List<String> args;
+ for (size_t i = 0; i < size; i++) {
+ char str[1024];
+ snprintf(str, 1024, "%p", (void *)((uintptr_t)bt_buffer[i] - relocation));
+ args.push_back(str);
+ }
+ args.push_back("-e");
+ args.push_back(_execpath);
+
+ // Try to get the file/line number using addr2line
+ int ret;
+ String output = "";
+ Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
+ Vector<String> addr2line_results;
+ if (err == OK) {
+ addr2line_results = output.substr(0, output.length() - 1).split("\n", false);
+ }
+
for (size_t i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
@@ -102,24 +123,7 @@ static void handle_crash(int sig) {
}
}
- List<String> args;
-
- char str[1024];
- snprintf(str, 1024, "%p", bt_buffer[i]);
- args.push_back(str);
- args.push_back("-e");
- args.push_back(_execpath);
-
- String output = "";
-
- // Try to get the file/line number using addr2line
- int ret;
- Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
- if (err == OK) {
- output = output.substr(0, output.length() - 1);
- }
-
- print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, output));
+ print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, err == OK ? addr2line_results[i] : ""));
}
free(strings);
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 747dcbd76c..f4d36f1a87 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -338,12 +338,17 @@ def configure(env: "Environment"):
env.Prepend(CPPPATH=["#platform/linuxbsd"])
+ env.Append(
+ CPPDEFINES=[
+ "LINUXBSD_ENABLED",
+ "UNIX_ENABLED",
+ ("_FILE_OFFSET_BITS", 64),
+ ]
+ )
+
if env["x11"]:
env.Append(CPPDEFINES=["X11_ENABLED"])
- env.Append(CPPDEFINES=["UNIX_ENABLED"])
- env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
-
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
if not env["use_volk"]:
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index e6925a2011..2c5a945b6c 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -36,7 +36,6 @@
void register_linuxbsd_exporter() {
Ref<EditorExportPlatformLinuxBSD> platform;
platform.instantiate();
- platform->set_logo(ImageTexture::create_from_image(memnew(Image(_linuxbsd_logo))));
platform->set_name("Linux/X11");
platform->set_os_name("Linux");
platform->set_chmod_flags(0755);
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index f6e59bf465..c900cad007 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -32,6 +32,15 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "platform/linuxbsd/logo_svg.gen.h"
+#include "platform/linuxbsd/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
Error EditorExportPlatformLinuxBSD::_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);
@@ -49,26 +58,47 @@ Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportP
}
Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
-
- if (err != OK) {
- return err;
- }
+ bool export_as_zip = p_path.ends_with("zip");
- String app_name;
+ String pkg_name;
if (String(GLOBAL_GET("application/config/name")) != "") {
- app_name = String(GLOBAL_GET("application/config/name"));
+ pkg_name = String(GLOBAL_GET("application/config/name"));
} else {
- app_name = "Unnamed";
+ pkg_name = "Unnamed";
+ }
+
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ // Setup temp folder.
+ String path = p_path;
+ String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+
+ Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
+ if (export_as_zip) {
+ if (tmp_app_dir.is_null()) {
+ return ERR_CANT_CREATE;
+ }
+ if (DirAccess::exists(tmp_dir_path)) {
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ }
+ }
+ tmp_app_dir->make_dir_recursive(tmp_dir_path);
+ path = tmp_dir_path.path_join(p_path.get_file().get_basename());
+ }
+
+ // Export project.
+ Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, path, p_flags);
+ if (err != OK) {
+ return err;
}
- app_name = OS::get_singleton()->get_safe_dir_name(app_name);
// Save console script.
if (err == OK) {
int con_scr = p_preset->get("debug/export_console_script");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
- String scr_path = p_path.get_basename() + ".sh";
- err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
+ String scr_path = path.get_basename() + ".sh";
+ err = _export_debug_script(p_preset, pkg_name, path.get_file(), scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
@@ -76,6 +106,27 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
}
}
+ // ZIP project.
+ if (export_as_zip) {
+ if (FileAccess::exists(p_path)) {
+ OS::get_singleton()->move_to_trash(p_path);
+ }
+
+ Ref<FileAccess> io_fa_dst;
+ zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
+
+ zip_folder_recursive(zip, tmp_dir_path, "", pkg_name);
+
+ zipClose(zip, nullptr);
+
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(pkg_name);
+ }
+ }
+
return err;
}
@@ -86,12 +137,51 @@ String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_targ
List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
list.push_back(p_preset->get("binary_format/architecture"));
+ list.push_back("zip");
+
return list;
}
void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64"));
+
+ String run_script = "#!/usr/bin/env bash\n"
+ "export DISPLAY=:0\n"
+ "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n"
+ "\"{temp_dir}/{exe_name}\" {cmd_args}";
+
+ String cleanup_script = "#!/usr/bin/env bash\n"
+ "kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n"
+ "rm -rf \"{temp_dir}\"";
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
+}
+
+bool EditorExportPlatformLinuxBSD::is_elf(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));
+ uint32_t magic = fb->get_32();
+ return (magic == 0x464c457f);
+}
+
+bool EditorExportPlatformLinuxBSD::is_shebang(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 EditorExportPlatformLinuxBSD::is_executable(const String &p_path) const {
+ return is_elf(p_path) || is_shebang(p_path);
}
Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
@@ -200,3 +290,235 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
}
return OK;
}
+
+Ref<Texture2D> EditorExportPlatformLinuxBSD::get_run_icon() const {
+ return run_icon;
+}
+
+bool EditorExportPlatformLinuxBSD::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool());
+ if (ssh_pid != 0 || !cleanup_commands.is_empty()) {
+ if (menu_options == 0) {
+ cleanup();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformLinuxBSD::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformLinuxBSD::get_options_count() const {
+ return menu_options;
+}
+
+String EditorExportPlatformLinuxBSD::get_option_label(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Linux/BSD system");
+}
+
+String EditorExportPlatformLinuxBSD::get_option_tooltip(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Linux/BSD system");
+}
+
+void EditorExportPlatformLinuxBSD::cleanup() {
+ if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) {
+ print_line("Terminating connection...");
+ OS::get_singleton()->kill(ssh_pid);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (!cleanup_commands.is_empty()) {
+ print_line("Stopping and deleting previous version...");
+ for (const SSHCleanupCommand &cmd : cleanup_commands) {
+ if (cmd.wait) {
+ ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ } else {
+ ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ }
+ }
+ }
+ ssh_pid = 0;
+ cleanup_commands.clear();
+}
+
+Error EditorExportPlatformLinuxBSD::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ cleanup();
+ if (p_device) { // Stop command, cleanup only.
+ return OK;
+ }
+
+ EditorProgress ep("run", TTR("Running..."), 5);
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("linuxbsd");
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest);
+ return err;
+ }
+ }
+
+ String host = p_preset->get("ssh_remote_deploy/host").operator String();
+ String port = p_preset->get("ssh_remote_deploy/port").operator String();
+ if (port.is_empty()) {
+ port = "22";
+ }
+ Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" ");
+ Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" ");
+
+ const String basepath = dest.path_join("tmp_linuxbsd_export");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (da->file_exists(basepath + ".zip")) { \
+ da->remove(basepath + ".zip"); \
+ } \
+ if (da->file_exists(basepath + "_start.sh")) { \
+ da->remove(basepath + "_start.sh"); \
+ } \
+ if (da->file_exists(basepath + "_clean.sh")) { \
+ da->remove(basepath + "_clean.sh"); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ if (ep.step(TTR("Exporting project..."), 1)) {
+ return ERR_SKIP;
+ }
+ Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags);
+ if (err != OK) {
+ DirAccess::remove_file_or_error(basepath + ".zip");
+ return err;
+ }
+
+ String cmd_args;
+ {
+ Vector<String> cmd_args_list;
+ gen_debug_flags(cmd_args_list, p_debug_flags);
+ for (int i = 0; i < cmd_args_list.size(); i++) {
+ if (i != 0) {
+ cmd_args += " ";
+ }
+ cmd_args += cmd_args_list[i];
+ }
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+ print_line("Creating temporary directory...");
+ ep.step(TTR("Creating temporary directory..."), 2);
+ String temp_dir;
+ err = ssh_run_on_remote(host, port, extra_args_ssh, "mktemp -d", &temp_dir);
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Uploading archive...");
+ ep.step(TTR("Uploading archive..."), 3);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ {
+ String run_script = p_preset->get("ssh_remote_deploy/run_script");
+ run_script = run_script.replace("{temp_dir}", temp_dir);
+ run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ run_script = run_script.replace("{exe_name}", basepath.get_file());
+ run_script = run_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_start.sh", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(run_script);
+ }
+
+ {
+ String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script");
+ clean_script = clean_script.replace("{temp_dir}", temp_dir);
+ clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ clean_script = clean_script.replace("{exe_name}", basepath.get_file());
+ clean_script = clean_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_clean.sh", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(clean_script);
+ }
+
+ print_line("Uploading scripts...");
+ ep.step(TTR("Uploading scripts..."), 4);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.sh", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"));
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.sh", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh"));
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Starting project...");
+ ep.step(TTR("Starting project..."), 5);
+ err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"), &ssh_pid, (use_remote) ? dbg_port : -1);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ cleanup_commands.clear();
+ cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh")));
+
+ print_line("Project started.");
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
+}
+
+EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() {
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
+ set_logo(ImageTexture::create_from_image(img));
+
+ img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ } else {
+ stop_icon.instantiate();
+ }
+}
diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h
index 71cf18ff3e..4f860c3fd0 100644
--- a/platform/linuxbsd/export/export_plugin.h
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -34,19 +34,58 @@
#include "core/io/file_access.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
-#include "platform/linuxbsd/logo.gen.h"
#include "scene/resources/texture.h"
class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC {
+ HashMap<String, String> extensions;
+
+ struct SSHCleanupCommand {
+ String host;
+ String port;
+ Vector<String> ssh_args;
+ String cmd_args;
+ bool wait = false;
+
+ SSHCleanupCommand(){};
+ SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
+ host = p_host;
+ port = p_port;
+ ssh_args = p_ssh_arg;
+ cmd_args = p_cmd_args;
+ wait = p_wait;
+ };
+ };
+
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+
+ Vector<SSHCleanupCommand> cleanup_commands;
+ OS::ProcessID ssh_pid = 0;
+ int menu_options = 0;
+
+ bool is_elf(const String &p_path) const;
+ bool is_shebang(const String &p_path) const;
+
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
public:
- void set_extension(const String &p_extension, const String &p_feature_key = "default");
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
+ virtual bool is_executable(const String &p_path) const override;
+
+ virtual Ref<Texture2D> get_run_icon() const override;
+ virtual bool poll_export() override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+ virtual void cleanup() override;
+
+ EditorExportPlatformLinuxBSD();
};
#endif // LINUXBSD_EXPORT_PLUGIN_H
diff --git a/platform/linuxbsd/logo.png b/platform/linuxbsd/logo.png
deleted file mode 100644
index 078654b757..0000000000
--- a/platform/linuxbsd/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/linuxbsd/logo.svg b/platform/linuxbsd/logo.svg
new file mode 100644
index 0000000000..e5f9f03e0c
--- /dev/null
+++ b/platform/linuxbsd/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32"><path d="M13 31h6s3 0 6-6c2.864-5.727-6-17-6-17h-6S3.775 18.55 7 25c3 6 6 6 6 6z" fill="#fff"/><path d="M15.876 28.636c-.05.322-.116.637-.204.941-.142.496-.35.993-.659 1.416.32.02.649.023.985.007a9.1 9.1 0 0 0 .985-.007c-.309-.423-.516-.92-.659-1.416a7.666 7.666 0 0 1-.203-.94l-.123.003c-.04 0-.081-.003-.122-.004z" fill="#333"/><path d="M21.693 21.916c-.629.01-.934.633-1.497.7-.694.08-1.128-.722-2.11-.123-.98.6-1.826 7.473.45 8.409 2.274.935 6.506-4.545 6.23-5.662-.275-1.116-1.146-.853-1.582-1.399-.436-.545.003-1.41-.995-1.82a1.246 1.246 0 0 0-.496-.105zm-11.461 0a1.315 1.315 0 0 0-.421.105c-.998.41-.56 1.275-.995 1.82-.436.546-1.31.283-1.586 1.4-.275 1.116 3.956 6.596 6.232 5.66 2.275-.935 1.429-7.808.448-8.408-.981-.6-1.415.204-2.11.122-.584-.068-.888-.739-1.568-.7z" fill="#f4bb37"/><path d="M15.998.99c-2.934 0-4.657 1.79-4.982 4.204-.324 2.414.198 2.856-.614 5.328-.813 2.472-4.456 6.71-4.37 10.62.026 1.217.166 2.27.41 3.192.3-.496.743-.846 1.066-.995.253-.117.375-.173.432-.194.008-.062.04-.205.098-.485.08-.386.387-.99.91-1.386-.005-.12-.01-.239-.013-.363-.06-3.033 3.073-6.318 3.65-8.236.577-1.917.326-2.114.421-2.59.096-.477.463-1.032.992-1.475a.23.23 0 0 1 .15-.06c.482-.005.965 1.75 1.898 1.752.933 0 1.419-2.141 1.956-1.692.529.443.896.998.992 1.474.095.477-.156.674.42 2.591.578 1.918 3.708 5.203 3.648 8.236-.003.123-.008.24-.014.36.526.396.834 1.002.914 1.389.058.28.09.423.098.485.057.021.18.08.432.197.323.15.764.499 1.063.995.244-.922.387-1.976.414-3.195.085-3.91-3.562-8.148-4.374-10.62-.813-2.472-.287-2.914-.611-5.328C20.659 2.78 18.933.99 15.998.99z" fill="#333"/></svg>
diff --git a/platform/linuxbsd/run_icon.svg b/platform/linuxbsd/run_icon.svg
new file mode 100644
index 0000000000..56465a0df3
--- /dev/null
+++ b/platform/linuxbsd/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444l-.058.001-.058-.001z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z" fill="#f4bb37" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696a.11.11 0 0 1 .07-.028c.228-.003.456.826.897.827.44 0 .67-1.01.923-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888-.001.058-.004.114-.007.17a1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914Z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 10fd9972e3..d4f82cc81e 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1420,31 +1420,35 @@ void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_reg
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- const WindowData &wd = windows[p_window];
+ windows[p_window].mpath = p_region;
+ _update_window_mouse_passthrough(p_window);
+}
+
+void DisplayServerX11::_update_window_mouse_passthrough(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
+ const Vector<Vector2> region_path = windows[p_window].mpath;
int event_base, error_base;
const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
if (ext_okay) {
- Region region;
- if (p_region.size() == 0) {
- region = XCreateRegion();
- XRectangle rect;
- rect.x = 0;
- rect.y = 0;
- rect.width = window_get_size_with_decorations(p_window).x;
- rect.height = window_get_size_with_decorations(p_window).y;
- XUnionRectWithRegion(&rect, region, region);
+ if (windows[p_window].mpass) {
+ Region region = XCreateRegion();
+ XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
+ } else if (region_path.size() == 0) {
+ XShapeCombineMask(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, None, ShapeSet);
} else {
- XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size());
- for (int i = 0; i < p_region.size(); i++) {
- points[i].x = p_region[i].x;
- points[i].y = p_region[i].y;
+ XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * region_path.size());
+ for (int i = 0; i < region_path.size(); i++) {
+ points[i].x = region_path[i].x;
+ points[i].y = region_path[i].y;
}
- region = XPolygonRegion(points, p_region.size(), EvenOddRule);
+ Region region = XPolygonRegion(points, region_path.size(), EvenOddRule);
memfree(points);
+ XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
}
- XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet);
- XDestroyRegion(region);
}
}
@@ -2312,6 +2316,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
window_set_size(window_get_size(p_window), p_window);
wd.borderless = p_enabled;
+ _update_window_mouse_passthrough(p_window);
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active.");
@@ -2345,6 +2350,10 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ _update_window_mouse_passthrough(p_window);
+ } break;
case WINDOW_FLAG_POPUP: {
XWindowAttributes xwa;
XSync(x11_display, False);
@@ -2398,6 +2407,9 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -4564,18 +4576,20 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
if (r_error != OK) {
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");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s --rendering-driver opengl3'\n\n"
+ "If you recently updated your video card drivers, try rebooting.",
+ executable_name),
+ "Unable to initialize Vulkan 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");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your video card drivers.\n\n"
+ "If you recently updated your video card drivers, try rebooting.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 43a66f95b2..437766d953 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -149,6 +149,8 @@ class DisplayServerX11 : public DisplayServer {
Callable input_text_callback;
Callable drop_files_callback;
+ Vector<Vector2> mpath;
+
WindowID transient_parent = INVALID_WINDOW_ID;
HashSet<WindowID> transient_children;
@@ -169,6 +171,7 @@ class DisplayServerX11 : public DisplayServer {
bool maximized = false;
bool is_popup = false;
bool layered_window = false;
+ bool mpass = false;
Rect2i parent_safe_rect;
@@ -245,6 +248,7 @@ class DisplayServerX11 : public DisplayServer {
Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const;
void _handle_selection_request_event(XSelectionRequestEvent *p_event) const;
+ void _update_window_mouse_passthrough(WindowID p_window);
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
String _clipboard_get(Atom p_source, Window x11_window) const;
diff --git a/platform/macos/README.md b/platform/macos/README.md
index feead80736..205c59e05d 100644
--- a/platform/macos/README.md
+++ b/platform/macos/README.md
@@ -11,7 +11,7 @@ packaging macOS export templates.
## Documentation
-- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html)
+- [Compiling for macOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_macos.html)
- Instructions on building this platform port from source.
- [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 7f57644a4c..4873db4b64 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -114,6 +114,7 @@ public:
bool resize_disabled = false;
bool no_focus = false;
bool is_popup = false;
+ bool mpass = false;
Rect2i parent_safe_rect;
};
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 759ae03d95..d992467042 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -166,6 +166,17 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
layer.contentsScale = scale;
}
+ NSColor *bg_color = [NSColor windowBackgroundColor];
+ Color _bg_color;
+ if (_get_window_early_clear_override(_bg_color)) {
+ bg_color = [NSColor colorWithCalibratedRed:_bg_color.r green:_bg_color.g blue:_bg_color.b alpha:1.f];
+ }
+
+ [wd.window_object setBackgroundColor:bg_color];
+ if (layer) {
+ [layer setBackgroundColor:bg_color.CGColor];
+ }
+
#if defined(VULKAN_ENABLED)
if (context_vulkan) {
Error err = context_vulkan->window_create(window_id_counter, p_vsync_mode, wd.window_view, p_rect.size.width, p_rect.size.height);
@@ -273,12 +284,17 @@ void DisplayServerMacOS::_set_window_per_pixel_transparency_enabled(bool p_enabl
#endif
wd.layered_window = true;
} else {
- [wd.window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
+ NSColor *bg_color = [NSColor windowBackgroundColor];
+ Color _bg_color;
+ if (_get_window_early_clear_override(_bg_color)) {
+ bg_color = [NSColor colorWithCalibratedRed:_bg_color.r green:_bg_color.g blue:_bg_color.b alpha:1.f];
+ }
+ [wd.window_object setBackgroundColor:bg_color];
[wd.window_object setOpaque:YES];
[wd.window_object setHasShadow:YES];
CALayer *layer = [(NSView *)wd.window_view layer];
if (layer) {
- [layer setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1].CGColor];
+ [layer setBackgroundColor:bg_color.CGColor];
[layer setOpaque:YES];
}
#if defined(GLES3_ENABLED)
@@ -2958,6 +2974,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ } break;
case WINDOW_FLAG_POPUP: {
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
@@ -2997,6 +3016,9 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window)
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -3471,7 +3493,11 @@ void DisplayServerMacOS::process_events() {
for (KeyValue<WindowID, WindowData> &E : windows) {
WindowData &wd = E.value;
- if (wd.mpath.size() > 0) {
+ if (wd.mpass) {
+ if (![wd.window_object ignoresMouseEvents]) {
+ [wd.window_object setIgnoresMouseEvents:YES];
+ }
+ } else if (wd.mpath.size() > 0) {
update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
if (Geometry2D::is_point_in_polygon(wd.mouse_pos, wd.mpath)) {
if ([wd.window_object ignoresMouseEvents]) {
@@ -3581,18 +3607,18 @@ DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver,
} 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");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your macOS version or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s'",
+ executable_command),
+ "Unable to initialize Vulkan 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");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your macOS version.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 311619f657..73fbd45400 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -38,8 +38,14 @@
#include "core/string/translation.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "platform/macos/logo_svg.gen.h"
+#include "platform/macos/run_icon_svg.gen.h"
-#include "modules/modules_enabled.gen.h" // For regex.
+#include "modules/modules_enabled.gen.h" // For svg and regex.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
if (p_preset->get("texture_format/s3tc")) {
@@ -207,6 +213,23 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
+
+ String run_script = "#!/usr/bin/env bash\n"
+ "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n"
+ "open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}";
+
+ String cleanup_script = "#!/usr/bin/env bash\n"
+ "kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")\n"
+ "rm -rf \"{temp_dir}\"";
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
}
void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) {
@@ -993,7 +1016,7 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str
return OK;
}
-bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const {
+bool EditorExportPlatformMacOS::is_shebang(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();
@@ -1001,7 +1024,7 @@ bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const {
}
bool EditorExportPlatformMacOS::is_executable(const String &p_path) const {
- return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shbang(p_path);
+ return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shebang(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) {
@@ -1082,7 +1105,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
} else {
pkg_name = "Unnamed";
}
-
pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
String export_format;
@@ -1684,7 +1706,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst);
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
- _zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name);
+ zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name);
zipClose(zip, nullptr);
}
@@ -1723,119 +1745,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
return err;
}
-void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
- String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder);
-
- Ref<DirAccess> da = DirAccess::open(dir);
- da->list_dir_begin();
- String f = da->get_next();
- while (!f.is_empty()) {
- if (f == "." || f == "..") {
- f = da->get_next();
- continue;
- }
- if (da->is_link(f)) {
- OS::DateTime dt = OS::get_singleton()->get_datetime();
-
- zip_fileinfo zipfi;
- zipfi.tmz_date.tm_year = dt.year;
- zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
- zipfi.tmz_date.tm_mday = dt.day;
- zipfi.tmz_date.tm_hour = dt.hour;
- zipfi.tmz_date.tm_min = dt.minute;
- zipfi.tmz_date.tm_sec = dt.second;
- zipfi.dosDate = 0;
- // 0120000: symbolic link type
- // 0000755: permissions rwxr-xr-x
- // 0000644: permissions rw-r--r--
- uint32_t _mode = 0120644;
- zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
- zipfi.internal_fa = 0;
-
- zipOpenNewFileInZip4(p_zip,
- p_folder.path_join(f).utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- Z_DEFLATED,
- Z_DEFAULT_COMPRESSION,
- 0,
- -MAX_WBITS,
- DEF_MEM_LEVEL,
- Z_DEFAULT_STRATEGY,
- nullptr,
- 0,
- 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
-
- String target = da->read_link(f);
- zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
- zipCloseFileInZip(p_zip);
- } else if (da->current_is_dir()) {
- _zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
- } else {
- OS::DateTime dt = OS::get_singleton()->get_datetime();
-
- zip_fileinfo zipfi;
- zipfi.tmz_date.tm_year = dt.year;
- zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
- zipfi.tmz_date.tm_mday = dt.day;
- zipfi.tmz_date.tm_hour = dt.hour;
- zipfi.tmz_date.tm_min = dt.minute;
- zipfi.tmz_date.tm_sec = dt.second;
- zipfi.dosDate = 0;
- // 0100000: regular file type
- // 0000755: permissions rwxr-xr-x
- // 0000644: permissions rw-r--r--
- uint32_t _mode = (is_executable(dir.path_join(f)) ? 0100755 : 0100644);
- zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
- zipfi.internal_fa = 0;
-
- zipOpenNewFileInZip4(p_zip,
- p_folder.path_join(f).utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- Z_DEFLATED,
- Z_DEFAULT_COMPRESSION,
- 0,
- -MAX_WBITS,
- DEF_MEM_LEVEL,
- Z_DEFAULT_STRATEGY,
- nullptr,
- 0,
- 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
-
- Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
- if (fa.is_null()) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f)));
- return;
- }
- const int bufsize = 16384;
- uint8_t buf[bufsize];
-
- while (true) {
- uint64_t got = fa->get_buffer(buf, bufsize);
- if (got == 0) {
- break;
- }
- zipWriteInFileInZip(p_zip, buf, got);
- }
-
- zipCloseFileInZip(p_zip);
- }
- f = da->get_next();
- }
- da->list_dir_end();
-}
-
bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
@@ -2012,9 +1921,242 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
return valid;
}
-EditorExportPlatformMacOS::EditorExportPlatformMacOS() {
- logo = ImageTexture::create_from_image(memnew(Image(_macos_logo)));
+Ref<Texture2D> EditorExportPlatformMacOS::get_run_icon() const {
+ return run_icon;
+}
+
+bool EditorExportPlatformMacOS::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool());
+ if (ssh_pid != 0 || !cleanup_commands.is_empty()) {
+ if (menu_options == 0) {
+ cleanup();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformMacOS::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformMacOS::get_options_count() const {
+ return menu_options;
+}
+
+String EditorExportPlatformMacOS::get_option_label(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote macOS system");
+}
+
+String EditorExportPlatformMacOS::get_option_tooltip(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote macOS system");
+}
+
+void EditorExportPlatformMacOS::cleanup() {
+ if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) {
+ print_line("Terminating connection...");
+ OS::get_singleton()->kill(ssh_pid);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (!cleanup_commands.is_empty()) {
+ print_line("Stopping and deleting previous version...");
+ for (const SSHCleanupCommand &cmd : cleanup_commands) {
+ if (cmd.wait) {
+ ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ } else {
+ ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ }
+ }
+ }
+ ssh_pid = 0;
+ cleanup_commands.clear();
+}
+
+Error EditorExportPlatformMacOS::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ cleanup();
+ if (p_device) { // Stop command, cleanup only.
+ return OK;
+ }
+
+ EditorProgress ep("run", TTR("Running..."), 5);
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("macos");
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest);
+ return err;
+ }
+ }
+
+ String pkg_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ String host = p_preset->get("ssh_remote_deploy/host").operator String();
+ String port = p_preset->get("ssh_remote_deploy/port").operator String();
+ if (port.is_empty()) {
+ port = "22";
+ }
+ Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" ");
+ Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" ");
+
+ const String basepath = dest.path_join("tmp_macos_export");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (da->file_exists(basepath + ".zip")) { \
+ da->remove(basepath + ".zip"); \
+ } \
+ if (da->file_exists(basepath + "_start.sh")) { \
+ da->remove(basepath + "_start.sh"); \
+ } \
+ if (da->file_exists(basepath + "_clean.sh")) { \
+ da->remove(basepath + "_clean.sh"); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ if (ep.step(TTR("Exporting project..."), 1)) {
+ return ERR_SKIP;
+ }
+ Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags);
+ if (err != OK) {
+ DirAccess::remove_file_or_error(basepath + ".zip");
+ return err;
+ }
+
+ String cmd_args;
+ {
+ Vector<String> cmd_args_list;
+ gen_debug_flags(cmd_args_list, p_debug_flags);
+ for (int i = 0; i < cmd_args_list.size(); i++) {
+ if (i != 0) {
+ cmd_args += " ";
+ }
+ cmd_args += cmd_args_list[i];
+ }
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+ print_line("Creating temporary directory...");
+ ep.step(TTR("Creating temporary directory..."), 2);
+ String temp_dir;
+ err = ssh_run_on_remote(host, port, extra_args_ssh, "mktemp -d", &temp_dir);
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Uploading archive...");
+ ep.step(TTR("Uploading archive..."), 3);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ {
+ String run_script = p_preset->get("ssh_remote_deploy/run_script");
+ run_script = run_script.replace("{temp_dir}", temp_dir);
+ run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ run_script = run_script.replace("{exe_name}", pkg_name);
+ run_script = run_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_start.sh", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(run_script);
+ }
+
+ {
+ String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script");
+ clean_script = clean_script.replace("{temp_dir}", temp_dir);
+ clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ clean_script = clean_script.replace("{exe_name}", pkg_name);
+ clean_script = clean_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_clean.sh", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(clean_script);
+ }
+
+ print_line("Uploading scripts...");
+ ep.step(TTR("Uploading scripts..."), 4);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.sh", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"));
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.sh", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh"));
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Starting project...");
+ ep.step(TTR("Starting project..."), 5);
+ err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"), &ssh_pid, (use_remote) ? dbg_port : -1);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ cleanup_commands.clear();
+ cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh")));
+
+ print_line("Project started.");
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
}
-EditorExportPlatformMacOS::~EditorExportPlatformMacOS() {
+EditorExportPlatformMacOS::EditorExportPlatformMacOS() {
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
+ logo = ImageTexture::create_from_image(img);
+
+ img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ } else {
+ stop_icon.instantiate();
+ }
}
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 7de6ddf304..c10192949c 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -36,12 +36,10 @@
#include "core/io/file_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
-#include "core/io/zip_io.h"
#include "core/os/os.h"
#include "core/version.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
-#include "platform/macos/logo.gen.h"
#include <sys/stat.h>
@@ -52,6 +50,30 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
Ref<ImageTexture> logo;
+ struct SSHCleanupCommand {
+ String host;
+ String port;
+ Vector<String> ssh_args;
+ String cmd_args;
+ bool wait = false;
+
+ SSHCleanupCommand(){};
+ SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
+ host = p_host;
+ port = p_port;
+ ssh_args = p_ssh_arg;
+ cmd_args = p_cmd_args;
+ wait = p_wait;
+ };
+ };
+
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+
+ Vector<SSHCleanupCommand> cleanup_commands;
+ OS::ProcessID ssh_pid = 0;
+ int menu_options = 0;
+
void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
@@ -65,14 +87,17 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
const String &p_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
- void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
bool use_codesign() const { return true; }
#ifdef MACOS_ENABLED
- bool use_dmg() const { return true; }
+ bool use_dmg() const {
+ return true;
+ }
#else
- bool use_dmg() const { return false; }
+ bool use_dmg() const {
+ return false;
+ }
#endif
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
@@ -97,7 +122,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
return true;
}
- bool is_shbang(const String &p_path) const;
+ bool is_shebang(const String &p_path) const;
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
@@ -105,9 +130,15 @@ protected:
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
public:
- virtual String get_name() const override { return "macOS"; }
- virtual String get_os_name() const override { return "macOS"; }
- virtual Ref<Texture2D> get_logo() const override { return logo; }
+ virtual String get_name() const override {
+ return "macOS";
+ }
+ 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 {
@@ -133,8 +164,16 @@ public:
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override {
}
+ virtual Ref<Texture2D> get_run_icon() const override;
+ virtual bool poll_export() override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+ virtual void cleanup() override;
+
EditorExportPlatformMacOS();
- ~EditorExportPlatformMacOS();
};
#endif // MACOS_EXPORT_PLUGIN_H
diff --git a/platform/macos/logo.png b/platform/macos/logo.png
deleted file mode 100644
index b5a660b165..0000000000
--- a/platform/macos/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/logo.svg b/platform/macos/logo.svg
new file mode 100644
index 0000000000..759583d76b
--- /dev/null
+++ b/platform/macos/logo.svg
@@ -0,0 +1 @@
+<svg height="32" viewBox="0 0 25.6 25.6" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M.948 19.474V6.126c0-2.767 2.42-5.178 5.178-5.178h6.904s-2.992 7.506-2.992 13.233c0 .346.337.69.69.69h2.877c0 6.648.906 8.436 1.266 9.781H6.126c-2.75 0-5.178-2.407-5.178-5.178z" fill="#1c9ef8"/><path d="M7.162 8.312v1.496" fill="none" stroke="#323232" stroke-linecap="round" stroke-width="1.036"/><path d="M10.729 14.871c-.352 0-.69-.344-.69-.69C10.038 8.414 13.03.948 13.03.948h6.444c2.77 0 5.178 2.416 5.178 5.178v13.348c0 2.754-2.407 5.178-5.178 5.178h-4.603c-.357-1.333-1.266-2.887-1.266-9.78z" fill="#e1e6ed"/><g fill="none" stroke="#323232" stroke-linecap="round"><path d="M17.575 8.255V9.75" stroke-width="1.036"/><path d="M5.55 16.943c1.037 1.794 3.907 2.876 6.79 2.876 2.877 0 5.745-1.068 6.789-2.876" stroke-width=".69"/></g></svg>
diff --git a/platform/macos/run_icon.svg b/platform/macos/run_icon.svg
new file mode 100644
index 0000000000..c7067bb4b6
--- /dev/null
+++ b/platform/macos/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-width:.93168;-inkscape-stroke:none" d="M4.418 1.055c-1.82 0-3.365 1.537-3.365 3.363v7.164c0 1.829 1.548 3.363 3.365 3.363h7.164c1.828 0 3.363-1.544 3.363-3.363V4.418c0-1.822-1.537-3.363-3.363-3.363H7.729Zm3.875 1.164h3.291c1.149 0 2.2 1.053 2.2 2.199v7.164c0 1.14-1.052 2.2-2.2 2.2h-2.15a8.884 8.884 0 0 1-.358-1.598c-.135.02-.487.082-.693.117a3.947 3.947 0 0 1-.049.004l-.008-.002a7.345 7.345 0 0 1-1.205-.004 7.114 7.114 0 0 1-.926-.139 6.057 6.057 0 0 1-.867-.271 3.843 3.843 0 0 1-.988-.566 3.214 3.214 0 0 1-.397-.378 2.8 2.8 0 0 1-.318-.441.558.558 0 0 1-.059-.424.564.564 0 0 1 .881-.299.56.56 0 0 1 .145.164c.083.138.188.26.312.362.096.082.2.158.307.224.12.075.243.142.371.201.285.139.583.247.89.319a5.35 5.35 0 0 0 1.282.158c.065 0 .129-.005.184-.006.056 0 .102-.005.148-.008l.096-.006c.114-.009.228-.02.31-.032.083-.013.11-.021.143-.028.099-.022.204-.058.327-.089a28.438 28.438 0 0 1-.06-1.929V8.53H6.887c.048-1.963.746-4.357 1.181-5.677.1-.293.184-.527.225-.633ZM4.973 5.03h.002a.562.562 0 0 1 .558.559v.805a.556.556 0 0 1-.558.558.56.56 0 0 1-.397-.162.565.565 0 0 1-.164-.396V5.59a.561.561 0 0 1 .559-.559Z"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-linecap:round;-inkscape-stroke:none" d="M26.117 11.467c.008.11.014.225.022.328.022.283.052.565.088.846l.012.053c1.238-.252 2.448-.829 3.011-1.803a.6.6 0 1 0-1.039-.6c-.28.486-1.161.936-2.094 1.176z" transform="translate(-15.37 .357) scale(.93168)"/><g style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-opacity:1"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 5.585v.862" transform="translate(-15.37 .357) scale(.93168)"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 4.984a.6.6 0 0 0-.6.6v.863a.6.6 0 0 0 .6.6.6.6 0 0 0 .6-.6v-.863a.6.6 0 0 0-.6-.6Z" transform="translate(-15.37 .357) scale(.93168)"/></g></svg>
diff --git a/platform/uwp/README.md b/platform/uwp/README.md
index 575f90e3c7..d69a8a8850 100644
--- a/platform/uwp/README.md
+++ b/platform/uwp/README.md
@@ -14,7 +14,7 @@ project template used for packaging the UWP export templates.
## Documentation
-- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html)
+- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_uwp.html)
- Instructions on building this platform port from source.
- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 6eb74fd90a..f810cb0ca9 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -30,8 +30,14 @@
#include "export_plugin.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
-#include "platform/uwp/logo.gen.h"
+#include "platform/uwp/logo_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg and regex.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
String EditorExportPlatformUWP::get_name() const {
return "UWP";
@@ -504,5 +510,13 @@ void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<Edit
}
EditorExportPlatformUWP::EditorExportPlatformUWP() {
- logo = ImageTexture::create_from_image(memnew(Image(_uwp_logo)));
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
+
+ logo = ImageTexture::create_from_image(img);
+#endif
}
diff --git a/platform/uwp/logo.png b/platform/uwp/logo.png
deleted file mode 100644
index 9017a30636..0000000000
--- a/platform/uwp/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/uwp/logo.svg b/platform/uwp/logo.svg
new file mode 100644
index 0000000000..5bcbdcfcd4
--- /dev/null
+++ b/platform/uwp/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="translate(8.981 1.816)"><circle style="fill:#2f75bb;fill-opacity:1;stroke:none;stroke-width:.815427" cx="7.019" cy="14.184" r="13.825"/><path d="m-1.192 8.234 6.73-.927v6.503h-6.73Zm0 11.899 6.73.927v-6.422h-6.73Zm7.47 1.026 8.952 1.236v-7.757H6.278Zm0-13.951v6.602h8.952V5.973Z" fill="#00abed" style="fill:#fff;fill-opacity:1"/></g></svg>
diff --git a/platform/web/README.md b/platform/web/README.md
index 1265ca09df..906eb508fe 100644
--- a/platform/web/README.md
+++ b/platform/web/README.md
@@ -10,7 +10,7 @@ this platform such as the html shell (web page).
## Documentation
-- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html)
+- [Compiling for the Web](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_web.html)
- Instructions on building this platform port from source.
- [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 7dd0515d3f..fdb9d107a7 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -787,8 +787,10 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
RasterizerGLES3::make_current();
} else {
- OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.",
- "Unable to initialize video driver");
+ OS::get_singleton()->alert(
+ "Your browser seems not to support WebGL 2.\n\n"
+ "If possible, consider updating your browser version and video card drivers.",
+ "Unable to initialize WebGL 2 video driver");
RasterizerDummy::make_current();
}
#else
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 3e11db6887..d8e04904c7 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -31,7 +31,15 @@
#include "export_plugin.h"
#include "core/config/project_settings.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "platform/web/logo_svg.gen.h"
+#include "platform/web/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
Error EditorExportPlatformWeb::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
Ref<FileAccess> io_fa;
@@ -153,7 +161,7 @@ void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<Edito
const String custom_head_include = p_preset->get("html/head_include");
HashMap<String, String> replaces;
replaces["$GODOT_URL"] = p_name + ".js";
- replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ replaces["$GODOT_PROJECT_NAME"] = GLOBAL_GET("application/config/name");
replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
replaces["$GODOT_CONFIG"] = str_config;
_replace_strings(replaces, p_html);
@@ -193,7 +201,7 @@ Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const St
}
Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
- String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ String proj_name = GLOBAL_GET("application/config/name");
if (proj_name.is_empty()) {
proj_name = "Godot Game";
}
@@ -651,8 +659,17 @@ EditorExportPlatformWeb::EditorExportPlatformWeb() {
server.instantiate();
server_thread.start(_server_thread_poll, this);
- logo = ImageTexture::create_from_image(memnew(Image(_web_logo)));
- run_icon = ImageTexture::create_from_image(memnew(Image(_web_run_icon)));
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
+ logo = ImageTexture::create_from_image(img);
+
+ img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {
diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h
index b85492b66f..e74c945837 100644
--- a/platform/web/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -38,11 +38,8 @@
#include "core/io/zip_io.h"
#include "editor/editor_node.h"
#include "editor/export/editor_export_platform.h"
-#include "main/splash.gen.h"
-#include "platform/web/logo.gen.h"
-#include "platform/web/run_icon.gen.h"
-
#include "editor_http_server.h"
+#include "main/splash.gen.h"
class EditorExportPlatformWeb : public EditorExportPlatform {
GDCLASS(EditorExportPlatformWeb, EditorExportPlatform);
diff --git a/platform/web/logo.png b/platform/web/logo.png
deleted file mode 100644
index c046d87dc4..0000000000
--- a/platform/web/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/web/logo.svg b/platform/web/logo.svg
new file mode 100644
index 0000000000..567b6f3c77
--- /dev/null
+++ b/platform/web/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M7 5h18v21H7z" fill="#fff"/><path d="M3.143 1 5.48 27.504 15.967 31l10.553-3.496L28.857 1zM23.78 9.565H11.473l.275 3.308h11.759l-.911 9.937-6.556 1.808v.02h-.073l-6.61-1.828-.402-5.076h3.195l.234 2.552 3.583.97 3.595-.97.402-4.165H8.788L7.93 6.37h16.145z" fill="#eb6428"/></svg>
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index e12f62f4ad..964bce01da 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -30,6 +30,7 @@
#include "os_web.h"
+#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
@@ -157,7 +158,22 @@ void OS_Web::vibrate_handheld(int p_duration_ms) {
}
String OS_Web::get_user_data_dir() const {
- return "/userfs";
+ String userfs = "/userfs";
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
+ if (!appname.is_empty()) {
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
+ if (use_custom_dir) {
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
+ if (custom_dir.is_empty()) {
+ custom_dir = appname;
+ }
+ return userfs.path_join(custom_dir).replace("\\", "/");
+ } else {
+ return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/");
+ }
+ }
+
+ return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
}
String OS_Web::get_cache_path() const {
diff --git a/platform/web/run_icon.png b/platform/web/run_icon.png
deleted file mode 100644
index 574abb0150..0000000000
--- a/platform/web/run_icon.png
+++ /dev/null
Binary files differ
diff --git a/platform/web/run_icon.svg b/platform/web/run_icon.svg
new file mode 100644
index 0000000000..494f53cb90
--- /dev/null
+++ b/platform/web/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M3.143 1 5.48 27.504 15.967 31l10.553-3.496L28.857 1ZM23.78 9.565H11.473l.275 3.308h11.759l-.911 9.937-6.556 1.808v.02h-.073l-6.61-1.828-.402-5.076h3.195l.234 2.552 3.583.97 3.595-.97.402-4.165H8.788L7.93 6.37h16.145Z" fill="#eb6428" style="fill:#e0e0e0;fill-opacity:1" transform="translate(.586 .586) scale(.46337)"/></svg>
diff --git a/platform/windows/README.md b/platform/windows/README.md
index c04032ae1d..4c775576fe 100644
--- a/platform/windows/README.md
+++ b/platform/windows/README.md
@@ -7,7 +7,7 @@ used by this platform.
## Documentation
-- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html)
+- [Compiling for Windows](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html)
- Instructions on building this platform port from source.
- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 2d787c84e2..631543763b 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -735,9 +735,23 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
wd.no_focus = true;
}
+ if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) {
+ wd.mpass = true;
+ }
if (p_flags & WINDOW_FLAG_POPUP_BIT) {
wd.is_popup = true;
}
+ if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) {
+ 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;
+ bb.fEnable = TRUE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+
+ wd.layered_window = true;
+ }
// Inherit icons from MAIN_WINDOW for all sub windows.
HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0);
@@ -775,6 +789,9 @@ void DisplayServerWindows::show_window(WindowID p_id) {
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
SetFocus(wd.hWnd); // Set keyboard focus.
}
+ if (wd.always_on_top) {
+ SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
+ }
}
void DisplayServerWindows::delete_sub_window(WindowID p_window) {
@@ -918,7 +935,7 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p
void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
- if (windows[p_window].mpath.size() == 0) {
+ if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) {
SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
} else {
POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size());
@@ -1499,6 +1516,10 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.no_focus = p_enabled;
_update_window_style(p_window);
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ _update_window_mouse_passthrough(p_window);
+ } break;
case WINDOW_FLAG_POPUP: {
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
@@ -1530,6 +1551,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -2464,6 +2488,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_NCHITTEST: {
+ if (windows[window_id].mpass) {
+ return HTTRANSPARENT;
+ }
+ } break;
case WM_MOUSEACTIVATE: {
if (windows[window_id].no_focus) {
return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages.
@@ -3656,7 +3685,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle;
DWORD dwStyle;
- _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
RECT WindowRect;
@@ -4130,18 +4159,20 @@ DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_drive
if (r_error != OK) {
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");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s --rendering-driver opengl3'\n\n"
+ "If you have recently updated your video card drivers, try rebooting.",
+ executable_name),
+ "Unable to initialize Vulkan 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");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your video card drivers.\n\n"
+ "If you have recently updated your video card drivers, try rebooting.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 84f2dee35e..ce4b94af59 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -370,6 +370,7 @@ class DisplayServerWindows : public DisplayServer {
bool window_has_focus = false;
bool exclusive = false;
bool context_created = false;
+ bool mpass = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index b0e2f5a05b..4112bb84b5 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -51,7 +51,6 @@ void register_windows_exporter() {
Ref<EditorExportPlatformWindows> platform;
platform.instantiate();
- platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo))));
platform->set_name("Windows Desktop");
platform->set_os_name("Windows");
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 7c61a79fc8..bf32b16018 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -34,6 +34,14 @@
#include "core/io/image_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "platform/windows/logo_svg.gen.h"
+#include "platform/windows/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
@@ -168,9 +176,39 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset>
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- String pck_path = p_path;
- if (p_preset->get("binary_format/embed_pck")) {
- pck_path = p_path.get_basename() + ".tmp";
+ bool export_as_zip = p_path.ends_with("zip");
+ bool embedded = p_preset->get("binary_format/embed_pck");
+
+ String pkg_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ // Setup temp folder.
+ String path = p_path;
+ String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+ Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
+ if (export_as_zip) {
+ if (tmp_app_dir.is_null()) {
+ return ERR_CANT_CREATE;
+ }
+ if (DirAccess::exists(tmp_dir_path)) {
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ }
+ }
+ tmp_app_dir->make_dir_recursive(tmp_dir_path);
+ path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe");
+ }
+
+ // Export project.
+ String pck_path = path;
+ if (embedded) {
+ pck_path = pck_path.get_basename() + ".tmp";
}
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
@@ -181,7 +219,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
- if (p_preset->get("binary_format/embed_pck") && err == OK) {
+ if (embedded && err == OK) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->rename(pck_path, p_path);
if (err != OK) {
@@ -189,6 +227,27 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
+ // ZIP project.
+ if (export_as_zip) {
+ if (FileAccess::exists(p_path)) {
+ OS::get_singleton()->move_to_trash(p_path);
+ }
+
+ Ref<FileAccess> io_fa_dst;
+ zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
+
+ zip_folder_recursive(zip, tmp_dir_path, "", pkg_name);
+
+ zipClose(zip, nullptr);
+
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(pkg_name);
+ }
+ }
+
return err;
}
@@ -199,6 +258,7 @@ String EditorExportPlatformWindows::get_template_file_name(const String &p_targe
List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
list.push_back("exe");
+ list.push_back("zip");
return list;
}
@@ -212,6 +272,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
@@ -235,6 +296,29 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+
+ String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
+ "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
+ "$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n"
+ "$settings = New-ScheduledTaskSettingsSet\n"
+ "$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n"
+ "Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n"
+ "Start-ScheduledTask -TaskName godot_remote_debug\n"
+ "while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue";
+
+ String cleanup_script = "Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n"
+ "Remove-Item -Recurse -Force '{temp_dir}'";
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
}
Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {
@@ -659,3 +743,227 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
}
return OK;
}
+
+Ref<Texture2D> EditorExportPlatformWindows::get_run_icon() const {
+ return run_icon;
+}
+
+bool EditorExportPlatformWindows::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool());
+ if (ssh_pid != 0 || !cleanup_commands.is_empty()) {
+ if (menu_options == 0) {
+ cleanup();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformWindows::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformWindows::get_options_count() const {
+ return menu_options;
+}
+
+String EditorExportPlatformWindows::get_option_label(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Windows system");
+}
+
+String EditorExportPlatformWindows::get_option_tooltip(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Windows system");
+}
+
+void EditorExportPlatformWindows::cleanup() {
+ if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) {
+ print_line("Terminating connection...");
+ OS::get_singleton()->kill(ssh_pid);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (!cleanup_commands.is_empty()) {
+ print_line("Stopping and deleting previous version...");
+ for (const SSHCleanupCommand &cmd : cleanup_commands) {
+ if (cmd.wait) {
+ ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ } else {
+ ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ }
+ }
+ }
+ ssh_pid = 0;
+ cleanup_commands.clear();
+}
+
+Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ cleanup();
+ if (p_device) { // Stop command, cleanup only.
+ return OK;
+ }
+
+ EditorProgress ep("run", TTR("Running..."), 5);
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows");
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest);
+ return err;
+ }
+ }
+
+ String host = p_preset->get("ssh_remote_deploy/host").operator String();
+ String port = p_preset->get("ssh_remote_deploy/port").operator String();
+ if (port.is_empty()) {
+ port = "22";
+ }
+ Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" ");
+ Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" ");
+
+ const String basepath = dest.path_join("tmp_windows_export");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (da->file_exists(basepath + ".zip")) { \
+ da->remove(basepath + ".zip"); \
+ } \
+ if (da->file_exists(basepath + "_start.ps1")) { \
+ da->remove(basepath + "_start.ps1"); \
+ } \
+ if (da->file_exists(basepath + "_clean.ps1")) { \
+ da->remove(basepath + "_clean.ps1"); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ if (ep.step(TTR("Exporting project..."), 1)) {
+ return ERR_SKIP;
+ }
+ Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags);
+ if (err != OK) {
+ DirAccess::remove_file_or_error(basepath + ".zip");
+ return err;
+ }
+
+ String cmd_args;
+ {
+ Vector<String> cmd_args_list;
+ gen_debug_flags(cmd_args_list, p_debug_flags);
+ for (int i = 0; i < cmd_args_list.size(); i++) {
+ if (i != 0) {
+ cmd_args += " ";
+ }
+ cmd_args += cmd_args_list[i];
+ }
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+ print_line("Creating temporary directory...");
+ ep.step(TTR("Creating temporary directory..."), 2);
+ String temp_dir;
+ err = ssh_run_on_remote(host, port, extra_args_ssh, "powershell -command \\\"\\$tmp = Join-Path \\$Env:Temp \\$(New-Guid); New-Item -Type Directory -Path \\$tmp | Out-Null; Write-Output \\$tmp\\\"", &temp_dir);
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Uploading archive...");
+ ep.step(TTR("Uploading archive..."), 3);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ {
+ String run_script = p_preset->get("ssh_remote_deploy/run_script");
+ run_script = run_script.replace("{temp_dir}", temp_dir);
+ run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ run_script = run_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ run_script = run_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_start.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(run_script);
+ }
+
+ {
+ String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script");
+ clean_script = clean_script.replace("{temp_dir}", temp_dir);
+ clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ clean_script = clean_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ clean_script = clean_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_clean.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(clean_script);
+ }
+
+ print_line("Uploading scripts...");
+ ep.step(TTR("Uploading scripts..."), 4);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Starting project...");
+ ep.step(TTR("Starting project..."), 5);
+ err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_start.ps1"), &ssh_pid, (use_remote) ? dbg_port : -1);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ cleanup_commands.clear();
+ cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_clean.ps1")));
+
+ print_line("Project started.");
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
+}
+
+EditorExportPlatformWindows::EditorExportPlatformWindows() {
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
+ set_logo(ImageTexture::create_from_image(img));
+
+ img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ } else {
+ stop_icon.instantiate();
+ }
+}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 96608728d3..fa75a17a1f 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -35,9 +35,32 @@
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
-#include "platform/windows/logo.gen.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
+ struct SSHCleanupCommand {
+ String host;
+ String port;
+ Vector<String> ssh_args;
+ String cmd_args;
+ bool wait = false;
+
+ SSHCleanupCommand(){};
+ SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
+ host = p_host;
+ port = p_port;
+ ssh_args = p_ssh_arg;
+ cmd_args = p_cmd_args;
+ wait = p_wait;
+ };
+ };
+
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+
+ Vector<SSHCleanupCommand> cleanup_commands;
+ OS::ProcessID ssh_pid = 0;
+ int menu_options = 0;
+
Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path);
Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
@@ -53,6 +76,17 @@ public:
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
+
+ virtual Ref<Texture2D> get_run_icon() const override;
+ virtual bool poll_export() override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+ virtual void cleanup() override;
+
+ EditorExportPlatformWindows();
};
#endif // WINDOWS_EXPORT_PLUGIN_H
diff --git a/platform/windows/logo.png b/platform/windows/logo.png
deleted file mode 100644
index f06b463850..0000000000
--- a/platform/windows/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/windows/logo.svg b/platform/windows/logo.svg
new file mode 100644
index 0000000000..77a0b20766
--- /dev/null
+++ b/platform/windows/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m1 5.132 12.295-1.694v11.879H1zm0 21.736 12.295 1.695V16.83H1zm13.647 1.875L31 31V16.83H14.647zm0-25.486v12.06H31V1z" fill="#00abed"/></svg>
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index b3831573cf..130c5f7b97 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1166,8 +1166,17 @@ String OS_Windows::get_environment(const String &p_var) const {
return "";
}
-bool OS_Windows::set_environment(const String &p_var, const String &p_value) const {
- return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data()));
+void OS_Windows::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ Char16String var = p_var.utf16();
+ Char16String value = p_value.utf16();
+ ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data()));
+}
+
+void OS_Windows::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
}
String OS_Windows::get_stdin_string() {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c33e0f6740..05110c2614 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -186,7 +186,8 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
virtual Vector<String> get_system_fonts() const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
diff --git a/platform/windows/run_icon.svg b/platform/windows/run_icon.svg
new file mode 100644
index 0000000000..0897276ef7
--- /dev/null
+++ b/platform/windows/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="stroke-width:.460341;fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 09f4406ffe..5036dd30b1 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -31,6 +31,7 @@
#include "path_2d.h"
#include "core/math/geometry_2d.h"
+#include "scene/main/timer.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
@@ -171,6 +172,12 @@ void Path2D::_curve_changed() {
}
queue_redraw();
+ for (int i = 0; i < get_child_count(); i++) {
+ PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i));
+ if (follow) {
+ follow->path_changed();
+ }
+ }
}
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
@@ -200,6 +207,14 @@ void Path2D::_bind_methods() {
/////////////////////////////////////////////////////////////////////////////////
+void PathFollow2D::path_changed() {
+ if (update_timer && !update_timer->is_stopped()) {
+ update_timer->start();
+ } else {
+ _update_transform();
+ }
+}
+
void PathFollow2D::_update_transform() {
if (!path) {
return;
@@ -230,6 +245,16 @@ void PathFollow2D::_update_transform() {
void PathFollow2D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_timer = memnew(Timer);
+ update_timer->set_wait_time(0.2);
+ update_timer->set_one_shot(true);
+ update_timer->connect("timeout", callable_mp(this, &PathFollow2D::_update_transform));
+ add_child(update_timer, false, Node::INTERNAL_MODE_BACK);
+ }
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
path = Object::cast_to<Path2D>(get_parent());
if (path) {
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 884743dd2a..89c77c49eb 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -34,6 +34,8 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/curve.h"
+class Timer;
+
class Path2D : public Node2D {
GDCLASS(Path2D, Node2D);
@@ -65,6 +67,7 @@ public:
private:
Path2D *path = nullptr;
real_t progress = 0.0;
+ Timer *update_timer = nullptr;
real_t h_offset = 0.0;
real_t v_offset = 0.0;
real_t lookahead = 4.0;
@@ -81,6 +84,8 @@ protected:
static void _bind_methods();
public:
+ void path_changed();
+
void set_progress(real_t p_progress);
real_t get_progress() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index ed07d5d11e..4f282dc0ab 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -482,7 +482,11 @@ void TileMap::set_selected_layer(int p_layer_id) {
ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size());
selected_layer = p_layer_id;
emit_signal(SNAME("changed"));
- _make_all_quadrants_dirty();
+
+ // Update the layers modulation.
+ for (unsigned int layer = 0; layer < layers.size(); layer++) {
+ _rendering_update_layer(layer);
+ }
}
int TileMap::get_selected_layer() const {
@@ -653,8 +657,7 @@ void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
}
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].modulate = p_modulate;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
+ _rendering_update_layer(p_layer);
emit_signal(SNAME("changed"));
}
@@ -703,8 +706,7 @@ void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
}
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].z_index = p_z_index;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
+ _rendering_update_layer(p_layer);
emit_signal(SNAME("changed"));
update_configuration_warnings();
@@ -1103,6 +1105,19 @@ void TileMap::_rendering_update_layer(int p_layer) {
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());
+
+ Color layer_modulate = get_layer_modulate(p_layer);
+ if (selected_layer >= 0 && p_layer != selected_layer) {
+ int z1 = get_layer_z_index(p_layer);
+ int z2 = get_layer_z_index(selected_layer);
+ if (z1 < z2 || (z1 == z2 && p_layer < selected_layer)) {
+ layer_modulate = layer_modulate.darkened(0.5);
+ } else if (z1 > z2 || (z1 == z2 && p_layer > selected_layer)) {
+ layer_modulate = layer_modulate.darkened(0.5);
+ layer_modulate.a *= 0.3;
+ }
+ }
+ rs->canvas_item_set_modulate(ci, layer_modulate);
}
void TileMap::_rendering_cleanup_layer(int p_layer) {
@@ -1145,19 +1160,6 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int prev_z_index = 0;
RID prev_ci;
- 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)) {
- tile_modulate = tile_modulate.darkened(0.5);
- } else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) {
- tile_modulate = tile_modulate.darkened(0.5);
- tile_modulate.a *= 0.3;
- }
- }
-
// Iterate over the cells of the quadrant.
for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
@@ -1227,7 +1229,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
// Drawing the tile in the canvas item.
- 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);
+ draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, get_self_modulate(), tile_data);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -2839,7 +2841,7 @@ void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
const int *r = p_data.ptr();
int offset = (format >= FORMAT_2) ? 3 : 2;
- ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data.");
+ ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset));
clear_layer(p_layer);
@@ -2979,11 +2981,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r
#ifdef TOOLS_ENABLED
Rect2 TileMap::_edit_get_rect() const {
// Return the visible rect of the tilemap
- if (pending_update) {
- const_cast<TileMap *>(this)->_update_dirty_quadrants();
- } else {
- const_cast<TileMap *>(this)->_recompute_rect_cache();
- }
+ const_cast<TileMap *>(this)->_recompute_rect_cache();
return rect_cache;
}
#endif
@@ -3738,6 +3736,22 @@ TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const {
return a;
}
+TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TypedArray<Vector2i>());
+
+ // Returns the cells used in the tilemap.
+ TypedArray<Vector2i> a;
+ for (const KeyValue<Vector2i, TileMapCell> &E : layers[p_layer].tile_map) {
+ if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.source_id) &&
+ (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.get_atlas_coords()) &&
+ (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.alternative_tile)) {
+ a.push_back(E.key);
+ }
+ }
+
+ return a;
+}
+
Rect2i TileMap::get_used_rect() { // Not const because of cache
// Return the rect of the currently used area
if (used_rect_cache_dirty) {
@@ -4030,6 +4044,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMap::get_surrounding_cells);
ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
+ ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "layer", "source_id", "atlas_coords", "alternative_tile"), &TileMap::get_used_cells_by_id, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index d187a917b5..7cf2a2eded 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -179,7 +179,7 @@ private:
FORMAT_2,
FORMAT_3
};
- mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present;
+ mutable DataFormat format = FORMAT_3;
static constexpr float FP_ADJUST = 0.00001;
@@ -340,7 +340,7 @@ public:
VisibilityMode get_navigation_visibility_mode();
// Cells accessors.
- void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
+ void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
void erase_cell(int p_layer, const Vector2i &p_coords);
int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
@@ -377,6 +377,7 @@ public:
Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
TypedArray<Vector2i> get_used_cells(int p_layer) const;
+ TypedArray<Vector2i> get_used_cells_by_id(int p_layer, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
Rect2i get_used_rect(); // Not const because of cache
// Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index a44e66ce2a..fe7f6837f0 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -61,11 +61,7 @@ void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const {
}
bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
- if (p_path == SNAME("override_pose")) {
- set_override_pose(p_value);
- } else if (p_path == SNAME("override_mode")) {
- set_override_mode(p_value);
- } else if (p_path == SNAME("use_external_skeleton")) {
+ if (p_path == SNAME("use_external_skeleton")) {
set_use_external_skeleton(p_value);
} else if (p_path == SNAME("external_skeleton")) {
set_external_skeleton(p_value);
@@ -75,11 +71,7 @@ bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
}
bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
- if (p_path == SNAME("override_pose")) {
- r_ret = get_override_pose();
- } else if (p_path == SNAME("override_mode")) {
- r_ret = get_override_mode();
- } else if (p_path == SNAME("use_external_skeleton")) {
+ if (p_path == SNAME("use_external_skeleton")) {
r_ret = get_use_external_skeleton();
} else if (p_path == SNAME("external_skeleton")) {
r_ret = get_external_skeleton();
@@ -208,14 +200,10 @@ void BoneAttachment3D::_transform_changed() {
Transform3D our_trans = get_transform();
if (use_external_skeleton) {
- our_trans = sk->world_transform_to_global_pose(get_global_transform());
+ our_trans = sk->get_global_transform().affine_inverse() * get_global_transform();
}
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true);
- }
+ sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
}
}
@@ -267,11 +255,7 @@ void BoneAttachment3D::set_override_pose(bool p_override) {
if (!override_pose) {
Skeleton3D *sk = _get_skeleton3d();
if (sk) {
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
- }
+ sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
}
_transform_changed();
}
@@ -282,27 +266,6 @@ bool BoneAttachment3D::get_override_pose() const {
return override_pose;
}
-void BoneAttachment3D::set_override_mode(int p_mode) {
- if (override_pose) {
- Skeleton3D *sk = _get_skeleton3d();
- if (sk) {
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
- }
- }
- override_mode = p_mode;
- _transform_changed();
- return;
- }
- override_mode = p_mode;
-}
-
-int BoneAttachment3D::get_override_mode() const {
- return override_mode;
-}
-
void BoneAttachment3D::set_use_external_skeleton(bool p_use_external) {
use_external_skeleton = p_use_external;
@@ -361,7 +324,7 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) {
if (sk) {
if (!override_pose) {
if (use_external_skeleton) {
- set_global_transform(sk->global_pose_to_world_transform(sk->get_bone_global_pose(bone_idx)));
+ set_global_transform(sk->get_global_transform() * sk->get_bone_global_pose(bone_idx));
} else {
set_transform(sk->get_bone_global_pose(bone_idx));
}
@@ -407,8 +370,6 @@ void BoneAttachment3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_override_pose", "override_pose"), &BoneAttachment3D::set_override_pose);
ClassDB::bind_method(D_METHOD("get_override_pose"), &BoneAttachment3D::get_override_pose);
- ClassDB::bind_method(D_METHOD("set_override_mode", "override_mode"), &BoneAttachment3D::set_override_mode);
- ClassDB::bind_method(D_METHOD("get_override_mode"), &BoneAttachment3D::get_override_mode);
ClassDB::bind_method(D_METHOD("set_use_external_skeleton", "use_external_skeleton"), &BoneAttachment3D::set_use_external_skeleton);
ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton);
@@ -420,4 +381,5 @@ void BoneAttachment3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_pose"), "set_override_pose", "get_override_pose");
}
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index 2065271bbe..327cbaa0ab 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -44,14 +44,8 @@ class BoneAttachment3D : public Node3D {
int bone_idx = -1;
bool override_pose = false;
- int override_mode = 0;
bool _override_dirty = false;
- enum OVERRIDE_MODES {
- MODE_GLOBAL_POSE,
- MODE_LOCAL_POSE,
- };
-
bool use_external_skeleton = false;
NodePath external_skeleton_node;
ObjectID external_skeleton_node_cache;
@@ -86,8 +80,6 @@ public:
void set_override_pose(bool p_override);
bool get_override_pose() const;
- void set_override_mode(int p_mode);
- int get_override_mode() const;
void set_use_external_skeleton(bool p_external_skeleton);
bool get_use_external_skeleton() const;
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index f8c54809da..d0f71768d2 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -442,7 +442,7 @@ void Label3D::_shape() {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- TypedArray<Vector2i> stt;
+ TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 8fc772e4b0..96cc941209 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -143,7 +143,7 @@ private:
void _generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, const Color &p_modulate, int p_priority = 0, int p_outline_size = 0);
protected:
- GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
void _notification(int p_what);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index a6d63619df..6940bad4a6 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -763,7 +763,15 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
MeshesFound &mf = meshes_found.write[m_i];
- Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale;
+ Size2i lightmap_size = mf.mesh->get_lightmap_size_hint();
+
+ if (lightmap_size == Size2i(0, 0)) {
+ // TODO we should compute a size if no lightmap hint is set, as we did in 3.x.
+ // For now set to basic size to avoid crash.
+ lightmap_size = Size2i(64, 64);
+ }
+
+ lightmap_size *= mf.lightmap_scale;
TypedArray<RID> overrides;
overrides.resize(mf.overrides.size());
for (int i = 0; i < mf.overrides.size(); i++) {
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 4eadaa603f..1b46879079 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -33,7 +33,6 @@
#include "core/object/message_queue.h"
#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
@@ -70,13 +69,6 @@ SkinReference::~SkinReference() {
bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
String path = p_path;
-#ifndef _3D_DISABLED
- if (path.begins_with("modification_stack")) {
- set_modification_stack(p_value);
- return true;
- }
-#endif //_3D_DISABLED
-
if (!path.begins_with("bones/")) {
return false;
}
@@ -113,13 +105,6 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
String path = p_path;
-#ifndef _3D_DISABLED
- if (path.begins_with("modification_stack")) {
- r_ret = modification_stack;
- return true;
- }
-#endif //_3D_DISABLED
-
if (!path.begins_with("bones/")) {
return false;
}
@@ -162,14 +147,6 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
-#ifndef _3D_DISABLED
- p_list->push_back(
- PropertyInfo(Variant::OBJECT, "modification_stack",
- PROPERTY_HINT_RESOURCE_TYPE,
- "SkeletonModificationStack3D",
- PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
-#endif //_3D_DISABLED
-
for (PropertyInfo &E : *p_list) {
_validate_property(E);
}
@@ -330,24 +307,10 @@ void Skeleton3D::_notification(int p_what) {
}
}
}
-
- if (modification_stack.is_valid()) {
- execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process);
- }
- } break;
-
- case NOTIFICATION_INTERNAL_PROCESS: {
- if (modification_stack.is_valid()) {
- execute_modifications(get_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_process);
- }
} break;
-
case NOTIFICATION_READY: {
- set_physics_process_internal(true);
- set_process_internal(true);
-
- if (modification_stack.is_valid()) {
- set_modification_stack(modification_stack);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(true);
}
} break;
#endif // _3D_DISABLED
@@ -395,99 +358,6 @@ Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const {
return bones[p_bone].pose_global_no_override;
}
-void Skeleton3D::clear_bones_local_pose_override() {
- for (int i = 0; i < bones.size(); i += 1) {
- bones.write[i].local_pose_override_amount = 0;
- }
- _make_dirty();
-}
-
-void Skeleton3D::set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- bones.write[p_bone].local_pose_override_amount = p_amount;
- bones.write[p_bone].local_pose_override = p_pose;
- bones.write[p_bone].local_pose_override_reset = !p_persistent;
- _make_dirty();
-}
-
-Transform3D Skeleton3D::get_bone_local_pose_override(int p_bone) const {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
- return bones[p_bone].local_pose_override;
-}
-
-void Skeleton3D::update_bone_rest_forward_vector(int p_bone, bool p_force_update) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
-
- if (bones[p_bone].rest_bone_forward_vector.length_squared() > 0 && p_force_update == false) {
- update_bone_rest_forward_axis(p_bone, p_force_update);
- }
-
- // If it is a child/leaf bone...
- if (get_bone_parent(p_bone) > 0) {
- bones.write[p_bone].rest_bone_forward_vector = bones[p_bone].rest.origin.normalized();
- } else {
- // If it has children...
- Vector<int> child_bones = get_bone_children(p_bone);
- if (child_bones.size() > 0) {
- Vector3 combined_child_dir = Vector3(0, 0, 0);
- for (int i = 0; i < child_bones.size(); i++) {
- combined_child_dir += bones[child_bones[i]].rest.origin.normalized();
- }
- combined_child_dir = combined_child_dir / child_bones.size();
- bones.write[p_bone].rest_bone_forward_vector = combined_child_dir.normalized();
- } else {
- WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone));
- WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone");
- bones.write[p_bone].rest_bone_forward_vector = Vector3(0, 1, 0);
- }
- }
- update_bone_rest_forward_axis(p_bone, p_force_update);
-}
-
-void Skeleton3D::update_bone_rest_forward_axis(int p_bone, bool p_force_update) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- if (bones[p_bone].rest_bone_forward_axis > -1 && p_force_update == false) {
- return;
- }
-
- Vector3 forward_axis_absolute = bones[p_bone].rest_bone_forward_vector.abs();
- if (forward_axis_absolute.x > forward_axis_absolute.y && forward_axis_absolute.x > forward_axis_absolute.z) {
- if (bones[p_bone].rest_bone_forward_vector.x > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_X_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_X_FORWARD;
- }
- } else if (forward_axis_absolute.y > forward_axis_absolute.x && forward_axis_absolute.y > forward_axis_absolute.z) {
- if (bones[p_bone].rest_bone_forward_vector.y > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Y_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Y_FORWARD;
- }
- } else {
- if (bones[p_bone].rest_bone_forward_vector.z > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Z_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Z_FORWARD;
- }
- }
-}
-
-Vector3 Skeleton3D::get_bone_axis_forward_vector(int p_bone) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3(0, 0, 0));
- return bones[p_bone].rest_bone_forward_vector;
-}
-
-int Skeleton3D::get_bone_axis_forward_enum(int p_bone) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
- return bones[p_bone].rest_bone_forward_axis;
-}
-
void Skeleton3D::set_motion_scale(float p_motion_scale) {
if (p_motion_scale <= 0) {
motion_scale = 1;
@@ -503,6 +373,10 @@ float Skeleton3D::get_motion_scale() const {
// Skeleton creation api
+uint64_t Skeleton3D::get_version() const {
+ return version;
+}
+
void Skeleton3D::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name.is_empty() || p_name.contains(":") || p_name.contains("/"));
@@ -546,6 +420,7 @@ void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
}
bones.write[p_bone].name = p_name;
+ version++;
}
bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
@@ -1068,23 +943,10 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest;
}
- if (b.local_pose_override_amount >= CMP_EPSILON) {
- Transform3D override_local_pose;
- if (b.parent >= 0) {
- override_local_pose = bonesptr[b.parent].pose_global * b.local_pose_override;
- } else {
- override_local_pose = b.local_pose_override;
- }
- b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount);
- }
-
if (b.global_pose_override_amount >= CMP_EPSILON) {
b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
}
- if (b.local_pose_override_reset) {
- b.local_pose_override_amount = 0.0;
- }
if (b.global_pose_override_reset) {
b.global_pose_override_amount = 0.0;
}
@@ -1100,100 +962,6 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
rest_dirty = false;
}
-// Helper functions
-
-Transform3D Skeleton3D::global_pose_to_world_transform(Transform3D p_global_pose) {
- return get_global_transform() * p_global_pose;
-}
-
-Transform3D Skeleton3D::world_transform_to_global_pose(Transform3D p_world_transform) {
- return get_global_transform().affine_inverse() * p_world_transform;
-}
-
-Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
- if (bones[p_bone_idx].parent >= 0) {
- int parent_bone_idx = bones[p_bone_idx].parent;
- Transform3D conversion_transform = get_bone_global_pose(parent_bone_idx).affine_inverse();
- return conversion_transform * p_global_pose;
- } else {
- return p_global_pose;
- }
-}
-
-Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
- if (bones[p_bone_idx].parent >= 0) {
- int parent_bone_idx = bones[p_bone_idx].parent;
- return bones[parent_bone_idx].pose_global * p_local_pose;
- } else {
- return p_local_pose;
- }
-}
-
-Basis Skeleton3D::global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Basis());
- Basis return_basis = p_basis;
-
- if (bones[p_bone_idx].rest_bone_forward_axis < 0) {
- update_bone_rest_forward_vector(p_bone_idx, true);
- }
-
- if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_X_FORWARD) {
- return_basis.rotate_local(Vector3(0, 1, 0), (Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_X_FORWARD) {
- return_basis.rotate_local(Vector3(0, 1, 0), -(Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Y_FORWARD) {
- return_basis.rotate_local(Vector3(1, 0, 0), -(Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Y_FORWARD) {
- return_basis.rotate_local(Vector3(1, 0, 0), (Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Z_FORWARD) {
- // Do nothing!
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Z_FORWARD) {
- return_basis.rotate_local(Vector3(0, 0, 1), Math_PI);
- }
-
- return return_basis;
-}
-
-// Modifications
-
-#ifndef _3D_DISABLED
-
-void Skeleton3D::set_modification_stack(Ref<SkeletonModificationStack3D> p_stack) {
- if (modification_stack.is_valid()) {
- modification_stack->is_setup = false;
- modification_stack->set_skeleton(nullptr);
- }
-
- modification_stack = p_stack;
- if (modification_stack.is_valid()) {
- modification_stack->set_skeleton(this);
- modification_stack->setup();
- }
-}
-Ref<SkeletonModificationStack3D> Skeleton3D::get_modification_stack() {
- return modification_stack;
-}
-
-void Skeleton3D::execute_modifications(real_t p_delta, int p_execution_mode) {
- if (!modification_stack.is_valid()) {
- return;
- }
-
- // Needed to avoid the issue where the stack looses reference to the skeleton when the scene is saved.
- if (modification_stack->skeleton != this) {
- modification_stack->set_skeleton(this);
- }
-
- modification_stack->execute(p_delta, p_execution_mode);
-}
-
-#endif // _3D_DISABLED
-
void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone);
ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone);
@@ -1204,6 +972,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent);
ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton3D::get_bone_count);
+ ClassDB::bind_method(D_METHOD("get_version"), &Skeleton3D::get_version);
ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest);
@@ -1243,23 +1012,12 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose);
ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override);
- ClassDB::bind_method(D_METHOD("clear_bones_local_pose_override"), &Skeleton3D::clear_bones_local_pose_override);
- ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override);
-
ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms);
ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);
ClassDB::bind_method(D_METHOD("set_motion_scale", "motion_scale"), &Skeleton3D::set_motion_scale);
ClassDB::bind_method(D_METHOD("get_motion_scale"), &Skeleton3D::get_motion_scale);
- // Helper functions
- ClassDB::bind_method(D_METHOD("global_pose_to_world_transform", "global_pose"), &Skeleton3D::global_pose_to_world_transform);
- ClassDB::bind_method(D_METHOD("world_transform_to_global_pose", "world_transform"), &Skeleton3D::world_transform_to_global_pose);
- ClassDB::bind_method(D_METHOD("global_pose_to_local_pose", "bone_idx", "global_pose"), &Skeleton3D::global_pose_to_local_pose);
- ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton3D::local_pose_to_global_pose);
- ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton3D::global_pose_z_forward_to_bone_forward);
-
ClassDB::bind_method(D_METHOD("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only);
ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only);
@@ -1271,11 +1029,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
- // Modifications
- ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton3D::set_modification_stack);
- ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton3D::get_modification_stack);
- ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
#ifndef _3D_DISABLED
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index f66cc2f9ed..3df909d936 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -32,7 +32,6 @@
#define SKELETON_3D_H
#include "scene/3d/node_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/skin.h"
typedef int BoneId;
@@ -64,8 +63,6 @@ public:
~SkinReference();
};
-class SkeletonModificationStack3D;
-
class Skeleton3D : public Node3D {
GDCLASS(Skeleton3D, Node3D);
@@ -104,17 +101,8 @@ private:
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
- real_t local_pose_override_amount;
- bool local_pose_override_reset;
- Transform3D local_pose_override;
-
Vector<int> child_bones;
- // The forward direction vector and rest bone forward axis are cached because they do not change
- // 99% of the time, but recalculating them can be expensive on models with many bones.
- Vector3 rest_bone_forward_vector;
- int rest_bone_forward_axis = -1;
-
Bone() {
parent = -1;
enabled = true;
@@ -124,12 +112,7 @@ private:
physical_bone = nullptr;
cache_parent_physical_bone = nullptr;
#endif // _3D_DISABLED
- local_pose_override_amount = 0;
- local_pose_override_reset = false;
child_bones = Vector<int>();
-
- rest_bone_forward_vector = Vector3(0, 0, 0);
- rest_bone_forward_axis = -1;
}
};
@@ -162,25 +145,13 @@ protected:
void _notification(int p_what);
static void _bind_methods();
-#ifndef _3D_DISABLED
- Ref<SkeletonModificationStack3D> modification_stack;
-#endif // _3D_DISABLED
-
public:
- enum Bone_Forward_Axis {
- BONE_AXIS_X_FORWARD = 0,
- BONE_AXIS_Y_FORWARD = 1,
- BONE_AXIS_Z_FORWARD = 2,
- BONE_AXIS_NEGATIVE_X_FORWARD = 3,
- BONE_AXIS_NEGATIVE_Y_FORWARD = 4,
- BONE_AXIS_NEGATIVE_Z_FORWARD = 5,
- };
-
enum {
NOTIFICATION_UPDATE_SKELETON = 50
};
// skeleton creation api
+ uint64_t get_version() const;
void add_bone(const String &p_name);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
@@ -233,10 +204,6 @@ public:
Transform3D get_bone_global_pose_override(int p_bone) const;
void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
- void clear_bones_local_pose_override();
- Transform3D get_bone_local_pose_override(int p_bone) const;
- void set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
-
void localize_rests(); // used for loaders and tools
Ref<Skin> create_skin_from_rest_transforms();
@@ -247,26 +214,6 @@ public:
void force_update_all_bone_transforms();
void force_update_bone_children_transforms(int bone_idx);
- void update_bone_rest_forward_vector(int p_bone, bool p_force_update = false);
- void update_bone_rest_forward_axis(int p_bone, bool p_force_update = false);
- Vector3 get_bone_axis_forward_vector(int p_bone);
- int get_bone_axis_forward_enum(int p_bone);
-
- // Helper functions
- Transform3D global_pose_to_world_transform(Transform3D p_global_pose);
- Transform3D world_transform_to_global_pose(Transform3D p_transform);
- Transform3D global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose);
- Transform3D local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose);
-
- Basis global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis);
-
- // Modifications
-#ifndef _3D_DISABLED
- Ref<SkeletonModificationStack3D> get_modification_stack();
- void set_modification_stack(Ref<SkeletonModificationStack3D> p_stack);
- void execute_modifications(real_t p_delta, int p_execution_mode);
-#endif // _3D_DISABLED
-
// Physical bone API
void set_animate_physical_bones(bool p_enabled);
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index f35cd3fbc5..75f54a925b 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -249,6 +249,26 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_invers
}
}
+static Vector3 get_bone_axis_forward_vector(Skeleton3D *skeleton, int p_bone) {
+ // If it is a child/leaf bone...
+ if (skeleton->get_bone_parent(p_bone) > 0) {
+ return skeleton->get_bone_rest(p_bone).origin.normalized();
+ }
+ // If it has children...
+ Vector<int> child_bones = skeleton->get_bone_children(p_bone);
+ if (child_bones.size() == 0) {
+ WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone));
+ WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone");
+ return Vector3(0, 1, 0);
+ }
+ Vector3 combined_child_dir = Vector3(0, 0, 0);
+ for (int i = 0; i < child_bones.size(); i++) {
+ combined_child_dir += skeleton->get_bone_rest(child_bones[i]).origin.normalized();
+ }
+ combined_child_dir = combined_child_dir / child_bones.size();
+ return combined_child_dir.normalized();
+}
+
void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) {
if (blending_delta <= 0.01f) {
// Before skipping, make sure we undo the global pose overrides
@@ -287,8 +307,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
new_bone_pose.origin = ci->current_pos;
if (!ci->children.is_empty()) {
- p_task->skeleton->update_bone_rest_forward_vector(ci->bone);
- Vector3 forward_vector = p_task->skeleton->get_bone_axis_forward_vector(ci->bone);
+ Vector3 forward_vector = get_bone_axis_forward_vector(p_task->skeleton, ci->bone);
// Rotate the bone towards the next bone in the chain:
new_bone_pose.basis.rotate_to_align(forward_vector, new_bone_pose.origin.direction_to(ci->children[0].current_pos));
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 1ef0774828..e074927b9b 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -229,15 +229,17 @@ AnimationNodeSync::AnimationNodeSync() {
////////////////////////////////////////////////////////
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
- r_list->push_back(PropertyInfo(Variant::BOOL, active));
- r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
+ r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort"));
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
- if (p_parameter == active || p_parameter == prev_active) {
+ if (p_parameter == request) {
+ return ONE_SHOT_REQUEST_NONE;
+ } else if (p_parameter == active) {
return false;
} else if (p_parameter == time_to_restart) {
return -1;
@@ -246,6 +248,13 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa
}
}
+bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const {
+ if (p_parameter == active) {
+ return true;
+ }
+ return false;
+}
+
void AnimationNodeOneShot::set_fadein_time(double p_time) {
fade_in = p_time;
}
@@ -303,41 +312,42 @@ bool AnimationNodeOneShot::has_filter() const {
}
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
+ OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
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 (!cur_active) {
- //make it as if this node doesn't exist, pass input 0 by.
- if (cur_prev_active) {
- set_parameter(prev_active, false);
- }
+ set_parameter(request, ONE_SHOT_REQUEST_NONE);
+
+ bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;
+ if (cur_request == ONE_SHOT_REQUEST_ABORT) {
+ set_parameter(active, false);
+ set_parameter(time_to_restart, -1);
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ } else if (!do_start && !cur_active) {
if (cur_time_to_restart >= 0.0 && !p_seek) {
cur_time_to_restart -= p_time;
if (cur_time_to_restart < 0) {
- //restart
- set_parameter(active, true);
- cur_active = true;
+ do_start = true; // Restart.
}
set_parameter(time_to_restart, cur_time_to_restart);
}
-
- return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ if (!do_start) {
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ }
}
bool os_seek = p_seek;
-
if (p_seek) {
cur_time = p_time;
}
- bool do_start = !cur_prev_active;
if (do_start) {
cur_time = 0;
os_seek = true;
- set_parameter(prev_active, true);
+ set_parameter(request, ONE_SHOT_REQUEST_NONE);
+ set_parameter(active, true);
}
real_t blend;
@@ -375,7 +385,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
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(time_to_restart, restart_sec);
@@ -419,6 +428,10 @@ void AnimationNodeOneShot::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_NONE);
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FIRE);
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_ABORT);
+
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
}
@@ -640,9 +653,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
anims += inputs[i].name;
}
- r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
- r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
- r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::STRING, current_state, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); // For interface.
+ r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately.
+ r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
+ r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
@@ -650,13 +664,22 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
if (p_parameter == time || p_parameter == prev_xfading) {
return 0.0;
- } else if (p_parameter == prev || p_parameter == prev_current) {
+ } else if (p_parameter == prev_index) {
return -1;
+ } else if (p_parameter == transition_request || p_parameter == current_state) {
+ return String();
} else {
return 0;
}
}
+bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const {
+ if (p_parameter == current_state || p_parameter == current_index) {
+ return true;
+ }
+ return false;
+}
+
String AnimationNodeTransition::get_caption() const {
return "Transition";
}
@@ -702,6 +725,17 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
+int AnimationNodeTransition::find_input_caption(const String &p_name) const {
+ int idx = -1;
+ for (int i = 0; i < MAX_INPUTS; i++) {
+ if (inputs[i].name == p_name) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+}
+
void AnimationNodeTransition::set_xfade_time(double p_fade) {
xfade_time = p_fade;
}
@@ -718,35 +752,62 @@ Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
return xfade_curve;
}
-void AnimationNodeTransition::set_from_start(bool p_from_start) {
- from_start = p_from_start;
+void AnimationNodeTransition::set_reset(bool p_reset) {
+ reset = p_reset;
}
-bool AnimationNodeTransition::is_from_start() const {
- return from_start;
+bool AnimationNodeTransition::is_reset() const {
+ return reset;
}
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
- int cur_current = get_parameter(current);
- int cur_prev = get_parameter(prev);
- int cur_prev_current = get_parameter(prev_current);
+ String cur_transition_request = get_parameter(transition_request);
+ int cur_current_index = get_parameter(current_index);
+ int cur_prev_index = get_parameter(prev_index);
double cur_time = get_parameter(time);
double cur_prev_xfading = get_parameter(prev_xfading);
- bool switched = cur_current != cur_prev_current;
+ bool switched = false;
+ bool restart = false;
+
+ if (!cur_transition_request.is_empty()) {
+ int new_idx = find_input_caption(cur_transition_request);
+ if (new_idx >= 0) {
+ if (cur_current_index == new_idx) {
+ // Transition to same state.
+ restart = reset;
+ cur_prev_xfading = 0;
+ set_parameter(prev_xfading, 0);
+ cur_prev_index = -1;
+ set_parameter(prev_index, -1);
+ } else {
+ switched = true;
+ cur_prev_index = cur_current_index;
+ set_parameter(prev_index, cur_current_index);
+ }
+ cur_current_index = new_idx;
+ set_parameter(current_index, cur_current_index);
+ set_parameter(current_state, cur_transition_request);
+ } else {
+ ERR_PRINT("No such input: '" + cur_transition_request + "'");
+ }
+ cur_transition_request = String();
+ set_parameter(transition_request, cur_transition_request);
+ }
- if (switched) {
- set_parameter(prev_current, cur_current);
- set_parameter(prev, cur_prev_current);
+ // Special case for restart.
+ if (restart) {
+ set_parameter(time, 0);
+ return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ }
- cur_prev = cur_prev_current;
+ if (switched) {
cur_prev_xfading = xfade_time;
cur_time = 0;
- switched = true;
}
- if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) {
+ if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) {
return 0;
}
@@ -754,15 +815,15 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
if (sync) {
for (int i = 0; i < enabled_inputs; i++) {
- if (i != cur_current && i != cur_prev) {
+ if (i != cur_current_index && i != cur_prev_index) {
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
}
}
}
- if (cur_prev < 0) { // process current animation, check for transition
+ if (cur_prev_index < 0) { // process current animation, check for transition
- rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
if (p_seek) {
cur_time = p_time;
@@ -770,8 +831,8 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
cur_time += p_time;
}
- if (inputs[cur_current].auto_advance && rem <= xfade_time) {
- set_parameter(current, (cur_current + 1) % enabled_inputs);
+ if (inputs[cur_current_index].auto_advance && rem <= xfade_time) {
+ set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs));
}
} else { // cross-fading from prev to current
@@ -783,21 +844,21 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
real_t blend_inv = 1.0 - blend;
- if (from_start && !p_seek && switched) { //just switched, seek to start of current
- rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
+ if (reset && !p_seek && switched) { //just switched, seek to start of current
+ rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
} else {
- rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
+ rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
}
if (p_seek) {
- blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
+ blend_input(cur_prev_index, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time = p_time;
} else {
- blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
+ blend_input(cur_prev_index, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time += p_time;
cur_prev_xfading -= p_time;
if (cur_prev_xfading < 0) {
- set_parameter(prev, -1);
+ set_parameter(prev_index, -1);
}
}
}
@@ -829,6 +890,7 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
+ ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption);
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
@@ -836,13 +898,13 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
- ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
- ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
+ ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset);
+ ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset);
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,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::BOOL, "from_start"), "set_from_start", "is_from_start");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
for (int i = 0; i < MAX_INPUTS; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index e72471202e..a1969bb621 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -96,6 +96,12 @@ class AnimationNodeOneShot : public AnimationNodeSync {
GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
public:
+ enum OneShotRequest {
+ ONE_SHOT_REQUEST_NONE,
+ ONE_SHOT_REQUEST_FIRE,
+ ONE_SHOT_REQUEST_ABORT,
+ };
+
enum MixMode {
MIX_MODE_BLEND,
MIX_MODE_ADD
@@ -110,13 +116,8 @@ private:
double autorestart_random_delay = 0.0;
MixMode mix = MIX_MODE_BLEND;
- /* bool active;
- bool do_start;
- double time;
- double remaining;*/
-
+ StringName request = PNAME("request");
StringName active = PNAME("active");
- StringName prev_active = "prev_active";
StringName time = "time";
StringName remaining = "remaining";
StringName time_to_restart = "time_to_restart";
@@ -127,6 +128,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
virtual String get_caption() const override;
@@ -153,6 +155,7 @@ public:
AnimationNodeOneShot();
};
+VARIANT_ENUM_CAST(AnimationNodeOneShot::OneShotRequest)
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
class AnimationNodeAdd2 : public AnimationNodeSync {
@@ -284,22 +287,19 @@ class AnimationNodeTransition : public AnimationNodeSync {
InputData inputs[MAX_INPUTS];
int enabled_inputs = 0;
- /*
- double prev_xfading;
- int prev;
- double time;
- int current;
- int prev_current; */
-
- StringName prev_xfading = "prev_xfading";
- StringName prev = "prev";
StringName time = "time";
- StringName current = PNAME("current");
- StringName prev_current = "prev_current";
+ StringName prev_xfading = "prev_xfading";
+ StringName prev_index = "prev_index";
+ StringName current_index = PNAME("current_index");
+ StringName current_state = PNAME("current_state");
+ StringName transition_request = PNAME("transition_request");
+
+ StringName prev_frame_current = "pf_current";
+ StringName prev_frame_current_idx = "pf_current_idx";
double xfade_time = 0.0;
Ref<Curve> xfade_curve;
- bool from_start = true;
+ bool reset = true;
void _update_inputs();
@@ -310,6 +310,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
virtual String get_caption() const override;
@@ -321,6 +322,7 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
+ int find_input_caption(const String &p_name) const;
void set_xfade_time(double p_fade);
double get_xfade_time() const;
@@ -328,8 +330,8 @@ public:
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
- void set_from_start(bool p_from_start);
- bool is_from_start() const;
+ void set_reset(bool p_reset);
+ bool is_reset() const;
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index f5df64dbdd..2c79e5fe06 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -107,6 +107,15 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
return xfade_curve;
}
+void AnimationNodeStateMachineTransition::set_reset(bool p_reset) {
+ reset = p_reset;
+ emit_changed();
+}
+
+bool AnimationNodeStateMachineTransition::is_reset() const {
+ return reset;
+}
+
void AnimationNodeStateMachineTransition::set_priority(int p_priority) {
priority = p_priority;
emit_changed();
@@ -132,6 +141,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
+ ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset);
+ ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset);
+
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority);
@@ -140,6 +152,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
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::BOOL, "reset"), "set_reset", "is_reset");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_GROUP("Switch", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
@@ -164,18 +179,27 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
////////////////////////////////////////////////////////
-void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) {
- start_request_travel = true;
- start_request = p_state;
+void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) {
+ travel_request = p_state;
+ reset_request_on_teleport = p_reset_on_teleport;
stop_request = false;
}
-void AnimationNodeStateMachinePlayback::start(const StringName &p_state) {
- start_request_travel = false;
+void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) {
+ travel_request = StringName();
+ reset_request = p_reset;
+ _start(p_state);
+}
+
+void AnimationNodeStateMachinePlayback::_start(const StringName &p_state) {
start_request = p_state;
stop_request = false;
}
+void AnimationNodeStateMachinePlayback::next() {
+ next_request = true;
+}
+
void AnimationNodeStateMachinePlayback::stop() {
stop_request = true;
}
@@ -212,7 +236,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
path.clear(); //a new one will be needed
if (current == p_travel) {
- return true; //nothing to do
+ return false; // Will teleport oneself (restart).
}
Vector2 current_pos = p_state_machine->states[current].position;
@@ -323,6 +347,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
}
double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
+ double rem = _process(p_state_machine, p_time, p_seek, p_is_external_seeking);
+ start_request = StringName();
+ next_request = false;
+ stop_request = false;
+ reset_request_on_teleport = false;
+ return rem;
+}
+
+double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
if (p_time == -1) {
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
if (anodesm.is_valid()) {
@@ -335,14 +368,13 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
//if not playing and it can restart, then restart
if (!playing && start_request == StringName()) {
if (!stop_request && p_state_machine->start_node) {
- start(p_state_machine->start_node);
+ _start(p_state_machine->start_node);
} else {
return 0;
}
}
if (playing && stop_request) {
- stop_request = false;
playing = false;
return 0;
}
@@ -350,42 +382,45 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
bool play_start = false;
if (start_request != StringName()) {
- if (start_request_travel) {
- if (!playing) {
- if (!stop_request && p_state_machine->start_node) {
- // can restart, just postpone traveling
- path.clear();
- current = p_state_machine->start_node;
- playing = true;
- play_start = true;
- } else {
- // stopped, invalid state
- String node_name = start_request;
- start_request = StringName(); //clear start request
- ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
- }
- } else {
- if (!_travel(p_state_machine, start_request)) {
- // can't travel, then teleport
- path.clear();
- current = start_request;
- play_start = true;
- }
- start_request = StringName(); //clear start request
- }
+ // teleport to start
+ if (p_state_machine->states.has(start_request)) {
+ path.clear();
+ current = start_request;
+ playing = true;
+ play_start = true;
} else {
- // teleport to start
- if (p_state_machine->states.has(start_request)) {
+ StringName node = start_request;
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ }
+ } else if (travel_request != StringName()) {
+ if (!playing) {
+ if (!stop_request && p_state_machine->start_node) {
+ // can restart, just postpone traveling
path.clear();
- current = start_request;
+ current = p_state_machine->start_node;
playing = true;
play_start = true;
- start_request = StringName(); //clear start request
} else {
- StringName node = start_request;
- start_request = StringName(); //clear start request
- ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ // stopped, invalid state
+ String node_name = travel_request;
+ travel_request = StringName();
+ ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
}
+ } else {
+ if (!_travel(p_state_machine, travel_request)) {
+ // can't travel, then teleport
+ if (p_state_machine->states.has(travel_request)) {
+ path.clear();
+ current = travel_request;
+ play_start = true;
+ reset_request = reset_request_on_teleport;
+ } else {
+ StringName node = travel_request;
+ travel_request = StringName();
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ }
+ }
+ travel_request = StringName();
}
}
@@ -396,8 +431,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = p_state_machine->start_node;
}
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
- pos_current = 0;
+ if (reset_request) {
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
+ pos_current = 0;
+ reset_request = false;
+ }
}
if (!p_state_machine->states.has(current)) {
@@ -421,7 +459,8 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend);
}
- double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+
+ double rem = do_start ? len_current : p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (fading_from != StringName()) {
double fade_blend_inv = 1.0 - fade_blend;
@@ -457,6 +496,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
+ reset_request = p_state_machine->transitions[i].transition->is_reset();
next = path[0];
}
}
@@ -513,6 +553,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
+ reset_request = p_state_machine->transitions[auto_advance_to].transition->is_reset();
}
}
@@ -567,7 +608,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
goto_next = fading_from == StringName();
}
- if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
+ if (next_request || goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
if (next_xfade) {
//time to fade, baby
fading_from = current;
@@ -591,7 +632,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = next;
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
+ if (reset_request) {
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
+ }
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
pos_current = MIN(pos_current, len_current);
p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
@@ -652,8 +695,9 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
}
void AnimationNodeStateMachinePlayback::_bind_methods() {
- ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel);
- ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start);
+ ClassDB::bind_method(D_METHOD("travel", "to_node", "reset_on_teleport"), &AnimationNodeStateMachinePlayback::travel, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("start", "node", "reset"), &AnimationNodeStateMachinePlayback::start, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("next"), &AnimationNodeStateMachinePlayback::next);
ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing);
ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 116589eb2f..8183d2025a 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -57,6 +57,7 @@ private:
StringName advance_condition_name;
float xfade_time = 0.0;
Ref<Curve> xfade_curve;
+ bool reset = true;
int priority = 1;
String advance_expression;
@@ -84,6 +85,9 @@ public:
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
+ void set_reset(bool p_reset);
+ bool is_reset() const;
+
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
@@ -131,10 +135,15 @@ class AnimationNodeStateMachinePlayback : public Resource {
bool playing = false;
StringName start_request;
- bool start_request_travel = false;
+ StringName travel_request;
+ bool reset_request = false;
+ bool reset_request_on_teleport = false;
+ bool next_request = false;
bool stop_request = false;
bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
+ void _start(const StringName &p_state);
+ double _process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
@@ -144,8 +153,9 @@ protected:
static void _bind_methods();
public:
- void travel(const StringName &p_state);
- void start(const StringName &p_state);
+ void travel(const StringName &p_state, bool p_reset_on_teleport = true);
+ void start(const StringName &p_state, bool p_reset = true);
+ void next();
void stop();
bool is_playing() const;
StringName get_current_node() const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 4714282347..0febe580db 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -745,7 +745,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_METHOD: {
- if (!nc->node) {
+ if (!nc->node || is_stopping) {
continue;
}
if (!p_is_current) {
@@ -808,7 +808,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_AUDIO: {
- if (!nc->node) {
+ if (!nc->node || is_stopping) {
continue;
}
@@ -915,6 +915,10 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_ANIMATION: {
+ if (is_stopping) {
+ continue;
+ }
+
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(nc->node);
if (!player) {
continue;
@@ -1658,7 +1662,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa
}
if (get_current_animation() != p_name) {
- _stop_playing_caches();
+ _stop_playing_caches(false);
}
c.current.from = &animation_set[name];
@@ -1732,11 +1736,11 @@ String AnimationPlayer::get_assigned_animation() const {
}
void AnimationPlayer::pause() {
- _stop_internal(false);
+ _stop_internal(false, false);
}
-void AnimationPlayer::stop() {
- _stop_internal(true);
+void AnimationPlayer::stop(bool p_keep_state) {
+ _stop_internal(true, p_keep_state);
}
void AnimationPlayer::set_speed_scale(float p_speed) {
@@ -1808,7 +1812,7 @@ void AnimationPlayer::_animation_changed(const StringName &p_name) {
}
}
-void AnimationPlayer::_stop_playing_caches() {
+void AnimationPlayer::_stop_playing_caches(bool p_reset) {
for (TrackNodeCache *E : playing_caches) {
if (E->node && E->audio_playing) {
E->node->call(SNAME("stop"));
@@ -1818,7 +1822,12 @@ void AnimationPlayer::_stop_playing_caches() {
if (!player) {
continue;
}
- player->stop();
+
+ if (p_reset) {
+ player->stop();
+ } else {
+ player->pause();
+ }
}
}
@@ -1830,7 +1839,7 @@ void AnimationPlayer::_node_removed(Node *p_node) {
}
void AnimationPlayer::clear_caches() {
- _stop_playing_caches();
+ _stop_playing_caches(true);
node_cache_map.clear();
@@ -1951,14 +1960,20 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
processing = p_process;
}
-void AnimationPlayer::_stop_internal(bool p_reset) {
- _stop_playing_caches();
+void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
+ _stop_playing_caches(p_reset);
Playback &c = playback;
c.blend.clear();
if (p_reset) {
+ if (p_keep_state) {
+ c.current.pos = 0;
+ } else {
+ is_stopping = true;
+ seek(0, true);
+ is_stopping = false;
+ }
c.current.from = nullptr;
c.current.speed_scale = 1;
- c.current.pos = 0;
}
_set_process(false);
queued.clear();
@@ -2089,7 +2104,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
old_values->restore();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Animation Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
@@ -2128,7 +2143,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("pause"), &AnimationPlayer::pause);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationPlayer::stop);
+ ClassDB::bind_method(D_METHOD("stop", "keep_state"), &AnimationPlayer::stop, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing);
ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 80ceb70d10..7e7d12f982 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -192,6 +192,7 @@ private:
uint64_t accum_pass = 1;
float speed_scale = 1.0;
double default_blend_time = 0.0;
+ bool is_stopping = false;
struct AnimationData {
String name;
@@ -277,7 +278,7 @@ private:
void _animation_process(double p_delta);
void _node_removed(Node *p_node);
- void _stop_playing_caches();
+ void _stop_playing_caches(bool p_reset);
// bind helpers
Vector<String> _get_animation_list() const {
@@ -294,7 +295,7 @@ private:
void _animation_changed(const StringName &p_name);
void _set_process(bool p_process, bool p_force = false);
- void _stop_internal(bool p_reset);
+ void _stop_internal(bool p_reset, bool p_keep_state);
bool playing = false;
@@ -348,7 +349,7 @@ public:
Vector<String> get_queue();
void clear_queue();
void pause();
- void stop();
+ void stop(bool p_keep_state = false);
bool is_playing() const;
String get_current_animation() const;
void set_current_animation(const String &p_anim);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index ab341797c7..dd00897422 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -54,13 +54,19 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter
return ret;
}
+bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const {
+ bool ret = false;
+ GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret);
+ return ret;
+}
+
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
StringName path = state->tree->property_parent_map[base_path][p_name];
- state->tree->property_map[path] = p_value;
+ state->tree->property_map[path].first = p_value;
}
Variant AnimationNode::get_parameter(const StringName &p_name) const {
@@ -69,7 +75,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), Variant());
StringName path = state->tree->property_parent_map[base_path][p_name];
- return state->tree->property_map[path];
+ return state->tree->property_map[path].first;
}
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -427,6 +433,7 @@ void AnimationNode::_bind_methods() {
GDVIRTUAL_BIND(_get_parameter_list);
GDVIRTUAL_BIND(_get_child_by_name, "name");
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
+ GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
GDVIRTUAL_BIND(_get_caption);
GDVIRTUAL_BIND(_has_filter);
@@ -1889,7 +1896,10 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A
StringName key = pinfo.name;
if (!property_map.has(p_base_path + key)) {
- property_map[p_base_path + key] = node->get_parameter_default_value(key);
+ Pair<Variant, bool> param;
+ param.first = node->get_parameter_default_value(key);
+ param.second = node->is_parameter_read_only(key);
+ property_map[p_base_path + key] = param;
}
property_parent_map[p_base_path][key] = p_base_path + key;
@@ -1931,7 +1941,10 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
}
if (property_map.has(p_name)) {
- property_map[p_name] = p_value;
+ if (is_inside_tree() && property_map[p_name].second) {
+ return false; // Prevent to set property by user.
+ }
+ property_map[p_name].first = p_value;
return true;
}
@@ -1944,7 +1957,7 @@ bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
}
if (property_map.has(p_name)) {
- r_ret = property_map[p_name];
+ r_ret = property_map[p_name].first;
return true;
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 2c1be6199c..52d3e1bd41 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -117,6 +117,7 @@ protected:
GDVIRTUAL0RC(Array, _get_parameter_list)
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
+ GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName)
GDVIRTUAL3RC(double, _process, double, bool, bool)
GDVIRTUAL0RC(String, _get_caption)
GDVIRTUAL0RC(bool, _has_filter)
@@ -124,6 +125,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const;
void set_parameter(const StringName &p_name, const Variant &p_value);
Variant get_parameter(const StringName &p_name) const;
@@ -304,7 +306,7 @@ private:
void _update_properties();
List<PropertyInfo> properties;
HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
- HashMap<StringName, Variant> property_map;
+ HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag.
struct Activity {
uint64_t last_pass = 0;
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index be8c23844f..39d1793368 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -280,7 +280,16 @@ bool Tween::step(double p_delta) {
}
if (!started) {
- ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners.");
+ if (tweeners.is_empty()) {
+ String tween_id;
+ Node *node = get_bound_node();
+ if (node) {
+ tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
+ } else {
+ tween_id = to_string();
+ }
+ ERR_FAIL_V_MSG(false, tween_id + ": started with no Tweeners.");
+ }
current_step = 0;
loops_done = 0;
total_time = 0;
@@ -393,6 +402,15 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, d
return ret;
}
+String Tween::to_string() {
+ String ret = Object::to_string();
+ Node *node = get_bound_node();
+ if (node) {
+ ret += vformat(" (bound to %s)", node->get_name());
+ }
+ return ret;
+}
+
void Tween::_bind_methods() {
ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property);
ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval);
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 08911d6623..58217db535 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -130,6 +130,8 @@ protected:
static void _bind_methods();
public:
+ virtual String to_string() override;
+
Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, double p_duration);
Ref<IntervalTweener> tween_interval(double p_time);
Ref<CallbackTweener> tween_callback(Callable p_callback);
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 9cc25bf743..d0326290ac 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -30,6 +30,7 @@
#include "base_button.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -127,7 +128,6 @@ void BaseButton::_notification(int p_what) {
status.hovering = false;
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
} break;
}
}
@@ -154,14 +154,10 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
if (status.press_attempt && status.pressing_inside) {
if (toggle_mode) {
bool is_pressed = p_event->is_pressed();
- if (Object::cast_to<InputEventShortcut>(*p_event)) {
- is_pressed = false;
- }
if ((is_pressed && action_mode == ACTION_MODE_BUTTON_PRESS) || (!is_pressed && action_mode == ACTION_MODE_BUTTON_RELEASE)) {
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();
@@ -187,7 +183,6 @@ 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"));
}
@@ -212,7 +207,6 @@ void BaseButton::set_disabled(bool p_disabled) {
}
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
}
queue_redraw();
}
@@ -267,6 +261,10 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_DISABLED;
}
+ if (in_shortcut_feedback) {
+ return DRAW_HOVER_PRESSED;
+ }
+
if (!status.press_attempt && status.hovering) {
if (status.pressed) {
return DRAW_HOVER_PRESSED;
@@ -285,7 +283,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
pressing = status.pressed;
}
- if ((shortcut_feedback || !status.shortcut_press) && pressing) {
+ if (pressing) {
return DRAW_PRESSED;
} else {
return DRAW_NORMAL;
@@ -339,6 +337,14 @@ bool BaseButton::is_keep_pressed_outside() const {
return keep_pressed_outside;
}
+void BaseButton::set_shortcut_feedback(bool p_enable) {
+ shortcut_feedback = p_enable;
+}
+
+bool BaseButton::is_shortcut_feedback() const {
+ return shortcut_feedback;
+}
+
void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) {
shortcut = p_shortcut;
set_process_shortcut_input(shortcut.is_valid());
@@ -348,13 +354,45 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
+void BaseButton::_shortcut_feedback_timeout() {
+ in_shortcut_feedback = false;
+ queue_redraw();
+}
+
void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- 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);
+ if (!is_disabled() && p_event->is_pressed() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) {
+ if (toggle_mode) {
+ status.pressed = !status.pressed;
+
+ if (status.pressed) {
+ _unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal(SNAME("pressed"), this);
+ }
+ }
+
+ _toggled(status.pressed);
+ _pressed();
+
+ } else {
+ _pressed();
+ }
+ queue_redraw();
accept_event();
+
+ if (shortcut_feedback) {
+ if (shortcut_feedback_timer == nullptr) {
+ shortcut_feedback_timer = memnew(Timer);
+ add_child(shortcut_feedback_timer);
+ shortcut_feedback_timer->set_wait_time(GLOBAL_GET("gui/timers/button_shortcut_feedback_highlight_time"));
+ shortcut_feedback_timer->connect("timeout", callable_mp(this, &BaseButton::_shortcut_feedback_timeout));
+ }
+
+ in_shortcut_feedback = true;
+ shortcut_feedback_timer->start();
+ }
}
}
@@ -393,14 +431,6 @@ bool BaseButton::_was_pressed_by_mouse() const {
return was_mouse_pressed;
}
-void BaseButton::set_shortcut_feedback(bool p_feedback) {
- shortcut_feedback = p_feedback;
-}
-
-bool BaseButton::is_shortcut_feedback() const {
- return shortcut_feedback;
-}
-
PackedStringArray BaseButton::get_configuration_warnings() const {
PackedStringArray warnings = Control::get_configuration_warnings();
@@ -429,6 +459,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode);
ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside);
ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside);
+ 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);
ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut);
ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut);
@@ -436,9 +468,6 @@ 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_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");
@@ -466,6 +495,8 @@ void BaseButton::_bind_methods() {
BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_PRESS);
BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_RELEASE);
+
+ GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/button_shortcut_feedback_highlight_time", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), 0.2);
}
BaseButton::BaseButton() {
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index f7c864c5fb..962a16c453 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -51,9 +51,9 @@ private:
bool shortcut_in_tooltip = true;
bool was_mouse_pressed = false;
bool keep_pressed_outside = false;
+ bool shortcut_feedback = true;
Ref<Shortcut> shortcut;
ObjectID shortcut_context;
- bool shortcut_feedback = true;
ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE;
struct Status {
@@ -61,7 +61,6 @@ private:
bool hovering = false;
bool press_attempt = false;
bool pressing_inside = false;
- bool shortcut_press = false;
bool disabled = false;
@@ -75,6 +74,10 @@ private:
void on_action_event(Ref<InputEvent> p_event);
+ Timer *shortcut_feedback_timer = nullptr;
+ bool in_shortcut_feedback = false;
+ void _shortcut_feedback_timeout();
+
protected:
virtual void pressed();
virtual void toggled(bool p_pressed);
@@ -122,6 +125,9 @@ public:
void set_keep_pressed_outside(bool p_on);
bool is_keep_pressed_outside() const;
+ void set_shortcut_feedback(bool p_enable);
+ bool is_shortcut_feedback() const;
+
void set_button_mask(BitField<MouseButtonMask> p_mask);
BitField<MouseButtonMask> get_button_mask() const;
@@ -133,9 +139,6 @@ public:
void set_button_group(const Ref<ButtonGroup> &p_group);
Ref<ButtonGroup> get_button_group() const;
- void set_shortcut_feedback(bool p_feedback);
- bool is_shortcut_feedback() const;
-
PackedStringArray get_configuration_warnings() const override;
BaseButton();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 7539810feb..c977d9d2fb 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -548,7 +548,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (k->is_action("ui_text_dedent", true)) {
- do_unindent();
+ unindent_lines();
accept_event();
return;
}
@@ -898,50 +898,6 @@ void CodeEdit::indent_lines() {
end_complex_operation();
}
-void CodeEdit::do_unindent() {
- if (!is_editable()) {
- return;
- }
-
- int cc = get_caret_column();
-
- if (has_selection() || cc <= 0) {
- unindent_lines();
- 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] != ' ') {
- 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;
- }
- }
- remove_text(cl, cc - spaces_to_remove, cl, cc);
- set_caret_column(MAX(0, cc - spaces_to_remove), c == 0, c);
- }
- }
- end_complex_operation();
-}
-
void CodeEdit::unindent_lines() {
if (!is_editable()) {
return;
@@ -2086,9 +2042,11 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
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;
// Strings do not nest like brackets, so ensure we don't add an additional closing pair.
- if (has_string_delimiter(String::chr(last_completion_char)) && post_brace_pair != -1 && last_char_matches) {
- remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
- adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ if (has_string_delimiter(String::chr(last_completion_char))) {
+ if (post_brace_pair != -1 && last_char_matches) {
+ remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ }
} else {
if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && last_char_matches) {
remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
@@ -2202,7 +2160,6 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_auto_indent_prefixes"), &CodeEdit::get_auto_indent_prefixes);
ClassDB::bind_method(D_METHOD("do_indent"), &CodeEdit::do_indent);
- ClassDB::bind_method(D_METHOD("do_unindent"), &CodeEdit::do_unindent);
ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines);
ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index c050b2266f..55fc5aa2ae 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -289,7 +289,6 @@ public:
TypedArray<String> get_auto_indent_prefixes() const;
void do_indent();
- void do_unindent();
void indent_lines();
void unindent_lines();
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b5846cb692..b0261dcf23 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -642,7 +642,7 @@ inline int ColorPicker::_get_preset_size() {
void ColorPicker::_add_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\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
- btn_preset_new->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCDU(btn_preset_new, ColorPicker);
btn_preset_new->set_button_group(preset_group);
preset_container->add_child(btn_preset_new);
btn_preset_new->set_pressed(true);
@@ -1544,10 +1544,6 @@ void ColorPicker::_bind_methods() {
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");
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 4188946494..fead0878fb 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -758,6 +758,7 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
}
void Control::set_begin(const Size2 &p_point) {
+ ERR_FAIL_COND(!isfinite(p_point.x) || !isfinite(p_point.y));
if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
return;
}
@@ -1405,6 +1406,7 @@ void Control::_set_size(const Size2 &p_size) {
}
void Control::set_size(const Size2 &p_size, bool p_keep_offsets) {
+ ERR_FAIL_COND(!isfinite(p_size.x) || !isfinite(p_size.y));
Size2 new_size = p_size;
Size2 min = get_combined_minimum_size();
if (new_size.x < min.x) {
@@ -1580,10 +1582,6 @@ void Control::set_block_minimum_size_adjust(bool p_block) {
data.block_minimum_size_adjust = p_block;
}
-bool Control::is_minimum_size_adjust_blocked() const {
- return data.block_minimum_size_adjust;
-}
-
Size2 Control::get_minimum_size() const {
Vector2 ms;
GDVIRTUAL_CALL(_get_minimum_size, ms);
@@ -1595,7 +1593,7 @@ void Control::set_custom_minimum_size(const Size2 &p_custom) {
return;
}
- if (isnan(p_custom.x) || isnan(p_custom.y)) {
+ if (!isfinite(p_custom.x) || !isfinite(p_custom.y)) {
// Prevent infinite loop.
return;
}
@@ -1821,19 +1819,6 @@ bool Control::is_focus_owner_in_shortcut_context() const {
// Drag and drop handling.
-void Control::set_drag_forwarding_compat(Object *p_base) {
- if (p_base != nullptr) {
- data.forward_drag = Callable(p_base, "_get_drag_data_fw").bind(this);
- data.forward_can_drop = Callable(p_base, "_can_drop_data_fw").bind(this);
- data.forward_drop = Callable(p_base, "_drop_data_fw").bind(this);
-
- } else {
- data.forward_drag = Callable();
- data.forward_can_drop = Callable();
- data.forward_drop = Callable();
- }
-}
-
void Control::set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop) {
data.forward_drag = p_drag;
data.forward_can_drop = p_can_drop;
@@ -2780,9 +2765,9 @@ void Control::end_bulk_theme_override() {
// Internationalization.
-TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+TypedArray<Vector3i> 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;
+ TypedArray<Vector3i> ret;
GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
return ret;
} else {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 22a37dd89e..a93a88e5b4 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -145,7 +145,7 @@ public:
TEXT_DIRECTION_AUTO = TextServer::DIRECTION_AUTO,
TEXT_DIRECTION_LTR = TextServer::DIRECTION_LTR,
TEXT_DIRECTION_RTL = TextServer::DIRECTION_RTL,
- TEXT_DIRECTION_INHERITED,
+ TEXT_DIRECTION_INHERITED = TextServer::DIRECTION_INHERITED,
};
private:
@@ -330,7 +330,7 @@ protected:
// Internationalization.
- virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ virtual TypedArray<Vector3i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
// Base object overrides.
@@ -340,7 +340,7 @@ protected:
// Exposed virtual methods.
GDVIRTUAL1RC(bool, _has_point, Vector2)
- GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
GDVIRTUAL0RC(Vector2, _get_minimum_size)
GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
@@ -464,7 +464,6 @@ public:
void update_minimum_size();
void set_block_minimum_size_adjust(bool p_block);
- bool is_minimum_size_adjust_blocked() const;
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
@@ -503,7 +502,6 @@ public:
// Drag and drop handling.
virtual void set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop);
- virtual void set_drag_forwarding_compat(Object *p_base);
virtual Variant get_drag_data(const Point2 &p_point);
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
@@ -634,4 +632,10 @@ VARIANT_ENUM_CAST(Control::LayoutMode);
VARIANT_ENUM_CAST(Control::LayoutDirection);
VARIANT_ENUM_CAST(Control::TextDirection);
+// G = get_drag_data_fw, C = can_drop_data_fw, D = drop_data_fw, U = underscore
+#define SET_DRAG_FORWARDING_CD(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_CDU(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_GCD(from, to) from->set_drag_forwarding(callable_mp(this, &to::get_drag_data_fw).bind(from), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_GCDU(from, to) from->set_drag_forwarding(callable_mp(this, &to::_get_drag_data_fw).bind(from), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from));
+
#endif // CONTROL_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 2fd6d666e5..6c495ab2c9 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1496,6 +1496,7 @@ float GraphEdit::get_zoom() const {
void GraphEdit::set_zoom_step(float p_zoom_step) {
p_zoom_step = abs(p_zoom_step);
+ ERR_FAIL_COND(!isfinite(p_zoom_step));
if (zoom_step == p_zoom_step) {
return;
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 372baeadae..25a27d5e1a 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -309,12 +309,6 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) {
shape_changed = true;
}
-Ref<Texture2D> ItemList::get_item_tag_icon(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Texture2D>());
-
- return items[p_idx].tag_icon;
-}
-
void ItemList::set_item_selectable(int p_idx, bool p_selectable) {
if (p_idx < 0) {
p_idx += get_item_count();
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 848f9a2ba9..934318dbb4 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -191,7 +191,6 @@ public:
Variant get_item_metadata(int p_idx) const;
void set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon);
- Ref<Texture2D> get_item_tag_icon(int p_idx) const;
void set_item_tooltip_enabled(int p_idx, const bool p_enabled);
bool is_item_tooltip_enabled(int p_idx) const;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index cafea83f16..f59702835c 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -222,6 +222,7 @@ void Label::_shape() {
}
}
lines_dirty = false;
+ lines_shaped_last_width = get_size().width;
}
_update_visible();
@@ -596,7 +597,13 @@ void Label::_notification(int p_what) {
} break;
case NOTIFICATION_RESIZED: {
- lines_dirty = true;
+ // It may happen that the reshaping due to this size change triggers a cascade of re-layout
+ // across the hierarchy where this label belongs to in a way that its size changes multiple
+ // times, but ending up with the original size it was already shaped for.
+ // This check prevents the catastrophic, freezing infinite cascade of re-layout.
+ if (lines_shaped_last_width != get_size().width) {
+ lines_dirty = true;
+ }
} break;
}
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 2350525236..b80646810b 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -49,6 +49,8 @@ private:
bool uppercase = false;
bool lines_dirty = true;
+ int lines_shaped_last_width = -1;
+
bool dirty = true;
bool font_dirty = true;
RID text_rid;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 5ab64b35fd..a7e50a765e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -4074,8 +4074,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL;
} else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
st_parser_type = TextServer::STRUCTURED_TEXT_LIST;
- } else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
- st_parser_type = TextServer::STRUCTURED_TEXT_NONE;
+ } else if (subtag_a[1] == "n" || subtag_a[1] == "gdscript") {
+ st_parser_type = TextServer::STRUCTURED_TEXT_GDSCRIPT;
} else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM;
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3457cfa94f..208cb29772 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -954,9 +954,6 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab")));
@@ -975,7 +972,7 @@ void TabContainer::_bind_methods() {
TabContainer::TabContainer() {
tab_bar = memnew(TabBar);
- tab_bar->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCDU(tab_bar, TabContainer);
add_child(tab_bar, false, INTERNAL_MODE_FRONT);
tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 108a533a74..8ffaa9e81f 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1208,7 +1208,15 @@ void TextEdit::_notification(int p_what) {
char_ofs = 0;
}
for (int j = 0; j < gl_size; j++) {
- const Variant *color_data = color_map.getptr(glyphs[j].start);
+ int64_t color_start = -1;
+ for (const Variant *key = color_map.next(nullptr); key; key = color_map.next(key)) {
+ if (int64_t(*key) <= glyphs[j].start) {
+ color_start = *key;
+ } else {
+ break;
+ }
+ }
+ const Variant *color_data = (color_start >= 0) ? color_map.getptr(color_start) : nullptr;
if (color_data != nullptr) {
current_color = (color_data->operator Dictionary()).get("color", font_color);
if (!editable && current_color.a > font_readonly_color.a) {
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 5a3f4af106..20472ab46e 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -178,6 +178,16 @@ void TextureRect::_bind_methods() {
BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED);
}
+#ifndef DISABLE_DEPRECATED
+bool TextureRect::_set(const StringName &p_name, const Variant &p_value) {
+ if ((p_name == SNAME("expand") || p_name == SNAME("ignore_texture_size")) && p_value.operator bool()) {
+ expand_mode = EXPAND_IGNORE_SIZE;
+ return true;
+ }
+ return false;
+}
+#endif
+
void TextureRect::_texture_changed() {
if (texture.is_valid()) {
queue_redraw();
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 6f17ebd87f..2425c6094b 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -69,6 +69,9 @@ protected:
void _notification(int p_what);
virtual Size2 get_minimum_size() const override;
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
public:
void set_texture(const Ref<Texture2D> &p_tex);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 3458b87b8d..2d985c2324 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -332,7 +332,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, TextServer::Struc
}
TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_column) const {
- ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_NONE);
+ ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_DEFAULT);
return cells[p_column].st_parser;
}
@@ -657,7 +657,7 @@ int TreeItem::get_custom_minimum_height() const {
/* Item manipulation */
-TreeItem *TreeItem::create_child(int p_idx) {
+TreeItem *TreeItem::create_child(int p_index) {
TreeItem *ti = memnew(TreeItem(tree));
if (tree) {
ti->cells.resize(tree->columns.size());
@@ -669,7 +669,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
int idx = 0;
while (c) {
- if (idx++ == p_idx) {
+ if (idx++ == p_index) {
c->prev = ti;
ti->next = c;
break;
@@ -683,7 +683,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
ti->prev = l_prev;
if (!children_cache.is_empty()) {
if (ti->next) {
- children_cache.insert(p_idx, ti);
+ children_cache.insert(p_index, ti);
} else {
children_cache.append(ti);
}
@@ -826,15 +826,15 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return next_item;
}
-TreeItem *TreeItem::get_child(int p_idx) {
+TreeItem *TreeItem::get_child(int p_index) {
_create_children_cache();
- if (p_idx < 0) {
- p_idx += children_cache.size();
+ if (p_index < 0) {
+ p_index += children_cache.size();
}
- ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
+ ERR_FAIL_INDEX_V(p_index, children_cache.size(), nullptr);
- return children_cache.get(p_idx);
+ return children_cache.get(p_index);
}
int TreeItem::get_visible_child_count() {
@@ -1058,28 +1058,28 @@ int TreeItem::get_button_count(int p_column) const {
return cells[p_column].buttons.size();
}
-Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const {
+Ref<Texture2D> TreeItem::get_button(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), Ref<Texture2D>());
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), Ref<Texture2D>());
- return cells[p_column].buttons[p_idx].texture;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), Ref<Texture2D>());
+ return cells[p_column].buttons[p_index].texture;
}
-String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const {
+String TreeItem::get_button_tooltip_text(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), String());
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String());
- return cells[p_column].buttons[p_idx].tooltip;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), String());
+ return cells[p_column].buttons[p_index].tooltip;
}
-int TreeItem::get_button_id(int p_column, int p_idx) const {
+int TreeItem::get_button_id(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), -1);
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1);
- return cells[p_column].buttons[p_idx].id;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), -1);
+ return cells[p_column].buttons[p_index].id;
}
-void TreeItem::erase_button(int p_column, int p_idx) {
+void TreeItem::erase_button(int p_column, int p_index) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells.write[p_column].buttons.remove_at(p_idx);
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
+ cells.write[p_column].buttons.remove_at(p_index);
_changed_notify(p_column);
}
@@ -1094,52 +1094,52 @@ int TreeItem::get_button_by_id(int p_column, int p_id) const {
return -1;
}
-void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button) {
+void TreeItem::set_button(int p_column, int p_index, const Ref<Texture2D> &p_button) {
ERR_FAIL_COND(p_button.is_null());
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].texture == p_button) {
+ if (cells[p_column].buttons[p_index].texture == p_button) {
return;
}
- cells.write[p_column].buttons.write[p_idx].texture = p_button;
+ cells.write[p_column].buttons.write[p_index].texture = p_button;
cells.write[p_column].cached_minimum_size_dirty = true;
_changed_notify(p_column);
}
-void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) {
+void TreeItem::set_button_color(int p_column, int p_index, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].color == p_color) {
+ if (cells[p_column].buttons[p_index].color == p_color) {
return;
}
- cells.write[p_column].buttons.write[p_idx].color = p_color;
+ cells.write[p_column].buttons.write[p_index].color = p_color;
_changed_notify(p_column);
}
-void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) {
+void TreeItem::set_button_disabled(int p_column, int p_index, bool p_disabled) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].disabled == p_disabled) {
+ if (cells[p_column].buttons[p_index].disabled == p_disabled) {
return;
}
- cells.write[p_column].buttons.write[p_idx].disabled = p_disabled;
+ cells.write[p_column].buttons.write[p_index].disabled = p_disabled;
cells.write[p_column].cached_minimum_size_dirty = true;
_changed_notify(p_column);
}
-bool TreeItem::is_button_disabled(int p_column, int p_idx) const {
+bool TreeItem::is_button_disabled(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), false);
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), false);
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), false);
- return cells[p_column].buttons[p_idx].disabled;
+ return cells[p_column].buttons[p_index].disabled;
}
void TreeItem::set_editable(int p_column, bool p_editable) {
@@ -1497,15 +1497,15 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count);
- ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text);
- ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id);
+ ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_index"), &TreeItem::get_button_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_index"), &TreeItem::get_button_id);
ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id);
- ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button);
- 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("get_button", "column", "button_index"), &TreeItem::get_button);
+ ClassDB::bind_method(D_METHOD("set_button", "column", "button_index", "button"), &TreeItem::set_button);
+ ClassDB::bind_method(D_METHOD("erase_button", "column", "button_index"), &TreeItem::erase_button);
+ ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_index", "disabled"), &TreeItem::set_button_disabled);
+ ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_index", "color"), &TreeItem::set_button_color);
+ ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_index"), &TreeItem::is_button_disabled);
ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text);
@@ -1518,7 +1518,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
- ClassDB::bind_method(D_METHOD("create_child", "idx"), &TreeItem::create_child, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("create_child", "index"), &TreeItem::create_child, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree);
ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
@@ -1529,7 +1529,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_child", "idx"), &TreeItem::get_child);
+ ClassDB::bind_method(D_METHOD("get_child", "index"), &TreeItem::get_child);
ClassDB::bind_method(D_METHOD("get_child_count"), &TreeItem::get_child_count);
ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index);
@@ -4108,14 +4108,14 @@ Size2 Tree::get_minimum_size() const {
}
}
-TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
+TreeItem *Tree::create_item(TreeItem *p_parent, int p_index) {
ERR_FAIL_COND_V(blocked > 0, nullptr);
TreeItem *ti = nullptr;
if (p_parent) {
ERR_FAIL_COND_V_MSG(p_parent->tree != this, nullptr, "A different tree owns the given parent");
- ti = p_parent->create_child(p_idx);
+ ti = p_parent->create_child(p_index);
} else {
if (!root) {
// No root exists, make the given item the new root.
@@ -4126,7 +4126,7 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
root = ti;
} else {
// Root exists, append or insert to root.
- ti = create_item(root, p_idx);
+ ti = create_item(root, p_index);
}
}
@@ -5162,7 +5162,7 @@ bool Tree::get_allow_reselect() const {
void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &Tree::clear);
- ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("create_item", "parent", "index"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root);
ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index e0ed5fdfb5..ec639ce439 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -247,15 +247,15 @@ public:
void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = "");
int get_button_count(int p_column) const;
- String get_button_tooltip_text(int p_column, int p_idx) const;
- Ref<Texture2D> get_button(int p_column, int p_idx) const;
- int get_button_id(int p_column, int p_idx) const;
- void erase_button(int p_column, int p_idx);
+ String get_button_tooltip_text(int p_column, int p_index) const;
+ Ref<Texture2D> get_button(int p_column, int p_index) const;
+ int get_button_id(int p_column, int p_index) const;
+ void erase_button(int p_column, int p_index);
int get_button_by_id(int p_column, int p_id) const;
- void set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button);
- void set_button_color(int p_column, int p_idx, const Color &p_color);
- void set_button_disabled(int p_column, int p_idx, bool p_disabled);
- bool is_button_disabled(int p_column, int p_idx) const;
+ void set_button(int p_column, int p_index, const Ref<Texture2D> &p_button);
+ void set_button_color(int p_column, int p_index, const Color &p_color);
+ void set_button_disabled(int p_column, int p_index, bool p_disabled);
+ bool is_button_disabled(int p_column, int p_index) const;
/* range works for mode number or mode combo */
@@ -329,7 +329,7 @@ public:
/* Item manipulation */
- TreeItem *create_child(int p_idx = -1);
+ TreeItem *create_child(int p_index = -1);
Tree *get_tree() const;
@@ -341,7 +341,7 @@ public:
TreeItem *get_prev_visible(bool p_wrap = false);
TreeItem *get_next_visible(bool p_wrap = false);
- TreeItem *get_child(int p_idx);
+ TreeItem *get_child(int p_index);
int get_visible_child_count();
int get_child_count();
TypedArray<TreeItem> get_children();
@@ -647,7 +647,7 @@ public:
void clear();
- TreeItem *create_item(TreeItem *p_parent = nullptr, int p_idx = -1);
+ TreeItem *create_item(TreeItem *p_parent = nullptr, int p_index = -1);
TreeItem *get_root() const;
TreeItem *get_last_item() const;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 3f98b540fc..a4af7988c6 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -483,7 +483,7 @@ bool CanvasItem::is_y_sort_enabled() const {
return y_sort_enabled;
}
-void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash) {
+void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash, bool p_aligned) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
float length = (p_to - p_from).length();
@@ -492,14 +492,20 @@ void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, cons
return;
}
- Point2 off = p_from;
Vector2 step = p_dash * (p_to - p_from).normalized();
- int steps = length / p_dash / 2;
- for (int i = 0; i < steps; i++) {
- RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, off, (off + step), p_color, p_width);
- off += 2 * step;
+ int steps = (p_aligned) ? Math::ceil(length / p_dash) : Math::floor(length / p_dash);
+ if (steps % 2 == 0) {
+ steps--;
+ }
+
+ Point2 off = p_from;
+ if (p_aligned) {
+ off += (p_to - p_from).normalized() * (length - steps * p_dash) / 2.0;
+ }
+ for (int i = 0; i < steps; i += 2) {
+ RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, (i == 0) ? p_from : off, (p_aligned && i == steps - 1) ? p_to : (off + step), p_color, p_width);
+ off += step * 2;
}
- RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, off, p_to, p_color, p_width);
}
void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
@@ -525,10 +531,13 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect
void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
Vector<Point2> points;
points.resize(p_point_count);
- const real_t delta_angle = p_end_angle - p_start_angle;
+ Point2 *points_ptr = points.ptrw();
+
+ // Clamp angle difference to full circle so arc won't overlap itself.
+ const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math_TAU, Math_TAU);
for (int i = 0; i < p_point_count; i++) {
real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
- points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
+ points_ptr[i] = p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius;
}
draw_polyline(points, p_color, p_width, p_antialiased);
@@ -552,7 +561,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
if (p_filled) {
- if (p_width != 1.0) {
+ if (p_width != -1.0) {
WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
}
@@ -561,7 +570,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
// Thick lines are offset depending on their width to avoid partial overlapping.
// Thin lines don't require an offset, so don't apply one in this case
real_t offset;
- if (p_width >= 2) {
+ if (p_width >= 0) {
offset = p_width / 2.0;
} else {
offset = 0.0;
@@ -641,11 +650,11 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
p_style_box->draw(canvas_item, p_rect);
}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t p_width) {
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width);
+ RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid);
}
void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
@@ -962,14 +971,14 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
- ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash"), &CanvasItem::draw_dashed_line, DEFVAL(1.0), DEFVAL(2.0));
+ ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(-1.0), DEFVAL(2.0), DEFVAL(true));
ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0));
+ ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0));
ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
@@ -977,7 +986,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
- ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_string", "font", "pos", "text", "alignment", "width", "font_size", "modulate", "jst_flags", "direction", "orientation"), &CanvasItem::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 47b40c9b46..b2c12b2ea2 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -247,14 +247,14 @@ public:
/* 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);
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ 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, bool p_aligned = true);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false);
void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false);
void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
- void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0);
- void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0);
- void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0);
+ void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0);
+ void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = -1.0);
void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color);
void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
@@ -262,7 +262,7 @@ public:
void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0);
void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
- void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1);
+ void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index b5c587c0aa..fbe11c94d1 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1134,7 +1134,6 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
ERR_FAIL_COND_V_MSG(p_scene.is_null(), ERR_INVALID_PARAMETER, "Can't change to a null scene. Use unload_current_scene() if you wish to unload it.");
Node *new_scene = p_scene->instantiate();
- new_scene = p_scene->instantiate();
ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE);
call_deferred(SNAME("_change_scene"), new_scene);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 7ca1f9d3ec..9efe649e6f 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1256,6 +1256,7 @@ void Viewport::_gui_show_tooltip() {
panel->set_transient(true);
panel->set_flag(Window::FLAG_NO_FOCUS, true);
panel->set_flag(Window::FLAG_POPUP, false);
+ panel->set_flag(Window::FLAG_MOUSE_PASSTHROUGH, true);
panel->set_wrap_controls(true);
panel->add_child(base_tooltip);
panel->gui_parent = this;
@@ -1401,7 +1402,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
xform = sw->get_canvas_transform();
}
- Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
+ Control *ret = _gui_find_control_at_pos(sw, p_global, xform);
if (ret) {
return ret;
}
@@ -1410,7 +1411,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
return nullptr;
}
-Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
+Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform) {
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1430,7 +1431,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
continue;
}
- Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform);
+ Control *ret = _gui_find_control_at_pos(ci, p_global, matrix);
if (ret) {
return ret;
}
@@ -1448,7 +1449,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
Control *drag_preview = _gui_get_drag_preview();
if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) {
- r_inv_xform = matrix;
return c;
}
@@ -1495,12 +1495,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Point2 mpos = mb->get_position();
if (mb->is_pressed()) {
- Size2 pos = mpos;
if (!gui.mouse_focus_mask.is_empty()) {
// Do not steal mouse focus and stuff while a focus mask exists.
gui.mouse_focus_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
} else {
- gui.mouse_focus = gui_find_control(pos);
+ gui.mouse_focus = gui_find_control(mpos);
gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
@@ -1519,10 +1518,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
mb = mb->xformed_by(Transform2D()); // Make a copy of the event.
- mb->set_global_position(pos);
-
- pos = gui.focus_inv_xform.xform(pos);
-
+ Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos);
mb->set_position(pos);
#ifdef DEBUG_ENABLED
@@ -1586,11 +1582,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
return;
}
- Size2 pos = mpos;
-
mb = mb->xformed_by(Transform2D()); // Make a copy.
- mb->set_global_position(pos);
- pos = gui.focus_inv_xform.xform(pos);
+ Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos);
mb->set_position(pos);
Control *mouse_focus = gui.mouse_focus;
@@ -1893,11 +1886,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool stopped = false;
if (over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
touch_event->set_position(pos);
stopped = _gui_call_input(over, touch_event);
}
@@ -1912,11 +1901,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr;
if (over && over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.last_mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
touch_event->set_position(pos);
stopped = _gui_call_input(over, touch_event);
@@ -1942,11 +1927,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool stopped = false;
if (over->can_process()) {
gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
gesture_event->set_position(pos);
stopped = _gui_call_input(over, gesture_event);
}
@@ -2393,7 +2374,6 @@ void Viewport::_post_gui_grab_click_focus() {
}
gui.mouse_focus = focus_grabber;
- gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
for (int i = 0; i < 3; i++) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 9f182682d7..603e92b071 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -374,7 +374,6 @@ private:
ObjectID drag_preview_id;
Ref<SceneTreeTimer> tooltip_timer;
double tooltip_delay = 0.0;
- Transform2D focus_inv_xform;
bool roots_order_dirty = false;
List<Control *> roots;
int canvas_sort_index = 0; //for sorting items with canvas as root
@@ -403,7 +402,7 @@ private:
void _gui_call_notification(Control *p_control, int p_what);
void _gui_sort_roots();
- Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
+ Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform);
void _gui_input_event(Ref<InputEvent> p_event);
void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index c5dbfffd7b..4baedc8c14 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -489,6 +489,7 @@ void Window::_make_window() {
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
+ DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id);
String tr_title = atr(title);
#ifdef DEBUG_ENABLED
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
@@ -1235,6 +1236,18 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
+void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) {
+ mpath = p_region;
+ if (window_id == DisplayServer::INVALID_WINDOW_ID) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id);
+}
+
+Vector<Vector2> Window::get_mouse_passthrough_polygon() const {
+ return mpath;
+}
+
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -2163,6 +2176,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling);
ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling);
+ ClassDB::bind_method(D_METHOD("set_mouse_passthrough_polygon", "polygon"), &Window::set_mouse_passthrough_polygon);
+ ClassDB::bind_method(D_METHOD("get_mouse_passthrough_polygon"), &Window::get_mouse_passthrough_polygon);
+
ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls);
ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls);
ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed);
@@ -2243,6 +2259,8 @@ void Window::_bind_methods() {
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
+
ADD_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
@@ -2255,6 +2273,7 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size");
@@ -2302,6 +2321,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(FLAG_POPUP);
BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
+ BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
diff --git a/scene/main/window.h b/scene/main/window.h
index b4887437a1..d819ca7c60 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -59,6 +59,7 @@ public:
FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP,
FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
+ FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
@@ -101,6 +102,7 @@ private:
mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
mutable Size2i min_size;
mutable Size2i max_size;
+ mutable Vector<Vector2> mpath;
mutable Mode mode = MODE_WINDOWED;
mutable bool flags[FLAG_MAX] = {};
bool visible = true;
@@ -281,6 +283,9 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
+ void set_mouse_passthrough_polygon(const Vector<Vector2> &p_region);
+ Vector<Vector2> get_mouse_passthrough_polygon() const;
+
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 00c538976f..d56b94b6fe 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -184,15 +184,7 @@
#include "scene/resources/skeleton_modification_2d_physicalbones.h"
#include "scene/resources/skeleton_modification_2d_stackholder.h"
#include "scene/resources/skeleton_modification_2d_twoboneik.h"
-#include "scene/resources/skeleton_modification_3d.h"
-#include "scene/resources/skeleton_modification_3d_ccdik.h"
-#include "scene/resources/skeleton_modification_3d_fabrik.h"
-#include "scene/resources/skeleton_modification_3d_jiggle.h"
-#include "scene/resources/skeleton_modification_3d_lookat.h"
-#include "scene/resources/skeleton_modification_3d_stackholder.h"
-#include "scene/resources/skeleton_modification_3d_twoboneik.h"
#include "scene/resources/skeleton_modification_stack_2d.h"
-#include "scene/resources/skeleton_modification_stack_3d.h"
#include "scene/resources/skeleton_profile.h"
#include "scene/resources/sky.h"
#include "scene/resources/sky_material.h"
@@ -833,15 +825,6 @@ void register_scene_types() {
GDREGISTER_CLASS(ConvexPolygonShape3D);
GDREGISTER_CLASS(ConcavePolygonShape3D);
- GDREGISTER_CLASS(SkeletonModificationStack3D);
- GDREGISTER_CLASS(SkeletonModification3D);
- GDREGISTER_CLASS(SkeletonModification3DLookAt);
- GDREGISTER_CLASS(SkeletonModification3DCCDIK);
- GDREGISTER_CLASS(SkeletonModification3DFABRIK);
- GDREGISTER_CLASS(SkeletonModification3DJiggle);
- GDREGISTER_CLASS(SkeletonModification3DTwoBoneIK);
- GDREGISTER_CLASS(SkeletonModification3DStackHolder);
-
OS::get_singleton()->yield(); // may take time to init
#endif // _3D_DISABLED
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index d92d4fa4a4..e51b48a4b1 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -82,7 +82,7 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
if (is_collision_outline_enabled()) {
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
// Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
- RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0, true);
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0);
}
}
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 746f2f8f9b..8b4656414d 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1043,6 +1043,18 @@ void Environment::_validate_property(PropertyInfo &p_property) const {
}
}
+ if (p_property.name == "ambient_light_color" || p_property.name == "ambient_light_energy") {
+ if (ambient_source == AMBIENT_SOURCE_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ }
+
+ if (p_property.name == "ambient_light_sky_contribution") {
+ if (ambient_source == AMBIENT_SOURCE_DISABLED || ambient_source == AMBIENT_SOURCE_COLOR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ }
+
if (p_property.name == "fog_aerial_perspective") {
if (bg_mode != BG_SKY) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 247927163b..f4a0db3930 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -194,25 +194,20 @@ void ImmediateMesh::surface_end() {
if (uses_normals) {
uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset];
- Vector3 n = normals[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 n = normals[i].octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(n.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(n.y * 65535, 0, 65535) << 16;
*normal = value;
}
if (uses_tangents) {
uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset];
- Plane t = tangents[i];
+ Vector2 t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(t.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(t.y * 65535, 0, 65535) << 16;
*tangent = value;
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index d5c3f7730b..3e2a952ea7 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -791,6 +791,14 @@ void BaseMaterial3D::_update_shader() {
code += "uniform vec4 refraction_texture_channel;\n";
}
+ if (features[FEATURE_REFRACTION]) {
+ code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;";
+ }
+
+ if (proximity_fade_enabled) {
+ code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;";
+ }
+
if (features[FEATURE_NORMAL_MAPPING]) {
code += "uniform sampler2D texture_normal : hint_roughness_normal," + texfilter_str + ";\n";
code += "uniform float normal_scale : hint_range(-16,16);\n";
@@ -1228,7 +1236,7 @@ void BaseMaterial3D::_update_shader() {
code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
}
code += " float ref_amount = 1.0 - albedo.a * albedo_tex.a;\n";
- code += " EMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
+ code += " EMISSION += textureLod(screen_texture,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
code += " ALBEDO *= 1.0 - ref_amount;\n";
code += " ALPHA = 1.0;\n";
@@ -1246,7 +1254,7 @@ void BaseMaterial3D::_update_shader() {
}
if (proximity_fade_enabled) {
- 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";
code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);\n";
code += " world_pos.xyz/=world_pos.w;\n";
code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 5e18b5df37..cedf4319f8 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -687,6 +687,7 @@ void Mesh::_bind_methods() {
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+ BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY);
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
@@ -1555,6 +1556,7 @@ void ArrayMesh::_recompute_aabb() {
// TODO: Need to add binding to add_surface using future MeshSurfaceData object.
void ArrayMesh::add_surface(BitField<ArrayFormat> 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) {
+ ERR_FAIL_COND(surfaces.size() == RS::MAX_MESH_SURFACES);
_create_if_empty();
Surface s;
@@ -1590,6 +1592,7 @@ void ArrayMesh::add_surface(BitField<ArrayFormat> p_format, PrimitiveType p_prim
}
void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, BitField<ArrayFormat> p_flags) {
+ ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX);
RS::SurfaceData surface;
@@ -2058,7 +2061,7 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces);
ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region);
ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region);
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 5ef66a22b6..86ed0001dd 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -2901,7 +2901,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- Array stt;
+ TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 22cd12b004..e62f26b17c 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -622,7 +622,7 @@ protected:
virtual void _create_mesh_array(Array &p_arr) const override;
public:
- GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
TextMesh();
~TextMesh();
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 80b9ff3f38..2e8b4f93be 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -49,10 +49,6 @@
///
-void ResourceLoaderText::set_local_path(const String &p_local_path) {
- res_path = p_local_path;
-}
-
Ref<Resource> ResourceLoaderText::get_resource() {
return resource;
}
@@ -1846,6 +1842,9 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
+ // Of course keys should also be cached, after all we can't prevent users from using resources as keys, right?
+ // See also ResourceFormatSaverBinaryInstance::_find_resources (when p_variant is of type Variant::DICTIONARY)
+ _find_resources(E);
Variant v = d[E];
_find_resources(v);
}
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 0f95e2fbfd..0cced3d20c 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -115,7 +115,6 @@ class ResourceLoaderText {
Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser);
public:
- void set_local_path(const String &p_local_path);
Ref<Resource> get_resource();
Error load();
Error set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid);
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
deleted file mode 100644
index 92fb4bfd78..0000000000
--- a/scene/resources/skeleton_modification_3d.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "skeleton_modification_3d.h"
-#include "scene/3d/skeleton_3d.h"
-
-void SkeletonModification3D::_execute(real_t p_delta) {
- GDVIRTUAL_CALL(_execute, p_delta);
-
- if (!enabled) {
- return;
- }
-}
-
-void SkeletonModification3D::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack) {
- is_setup = true;
- } else {
- WARN_PRINT("Could not setup modification with name " + this->get_name());
- }
-
- GDVIRTUAL_CALL(_setup_modification, Ref<SkeletonModificationStack3D>(p_stack));
-}
-
-void SkeletonModification3D::set_enabled(bool p_enabled) {
- enabled = p_enabled;
-}
-
-bool SkeletonModification3D::get_enabled() {
- return enabled;
-}
-
-// Helper function. Needed for CCDIK.
-real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert) {
- // Map to the 0 to 360 range (in radians though) instead of the -180 to 180 range.
- if (p_angle < 0) {
- p_angle = Math_TAU + p_angle;
- }
-
- // Make min and max in the range of 0 to 360 (in radians), and make sure they are in the right order
- if (p_min_bound < 0) {
- p_min_bound = Math_TAU + p_min_bound;
- }
- if (p_max_bound < 0) {
- p_max_bound = Math_TAU + p_max_bound;
- }
- if (p_min_bound > p_max_bound) {
- SWAP(p_min_bound, p_max_bound);
- }
-
- bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
- bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
-
- // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
-
- return p_angle;
-}
-
-bool SkeletonModification3D::_print_execution_error(bool p_condition, String p_message) {
- // If the modification is not setup, don't bother printing the error
- if (!is_setup) {
- return p_condition;
- }
-
- if (p_condition && !execution_error_found) {
- ERR_PRINT(p_message);
- execution_error_found = true;
- }
- return p_condition;
-}
-
-Ref<SkeletonModificationStack3D> SkeletonModification3D::get_modification_stack() {
- return stack;
-}
-
-void SkeletonModification3D::set_is_setup(bool p_is_setup) {
- is_setup = p_is_setup;
-}
-
-bool SkeletonModification3D::get_is_setup() const {
- return is_setup;
-}
-
-void SkeletonModification3D::set_execution_mode(int p_mode) {
- execution_mode = p_mode;
-}
-
-int SkeletonModification3D::get_execution_mode() const {
- return execution_mode;
-}
-
-void SkeletonModification3D::_bind_methods() {
- GDVIRTUAL_BIND(_execute, "delta");
- GDVIRTUAL_BIND(_setup_modification, "modification_stack")
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification3D::set_enabled);
- ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification3D::get_enabled);
- ClassDB::bind_method(D_METHOD("get_modification_stack"), &SkeletonModification3D::get_modification_stack);
- ClassDB::bind_method(D_METHOD("set_is_setup", "is_setup"), &SkeletonModification3D::set_is_setup);
- ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModification3D::get_is_setup);
- ClassDB::bind_method(D_METHOD("set_execution_mode", "execution_mode"), &SkeletonModification3D::set_execution_mode);
- ClassDB::bind_method(D_METHOD("get_execution_mode"), &SkeletonModification3D::get_execution_mode);
- 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");
-}
-
-SkeletonModification3D::SkeletonModification3D() {
- stack = nullptr;
- is_setup = false;
-}
diff --git a/scene/resources/skeleton_modification_3d.h b/scene/resources/skeleton_modification_3d.h
deleted file mode 100644
index 367adbd977..0000000000
--- a/scene/resources/skeleton_modification_3d.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_H
-#define SKELETON_MODIFICATION_3D_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_stack_3d.h"
-
-class SkeletonModificationStack3D;
-
-class SkeletonModification3D : public Resource {
- GDCLASS(SkeletonModification3D, Resource);
- friend class Skeleton3D;
- friend class SkeletonModificationStack3D;
-
-protected:
- static void _bind_methods();
-
- SkeletonModificationStack3D *stack = nullptr;
- int execution_mode = 0; // 0 = process
-
- bool enabled = true;
- bool is_setup = false;
- bool execution_error_found = false;
-
- bool _print_execution_error(bool p_condition, String p_message);
-
- GDVIRTUAL1(_execute, double)
- GDVIRTUAL1(_setup_modification, Ref<SkeletonModificationStack3D>)
-
-public:
- virtual void _execute(real_t p_delta);
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack);
-
- real_t clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert);
-
- void set_enabled(bool p_enabled);
- bool get_enabled();
-
- void set_execution_mode(int p_mode);
- int get_execution_mode() const;
-
- Ref<SkeletonModificationStack3D> get_modification_stack();
-
- void set_is_setup(bool p_setup);
- bool get_is_setup() const;
-
- SkeletonModification3D();
-};
-
-#endif // SKELETON_MODIFICATION_3D_H
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
deleted file mode 100644
index b5c930f970..0000000000
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_ccdik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_ccdik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DCCDIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- int ccdik_data_size = ccdik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, ccdik_data_size, false);
-
- if (what == "bone_name") {
- set_ccdik_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_ccdik_joint_bone_index(which, p_value);
- } else if (what == "ccdik_axis") {
- set_ccdik_joint_ccdik_axis(which, p_value);
- } else if (what == "enable_joint_constraint") {
- set_ccdik_joint_enable_constraint(which, p_value);
- } else if (what == "joint_constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(real_t(p_value)));
- } else if (what == "joint_constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(real_t(p_value)));
- } else if (what == "joint_constraint_angles_invert") {
- set_ccdik_joint_constraint_invert(which, p_value);
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DCCDIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int ccdik_data_size = ccdik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, ccdik_data_size, false);
-
- if (what == "bone_name") {
- r_ret = get_ccdik_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_ccdik_joint_bone_index(which);
- } else if (what == "ccdik_axis") {
- r_ret = get_ccdik_joint_ccdik_axis(which);
- } else if (what == "enable_joint_constraint") {
- r_ret = get_ccdik_joint_enable_constraint(which);
- } else if (what == "joint_constraint_angle_min") {
- r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
- } else if (what == "joint_constraint_angle_max") {
- r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
- } else if (what == "joint_constraint_angles_invert") {
- r_ret = get_ccdik_joint_constraint_invert(which);
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- 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));
-
- 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) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_min", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_max", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "joint_constraint_angles_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
-}
-
-void SkeletonModification3DCCDIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update");
- update_target_cache();
- return;
- }
- if (tip_node_cache.is_null()) {
- _print_execution_error(true, "Tip cache is out of date. Attempting to update");
- update_tip_cache();
- return;
- }
-
- // Reset the local bone overrides for CCDIK affected nodes
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- stack->skeleton->set_bone_local_pose_override(ccdik_data_chain[i].bone_idx,
- stack->skeleton->get_bone_local_pose_override(ccdik_data_chain[i].bone_idx),
- 0.0, false);
- }
-
- Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- Node3D *node_tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
-
- if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- if (_print_execution_error(!node_tip || !node_tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
-
- if (use_high_quality_solve) {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- for (uint32_t j = i; j < ccdik_data_chain.size(); j++) {
- _execute_ccdik_joint(j, node_target, node_tip);
- }
- }
- } else {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- _execute_ccdik_joint(i, node_target, node_tip);
- }
- }
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip) {
- CCDIK_Joint_Data ccdik_data = ccdik_data_chain[p_joint_idx];
-
- if (_print_execution_error(ccdik_data.bone_idx < 0 || ccdik_data.bone_idx > stack->skeleton->get_bone_count(),
- "CCDIK joint: bone index for joint" + itos(p_joint_idx) + " not found. Cannot execute modification!")) {
- return;
- }
-
- Transform3D bone_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->get_bone_global_pose(ccdik_data.bone_idx));
- Transform3D tip_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_tip->get_global_transform()));
- Transform3D target_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()));
-
- if (tip_trans.origin.distance_to(target_trans.origin) <= 0.01) {
- return;
- }
-
- // Inspired (and very loosely based on) by the CCDIK algorithm made by Zalo on GitHub (https://github.com/zalo/MathUtilities)
- // Convert the 3D position to a 2D position so we can use Atan2 (via the angle function)
- // to know how much rotation we need on the given axis to place the tip at the target.
- Vector2 tip_pos_2d;
- Vector2 target_pos_2d;
- if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) {
- tip_pos_2d = Vector2(tip_trans.origin.y, tip_trans.origin.z);
- target_pos_2d = Vector2(target_trans.origin.y, target_trans.origin.z);
- bone_trans.basis.rotate_local(Vector3(1, 0, 0), target_pos_2d.angle() - tip_pos_2d.angle());
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) {
- tip_pos_2d = Vector2(tip_trans.origin.z, tip_trans.origin.x);
- target_pos_2d = Vector2(target_trans.origin.z, target_trans.origin.x);
- bone_trans.basis.rotate_local(Vector3(0, 1, 0), target_pos_2d.angle() - tip_pos_2d.angle());
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) {
- tip_pos_2d = Vector2(tip_trans.origin.x, tip_trans.origin.y);
- target_pos_2d = Vector2(target_trans.origin.x, target_trans.origin.y);
- bone_trans.basis.rotate_local(Vector3(0, 0, 1), target_pos_2d.angle() - tip_pos_2d.angle());
- } else {
- // Should never happen, but...
- ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!");
- }
-
- if (ccdik_data.enable_constraint) {
- Vector3 rotation_axis;
- real_t rotation_angle;
- bone_trans.basis.get_axis_angle(rotation_axis, rotation_angle);
-
- // Note: When the axis has a negative direction, the angle is OVER 180 degrees and therefore we need to account for this
- // when constraining.
- if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) {
- if (rotation_axis.x < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(1, 0, 0);
- }
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) {
- if (rotation_axis.y < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(0, 1, 0);
- }
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) {
- if (rotation_axis.z < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(0, 0, 1);
- }
- } else {
- // Should never happen, but...
- ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!");
- }
- rotation_angle = clamp_angle(rotation_angle, ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angles_invert);
-
- bone_trans.basis.set_axis_angle(rotation_axis, rotation_angle);
- }
-
- stack->skeleton->set_bone_local_pose_override(ccdik_data.bone_idx, bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(ccdik_data.bone_idx);
-}
-
-void SkeletonModification3DCCDIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_target_cache();
- update_tip_cache();
- }
-}
-
-void SkeletonModification3DCCDIK::update_target_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DCCDIK::update_tip_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
-
- tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(tip_node)) {
- Node *node = stack->skeleton->get_node(tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache: node is not in scene tree!");
- tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DCCDIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_target_cache();
-}
-
-NodePath SkeletonModification3DCCDIK::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DCCDIK::set_tip_node(const NodePath &p_tip_node) {
- tip_node = p_tip_node;
- update_tip_cache();
-}
-
-NodePath SkeletonModification3DCCDIK::get_tip_node() const {
- return tip_node;
-}
-
-void SkeletonModification3DCCDIK::set_use_high_quality_solve(bool p_high_quality) {
- use_high_quality_solve = p_high_quality;
-}
-
-bool SkeletonModification3DCCDIK::get_use_high_quality_solve() const {
- return use_high_quality_solve;
-}
-
-// CCDIK joint data functions
-String SkeletonModification3DCCDIK::get_ccdik_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String());
- return ccdik_data_chain[p_joint_idx].bone_name;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].bone_name = p_bone_name;
-
- if (stack) {
- if (stack->skeleton) {
- ccdik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return ccdik_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- ccdik_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- ccdik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return ccdik_data_chain[p_joint_idx].ccdik_axis;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_axis < 0, "CCDIK axis is out of range: The axis mode is too low!");
- ccdik_data_chain[p_joint_idx].ccdik_axis = p_axis;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].enable_constraint;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].enable_constraint = p_enable;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angle_min;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angle_min = p_angle_min;
-}
-
-real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angle_max;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angle_max = p_angle_max;
-}
-
-bool SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angles_invert;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angles_invert = p_invert;
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_data_chain_length() {
- return ccdik_data_chain.size();
-}
-void SkeletonModification3DCCDIK::set_ccdik_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- ccdik_data_chain.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DCCDIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DCCDIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DCCDIK::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DCCDIK::set_tip_node);
- ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DCCDIK::get_tip_node);
-
- ClassDB::bind_method(D_METHOD("set_use_high_quality_solve", "high_quality_solve"), &SkeletonModification3DCCDIK::set_use_high_quality_solve);
- ClassDB::bind_method(D_METHOD("get_use_high_quality_solve"), &SkeletonModification3DCCDIK::get_use_high_quality_solve);
-
- // CCDIK joint data functions
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_name", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_index", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_ccdik_axis", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_ccdik_axis", "joint_idx", "axis"), &SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_enable_joint_constraint", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_enable_joint_constraint", "joint_idx", "enable"), &SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_min", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_min", "joint_idx", "min_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_max", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_max", "joint_idx", "max_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_invert", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_invert", "joint_idx", "invert"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert);
-
- ClassDB::bind_method(D_METHOD("set_ccdik_data_chain_length", "length"), &SkeletonModification3DCCDIK::set_ccdik_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_ccdik_data_chain_length"), &SkeletonModification3DCCDIK::get_ccdik_data_chain_length);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "tip_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_tip_node", "get_tip_node");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "high_quality_solve", PROPERTY_HINT_NONE, ""), "set_use_high_quality_solve", "get_use_high_quality_solve");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "ccdik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_ccdik_data_chain_length", "get_ccdik_data_chain_length");
-}
-
-SkeletonModification3DCCDIK::SkeletonModification3DCCDIK() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DCCDIK::~SkeletonModification3DCCDIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h
deleted file mode 100644
index 30c29bb3aa..0000000000
--- a/scene/resources/skeleton_modification_3d_ccdik.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_ccdik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_CCDIK_H
-#define SKELETON_MODIFICATION_3D_CCDIK_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DCCDIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D);
-
-private:
- enum CCDIK_Axes {
- AXIS_X,
- AXIS_Y,
- AXIS_Z
- };
-
- struct CCDIK_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
- int ccdik_axis = 0;
-
- bool enable_constraint = false;
- real_t constraint_angle_min = 0;
- real_t constraint_angle_max = (2.0 * Math_PI);
- bool constraint_angles_invert = false;
- };
-
- LocalVector<CCDIK_Joint_Data> ccdik_data_chain;
- NodePath target_node;
- ObjectID target_node_cache;
-
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_high_quality_solve = true;
-
- void update_target_cache();
- void update_tip_cache();
-
- void _execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip);
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_tip_node(const NodePath &p_tip_node);
- NodePath get_tip_node() const;
-
- void set_use_high_quality_solve(bool p_solve);
- bool get_use_high_quality_solve() const;
-
- String get_ccdik_joint_bone_name(int p_joint_idx) const;
- void set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name);
- int get_ccdik_joint_bone_index(int p_joint_idx) const;
- void set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx);
- int get_ccdik_joint_ccdik_axis(int p_joint_idx) const;
- void set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis);
- bool get_ccdik_joint_enable_constraint(int p_joint_idx) const;
- void set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable);
- real_t get_ccdik_joint_constraint_angle_min(int p_joint_idx) const;
- void set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min);
- real_t get_ccdik_joint_constraint_angle_max(int p_joint_idx) const;
- void set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max);
- bool get_ccdik_joint_constraint_invert(int p_joint_idx) const;
- void set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert);
-
- int get_ccdik_data_chain_length();
- void set_ccdik_data_chain_length(int p_new_length);
-
- SkeletonModification3DCCDIK();
- ~SkeletonModification3DCCDIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_CCDIK_H
diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
deleted file mode 100644
index 9fb7ade155..0000000000
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ /dev/null
@@ -1,628 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_fabrik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_fabrik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- int fabrik_data_size = fabrik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
-
- if (what == "bone_name") {
- set_fabrik_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_fabrik_joint_bone_index(which, p_value);
- } else if (what == "length") {
- set_fabrik_joint_length(which, p_value);
- } else if (what == "magnet_position") {
- set_fabrik_joint_magnet(which, p_value);
- } else if (what == "auto_calculate_length") {
- set_fabrik_joint_auto_calculate_length(which, p_value);
- } else if (what == "use_tip_node") {
- set_fabrik_joint_use_tip_node(which, p_value);
- } else if (what == "tip_node") {
- set_fabrik_joint_tip_node(which, p_value);
- } else if (what == "use_target_basis") {
- set_fabrik_joint_use_target_basis(which, p_value);
- } else if (what == "roll") {
- set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int fabrik_data_size = fabrik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
-
- if (what == "bone_name") {
- r_ret = get_fabrik_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_fabrik_joint_bone_index(which);
- } else if (what == "length") {
- r_ret = get_fabrik_joint_length(which);
- } else if (what == "magnet_position") {
- r_ret = get_fabrik_joint_magnet(which);
- } else if (what == "auto_calculate_length") {
- r_ret = get_fabrik_joint_auto_calculate_length(which);
- } else if (what == "use_tip_node") {
- r_ret = get_fabrik_joint_use_tip_node(which);
- } else if (what == "tip_node") {
- r_ret = get_fabrik_joint_tip_node(which);
- } else if (what == "use_target_basis") {
- r_ret = get_fabrik_joint_use_target_basis(which);
- } else if (what == "roll") {
- r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which));
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "auto_calculate_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-
- if (!fabrik_data_chain[i].auto_calculate_length) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- } else {
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (fabrik_data_chain[i].use_tip_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
- }
-
- // Cannot apply magnet to the origin of the chain, as it will not do anything.
- if (i > 0) {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- // Only give the override basis option on the last bone in the chain, so only include it for the last bone.
- if (i == fabrik_data_chain.size() - 1) {
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
-}
-
-void SkeletonModification3DFABRIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_target_cache();
- return;
- }
-
- if (_print_execution_error(fabrik_data_chain.size() <= 1, "FABRIK requires at least two joints to operate. Cannot execute modification!")) {
- return;
- }
-
- Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
-
- // Make sure the transform cache is the correct size
- if (fabrik_transforms.size() != fabrik_data_chain.size()) {
- fabrik_transforms.resize(fabrik_data_chain.size());
- }
-
- // Verify that all joints have a valid bone ID, and that all bone lengths are zero or more
- // Also, while we are here, apply magnet positions.
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- if (_print_execution_error(fabrik_data_chain[i].bone_idx < 0, "FABRIK Joint " + itos(i) + " has an invalid bone ID. Cannot execute!")) {
- return;
- }
-
- if (fabrik_data_chain[i].length < 0 && fabrik_data_chain[i].auto_calculate_length) {
- fabrik_joint_auto_calculate_length(i);
- }
- if (_print_execution_error(fabrik_data_chain[i].length < 0, "FABRIK Joint " + itos(i) + " has an invalid joint length. Cannot execute!")) {
- return;
- }
- fabrik_transforms[i] = stack->skeleton->get_bone_global_pose(fabrik_data_chain[i].bone_idx);
-
- // Apply magnet positions:
- if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) {
- int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx);
- Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx));
- fabrik_transforms[i].origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position);
- } else {
- fabrik_transforms[i].origin += fabrik_data_chain[i].magnet_position;
- }
- }
- Transform3D origin_global_pose_trans = stack->skeleton->get_bone_global_pose_no_override(fabrik_data_chain[0].bone_idx);
-
- target_global_pose = stack->skeleton->world_transform_to_global_pose(node_target->get_global_transform());
- origin_global_pose = origin_global_pose_trans;
-
- final_joint_idx = fabrik_data_chain.size() - 1;
- real_t target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
- chain_iterations = 0;
-
- while (target_distance > chain_tolerance) {
- chain_backwards();
- chain_forwards();
-
- // update the target distance
- target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
-
- // update chain iterations
- chain_iterations += 1;
- if (chain_iterations >= chain_max_iterations) {
- break;
- }
- }
- chain_apply();
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DFABRIK::chain_backwards() {
- int final_bone_idx = fabrik_data_chain[final_joint_idx].bone_idx;
- Transform3D final_joint_trans = fabrik_transforms[final_joint_idx];
-
- // Get the direction the final bone is facing in.
- stack->skeleton->update_bone_rest_forward_vector(final_bone_idx);
- Transform3D final_bone_direction_trans = final_joint_trans.looking_at(target_global_pose.origin, Vector3(0, 1, 0));
- final_bone_direction_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(final_bone_idx, final_bone_direction_trans.basis);
- Vector3 direction = final_bone_direction_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
-
- // If set to override, then use the target's Basis rather than the bone's
- if (fabrik_data_chain[final_joint_idx].use_target_basis) {
- direction = target_global_pose.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
- }
-
- // set the position of the final joint to the target position
- final_joint_trans.origin = target_global_pose.origin - (direction * fabrik_data_chain[final_joint_idx].length);
- fabrik_transforms[final_joint_idx] = final_joint_trans;
-
- // for all other joints, move them towards the target
- int i = final_joint_idx;
- while (i >= 1) {
- Transform3D next_bone_trans = fabrik_transforms[i];
- i -= 1;
- Transform3D current_trans = fabrik_transforms[i];
-
- real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin));
- current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length);
-
- // Save the result
- fabrik_transforms[i] = current_trans;
- }
-}
-
-void SkeletonModification3DFABRIK::chain_forwards() {
- // Set root at the initial position.
- Transform3D root_transform = fabrik_transforms[0];
-
- root_transform.origin = origin_global_pose.origin;
- fabrik_transforms[0] = origin_global_pose;
-
- for (uint32_t i = 0; i < fabrik_data_chain.size() - 1; i++) {
- Transform3D current_trans = fabrik_transforms[i];
- Transform3D next_bone_trans = fabrik_transforms[i + 1];
-
- real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin));
- next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length);
-
- // Save the result
- fabrik_transforms[i + 1] = next_bone_trans;
- }
-}
-
-void SkeletonModification3DFABRIK::chain_apply() {
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- int current_bone_idx = fabrik_data_chain[i].bone_idx;
- Transform3D current_trans = fabrik_transforms[i];
-
- // If this is the last bone in the chain...
- if (i == fabrik_data_chain.size() - 1) {
- if (fabrik_data_chain[i].use_target_basis == false) { // Point to target...
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
- // Rotate the bone towards the target:
- current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(target_global_pose.origin));
- current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
- } else { // Use the target's Basis...
- current_trans.basis = target_global_pose.basis.orthonormalized().scaled(current_trans.basis.get_scale());
- }
- } else { // every other bone in the chain...
- Transform3D next_trans = fabrik_transforms[i + 1];
-
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
- // Rotate the bone towards the next bone in the chain:
- current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(next_trans.origin));
- current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
- }
- stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true);
- }
-
- // Update all the bones so the next modification has up-to-date data.
- stack->skeleton->force_update_all_bone_transforms();
-}
-
-void SkeletonModification3DFABRIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_target_cache();
-
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- update_joint_tip_cache(i);
- }
- }
-}
-
-void SkeletonModification3DFABRIK::update_target_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DFABRIK::update_joint_tip_cache(int p_joint_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_MSG(p_joint_idx, bone_chain_size, "FABRIK joint not found");
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
- fabrik_data_chain[p_joint_idx].tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && fabrik_data_chain[p_joint_idx].tip_node.is_empty() == false) {
- if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].tip_node)) {
- Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is not in scene tree!");
- fabrik_data_chain[p_joint_idx].tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DFABRIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_target_cache();
-}
-
-NodePath SkeletonModification3DFABRIK::get_target_node() const {
- return target_node;
-}
-
-int SkeletonModification3DFABRIK::get_fabrik_data_chain_length() {
- return fabrik_data_chain.size();
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- fabrik_data_chain.resize(p_length);
- fabrik_transforms.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DFABRIK::get_chain_tolerance() {
- return chain_tolerance;
-}
-
-void SkeletonModification3DFABRIK::set_chain_tolerance(real_t p_tolerance) {
- ERR_FAIL_COND_MSG(p_tolerance <= 0, "FABRIK chain tolerance must be more than zero!");
- chain_tolerance = p_tolerance;
-}
-
-int SkeletonModification3DFABRIK::get_chain_max_iterations() {
- return chain_max_iterations;
-}
-void SkeletonModification3DFABRIK::set_chain_max_iterations(int p_iterations) {
- ERR_FAIL_COND_MSG(p_iterations <= 0, "FABRIK chain iterations must be at least one. Set enabled to false to disable the FABRIK chain.");
- chain_max_iterations = p_iterations;
-}
-
-// FABRIK joint data functions
-String SkeletonModification3DFABRIK::get_fabrik_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String());
- return fabrik_data_chain[p_joint_idx].bone_name;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].bone_name = p_bone_name;
-
- if (stack) {
- if (stack->skeleton) {
- fabrik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return fabrik_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- fabrik_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- fabrik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DFABRIK::get_fabrik_joint_length(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return fabrik_data_chain[p_joint_idx].length;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_length < 0, "FABRIK joint length cannot be less than zero!");
-
- if (!is_setup) {
- fabrik_data_chain[p_joint_idx].length = p_bone_length;
- return;
- }
-
- if (fabrik_data_chain[p_joint_idx].auto_calculate_length) {
- WARN_PRINT("FABRIK Length not set: auto calculate length is enabled for this joint!");
- fabrik_joint_auto_calculate_length(p_joint_idx);
- } else {
- fabrik_data_chain[p_joint_idx].length = p_bone_length;
- }
-
- execution_error_found = false;
-}
-
-Vector3 SkeletonModification3DFABRIK::get_fabrik_joint_magnet(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3());
- return fabrik_data_chain[p_joint_idx].magnet_position;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].magnet_position = p_magnet;
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].auto_calculate_length;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].auto_calculate_length = p_auto_calculate;
- fabrik_joint_auto_calculate_length(p_joint_idx);
- notify_property_list_changed();
-}
-
-void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_joint_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- if (!fabrik_data_chain[p_joint_idx].auto_calculate_length) {
- return;
- }
-
- if (!stack || !stack->skeleton || !is_setup) {
- _print_execution_error(true, "Cannot auto calculate joint length: modification is not properly setup!");
- return;
- }
- ERR_FAIL_INDEX_MSG(fabrik_data_chain[p_joint_idx].bone_idx, stack->skeleton->get_bone_count(),
- "Bone for joint " + itos(p_joint_idx) + " is not set or points to an unknown bone!");
-
- if (fabrik_data_chain[p_joint_idx].use_tip_node) { // Use the tip node to update joint length.
-
- update_joint_tip_cache(p_joint_idx);
-
- Node3D *tip_node = Object::cast_to<Node3D>(ObjectDB::get_instance(fabrik_data_chain[p_joint_idx].tip_node_cache));
- ERR_FAIL_COND_MSG(!tip_node, "Tip node for joint " + itos(p_joint_idx) + "is not a Node3D-based node. Cannot calculate length...");
- ERR_FAIL_COND_MSG(!tip_node->is_inside_tree(), "Tip node for joint " + itos(p_joint_idx) + "is not in the scene tree. Cannot calculate length...");
-
- Transform3D node_trans = tip_node->get_global_transform();
- node_trans = stack->skeleton->world_transform_to_global_pose(node_trans);
- //node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans);
- //fabrik_data_chain[p_joint_idx].length = node_trans.origin.length();
-
- fabrik_data_chain[p_joint_idx].length = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx).origin.distance_to(node_trans.origin);
-
- } else { // Use child bone(s) to update joint length, if possible
- Vector<int> bone_children = stack->skeleton->get_bone_children(fabrik_data_chain[p_joint_idx].bone_idx);
- if (bone_children.size() <= 0) {
- ERR_FAIL_MSG("Cannot calculate length for joint " + itos(p_joint_idx) + "joint uses leaf bone. \nPlease manually set the bone length or use a tip node!");
- return;
- }
-
- Transform3D bone_trans = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx);
-
- real_t final_length = 0;
- for (int i = 0; i < bone_children.size(); i++) {
- Transform3D child_transform = stack->skeleton->get_bone_global_pose(bone_children[i]);
- final_length += bone_trans.origin.distance_to(child_transform.origin);
- //final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length();
- }
- fabrik_data_chain[p_joint_idx].length = final_length / bone_children.size();
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].use_tip_node;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].use_tip_node = p_use_tip_node;
- notify_property_list_changed();
-}
-
-NodePath SkeletonModification3DFABRIK::get_fabrik_joint_tip_node(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, NodePath());
- return fabrik_data_chain[p_joint_idx].tip_node;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].tip_node = p_tip_node;
- update_joint_tip_cache(p_joint_idx);
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].use_target_basis;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_target_basis) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].use_target_basis = p_use_target_basis;
-}
-
-real_t SkeletonModification3DFABRIK::get_fabrik_joint_roll(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0);
- return fabrik_data_chain[p_joint_idx].roll;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_roll(int p_joint_idx, real_t p_roll) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].roll = p_roll;
-}
-
-void SkeletonModification3DFABRIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DFABRIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DFABRIK::get_target_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification3DFABRIK::set_fabrik_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification3DFABRIK::get_fabrik_data_chain_length);
- ClassDB::bind_method(D_METHOD("set_chain_tolerance", "tolerance"), &SkeletonModification3DFABRIK::set_chain_tolerance);
- ClassDB::bind_method(D_METHOD("get_chain_tolerance"), &SkeletonModification3DFABRIK::get_chain_tolerance);
- ClassDB::bind_method(D_METHOD("set_chain_max_iterations", "max_iterations"), &SkeletonModification3DFABRIK::set_chain_max_iterations);
- ClassDB::bind_method(D_METHOD("get_chain_max_iterations"), &SkeletonModification3DFABRIK::get_chain_max_iterations);
-
- // FABRIK joint data functions
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_name", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_length);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_length", "joint_idx", "length"), &SkeletonModification3DFABRIK::set_fabrik_joint_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_magnet);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet", "joint_idx", "magnet_position"), &SkeletonModification3DFABRIK::set_fabrik_joint_magnet);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_auto_calculate_length", "joint_idx", "auto_calculate_length"), &SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_tip_node", "joint_idx", "use_tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_tip_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_tip_node", "joint_idx", "tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_tip_node);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_basis", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_basis", "joint_idx", "use_target_basis"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "chain_tolerance", PROPERTY_HINT_RANGE, "0,100,0.001"), "set_chain_tolerance", "get_chain_tolerance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "chain_max_iterations", PROPERTY_HINT_RANGE, "1,50,1"), "set_chain_max_iterations", "get_chain_max_iterations");
-}
-
-SkeletonModification3DFABRIK::SkeletonModification3DFABRIK() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DFABRIK::~SkeletonModification3DFABRIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h
deleted file mode 100644
index c834658093..0000000000
--- a/scene/resources/skeleton_modification_3d_fabrik.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_fabrik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_FABRIK_H
-#define SKELETON_MODIFICATION_3D_FABRIK_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DFABRIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D);
-
-private:
- struct FABRIK_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
- real_t length = -1;
- Vector3 magnet_position = Vector3(0, 0, 0);
-
- bool auto_calculate_length = true;
- bool use_tip_node = false;
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_target_basis = false;
- real_t roll = 0;
- };
-
- LocalVector<FABRIK_Joint_Data> fabrik_data_chain;
- LocalVector<Transform3D> fabrik_transforms;
-
- NodePath target_node;
- ObjectID target_node_cache;
-
- real_t chain_tolerance = 0.01;
- int chain_max_iterations = 10;
- int chain_iterations = 0;
-
- void update_target_cache();
- void update_joint_tip_cache(int p_joint_idx);
-
- int final_joint_idx = 0;
- Transform3D target_global_pose;
- Transform3D origin_global_pose;
-
- void chain_backwards();
- void chain_forwards();
- void chain_apply();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- int get_fabrik_data_chain_length();
- void set_fabrik_data_chain_length(int p_new_length);
-
- real_t get_chain_tolerance();
- void set_chain_tolerance(real_t p_tolerance);
-
- int get_chain_max_iterations();
- void set_chain_max_iterations(int p_iterations);
-
- String get_fabrik_joint_bone_name(int p_joint_idx) const;
- void set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name);
- int get_fabrik_joint_bone_index(int p_joint_idx) const;
- void set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx);
- real_t get_fabrik_joint_length(int p_joint_idx) const;
- void set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length);
- Vector3 get_fabrik_joint_magnet(int p_joint_idx) const;
- void set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet);
- bool get_fabrik_joint_auto_calculate_length(int p_joint_idx) const;
- void set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate);
- void fabrik_joint_auto_calculate_length(int p_joint_idx);
- bool get_fabrik_joint_use_tip_node(int p_joint_idx) const;
- void set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node);
- NodePath get_fabrik_joint_tip_node(int p_joint_idx) const;
- void set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node);
- bool get_fabrik_joint_use_target_basis(int p_joint_idx) const;
- void set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_basis);
- real_t get_fabrik_joint_roll(int p_joint_idx) const;
- void set_fabrik_joint_roll(int p_joint_idx, real_t p_roll);
-
- SkeletonModification3DFABRIK();
- ~SkeletonModification3DFABRIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_FABRIK_H
diff --git a/scene/resources/skeleton_modification_3d_jiggle.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp
deleted file mode 100644
index 2cfc7fb10f..0000000000
--- a/scene/resources/skeleton_modification_3d_jiggle.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_jiggle.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_jiggle.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DJiggle::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int jiggle_size = jiggle_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, jiggle_size, false);
-
- if (what == "bone_name") {
- set_jiggle_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_jiggle_joint_bone_index(which, p_value);
- } else if (what == "override_defaults") {
- set_jiggle_joint_override(which, p_value);
- } else if (what == "stiffness") {
- set_jiggle_joint_stiffness(which, p_value);
- } else if (what == "mass") {
- set_jiggle_joint_mass(which, p_value);
- } else if (what == "damping") {
- set_jiggle_joint_damping(which, p_value);
- } else if (what == "use_gravity") {
- set_jiggle_joint_use_gravity(which, p_value);
- } else if (what == "gravity") {
- set_jiggle_joint_gravity(which, p_value);
- } else if (what == "roll") {
- set_jiggle_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
- }
- return true;
- } else {
- if (path == "use_colliders") {
- set_use_colliders(p_value);
- } else if (path == "collision_mask") {
- set_collision_mask(p_value);
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DJiggle::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int jiggle_size = jiggle_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, jiggle_size, false);
-
- if (what == "bone_name") {
- r_ret = get_jiggle_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_jiggle_joint_bone_index(which);
- } else if (what == "override_defaults") {
- r_ret = get_jiggle_joint_override(which);
- } else if (what == "stiffness") {
- r_ret = get_jiggle_joint_stiffness(which);
- } else if (what == "mass") {
- r_ret = get_jiggle_joint_mass(which);
- } else if (what == "damping") {
- r_ret = get_jiggle_joint_damping(which);
- } else if (what == "use_gravity") {
- r_ret = get_jiggle_joint_use_gravity(which);
- } else if (what == "gravity") {
- r_ret = get_jiggle_joint_gravity(which);
- } else if (what == "roll") {
- r_ret = Math::rad_to_deg(get_jiggle_joint_roll(which));
- }
- return true;
- } else {
- if (path == "use_colliders") {
- r_ret = get_use_colliders();
- } else if (path == "collision_mask") {
- r_ret = get_collision_mask();
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DJiggle::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_colliders) {
- p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS, "", PROPERTY_USAGE_DEFAULT));
- }
-
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-
- if (jiggle_data_chain[i].override_defaults) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (jiggle_data_chain[i].use_gravity) {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
- }
-}
-
-void SkeletonModification3DJiggle::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache();
- return;
- }
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- _print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!");
-
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- _execute_jiggle_joint(i, target, p_delta);
- }
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DJiggle::_execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta) {
- // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone
- // With modifications by TwistedTwigleg.
-
- if (jiggle_data_chain[p_joint_idx].bone_idx <= -2) {
- jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(jiggle_data_chain[p_joint_idx].bone_name);
- }
- if (_print_execution_error(
- jiggle_data_chain[p_joint_idx].bone_idx < 0 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count(),
- "Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification!")) {
- return;
- }
-
- Transform3D bone_local_pos = stack->skeleton->get_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx);
- if (bone_local_pos == Transform3D()) {
- bone_local_pos = stack->skeleton->get_bone_pose(jiggle_data_chain[p_joint_idx].bone_idx);
- }
-
- Transform3D new_bone_trans = stack->skeleton->local_pose_to_global_pose(jiggle_data_chain[p_joint_idx].bone_idx, bone_local_pos);
- Vector3 target_position = stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()).origin;
-
- jiggle_data_chain[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta;
-
- if (jiggle_data_chain[p_joint_idx].use_gravity) {
- Vector3 gravity_to_apply = new_bone_trans.basis.inverse().xform(jiggle_data_chain[p_joint_idx].gravity);
- jiggle_data_chain[p_joint_idx].force += gravity_to_apply * p_delta;
- }
-
- jiggle_data_chain[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass;
- jiggle_data_chain[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping);
-
- jiggle_data_chain[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force;
- jiggle_data_chain[p_joint_idx].dynamic_position += new_bone_trans.origin - jiggle_data_chain[p_joint_idx].last_position;
- jiggle_data_chain[p_joint_idx].last_position = new_bone_trans.origin;
-
- // Collision detection/response
- if (use_colliders) {
- if (execution_mode == SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process) {
- Ref<World3D> world_3d = stack->skeleton->get_world_3d();
- ERR_FAIL_COND(world_3d.is_null());
- PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- PhysicsDirectSpaceState3D::RayResult ray_result;
-
- // Convert to world transforms, which is what the physics server needs
- Transform3D new_bone_trans_world = stack->skeleton->global_pose_to_world_transform(new_bone_trans);
- Transform3D dynamic_position_world = stack->skeleton->global_pose_to_world_transform(Transform3D(Basis(), jiggle_data_chain[p_joint_idx].dynamic_position));
-
- PhysicsDirectSpaceState3D::RayParameters ray_params;
- ray_params.from = new_bone_trans_world.origin;
- ray_params.to = dynamic_position_world.get_origin();
- ray_params.collision_mask = collision_mask;
-
- bool ray_hit = space_state->intersect_ray(ray_params, ray_result);
-
- if (ray_hit) {
- jiggle_data_chain[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position;
- jiggle_data_chain[p_joint_idx].acceleration = Vector3(0, 0, 0);
- jiggle_data_chain[p_joint_idx].velocity = Vector3(0, 0, 0);
- } else {
- jiggle_data_chain[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position;
- }
-
- } else {
- WARN_PRINT_ONCE("Jiggle modifier: You cannot detect colliders without the stack mode being set to _physics_process!");
- }
- }
-
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx);
-
- // Rotate the bone using the dynamic position!
- new_bone_trans.basis.rotate_to_align(forward_vector, new_bone_trans.origin.direction_to(jiggle_data_chain[p_joint_idx].dynamic_position));
-
- // Roll
- new_bone_trans.basis.rotate_local(forward_vector, jiggle_data_chain[p_joint_idx].roll);
-
- new_bone_trans = stack->skeleton->global_pose_to_local_pose(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans);
- stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(jiggle_data_chain[p_joint_idx].bone_idx);
-}
-
-void SkeletonModification3DJiggle::_update_jiggle_joint_data() {
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- if (!jiggle_data_chain[i].override_defaults) {
- set_jiggle_joint_stiffness(i, stiffness);
- set_jiggle_joint_mass(i, mass);
- set_jiggle_joint_damping(i, damping);
- set_jiggle_joint_use_gravity(i, use_gravity);
- set_jiggle_joint_gravity(i, gravity);
- }
- }
-}
-
-void SkeletonModification3DJiggle::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack) {
- is_setup = true;
- execution_error_found = false;
-
- if (stack->skeleton) {
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- int bone_idx = jiggle_data_chain[i].bone_idx;
- if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) {
- jiggle_data_chain[i].dynamic_position = stack->skeleton->local_pose_to_global_pose(bone_idx, stack->skeleton->get_bone_local_pose_override(bone_idx)).origin;
- }
- }
- }
-
- update_cache();
- }
-}
-
-void SkeletonModification3DJiggle::update_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DJiggle::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache();
-}
-
-NodePath SkeletonModification3DJiggle::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DJiggle::set_stiffness(real_t p_stiffness) {
- ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
- stiffness = p_stiffness;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_stiffness() const {
- return stiffness;
-}
-
-void SkeletonModification3DJiggle::set_mass(real_t p_mass) {
- ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
- mass = p_mass;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_mass() const {
- return mass;
-}
-
-void SkeletonModification3DJiggle::set_damping(real_t p_damping) {
- ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
- ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!");
- damping = p_damping;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_damping() const {
- return damping;
-}
-
-void SkeletonModification3DJiggle::set_use_gravity(bool p_use_gravity) {
- use_gravity = p_use_gravity;
- _update_jiggle_joint_data();
-}
-
-bool SkeletonModification3DJiggle::get_use_gravity() const {
- return use_gravity;
-}
-
-void SkeletonModification3DJiggle::set_gravity(Vector3 p_gravity) {
- gravity = p_gravity;
- _update_jiggle_joint_data();
-}
-
-Vector3 SkeletonModification3DJiggle::get_gravity() const {
- return gravity;
-}
-
-void SkeletonModification3DJiggle::set_use_colliders(bool p_use_collider) {
- use_colliders = p_use_collider;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_use_colliders() const {
- return use_colliders;
-}
-
-void SkeletonModification3DJiggle::set_collision_mask(int p_mask) {
- collision_mask = p_mask;
-}
-
-int SkeletonModification3DJiggle::get_collision_mask() const {
- return collision_mask;
-}
-
-// Jiggle joint data functions
-int SkeletonModification3DJiggle::get_jiggle_data_chain_length() {
- return jiggle_data_chain.size();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- jiggle_data_chain.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_bone_name(int p_joint_idx, String p_name) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
-
- jiggle_data_chain[p_joint_idx].bone_name = p_name;
- if (stack && stack->skeleton) {
- jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DJiggle::get_jiggle_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, "");
- return jiggle_data_chain[p_joint_idx].bone_name;
-}
-
-int SkeletonModification3DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- jiggle_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- jiggle_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].override_defaults = p_override;
- _update_jiggle_joint_data();
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_jiggle_joint_override(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return jiggle_data_chain[p_joint_idx].override_defaults;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].stiffness = p_stiffness;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].stiffness;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_mass(int p_joint_idx, real_t p_mass) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].mass = p_mass;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_mass(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].mass;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_damping(int p_joint_idx, real_t p_damping) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].damping = p_damping;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_damping(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].damping;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].use_gravity = p_use_gravity;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return jiggle_data_chain[p_joint_idx].use_gravity;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].gravity = p_gravity;
-}
-
-Vector3 SkeletonModification3DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3(0, 0, 0));
- return jiggle_data_chain[p_joint_idx].gravity;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_roll(int p_joint_idx, real_t p_roll) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].roll = p_roll;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_roll(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0);
- return jiggle_data_chain[p_joint_idx].roll;
-}
-
-void SkeletonModification3DJiggle::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DJiggle::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DJiggle::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification3DJiggle::set_jiggle_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification3DJiggle::get_jiggle_data_chain_length);
-
- ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification3DJiggle::set_stiffness);
- ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification3DJiggle::get_stiffness);
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification3DJiggle::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification3DJiggle::get_mass);
- ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification3DJiggle::set_damping);
- ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification3DJiggle::get_damping);
- ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification3DJiggle::set_use_gravity);
- ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification3DJiggle::get_use_gravity);
- ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification3DJiggle::set_gravity);
- ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification3DJiggle::get_gravity);
-
- ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification3DJiggle::set_use_colliders);
- ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification3DJiggle::get_use_colliders);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SkeletonModification3DJiggle::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification3DJiggle::get_collision_mask);
-
- // Jiggle joint data functions
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_name", "joint_idx", "name"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_name", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification3DJiggle::set_jiggle_joint_override);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_override);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification3DJiggle::set_jiggle_joint_stiffness);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_stiffness);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification3DJiggle::set_jiggle_joint_mass);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_mass);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification3DJiggle::set_jiggle_joint_damping);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_damping);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_use_gravity);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_use_gravity);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_gravity);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_gravity);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_roll", "joint_idx", "roll"), &SkeletonModification3DJiggle::set_jiggle_joint_roll);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_roll", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_roll);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length");
- ADD_GROUP("Default Joint Settings", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
- ADD_GROUP("", "");
-}
-
-SkeletonModification3DJiggle::SkeletonModification3DJiggle() {
- stack = nullptr;
- is_setup = false;
- jiggle_data_chain = Vector<Jiggle_Joint_Data>();
- stiffness = 3;
- mass = 0.75;
- damping = 0.75;
- use_gravity = false;
- gravity = Vector3(0, -6.0, 0);
- enabled = true;
-}
-
-SkeletonModification3DJiggle::~SkeletonModification3DJiggle() {
-}
diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h
deleted file mode 100644
index cca620a72d..0000000000
--- a/scene/resources/skeleton_modification_3d_jiggle.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_jiggle.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H
-#define SKELETON_MODIFICATION_3D_JIGGLE_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DJiggle : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D);
-
-private:
- struct Jiggle_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
-
- bool override_defaults = false;
- real_t stiffness = 3;
- real_t mass = 0.75;
- real_t damping = 0.75;
- bool use_gravity = false;
- Vector3 gravity = Vector3(0, -6.0, 0);
- real_t roll = 0;
-
- Vector3 cached_rotation = Vector3(0, 0, 0);
- Vector3 force = Vector3(0, 0, 0);
- Vector3 acceleration = Vector3(0, 0, 0);
- Vector3 velocity = Vector3(0, 0, 0);
- Vector3 last_position = Vector3(0, 0, 0);
- Vector3 dynamic_position = Vector3(0, 0, 0);
-
- Vector3 last_noncollision_position = Vector3(0, 0, 0);
- };
-
- NodePath target_node;
- ObjectID target_node_cache;
- LocalVector<Jiggle_Joint_Data> jiggle_data_chain;
-
- real_t stiffness = 3;
- real_t mass = 0.75;
- real_t damping = 0.75;
- bool use_gravity = false;
- Vector3 gravity = Vector3(0, -6.0, 0);
-
- bool use_colliders = false;
- uint32_t collision_mask = 1;
-
- void update_cache();
- void _execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta);
- void _update_jiggle_joint_data();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_stiffness(real_t p_stiffness);
- real_t get_stiffness() const;
- void set_mass(real_t p_mass);
- real_t get_mass() const;
- void set_damping(real_t p_damping);
- real_t get_damping() const;
-
- void set_use_gravity(bool p_use_gravity);
- bool get_use_gravity() const;
- void set_gravity(Vector3 p_gravity);
- Vector3 get_gravity() const;
-
- void set_use_colliders(bool p_use_colliders);
- bool get_use_colliders() const;
- void set_collision_mask(int p_mask);
- int get_collision_mask() const;
-
- int get_jiggle_data_chain_length();
- void set_jiggle_data_chain_length(int p_new_length);
-
- void set_jiggle_joint_bone_name(int p_joint_idx, String p_name);
- String get_jiggle_joint_bone_name(int p_joint_idx) const;
- void set_jiggle_joint_bone_index(int p_joint_idx, int p_idx);
- int get_jiggle_joint_bone_index(int p_joint_idx) const;
-
- void set_jiggle_joint_override(int p_joint_idx, bool p_override);
- bool get_jiggle_joint_override(int p_joint_idx) const;
- void set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness);
- real_t get_jiggle_joint_stiffness(int p_joint_idx) const;
- void set_jiggle_joint_mass(int p_joint_idx, real_t p_mass);
- real_t get_jiggle_joint_mass(int p_joint_idx) const;
- void set_jiggle_joint_damping(int p_joint_idx, real_t p_damping);
- real_t get_jiggle_joint_damping(int p_joint_idx) const;
- void set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity);
- bool get_jiggle_joint_use_gravity(int p_joint_idx) const;
- void set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity);
- Vector3 get_jiggle_joint_gravity(int p_joint_idx) const;
- void set_jiggle_joint_roll(int p_joint_idx, real_t p_roll);
- real_t get_jiggle_joint_roll(int p_joint_idx) const;
-
- SkeletonModification3DJiggle();
- ~SkeletonModification3DJiggle();
-};
-
-#endif // SKELETON_MODIFICATION_3D_JIGGLE_H
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
deleted file mode 100644
index 57eedeb64e..0000000000
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_lookat.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_lookat.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DLookAt::_set(const StringName &p_path, const Variant &p_value) {
- if (p_path == "lock_rotation_to_plane") {
- set_lock_rotation_to_plane(p_value);
- } else if (p_path == "lock_rotation_plane") {
- set_lock_rotation_plane(p_value);
- } else if (p_path == "additional_rotation") {
- Vector3 tmp = p_value;
- tmp.x = Math::deg_to_rad(tmp.x);
- tmp.y = Math::deg_to_rad(tmp.y);
- tmp.z = Math::deg_to_rad(tmp.z);
- set_additional_rotation(tmp);
- }
-
- return true;
-}
-
-bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret) const {
- if (p_path == "lock_rotation_to_plane") {
- r_ret = get_lock_rotation_to_plane();
- } else if (p_path == "lock_rotation_plane") {
- r_ret = get_lock_rotation_plane();
- } else if (p_path == "additional_rotation") {
- Vector3 tmp = get_additional_rotation();
- tmp.x = Math::rad_to_deg(tmp.x);
- tmp.y = Math::rad_to_deg(tmp.y);
- tmp.z = Math::rad_to_deg(tmp.z);
- r_ret = tmp;
- }
-
- return true;
-}
-
-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::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-}
-
-void SkeletonModification3DLookAt::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache();
- return;
- }
-
- if (bone_idx <= -2) {
- bone_idx = stack->skeleton->find_bone(bone_name);
- }
-
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- if (_print_execution_error(bone_idx <= -1, "Bone index is invalid. Cannot execute modification!")) {
- return;
- }
- Transform3D new_bone_trans = stack->skeleton->get_bone_local_pose_override(bone_idx);
- if (new_bone_trans == Transform3D()) {
- new_bone_trans = stack->skeleton->get_bone_pose(bone_idx);
- }
- Vector3 target_pos = stack->skeleton->global_pose_to_local_pose(bone_idx, stack->skeleton->world_transform_to_global_pose(target->get_global_transform())).origin;
-
- // Lock the rotation to a plane relative to the bone by changing the target position
- if (lock_rotation_to_plane) {
- if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_X) {
- target_pos.x = new_bone_trans.origin.x;
- } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Y) {
- target_pos.y = new_bone_trans.origin.y;
- } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Z) {
- target_pos.z = new_bone_trans.origin.z;
- }
- }
-
- // Look at the target!
- new_bone_trans = new_bone_trans.looking_at(target_pos, Vector3(0, 1, 0));
- // Convert from Z-forward to whatever direction the bone faces.
- stack->skeleton->update_bone_rest_forward_vector(bone_idx);
- new_bone_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(bone_idx, new_bone_trans.basis);
-
- // Apply additional rotation
- new_bone_trans.basis.rotate_local(Vector3(1, 0, 0), additional_rotation.x);
- new_bone_trans.basis.rotate_local(Vector3(0, 1, 0), additional_rotation.y);
- new_bone_trans.basis.rotate_local(Vector3(0, 0, 1), additional_rotation.z);
-
- stack->skeleton->set_bone_local_pose_override(bone_idx, new_bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(bone_idx);
-
- // If we completed it successfully, then we can set execution_error_found to false
- execution_error_found = false;
-}
-
-void SkeletonModification3DLookAt::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_cache();
- }
-}
-
-void SkeletonModification3DLookAt::set_bone_name(String p_name) {
- bone_name = p_name;
- if (stack) {
- if (stack->skeleton) {
- bone_idx = stack->skeleton->find_bone(bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DLookAt::get_bone_name() const {
- return bone_name;
-}
-
-int SkeletonModification3DLookAt::get_bone_index() const {
- return bone_idx;
-}
-
-void SkeletonModification3DLookAt::set_bone_index(int p_bone_idx) {
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DLookAt::update_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: Node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: Node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DLookAt::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache();
-}
-
-NodePath SkeletonModification3DLookAt::get_target_node() const {
- return target_node;
-}
-
-Vector3 SkeletonModification3DLookAt::get_additional_rotation() const {
- return additional_rotation;
-}
-
-void SkeletonModification3DLookAt::set_additional_rotation(Vector3 p_offset) {
- additional_rotation = p_offset;
-}
-
-bool SkeletonModification3DLookAt::get_lock_rotation_to_plane() const {
- return lock_rotation_plane;
-}
-
-void SkeletonModification3DLookAt::set_lock_rotation_to_plane(bool p_lock_rotation) {
- lock_rotation_to_plane = p_lock_rotation;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DLookAt::get_lock_rotation_plane() const {
- return lock_rotation_plane;
-}
-
-void SkeletonModification3DLookAt::set_lock_rotation_plane(int p_plane) {
- lock_rotation_plane = p_plane;
-}
-
-void SkeletonModification3DLookAt::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_bone_name", "name"), &SkeletonModification3DLookAt::set_bone_name);
- ClassDB::bind_method(D_METHOD("get_bone_name"), &SkeletonModification3DLookAt::get_bone_name);
-
- ClassDB::bind_method(D_METHOD("set_bone_index", "bone_idx"), &SkeletonModification3DLookAt::set_bone_index);
- ClassDB::bind_method(D_METHOD("get_bone_index"), &SkeletonModification3DLookAt::get_bone_index);
-
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DLookAt::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DLookAt::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_additional_rotation", "additional_rotation"), &SkeletonModification3DLookAt::set_additional_rotation);
- ClassDB::bind_method(D_METHOD("get_additional_rotation"), &SkeletonModification3DLookAt::get_additional_rotation);
-
- ClassDB::bind_method(D_METHOD("set_lock_rotation_to_plane", "lock_to_plane"), &SkeletonModification3DLookAt::set_lock_rotation_to_plane);
- ClassDB::bind_method(D_METHOD("get_lock_rotation_to_plane"), &SkeletonModification3DLookAt::get_lock_rotation_to_plane);
- ClassDB::bind_method(D_METHOD("set_lock_rotation_plane", "plane"), &SkeletonModification3DLookAt::set_lock_rotation_plane);
- ClassDB::bind_method(D_METHOD("get_lock_rotation_plane"), &SkeletonModification3DLookAt::get_lock_rotation_plane);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_index"), "set_bone_index", "get_bone_index");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
-}
-
-SkeletonModification3DLookAt::SkeletonModification3DLookAt() {
- stack = nullptr;
- is_setup = false;
- bone_name = "";
- bone_idx = -2;
- additional_rotation = Vector3();
- lock_rotation_to_plane = false;
- enabled = true;
-}
-
-SkeletonModification3DLookAt::~SkeletonModification3DLookAt() {
-}
diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h
deleted file mode 100644
index 9a25ac530d..0000000000
--- a/scene/resources/skeleton_modification_3d_lookat.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_lookat.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_LOOKAT_H
-#define SKELETON_MODIFICATION_3D_LOOKAT_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DLookAt : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D);
-
-private:
- String bone_name = "";
- int bone_idx = -1;
- NodePath target_node;
- ObjectID target_node_cache;
-
- Vector3 additional_rotation = Vector3(1, 0, 0);
- bool lock_rotation_to_plane = false;
- int lock_rotation_plane = ROTATION_PLANE_X;
-
- void update_cache();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- enum ROTATION_PLANE {
- ROTATION_PLANE_X,
- ROTATION_PLANE_Y,
- ROTATION_PLANE_Z
- };
-
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_bone_name(String p_name);
- String get_bone_name() const;
-
- void set_bone_index(int p_idx);
- int get_bone_index() const;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_additional_rotation(Vector3 p_offset);
- Vector3 get_additional_rotation() const;
-
- void set_lock_rotation_to_plane(bool p_lock_to_plane);
- bool get_lock_rotation_to_plane() const;
- void set_lock_rotation_plane(int p_plane);
- int get_lock_rotation_plane() const;
-
- SkeletonModification3DLookAt();
- ~SkeletonModification3DLookAt();
-};
-
-#endif // SKELETON_MODIFICATION_3D_LOOKAT_H
diff --git a/scene/resources/skeleton_modification_3d_stackholder.cpp b/scene/resources/skeleton_modification_3d_stackholder.cpp
deleted file mode 100644
index 1598badb30..0000000000
--- a/scene/resources/skeleton_modification_3d_stackholder.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_stackholder.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_stackholder.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DStackHolder::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path == "held_modification_stack") {
- set_held_modification_stack(p_value);
- }
- return true;
-}
-
-bool SkeletonModification3DStackHolder::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path == "held_modification_stack") {
- r_ret = get_held_modification_stack();
- }
- return true;
-}
-
-void SkeletonModification3DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
-}
-
-void SkeletonModification3DStackHolder::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
-
- if (held_modification_stack.is_valid()) {
- held_modification_stack->execute(p_delta, execution_mode);
- }
-}
-
-void SkeletonModification3DStackHolder::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
-
- if (held_modification_stack.is_valid()) {
- held_modification_stack->set_skeleton(stack->get_skeleton());
- held_modification_stack->setup();
- }
- }
-}
-
-void SkeletonModification3DStackHolder::set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack) {
- held_modification_stack = p_held_stack;
-
- if (is_setup && held_modification_stack.is_valid()) {
- held_modification_stack->set_skeleton(stack->get_skeleton());
- held_modification_stack->setup();
- }
-}
-
-Ref<SkeletonModificationStack3D> SkeletonModification3DStackHolder::get_held_modification_stack() const {
- return held_modification_stack;
-}
-
-void SkeletonModification3DStackHolder::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_held_modification_stack", "held_modification_stack"), &SkeletonModification3DStackHolder::set_held_modification_stack);
- ClassDB::bind_method(D_METHOD("get_held_modification_stack"), &SkeletonModification3DStackHolder::get_held_modification_stack);
-}
-
-SkeletonModification3DStackHolder::SkeletonModification3DStackHolder() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DStackHolder::~SkeletonModification3DStackHolder() {
-}
diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/scene/resources/skeleton_modification_3d_stackholder.h
deleted file mode 100644
index da39044f97..0000000000
--- a/scene/resources/skeleton_modification_3d_stackholder.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_stackholder.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H
-#define SKELETON_MODIFICATION_3D_STACKHOLDER_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DStackHolder : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D);
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- Ref<SkeletonModificationStack3D> held_modification_stack;
-
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack);
- Ref<SkeletonModificationStack3D> get_held_modification_stack() const;
-
- SkeletonModification3DStackHolder();
- ~SkeletonModification3DStackHolder();
-};
-
-#endif // SKELETON_MODIFICATION_3D_STACKHOLDER_H
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp
deleted file mode 100644
index 7d5b4d2b55..0000000000
--- a/scene/resources/skeleton_modification_3d_twoboneik.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_twoboneik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "scene/resources/skeleton_modification_3d_twoboneik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DTwoBoneIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path == "use_tip_node") {
- set_use_tip_node(p_value);
- } else if (path == "tip_node") {
- set_tip_node(p_value);
- } else if (path == "auto_calculate_joint_length") {
- set_auto_calculate_joint_length(p_value);
- } else if (path == "use_pole_node") {
- set_use_pole_node(p_value);
- } else if (path == "pole_node") {
- set_pole_node(p_value);
- } else if (path == "joint_one_length") {
- set_joint_one_length(p_value);
- } else if (path == "joint_two_length") {
- set_joint_two_length(p_value);
- } else if (path == "joint_one/bone_name") {
- set_joint_one_bone_name(p_value);
- } else if (path == "joint_one/bone_idx") {
- set_joint_one_bone_idx(p_value);
- } else if (path == "joint_one/roll") {
- set_joint_one_roll(Math::deg_to_rad(real_t(p_value)));
- } else if (path == "joint_two/bone_name") {
- set_joint_two_bone_name(p_value);
- } else if (path == "joint_two/bone_idx") {
- set_joint_two_bone_idx(p_value);
- } else if (path == "joint_two/roll") {
- set_joint_two_roll(Math::deg_to_rad(real_t(p_value)));
- }
-
- return true;
-}
-
-bool SkeletonModification3DTwoBoneIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path == "use_tip_node") {
- r_ret = get_use_tip_node();
- } else if (path == "tip_node") {
- r_ret = get_tip_node();
- } else if (path == "auto_calculate_joint_length") {
- r_ret = get_auto_calculate_joint_length();
- } else if (path == "use_pole_node") {
- r_ret = get_use_pole_node();
- } else if (path == "pole_node") {
- r_ret = get_pole_node();
- } else if (path == "joint_one_length") {
- r_ret = get_joint_one_length();
- } else if (path == "joint_two_length") {
- r_ret = get_joint_two_length();
- } else if (path == "joint_one/bone_name") {
- r_ret = get_joint_one_bone_name();
- } else if (path == "joint_one/bone_idx") {
- r_ret = get_joint_one_bone_idx();
- } else if (path == "joint_one/roll") {
- r_ret = Math::rad_to_deg(get_joint_one_roll());
- } else if (path == "joint_two/bone_name") {
- r_ret = get_joint_two_bone_name();
- } else if (path == "joint_two/bone_idx") {
- r_ret = get_joint_two_bone_idx();
- } else if (path == "joint_two/roll") {
- r_ret = Math::rad_to_deg(get_joint_two_roll());
- }
-
- return true;
-}
-
-void SkeletonModification3DTwoBoneIK::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_tip_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_joint_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (!auto_calculate_joint_length) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_pole_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_pole_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "pole_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_one/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, "joint_one/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_two/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, "joint_two/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
-}
-
-void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
-
- if (!enabled) {
- return;
- }
-
- if (_print_execution_error(joint_one_bone_idx < 0 || joint_two_bone_idx < 0,
- "One (or more) of the bones in the modification have invalid bone indexes. Cannot execute modification!")) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache_target();
- return;
- }
-
- // Update joint lengths (if needed)
- if (auto_calculate_joint_length && (joint_one_length < 0 || joint_two_length < 0)) {
- calculate_joint_lengths();
- }
-
- // Adopted from the links below:
- // http://theorangeduck.com/page/simple-two-joint
- // https://www.alanzucconi.com/2018/05/02/ik-2d-2/
- // With modifications by TwistedTwigleg
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- Transform3D target_trans = stack->skeleton->world_transform_to_global_pose(target->get_global_transform());
-
- Transform3D bone_one_trans;
- Transform3D bone_two_trans;
-
- // Make the first joint look at the pole, and the second look at the target. That way, the
- // TwoBoneIK solver has to really only handle extension/contraction, which should make it align with the pole.
- if (use_pole_node) {
- if (pole_node_cache.is_null()) {
- _print_execution_error(true, "Pole cache is out of date. Attempting to update...");
- update_cache_pole();
- return;
- }
-
- Node3D *pole = Object::cast_to<Node3D>(ObjectDB::get_instance(pole_node_cache));
- if (_print_execution_error(!pole || !pole->is_inside_tree(), "Pole node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- Transform3D pole_trans = stack->skeleton->world_transform_to_global_pose(pole->get_global_transform());
-
- Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx);
- if (bone_one_local_pos == Transform3D()) {
- bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx);
- }
- Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx);
- if (bone_two_local_pos == Transform3D()) {
- bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx);
- }
-
- bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos);
- bone_one_trans = bone_one_trans.looking_at(pole_trans.origin, Vector3(0, 1, 0));
- bone_one_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_one_bone_idx, bone_one_trans.basis);
- stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx);
- bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll);
- stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans), stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx);
-
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos);
- bone_two_trans = bone_two_trans.looking_at(target_trans.origin, Vector3(0, 1, 0));
- bone_two_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_two_bone_idx, bone_two_trans.basis);
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans), stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- } else {
- Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx);
- if (bone_one_local_pos == Transform3D()) {
- bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx);
- }
- Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx);
- if (bone_two_local_pos == Transform3D()) {
- bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx);
- }
-
- bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos);
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos);
- }
-
- Transform3D bone_two_tip_trans;
- if (use_tip_node) {
- if (tip_node_cache.is_null()) {
- _print_execution_error(true, "Tip cache is out of date. Attempting to update...");
- update_cache_tip();
- return;
- }
- Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
- if (_print_execution_error(!tip || !tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- bone_two_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform());
- } else {
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_tip_trans = bone_two_trans;
- bone_two_tip_trans.origin += bone_two_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx)).normalized() * joint_two_length;
- }
-
- real_t joint_one_to_target_length = bone_one_trans.origin.distance_to(target_trans.origin);
- if (joint_one_length + joint_two_length < joint_one_to_target_length) {
- // Set the target *just* out of reach to straighten the bones
- joint_one_to_target_length = joint_one_length + joint_two_length + 0.01;
- } else if (joint_one_to_target_length < joint_one_length) {
- // Place the target in reach so the solver doesn't do crazy things
- joint_one_to_target_length = joint_one_length;
- }
-
- // Get the square lengths for all three sides of the triangle we'll use to calculate the angles
- real_t sqr_one_length = joint_one_length * joint_one_length;
- real_t sqr_two_length = joint_two_length * joint_two_length;
- real_t sqr_three_length = joint_one_to_target_length * joint_one_to_target_length;
-
- // Calculate the angles for the first joint using the law of cosigns
- real_t ac_ab_0 = Math::acos(CLAMP(bone_two_tip_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_one_trans.origin)), -1, 1));
- real_t ac_at_0 = Math::acos(CLAMP(bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).dot(bone_one_trans.origin.direction_to(target_trans.origin)), -1, 1));
- real_t ac_ab_1 = Math::acos(CLAMP((sqr_two_length - sqr_one_length - sqr_three_length) / (-2.0 * joint_one_length * joint_one_to_target_length), -1, 1));
-
- // Calculate the angles of rotation. Angle 0 is the extension/contraction axis, while angle 1 is the rotation axis to align the triangle to the target
- Vector3 axis_0 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(bone_two_trans.origin));
- Vector3 axis_1 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(target_trans.origin));
-
- // Make a quaternion with the delta rotation needed to rotate the first joint into alignment and apply it to the transform.
- Quaternion bone_one_quat = bone_one_trans.basis.get_rotation_quaternion();
- Quaternion rot_0 = Quaternion(bone_one_quat.inverse().xform(axis_0).normalized(), (ac_ab_1 - ac_ab_0));
- Quaternion rot_2 = Quaternion(bone_one_quat.inverse().xform(axis_1).normalized(), ac_at_0);
- bone_one_trans.basis.set_quaternion(bone_one_quat * (rot_0 * rot_2));
-
- stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx);
- bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll);
-
- // Apply the rotation to the first joint
- bone_one_trans = stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans);
- bone_one_trans.origin = Vector3(0, 0, 0);
- stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, bone_one_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx);
-
- if (use_pole_node) {
- // Update bone_two_trans so its at the latest position, with the rotation of bone_one_trans taken into account, then look at the target.
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx));
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_to_align(forward_vector, bone_two_trans.origin.direction_to(target_trans.origin));
-
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
-
- bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- } else {
- // Calculate the angles for the second joint using the law of cosigns, make a quaternion with the delta rotation needed to rotate the joint into
- // alignment, and then apply it to the second joint.
- real_t ba_bc_0 = Math::acos(CLAMP(bone_two_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_two_tip_trans.origin)), -1, 1));
- real_t ba_bc_1 = Math::acos(CLAMP((sqr_three_length - sqr_one_length - sqr_two_length) / (-2.0 * joint_one_length * joint_two_length), -1, 1));
- Quaternion bone_two_quat = bone_two_trans.basis.get_rotation_quaternion();
- Quaternion rot_1 = Quaternion(bone_two_quat.inverse().xform(axis_0).normalized(), (ba_bc_1 - ba_bc_0));
- bone_two_trans.basis.set_quaternion(bone_two_quat * rot_1);
-
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
-
- bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans);
- bone_two_trans.origin = Vector3(0, 0, 0);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- }
-}
-
-void SkeletonModification3DTwoBoneIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_cache_target();
- update_cache_tip();
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_target() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: Target node is this modification's skeleton or cannot be found. Cannot execute modification");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: Target node is not in the scene tree. Cannot execute modification!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_tip() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
-
- tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(tip_node)) {
- Node *node = stack->skeleton->get_node(tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache: Tip node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache: Tip node is not in the scene tree. Cannot execute modification!");
- tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_pole() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update pole cache: modification is not properly setup!");
- return;
- }
-
- pole_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(pole_node)) {
- Node *node = stack->skeleton->get_node(pole_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update pole cache: Pole node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update pole cache: Pole node is not in the scene tree. Cannot execute modification!");
- pole_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache_target();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_use_tip_node(const bool p_use_tip_node) {
- use_tip_node = p_use_tip_node;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_use_tip_node() const {
- return use_tip_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_tip_node(const NodePath &p_tip_node) {
- tip_node = p_tip_node;
- update_cache_tip();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_tip_node() const {
- return tip_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_use_pole_node(const bool p_use_pole_node) {
- use_pole_node = p_use_pole_node;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_use_pole_node() const {
- return use_pole_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_pole_node(const NodePath &p_pole_node) {
- pole_node = p_pole_node;
- update_cache_pole();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_pole_node() const {
- return pole_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length(bool p_calculate) {
- auto_calculate_joint_length = p_calculate;
- if (p_calculate) {
- calculate_joint_lengths();
- }
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length() const {
- return auto_calculate_joint_length;
-}
-
-void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() {
- if (!is_setup) {
- return; // fail silently, as we likely just loaded the scene.
- }
- ERR_FAIL_COND_MSG(!stack || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot calculate joint lengths!");
- ERR_FAIL_COND_MSG(joint_one_bone_idx <= -1 || joint_two_bone_idx <= -1,
- "One of the bones in the TwoBoneIK modification are not set! Cannot calculate joint lengths!");
-
- Transform3D bone_one_rest_trans = stack->skeleton->get_bone_global_pose(joint_one_bone_idx);
- Transform3D bone_two_rest_trans = stack->skeleton->get_bone_global_pose(joint_two_bone_idx);
-
- joint_one_length = bone_one_rest_trans.origin.distance_to(bone_two_rest_trans.origin);
-
- if (use_tip_node) {
- if (tip_node_cache.is_null()) {
- update_cache_tip();
- WARN_PRINT("Tip cache is out of date. Updating...");
- }
-
- Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
- if (tip) {
- Transform3D bone_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform());
- joint_two_length = bone_two_rest_trans.origin.distance_to(bone_tip_trans.origin);
- }
- } else {
- // Attempt to use children bones to get the length
- Vector<int> bone_two_children = stack->skeleton->get_bone_children(joint_two_bone_idx);
- if (bone_two_children.size() > 0) {
- joint_two_length = 0;
- for (int i = 0; i < bone_two_children.size(); i++) {
- joint_two_length += bone_two_rest_trans.origin.distance_to(
- stack->skeleton->get_bone_global_pose(bone_two_children[i]).origin);
- }
- joint_two_length = joint_two_length / bone_two_children.size();
- } else {
- WARN_PRINT("TwoBoneIK modification: Cannot auto calculate length for joint 2! Auto setting the length to 1...");
- joint_two_length = 1.0;
- }
- }
- execution_error_found = false;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_bone_name(String p_bone_name) {
- joint_one_bone_name = p_bone_name;
- if (stack && stack->skeleton) {
- joint_one_bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DTwoBoneIK::get_joint_one_bone_name() const {
- return joint_one_bone_name;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx(int p_bone_idx) {
- joint_one_bone_idx = p_bone_idx;
- if (stack && stack->skeleton) {
- joint_one_bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx() const {
- return joint_one_bone_idx;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_length(real_t p_length) {
- joint_one_length = p_length;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_one_length() const {
- return joint_one_length;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_bone_name(String p_bone_name) {
- joint_two_bone_name = p_bone_name;
- if (stack && stack->skeleton) {
- joint_two_bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DTwoBoneIK::get_joint_two_bone_name() const {
- return joint_two_bone_name;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx(int p_bone_idx) {
- joint_two_bone_idx = p_bone_idx;
- if (stack && stack->skeleton) {
- joint_two_bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx() const {
- return joint_two_bone_idx;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_length(real_t p_length) {
- joint_two_length = p_length;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_two_length() const {
- return joint_two_length;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_roll(real_t p_roll) {
- joint_one_roll = p_roll;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_one_roll() const {
- return joint_one_roll;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_roll(real_t p_roll) {
- joint_two_roll = p_roll;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_two_roll() const {
- return joint_two_roll;
-}
-
-void SkeletonModification3DTwoBoneIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DTwoBoneIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DTwoBoneIK::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_use_pole_node", "use_pole_node"), &SkeletonModification3DTwoBoneIK::set_use_pole_node);
- ClassDB::bind_method(D_METHOD("get_use_pole_node"), &SkeletonModification3DTwoBoneIK::get_use_pole_node);
- ClassDB::bind_method(D_METHOD("set_pole_node", "pole_nodepath"), &SkeletonModification3DTwoBoneIK::set_pole_node);
- ClassDB::bind_method(D_METHOD("get_pole_node"), &SkeletonModification3DTwoBoneIK::get_pole_node);
-
- ClassDB::bind_method(D_METHOD("set_use_tip_node", "use_tip_node"), &SkeletonModification3DTwoBoneIK::set_use_tip_node);
- ClassDB::bind_method(D_METHOD("get_use_tip_node"), &SkeletonModification3DTwoBoneIK::get_use_tip_node);
- ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DTwoBoneIK::set_tip_node);
- ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DTwoBoneIK::get_tip_node);
-
- ClassDB::bind_method(D_METHOD("set_auto_calculate_joint_length", "auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length);
- ClassDB::bind_method(D_METHOD("get_auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_one_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_name);
- ClassDB::bind_method(D_METHOD("get_joint_one_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_name);
- ClassDB::bind_method(D_METHOD("set_joint_one_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx);
- ClassDB::bind_method(D_METHOD("get_joint_one_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx);
- ClassDB::bind_method(D_METHOD("set_joint_one_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_one_length);
- ClassDB::bind_method(D_METHOD("get_joint_one_length"), &SkeletonModification3DTwoBoneIK::get_joint_one_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_two_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_name);
- ClassDB::bind_method(D_METHOD("get_joint_two_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_name);
- ClassDB::bind_method(D_METHOD("set_joint_two_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx);
- ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx);
- ClassDB::bind_method(D_METHOD("set_joint_two_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_two_length);
- ClassDB::bind_method(D_METHOD("get_joint_two_length"), &SkeletonModification3DTwoBoneIK::get_joint_two_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_one_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_one_roll);
- ClassDB::bind_method(D_METHOD("get_joint_one_roll"), &SkeletonModification3DTwoBoneIK::get_joint_one_roll);
- ClassDB::bind_method(D_METHOD("set_joint_two_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_two_roll);
- ClassDB::bind_method(D_METHOD("get_joint_two_roll"), &SkeletonModification3DTwoBoneIK::get_joint_two_roll);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_GROUP("", "");
-}
-
-SkeletonModification3DTwoBoneIK::SkeletonModification3DTwoBoneIK() {
- stack = nullptr;
- is_setup = false;
-}
-
-SkeletonModification3DTwoBoneIK::~SkeletonModification3DTwoBoneIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h
deleted file mode 100644
index 57481e0181..0000000000
--- a/scene/resources/skeleton_modification_3d_twoboneik.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_twoboneik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_3D_TWOBONEIK_H
-#define SKELETON_MODIFICATION_3D_TWOBONEIK_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DTwoBoneIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D);
-
-private:
- NodePath target_node;
- ObjectID target_node_cache;
-
- bool use_tip_node = false;
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_pole_node = false;
- NodePath pole_node;
- ObjectID pole_node_cache;
-
- String joint_one_bone_name = "";
- int joint_one_bone_idx = -1;
- String joint_two_bone_name = "";
- int joint_two_bone_idx = -1;
-
- bool auto_calculate_joint_length = false;
- real_t joint_one_length = -1;
- real_t joint_two_length = -1;
-
- real_t joint_one_roll = 0;
- real_t joint_two_roll = 0;
-
- void update_cache_target();
- void update_cache_tip();
- void update_cache_pole();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_use_tip_node(const bool p_use_tip_node);
- bool get_use_tip_node() const;
- void set_tip_node(const NodePath &p_tip_node);
- NodePath get_tip_node() const;
-
- void set_use_pole_node(const bool p_use_pole_node);
- bool get_use_pole_node() const;
- void set_pole_node(const NodePath &p_pole_node);
- NodePath get_pole_node() const;
-
- void set_auto_calculate_joint_length(bool p_calculate);
- bool get_auto_calculate_joint_length() const;
- void calculate_joint_lengths();
-
- void set_joint_one_bone_name(String p_bone_name);
- String get_joint_one_bone_name() const;
- void set_joint_one_bone_idx(int p_bone_idx);
- int get_joint_one_bone_idx() const;
- void set_joint_one_length(real_t p_length);
- real_t get_joint_one_length() const;
-
- void set_joint_two_bone_name(String p_bone_name);
- String get_joint_two_bone_name() const;
- void set_joint_two_bone_idx(int p_bone_idx);
- int get_joint_two_bone_idx() const;
- void set_joint_two_length(real_t p_length);
- real_t get_joint_two_length() const;
-
- void set_joint_one_roll(real_t p_roll);
- real_t get_joint_one_roll() const;
- void set_joint_two_roll(real_t p_roll);
- real_t get_joint_two_roll() const;
-
- SkeletonModification3DTwoBoneIK();
- ~SkeletonModification3DTwoBoneIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_TWOBONEIK_H
diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp
deleted file mode 100644
index 32708e198a..0000000000
--- a/scene/resources/skeleton_modification_stack_3d.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_stack_3d.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "skeleton_modification_stack_3d.h"
-#include "scene/3d/skeleton_3d.h"
-
-///////////////////////////////////////
-// ModificationStack3D
-///////////////////////////////////////
-
-void SkeletonModificationStack3D::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < modifications.size(); i++) {
- p_list->push_back(
- PropertyInfo(Variant::OBJECT, "modifications/" + itos(i),
- PROPERTY_HINT_RESOURCE_TYPE,
- "SkeletonModification3D",
- PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
- }
-}
-
-bool SkeletonModificationStack3D::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("modifications/")) {
- int mod_idx = path.get_slicec('/', 1).to_int();
- set_modification(mod_idx, p_value);
- return true;
- }
- return true;
-}
-
-bool SkeletonModificationStack3D::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("modifications/")) {
- int mod_idx = path.get_slicec('/', 1).to_int();
- r_ret = get_modification(mod_idx);
- return true;
- }
- return true;
-}
-
-void SkeletonModificationStack3D::setup() {
- if (is_setup) {
- return;
- }
-
- if (skeleton != nullptr) {
- is_setup = true;
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
- modifications[i]->_setup_modification(this);
- }
- } else {
- WARN_PRINT("Cannot setup SkeletonModificationStack3D: no skeleton set!");
- }
-}
-
-void SkeletonModificationStack3D::execute(real_t p_delta, int p_execution_mode) {
- ERR_FAIL_COND_MSG(!is_setup || skeleton == nullptr || is_queued_for_deletion(),
- "Modification stack is not properly setup and therefore cannot execute!");
-
- if (!skeleton->is_inside_tree()) {
- ERR_PRINT_ONCE("Skeleton is not inside SceneTree! Cannot execute modification!");
- return;
- }
-
- if (!enabled) {
- return;
- }
-
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
-
- if (modifications[i]->get_execution_mode() == p_execution_mode) {
- modifications[i]->_execute(p_delta);
- }
- }
-}
-
-void SkeletonModificationStack3D::enable_all_modifications(bool p_enabled) {
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
- modifications[i]->set_enabled(p_enabled);
- }
-}
-
-Ref<SkeletonModification3D> SkeletonModificationStack3D::get_modification(int p_mod_idx) const {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX_V(p_mod_idx, modifications_size, nullptr);
- return modifications[p_mod_idx];
-}
-
-void SkeletonModificationStack3D::add_modification(Ref<SkeletonModification3D> p_mod) {
- ERR_FAIL_NULL(p_mod);
- p_mod->_setup_modification(this);
- modifications.push_back(p_mod);
-}
-
-void SkeletonModificationStack3D::delete_modification(int p_mod_idx) {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX(p_mod_idx, modifications_size);
- modifications.remove_at(p_mod_idx);
-}
-
-void SkeletonModificationStack3D::set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod) {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX(p_mod_idx, modifications_size);
-
- if (p_mod == nullptr) {
- modifications.remove_at(p_mod_idx);
- } else {
- p_mod->_setup_modification(this);
- modifications[p_mod_idx] = p_mod;
- }
-}
-
-void SkeletonModificationStack3D::set_modification_count(int p_count) {
- ERR_FAIL_COND_MSG(p_count < 0, "Modification count cannot be less than zero.");
- modifications.resize(p_count);
- notify_property_list_changed();
-}
-
-int SkeletonModificationStack3D::get_modification_count() const {
- return modifications.size();
-}
-
-void SkeletonModificationStack3D::set_skeleton(Skeleton3D *p_skeleton) {
- skeleton = p_skeleton;
-}
-
-Skeleton3D *SkeletonModificationStack3D::get_skeleton() const {
- return skeleton;
-}
-
-bool SkeletonModificationStack3D::get_is_setup() const {
- return is_setup;
-}
-
-void SkeletonModificationStack3D::set_enabled(bool p_enabled) {
- enabled = p_enabled;
-
- if (!enabled && is_setup && skeleton != nullptr) {
- skeleton->clear_bones_local_pose_override();
- }
-}
-
-bool SkeletonModificationStack3D::get_enabled() const {
- return enabled;
-}
-
-void SkeletonModificationStack3D::set_strength(real_t p_strength) {
- ERR_FAIL_COND_MSG(p_strength < 0, "Strength cannot be less than zero!");
- ERR_FAIL_COND_MSG(p_strength > 1, "Strength cannot be more than one!");
- strength = p_strength;
-}
-
-real_t SkeletonModificationStack3D::get_strength() const {
- return strength;
-}
-
-void SkeletonModificationStack3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("setup"), &SkeletonModificationStack3D::setup);
- ClassDB::bind_method(D_METHOD("execute", "delta", "execution_mode"), &SkeletonModificationStack3D::execute);
-
- ClassDB::bind_method(D_METHOD("enable_all_modifications", "enabled"), &SkeletonModificationStack3D::enable_all_modifications);
- ClassDB::bind_method(D_METHOD("get_modification", "mod_idx"), &SkeletonModificationStack3D::get_modification);
- ClassDB::bind_method(D_METHOD("add_modification", "modification"), &SkeletonModificationStack3D::add_modification);
- ClassDB::bind_method(D_METHOD("delete_modification", "mod_idx"), &SkeletonModificationStack3D::delete_modification);
- ClassDB::bind_method(D_METHOD("set_modification", "mod_idx", "modification"), &SkeletonModificationStack3D::set_modification);
-
- ClassDB::bind_method(D_METHOD("set_modification_count", "count"), &SkeletonModificationStack3D::set_modification_count);
- ClassDB::bind_method(D_METHOD("get_modification_count"), &SkeletonModificationStack3D::get_modification_count);
-
- ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModificationStack3D::get_is_setup);
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModificationStack3D::set_enabled);
- ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModificationStack3D::get_enabled);
-
- ClassDB::bind_method(D_METHOD("set_strength", "strength"), &SkeletonModificationStack3D::set_strength);
- ClassDB::bind_method(D_METHOD("get_strength"), &SkeletonModificationStack3D::get_strength);
-
- ClassDB::bind_method(D_METHOD("get_skeleton"), &SkeletonModificationStack3D::get_skeleton);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count");
-}
-
-SkeletonModificationStack3D::SkeletonModificationStack3D() {
-}
diff --git a/scene/resources/skeleton_modification_stack_3d.h b/scene/resources/skeleton_modification_stack_3d.h
deleted file mode 100644
index fd490c49e9..0000000000
--- a/scene/resources/skeleton_modification_stack_3d.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_stack_3d.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef SKELETON_MODIFICATION_STACK_3D_H
-#define SKELETON_MODIFICATION_STACK_3D_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-
-class Skeleton3D;
-class SkeletonModification3D;
-
-class SkeletonModificationStack3D : public Resource {
- GDCLASS(SkeletonModificationStack3D, Resource);
- friend class Skeleton3D;
- friend class SkeletonModification3D;
-
-protected:
- static void _bind_methods();
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual bool _set(const StringName &p_path, const Variant &p_value);
- virtual bool _get(const StringName &p_path, Variant &r_ret) const;
-
-public:
- Skeleton3D *skeleton = nullptr;
- bool is_setup = false;
- bool enabled = false;
- real_t strength = 1.0;
-
- enum EXECUTION_MODE {
- execution_mode_process,
- execution_mode_physics_process,
- };
-
- LocalVector<Ref<SkeletonModification3D>> modifications = LocalVector<Ref<SkeletonModification3D>>();
- int modifications_count = 0;
-
- virtual void setup();
- virtual void execute(real_t p_delta, int p_execution_mode);
-
- void enable_all_modifications(bool p_enable);
- Ref<SkeletonModification3D> get_modification(int p_mod_idx) const;
- void add_modification(Ref<SkeletonModification3D> p_mod);
- void delete_modification(int p_mod_idx);
- void set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod);
-
- void set_modification_count(int p_count);
- int get_modification_count() const;
-
- void set_skeleton(Skeleton3D *p_skeleton);
- Skeleton3D *get_skeleton() const;
-
- bool get_is_setup() const;
-
- void set_enabled(bool p_enabled);
- bool get_enabled() const;
-
- void set_strength(real_t p_strength);
- real_t get_strength() const;
-
- SkeletonModificationStack3D();
-};
-
-#endif // SKELETON_MODIFICATION_STACK_3D_H
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 4043b73b71..94e78fc3aa 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -473,6 +473,7 @@ void TileSet::_compute_next_source_id() {
int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) {
ERR_FAIL_COND_V(!p_tile_set_source.is_valid(), TileSet::INVALID_SOURCE);
ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), TileSet::INVALID_SOURCE, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override));
+ ERR_FAIL_COND_V_MSG(p_atlas_source_id_override < 0 && p_atlas_source_id_override != TileSet::INVALID_SOURCE, TileSet::INVALID_SOURCE, vformat("Provided source ID %d is not valid. Negative source IDs are not allowed.", p_atlas_source_id_override));
int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
sources[new_source_id] = p_tile_set_source;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 4c99563a91..76fb2d1367 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -2734,9 +2734,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
@@ -2799,7 +2796,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 432d5a5b59..ec89c87bd2 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -771,6 +771,23 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade
break;
}
return u + ";\n";
+ } else if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+ String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "screen_tex");
+ return u + " : hint_screen_texture;\n";
+ } else if (source == SOURCE_DEPTH || source == SOURCE_3D_NORMAL || source == SOURCE_ROUGHNESS) {
+ String sampler_name = "";
+ String hint = " : ";
+ if (source == SOURCE_DEPTH) {
+ sampler_name = "depth_tex";
+ hint += "hint_depth_texture;\n";
+ } else if (source == SOURCE_3D_NORMAL) {
+ sampler_name = "screen_normal_tex";
+ hint += "hint_normal_roughness_texture;\n";
+ } else if (source == SOURCE_ROUGHNESS) {
+ sampler_name = "screen_roughness_tex";
+ hint += "hint_normal_roughness_texture;\n";
+ }
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, sampler_name) + hint;
}
return String();
@@ -824,17 +841,18 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
}
if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+ String id = make_unique_id(p_type, p_id, "screen_tex");
if (p_input_vars[0].is_empty() || p_for_preview) { // Use UV by default.
if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0);\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", 0.0);\n";
} else {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
}
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", 0.0);\n";
} else {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
return code;
}
@@ -871,23 +889,58 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
return code;
}
- if (source == SOURCE_DEPTH) {
+ if (source == SOURCE_DEPTH || source == SOURCE_ROUGHNESS) {
if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ String var_name = "";
+ String sampler_name = "";
+
+ if (source == SOURCE_DEPTH) {
+ var_name = "_depth";
+ sampler_name = "depth_tex";
+ } else if (source == SOURCE_ROUGHNESS) {
+ var_name = "_screen_roughness";
+ sampler_name = "screen_roughness_tex";
+ }
+
+ String id = make_unique_id(p_type, p_id, sampler_name);
code += " {\n";
if (p_input_vars[0].is_empty()) { // Use UV by default.
if (p_input_vars[1].is_empty()) {
- code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n";
+ code += " float " + var_name + " = texture(" + id + ", " + default_uv + ").r;\n";
} else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n";
+ code += " float " + var_name + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ").r;\n";
}
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n";
+ code += " float " + var_name + " = texture(" + id + ", " + p_input_vars[0] + ".xy).r;\n";
} else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n";
+ code += " float " + var_name + " = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n";
}
- code += " " + p_output_vars[0] + " = vec4(_depth, _depth, _depth, 1.0);\n";
+ code += " " + p_output_vars[0] + " = vec4(" + var_name + ", " + var_name + ", " + var_name + ", 1.0);\n";
+ code += " }\n";
+ return code;
+ }
+ }
+
+ if (source == SOURCE_3D_NORMAL) {
+ if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ String id = make_unique_id(p_type, p_id, "screen_normal_tex");
+ code += " {\n";
+ if (p_input_vars[0].is_empty()) { // Use UV by default.
+ if (p_input_vars[1].is_empty()) {
+ code += " vec3 _screen_normal = texture(" + id + ", " + default_uv + ").xyz;\n";
+ } else {
+ code += " vec3 _screen_normal = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ").xyz;\n";
+ }
+ } else if (p_input_vars[1].is_empty()) {
+ //no lod
+ code += " vec3 _screen_normal = texture(" + id + ", " + p_input_vars[0] + ".xy).xyz;\n";
+ } else {
+ code += " vec3 _screen_normal = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").xyz;\n";
+ }
+
+ code += " " + p_output_vars[0] + " = vec4(_screen_normal, 1.0);\n";
code += " }\n";
return code;
}
@@ -921,6 +974,12 @@ void VisualShaderNodeTexture::set_source(Source p_source) {
case SOURCE_PORT:
simple_decl = false;
break;
+ case SOURCE_3D_NORMAL:
+ simple_decl = false;
+ break;
+ case SOURCE_ROUGHNESS:
+ simple_decl = false;
+ break;
default:
break;
}
@@ -990,8 +1049,8 @@ String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::T
return String(); // all good
}
- if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
- if (get_output_port_for_preview() == 0) { // DEPTH_TEXTURE is not supported in preview(canvas_item) shader
+ if ((source == SOURCE_DEPTH || source == SOURCE_3D_NORMAL || source == SOURCE_ROUGHNESS) && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ if (get_output_port_for_preview() == 0) { // DEPTH_TEXTURE and NORMAL_ROUGHNESS_TEXTURE are not supported in preview(canvas_item) shader
return RTR("Invalid source for preview.");
}
return String(); // all good
@@ -1010,7 +1069,7 @@ void VisualShaderNodeTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort,ScreenNormal,Roughness"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type");
@@ -1020,6 +1079,8 @@ void VisualShaderNodeTexture::_bind_methods() {
BIND_ENUM_CONSTANT(SOURCE_2D_NORMAL);
BIND_ENUM_CONSTANT(SOURCE_DEPTH);
BIND_ENUM_CONSTANT(SOURCE_PORT);
+ BIND_ENUM_CONSTANT(SOURCE_3D_NORMAL);
+ BIND_ENUM_CONSTANT(SOURCE_ROUGHNESS);
BIND_ENUM_CONSTANT(SOURCE_MAX);
BIND_ENUM_CONSTANT(TYPE_DATA);
@@ -1702,11 +1763,15 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const
return false;
}
+String VisualShaderNodeLinearSceneDepth::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n";
+}
+
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 += " float __log_depth = textureLod(" + make_unique_id(p_type, p_id, "depth_tex") + ", 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";
@@ -6101,7 +6166,7 @@ VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() {
//////////////
-String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) {
+String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat, VisualShaderNodeTextureParameter::TextureSource p_texture_source) {
String code;
bool has_colon = false;
@@ -6204,6 +6269,33 @@ String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_
}
}
+ {
+ String source_code;
+
+ switch (p_texture_source) {
+ case VisualShaderNodeTextureParameter::SOURCE_SCREEN:
+ source_code = "hint_screen_texture";
+ break;
+ case VisualShaderNodeTextureParameter::SOURCE_DEPTH:
+ source_code = "hint_depth_texture";
+ break;
+ case VisualShaderNodeTextureParameter::SOURCE_NORMAL_ROUGHNESS:
+ source_code = "hint_normal_roughness_texture";
+ break;
+ default:
+ break;
+ }
+
+ if (!source_code.is_empty()) {
+ if (!has_colon) {
+ code += " : ";
+ } else {
+ code += ", ";
+ }
+ code += source_code;
+ }
+ }
+
return code;
}
@@ -6290,6 +6382,19 @@ VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter
return texture_repeat;
}
+void VisualShaderNodeTextureParameter::set_texture_source(TextureSource p_source) {
+ ERR_FAIL_INDEX(int(p_source), int(SOURCE_MAX));
+ if (texture_source == p_source) {
+ return;
+ }
+ texture_source = p_source;
+ emit_changed();
+}
+
+VisualShaderNodeTextureParameter::TextureSource VisualShaderNodeTextureParameter::get_texture_source() const {
+ return texture_source;
+}
+
Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("texture_type");
@@ -6298,6 +6403,7 @@ Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() c
}
props.push_back("texture_filter");
props.push_back("texture_repeat");
+ props.push_back("texture_source");
return props;
}
@@ -6311,6 +6417,7 @@ HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_prope
names.insert("color_default", RTR("Default Color"));
names.insert("texture_filter", RTR("Filter"));
names.insert("texture_repeat", RTR("Repeat"));
+ names.insert("texture_source", RTR("Source"));
return names;
}
@@ -6318,19 +6425,23 @@ void VisualShaderNodeTextureParameter::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type);
- ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default);
+ ClassDB::bind_method(D_METHOD("set_color_default", "color"), &VisualShaderNodeTextureParameter::set_color_default);
ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default);
ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter);
ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter);
- ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &VisualShaderNodeTextureParameter::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::get_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_source", "source"), &VisualShaderNodeTextureParameter::set_texture_source);
+ ClassDB::bind_method(D_METHOD("get_texture_source"), &VisualShaderNodeTextureParameter::get_texture_source);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_source", PROPERTY_HINT_ENUM, "None,Screen,Depth,NormalRoughness"), "set_texture_source", "get_texture_source");
BIND_ENUM_CONSTANT(TYPE_DATA);
BIND_ENUM_CONSTANT(TYPE_COLOR);
@@ -6356,6 +6467,12 @@ void VisualShaderNodeTextureParameter::_bind_methods() {
BIND_ENUM_CONSTANT(REPEAT_ENABLED);
BIND_ENUM_CONSTANT(REPEAT_DISABLED);
BIND_ENUM_CONSTANT(REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(SOURCE_NONE);
+ BIND_ENUM_CONSTANT(SOURCE_SCREEN);
+ BIND_ENUM_CONSTANT(SOURCE_DEPTH);
+ BIND_ENUM_CONSTANT(SOURCE_NORMAL_ROUGHNESS);
+ BIND_ENUM_CONSTANT(SOURCE_MAX);
}
bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const {
@@ -6396,7 +6513,7 @@ String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) cons
String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6407,7 +6524,7 @@ VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
////////////// Texture Parameter (Triplanar)
String VisualShaderNodeTextureParameterTriplanar::get_caption() const {
- return "TextureUniformTriplanar";
+ return "TextureParameterTriplanar";
}
int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const {
@@ -6496,7 +6613,7 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shade
String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6542,7 +6659,7 @@ String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port)
String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6562,7 +6679,7 @@ String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) cons
String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6582,7 +6699,7 @@ String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const
String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 07843c0264..8d0f88d83a 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -385,6 +385,8 @@ public:
SOURCE_2D_NORMAL,
SOURCE_DEPTH,
SOURCE_PORT,
+ SOURCE_3D_NORMAL,
+ SOURCE_ROUGHNESS,
SOURCE_MAX,
};
@@ -668,6 +670,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual bool has_output_port_preview(int p_port) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String 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 = false) const override;
VisualShaderNodeLinearSceneDepth();
@@ -2362,11 +2365,20 @@ public:
REPEAT_MAX,
};
+ enum TextureSource {
+ SOURCE_NONE,
+ SOURCE_SCREEN,
+ SOURCE_DEPTH,
+ SOURCE_NORMAL_ROUGHNESS,
+ SOURCE_MAX,
+ };
+
protected:
TextureType texture_type = TYPE_DATA;
ColorDefault color_default = COLOR_DEFAULT_WHITE;
TextureFilter texture_filter = FILTER_DEFAULT;
TextureRepeat texture_repeat = REPEAT_DEFAULT;
+ TextureSource texture_source = SOURCE_NONE;
protected:
static void _bind_methods();
@@ -2398,6 +2410,9 @@ public:
void set_texture_repeat(TextureRepeat p_repeat);
TextureRepeat get_texture_repeat() const;
+ void set_texture_source(TextureSource p_source);
+ TextureSource get_texture_source() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
@@ -2408,6 +2423,7 @@ VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureSource)
///////////////////////////////////////
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 82343e0402..39f14439f4 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -848,6 +848,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP);
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
diff --git a/servers/display_server.h b/servers/display_server.h
index f8ade60aca..aa30b25b65 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -311,6 +311,7 @@ public:
WINDOW_FLAG_NO_FOCUS,
WINDOW_FLAG_POPUP,
WINDOW_FLAG_EXTEND_TO_TITLE,
+ WINDOW_FLAG_MOUSE_PASSTHROUGH,
WINDOW_FLAG_MAX,
};
@@ -323,6 +324,7 @@ public:
WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS),
WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP),
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
+ WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
};
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index 88f2040d17..e5678914fe 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -1011,9 +1011,11 @@ bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transfor
if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {
if (p_result_callback) {
if (p_swap) {
- p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata);
+ Vector3 normal = (res.witnesses[1] - res.witnesses[0]).normalized();
+ p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, normal, p_userdata);
} else {
- p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata);
+ Vector3 normal = (res.witnesses[0] - res.witnesses[1]).normalized();
+ p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, normal, p_userdata);
}
}
return true;
diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp
index ce3da390cb..619e6c00be 100644
--- a/servers/physics_3d/godot_body_pair_3d.cpp
+++ b/servers/physics_3d/godot_body_pair_3d.cpp
@@ -38,12 +38,12 @@
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
-void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
GodotBodyPair3D *pair = static_cast<GodotBodyPair3D *>(p_userdata);
- pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal);
}
-void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) {
Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A);
Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B);
@@ -577,12 +577,12 @@ GodotBodyPair3D::~GodotBodyPair3D() {
B->remove_constraint(this);
}
-void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
GodotBodySoftBodyPair3D *pair = static_cast<GodotBodySoftBodyPair3D *>(p_userdata);
- pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal);
}
-void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) {
Vector3 local_A = body->get_inv_transform().xform(p_point_A);
Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B);
@@ -591,7 +591,7 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i
contact.index_B = p_index_B;
contact.local_A = local_A;
contact.local_B = local_B;
- contact.normal = (p_point_A - p_point_B).normalized();
+ contact.normal = (normal.dot((p_point_A - p_point_B)) < 0 ? -normal : normal);
contact.used = true;
// Attempt to determine if the contact will be reused.
diff --git a/servers/physics_3d/godot_body_pair_3d.h b/servers/physics_3d/godot_body_pair_3d.h
index c3165c7fcf..a8f5180dd5 100644
--- a/servers/physics_3d/godot_body_pair_3d.h
+++ b/servers/physics_3d/godot_body_pair_3d.h
@@ -97,9 +97,9 @@ class GodotBodyPair3D : public GodotBodyContact3D {
Contact contacts[MAX_CONTACTS];
int contact_count = 0;
- static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
- void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal);
void validate_contacts();
bool _test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B);
@@ -126,9 +126,9 @@ class GodotBodySoftBodyPair3D : public GodotBodyContact3D {
LocalVector<Contact> contacts;
- static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
- void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal);
void validate_contacts();
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index 0b92b745fe..fb5a67c008 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -81,9 +81,11 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(supports[i], 0, support_A, 0, p_userdata);
+ Vector3 normal = (support_A - supports[i]).normalized();
+ p_result_callback(supports[i], 0, support_A, 0, normal, p_userdata);
} else {
- p_result_callback(support_A, 0, supports[i], 0, p_userdata);
+ Vector3 normal = (supports[i] - support_A).normalized();
+ p_result_callback(support_A, 0, supports[i], 0, normal, p_userdata);
}
}
}
@@ -126,9 +128,11 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A,
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(support_B, 0, support_A, 0, p_userdata);
+ Vector3 normal = (support_B - support_A).normalized();
+ p_result_callback(support_B, 0, support_A, 0, normal, p_userdata);
} else {
- p_result_callback(support_A, 0, support_B, 0, p_userdata);
+ Vector3 normal = (support_A - support_B).normalized();
+ p_result_callback(support_A, 0, support_B, 0, normal, p_userdata);
}
}
return true;
@@ -142,7 +146,7 @@ struct _SoftBodyContactCollisionInfo {
int contact_count = 0;
};
-void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
_SoftBodyContactCollisionInfo &cinfo = *(static_cast<_SoftBodyContactCollisionInfo *>(p_userdata));
++cinfo.contact_count;
@@ -152,9 +156,9 @@ void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A
}
if (cinfo.swap_result) {
- cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
+ cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, -normal, cinfo.userdata);
} else {
- cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata);
+ cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, normal, cinfo.userdata);
}
}
diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/servers/physics_3d/godot_collision_solver_3d.h
index 7ef0dc97ac..36ea79576e 100644
--- a/servers/physics_3d/godot_collision_solver_3d.h
+++ b/servers/physics_3d/godot_collision_solver_3d.h
@@ -35,11 +35,11 @@
class GodotCollisionSolver3D {
public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
private:
static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata);
- static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex);
static bool concave_callback(void *p_userdata, GodotShape3D *p_convex);
static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index d13f4ee801..66d1811abb 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -75,11 +75,13 @@ struct _CollectorCallback {
Vector3 normal;
Vector3 *prev_axis = nullptr;
- _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+ _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 p_normal) {
+ if (p_normal.dot(p_point_B - p_point_A) < 0)
+ p_normal = -p_normal;
if (swap) {
- callback(p_point_B, 0, p_point_A, 0, userdata);
+ callback(p_point_B, 0, p_point_A, 0, -p_normal, userdata);
} else {
- callback(p_point_A, 0, p_point_B, 0, userdata);
+ callback(p_point_A, 0, p_point_B, 0, p_normal, userdata);
}
}
};
@@ -92,7 +94,7 @@ static void _generate_contacts_point_point(const Vector3 *p_points_A, int p_poin
ERR_FAIL_COND(p_point_count_B != 1);
#endif
- p_callback->call(*p_points_A, *p_points_B);
+ p_callback->call(*p_points_A, *p_points_B, p_callback->normal);
}
static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -102,7 +104,7 @@ static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point
#endif
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B);
- p_callback->call(*p_points_A, closest_B);
+ p_callback->call(*p_points_A, closest_B, p_callback->normal);
}
static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -111,9 +113,9 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point
ERR_FAIL_COND(p_point_count_B < 3);
#endif
- Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A);
-
- p_callback->call(*p_points_A, closest_B);
+ Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]);
+ Vector3 closest_B = plane.project(*p_points_A);
+ p_callback->call(*p_points_A, closest_B, plane.get_normal());
}
static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -122,9 +124,9 @@ static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_poi
ERR_FAIL_COND(p_point_count_B != 3);
#endif
- Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A);
-
- p_callback->call(*p_points_A, closest_B);
+ Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]);
+ Vector3 closest_B = plane.project(*p_points_A);
+ p_callback->call(*p_points_A, closest_B, plane.get_normal());
}
static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -154,8 +156,8 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
sa.sort(dvec, 4);
//use the middle ones as contacts
- p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]);
- p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]);
+ p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1], p_callback->normal);
+ p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2], p_callback->normal);
return;
}
@@ -170,7 +172,14 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 closest_A = p_points_A[0] + rel_A * d;
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B);
- p_callback->call(closest_A, closest_B);
+ // The normal should be perpendicular to both edges.
+ Vector3 normal = rel_A.cross(rel_B);
+ real_t normal_len = normal.length();
+ if (normal_len > 1e-3)
+ normal /= normal_len;
+ else
+ normal = p_callback->normal;
+ p_callback->call(closest_A, closest_B, normal);
}
static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -267,7 +276,7 @@ static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_poin
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_plane.get_normal());
}
}
@@ -352,7 +361,7 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_
continue;
}
- p_callback->call(clipbuf_src[i], closest_B);
+ p_callback->call(clipbuf_src[i], closest_B, plane_B.get_normal());
}
}
@@ -431,7 +440,7 @@ static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_poin
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_plane.get_normal());
}
}
@@ -534,7 +543,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_B_plane.get_normal());
}
}
@@ -678,7 +687,7 @@ public:
return true;
}
- static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata;
Vector3 axis = (p_point_B - p_point_A);
real_t depth = axis.length();
@@ -802,11 +811,11 @@ static void analytic_sphere_collision(const Vector3 &p_origin_a, real_t p_radius
if (p_radius_a < p_radius_b) {
Vector3 point_a = p_origin_a - b_to_a * p_radius_a;
Vector3 point_b = point_a + b_to_a * overlap;
- p_collector->call(point_a, point_b); // Consider adding b_to_a vector
+ p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector
} else {
Vector3 point_b = p_origin_b + b_to_a * p_radius_b;
Vector3 point_a = point_b - b_to_a * overlap;
- p_collector->call(point_a, point_b); // Consider adding b_to_a vector
+ p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector
}
}
@@ -859,8 +868,8 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_
axis = delta / length;
}
Vector3 point_a = p_transform_a.origin + (sphere_A->get_radius() + p_margin_a) * axis;
- Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest);
- p_collector->call(point_a, point_b);
+ Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest);
+ p_collector->call(point_a, point_b, axis);
}
template <bool withMargin>
@@ -926,8 +935,8 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu
axis = delta / length;
}
Vector3 point_a = p_transform_a.origin + (p_radius_a + p_margin_a) * axis;
- Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest);
- p_collector->call(point_a, point_b);
+ Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest);
+ p_collector->call(point_a, point_b, axis);
}
template <bool withMargin>
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index e8250acb45..b6d8acfbf3 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -1737,7 +1737,7 @@ void GodotPhysicsServer3D::_update_shapes() {
}
}
-void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata);
if (cbk->max == 0) {
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index 3da0c6debe..040e673dcd 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -77,7 +77,7 @@ public:
Vector3 *ptr = nullptr;
};
- static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
virtual RID world_boundary_shape_create() override;
virtual RID separation_ray_shape_create() override;
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index c3aad22932..93572965d2 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -445,7 +445,7 @@ struct _RestCallbackData {
_RestResultData *other_results = nullptr;
};
-static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
_RestCallbackData *rd = static_cast<_RestCallbackData *>(p_userdata);
Vector3 contact_rel = p_point_B - p_point_A;
@@ -480,7 +480,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
// Keep this result as separate result.
result.len = len;
result.contact = p_point_B;
- result.normal = contact_rel / len;
+ result.normal = normal;
result.object = rd->object;
result.shape = rd->shape;
result.local_shape = rd->local_shape;
@@ -499,7 +499,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
rd->best_result.len = len;
rd->best_result.contact = p_point_B;
- rd->best_result.normal = contact_rel / len;
+ rd->best_result.normal = normal;
rd->best_result.object = rd->object;
rd->best_result.shape = rd->shape;
rd->best_result.local_shape = rd->local_shape;
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 3510b415d8..4265ee5518 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -597,7 +597,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
Vector2 end_left;
Vector2 end_right;
- if (p_width > 1.001) {
+ if (p_width >= 0.0) {
begin_left = p_from + t;
begin_right = p_from - t;
end_left = p_to + t;
@@ -628,7 +628,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
// This value is empirically determined to provide good antialiasing quality
// while not making lines appear too soft.
float border_size = 1.25f;
- if (p_width < 1.0f) {
+ if (0.0f <= p_width && p_width < 1.0f) {
border_size *= p_width;
}
Vector2 dir2 = diff.normalized();
@@ -769,6 +769,49 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
}
}
+static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) {
+ int point_count = p_points.size();
+
+ bool is_last_point = (p_index == point_count - 1);
+
+ Vector2 segment_dir;
+
+ if (is_last_point) {
+ segment_dir = p_prev_segment_dir;
+ } else {
+ segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized();
+
+ if (segment_dir.is_zero_approx()) {
+ segment_dir = p_prev_segment_dir;
+ }
+ }
+
+ return segment_dir;
+}
+
+static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) {
+ Vector2 bisector;
+ float length = 1.0f;
+
+ bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized();
+
+ float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir));
+ float sin_angle = sinf(angle);
+
+ if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) {
+ length = 1.0f / sin_angle;
+ length = CLAMP(length, -3.0f, 3.0f);
+ } else {
+ bisector = p_segment_dir.orthogonal();
+ }
+
+ if (bisector.is_zero_approx()) {
+ bisector = p_segment_dir.orthogonal();
+ }
+
+ return bisector * length;
+}
+
void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
ERR_FAIL_COND(p_points.size() < 2);
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
@@ -777,11 +820,30 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color color = Color(1, 1, 1, 1);
Vector<int> indices;
- int pc = p_points.size();
- int pc2 = pc * 2;
+ int point_count = p_points.size();
+ int polyline_point_count = point_count * 2;
+
+ bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]);
+ Vector2 first_segment_dir;
+ Vector2 last_segment_dir;
- Vector2 prev_t;
- int j2;
+ // Search for first non-zero vector between two segments.
+ for (int i = 1; i < point_count; i++) {
+ first_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
+
+ if (!first_segment_dir.is_zero_approx()) {
+ break;
+ }
+ }
+
+ // Search for last non-zero vector between two segments.
+ for (int i = point_count - 1; i >= 1; i--) {
+ last_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
+
+ if (!last_segment_dir.is_zero_approx()) {
+ break;
+ }
+ }
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_COND(!pline);
@@ -789,8 +851,8 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
PackedColorArray colors;
PackedVector2Array points;
- colors.resize(pc2);
- points.resize(pc2);
+ colors.resize(polyline_point_count);
+ points.resize(polyline_point_count);
Vector2 *points_ptr = points.ptrw();
Color *colors_ptr = colors.ptrw();
@@ -845,14 +907,14 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
PackedColorArray colors_left;
PackedVector2Array points_left;
- colors_left.resize(pc2);
- points_left.resize(pc2);
+ colors_left.resize(polyline_point_count);
+ points_left.resize(polyline_point_count);
PackedColorArray colors_right;
PackedVector2Array points_right;
- colors_right.resize(pc2);
- points_right.resize(pc2);
+ colors_right.resize(polyline_point_count);
+ points_right.resize(polyline_point_count);
Item::CommandPolygon *pline_begin = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_COND(!pline_begin);
@@ -898,79 +960,81 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color *colors_left_ptr = colors_left.ptrw();
Color *colors_right_ptr = colors_right.ptrw();
- for (int i = 0, j = 0; i < pc; i++, j += 2) {
- bool is_begin = i == 0;
- bool is_end = i == pc - 1;
+ Vector2 prev_segment_dir;
+ for (int i = 0; i < point_count; i++) {
+ bool is_first_point = (i == 0);
+ bool is_last_point = (i == point_count - 1);
- Vector2 t;
- Vector2 end_border;
- Vector2 begin_border;
- if (is_end) {
- t = prev_t;
- end_border = (p_points[i] - p_points[i - 1]).normalized() * border_size;
- } else {
- t = (p_points[i + 1] - p_points[i]).normalized().orthogonal();
- if (is_begin) {
- prev_t = t;
- begin_border = (p_points[i] - p_points[i + 1]).normalized() * border_size;
- }
+ Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
+ if (is_first_point && loop) {
+ prev_segment_dir = last_segment_dir;
+ } else if (is_last_point && loop) {
+ prev_segment_dir = first_segment_dir;
}
- j2 = j + 1;
+ Vector2 base_edge_offset;
+ if (is_first_point && !loop) {
+ base_edge_offset = first_segment_dir.orthogonal();
+ } else if (is_last_point && !loop) {
+ base_edge_offset = last_segment_dir.orthogonal();
+ } else {
+ base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
+ }
- Vector2 dir = (t + prev_t).normalized();
- Vector2 tangent = dir * p_width * 0.5;
- Vector2 border = dir * border_size;
+ Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
+ Vector2 border = base_edge_offset * border_size;
Vector2 pos = p_points[i];
- points_ptr[j] = pos + tangent;
- points_ptr[j2] = pos - tangent;
+ points_ptr[i * 2 + 0] = pos + edge_offset;
+ points_ptr[i * 2 + 1] = pos - edge_offset;
- points_left_ptr[j] = pos + tangent + border;
- points_left_ptr[j2] = pos + tangent;
+ points_left_ptr[i * 2 + 0] = pos + edge_offset + border;
+ points_left_ptr[i * 2 + 1] = pos + edge_offset;
- points_right_ptr[j] = pos - tangent;
- points_right_ptr[j2] = pos - tangent - border;
+ points_right_ptr[i * 2 + 0] = pos - edge_offset;
+ points_right_ptr[i * 2 + 1] = pos - edge_offset - border;
if (i < p_colors.size()) {
color = p_colors[i];
color2 = Color(color.r, color.g, color.b, 0);
}
- colors_ptr[j] = color;
- colors_ptr[j2] = color;
+ colors_ptr[i * 2 + 0] = color;
+ colors_ptr[i * 2 + 1] = color;
+
+ colors_left_ptr[i * 2 + 0] = color2;
+ colors_left_ptr[i * 2 + 1] = color;
- colors_left_ptr[j] = color2;
- colors_left_ptr[j2] = color;
+ colors_right_ptr[i * 2 + 0] = color;
+ colors_right_ptr[i * 2 + 1] = color2;
- colors_right_ptr[j] = color;
- colors_right_ptr[j2] = color2;
+ if (is_first_point) {
+ Vector2 begin_border = loop ? Vector2() : -segment_dir * border_size;
- if (is_begin) {
- points_begin_ptr[0] = pos + tangent + begin_border;
- points_begin_ptr[1] = pos - tangent + begin_border;
- points_begin_ptr[2] = pos + tangent;
- points_begin_ptr[3] = pos - tangent;
+ points_begin_ptr[0] = pos + edge_offset + begin_border;
+ points_begin_ptr[1] = pos - edge_offset + begin_border;
+ points_begin_ptr[2] = pos + edge_offset;
+ points_begin_ptr[3] = pos - edge_offset;
colors_begin_ptr[0] = color2;
colors_begin_ptr[1] = color2;
colors_begin_ptr[2] = color;
colors_begin_ptr[3] = color;
- points_begin_left_corner_ptr[0] = pos - tangent - border;
- points_begin_left_corner_ptr[1] = pos - tangent + begin_border - border;
- points_begin_left_corner_ptr[2] = pos - tangent;
- points_begin_left_corner_ptr[3] = pos - tangent + begin_border;
+ points_begin_left_corner_ptr[0] = pos - edge_offset - border;
+ points_begin_left_corner_ptr[1] = pos - edge_offset + begin_border - border;
+ points_begin_left_corner_ptr[2] = pos - edge_offset;
+ points_begin_left_corner_ptr[3] = pos - edge_offset + begin_border;
colors_begin_left_corner_ptr[0] = color2;
colors_begin_left_corner_ptr[1] = color2;
colors_begin_left_corner_ptr[2] = color;
colors_begin_left_corner_ptr[3] = color2;
- points_begin_right_corner_ptr[0] = pos + tangent + begin_border;
- points_begin_right_corner_ptr[1] = pos + tangent + begin_border + border;
- points_begin_right_corner_ptr[2] = pos + tangent;
- points_begin_right_corner_ptr[3] = pos + tangent + border;
+ points_begin_right_corner_ptr[0] = pos + edge_offset + begin_border;
+ points_begin_right_corner_ptr[1] = pos + edge_offset + begin_border + border;
+ points_begin_right_corner_ptr[2] = pos + edge_offset;
+ points_begin_right_corner_ptr[3] = pos + edge_offset + border;
colors_begin_right_corner_ptr[0] = color2;
colors_begin_right_corner_ptr[1] = color2;
@@ -978,31 +1042,33 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
colors_begin_right_corner_ptr[3] = color2;
}
- if (is_end) {
- points_end_ptr[0] = pos + tangent + end_border;
- points_end_ptr[1] = pos - tangent + end_border;
- points_end_ptr[2] = pos + tangent;
- points_end_ptr[3] = pos - tangent;
+ if (is_last_point) {
+ Vector2 end_border = loop ? Vector2() : prev_segment_dir * border_size;
+
+ points_end_ptr[0] = pos + edge_offset + end_border;
+ points_end_ptr[1] = pos - edge_offset + end_border;
+ points_end_ptr[2] = pos + edge_offset;
+ points_end_ptr[3] = pos - edge_offset;
colors_end_ptr[0] = color2;
colors_end_ptr[1] = color2;
colors_end_ptr[2] = color;
colors_end_ptr[3] = color;
- points_end_left_corner_ptr[0] = pos - tangent - border;
- points_end_left_corner_ptr[1] = pos - tangent + end_border - border;
- points_end_left_corner_ptr[2] = pos - tangent;
- points_end_left_corner_ptr[3] = pos - tangent + end_border;
+ points_end_left_corner_ptr[0] = pos - edge_offset - border;
+ points_end_left_corner_ptr[1] = pos - edge_offset + end_border - border;
+ points_end_left_corner_ptr[2] = pos - edge_offset;
+ points_end_left_corner_ptr[3] = pos - edge_offset + end_border;
colors_end_left_corner_ptr[0] = color2;
colors_end_left_corner_ptr[1] = color2;
colors_end_left_corner_ptr[2] = color;
colors_end_left_corner_ptr[3] = color2;
- points_end_right_corner_ptr[0] = pos + tangent + end_border;
- points_end_right_corner_ptr[1] = pos + tangent + end_border + border;
- points_end_right_corner_ptr[2] = pos + tangent;
- points_end_right_corner_ptr[3] = pos + tangent + border;
+ points_end_right_corner_ptr[0] = pos + edge_offset + end_border;
+ points_end_right_corner_ptr[1] = pos + edge_offset + end_border + border;
+ points_end_right_corner_ptr[2] = pos + edge_offset;
+ points_end_right_corner_ptr[3] = pos + edge_offset + border;
colors_end_right_corner_ptr[0] = color2;
colors_end_right_corner_ptr[1] = color2;
@@ -1010,7 +1076,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
colors_end_right_corner_ptr[3] = color2;
}
- prev_t = t;
+ prev_segment_dir = segment_dir;
}
pline_begin->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
@@ -1039,33 +1105,41 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
} else {
// Makes a single triangle strip for drawing the line.
- for (int i = 0, j = 0; i < pc; i++, j += 2) {
- Vector2 t;
- if (i == pc - 1) {
- t = prev_t;
- } else {
- t = (p_points[i + 1] - p_points[i]).normalized().orthogonal();
- if (i == 0) {
- prev_t = t;
- }
+ Vector2 prev_segment_dir;
+ for (int i = 0; i < point_count; i++) {
+ bool is_first_point = (i == 0);
+ bool is_last_point = (i == point_count - 1);
+
+ Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
+ if (is_first_point && loop) {
+ prev_segment_dir = last_segment_dir;
+ } else if (is_last_point && loop) {
+ prev_segment_dir = first_segment_dir;
}
- j2 = j + 1;
+ Vector2 base_edge_offset;
+ if (is_first_point && !loop) {
+ base_edge_offset = first_segment_dir.orthogonal();
+ } else if (is_last_point && !loop) {
+ base_edge_offset = last_segment_dir.orthogonal();
+ } else {
+ base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
+ }
- Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+ Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
Vector2 pos = p_points[i];
- points_ptr[j] = pos + tangent;
- points_ptr[j2] = pos - tangent;
+ points_ptr[i * 2 + 0] = pos + edge_offset;
+ points_ptr[i * 2 + 1] = pos - edge_offset;
if (i < p_colors.size()) {
color = p_colors[i];
}
- colors_ptr[j] = color;
- colors_ptr[j2] = color;
+ colors_ptr[i * 2 + 0] = color;
+ colors_ptr[i * 2 + 1] = color;
- prev_t = t;
+ prev_segment_dir = segment_dir;
}
}
@@ -1077,7 +1151,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin
ERR_FAIL_COND(p_points.size() < 2);
// TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
- if (p_width <= 1) {
+ if (p_width < 0) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -1133,20 +1207,23 @@ void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos,
static const int circle_points = 64;
points.resize(circle_points);
+ Vector2 *points_ptr = points.ptrw();
const real_t circle_point_step = Math_TAU / circle_points;
for (int i = 0; i < circle_points; i++) {
float angle = i * circle_point_step;
- points.write[i].x = Math::cos(angle) * p_radius;
- points.write[i].y = Math::sin(angle) * p_radius;
- points.write[i] += p_pos;
+ points_ptr[i].x = Math::cos(angle) * p_radius;
+ points_ptr[i].y = Math::sin(angle) * p_radius;
+ points_ptr[i] += p_pos;
}
+
indices.resize((circle_points - 2) * 3);
+ int *indices_ptr = indices.ptrw();
for (int i = 0; i < circle_points - 2; i++) {
- indices.write[i * 3 + 0] = 0;
- indices.write[i * 3 + 1] = i + 1;
- indices.write[i * 3 + 2] = i + 2;
+ indices_ptr[i * 3 + 0] = 0;
+ indices_ptr[i * 3 + 1] = i + 1;
+ indices_ptr[i * 3 + 2] = i + 2;
}
Vector<Color> color;
@@ -1313,7 +1390,7 @@ void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r
style->axis_y = p_y_axis_mode;
}
-void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) {
+void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) {
uint32_t pc = p_points.size();
ERR_FAIL_COND(pc == 0 || pc > 4);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 4d0be48cc0..2494ddf631 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -221,9 +221,9 @@ public:
void canvas_item_set_update_when_visible(RID p_item, bool p_update);
- void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
+ void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false);
void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
- void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
@@ -231,7 +231,7 @@ public:
void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0);
void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1));
- void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0);
+ void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture);
void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID());
void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1);
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID());
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 863e8d6c15..7e02f98ce9 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1085,8 +1085,8 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky->reflection.dirty = true;
}
+ sky_scene_state.ubo.directional_light_count = 0;
if (shader_data->uses_light) {
- sky_scene_state.ubo.directional_light_count = 0;
// Run through the list of lights in the scene and pick out the Directional Lights.
// 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
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 7eabce2f79..412406c0b4 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
@@ -44,7 +44,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
- uses_screen_texture = false;
if (code.is_empty()) {
return; //just invalid, but no error
@@ -73,9 +72,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
uses_position = false;
uses_sss = false;
uses_transmittance = false;
- uses_screen_texture = false;
- uses_depth_texture = false;
- uses_normal_texture = false;
uses_time = false;
writes_modelview_or_projection = false;
uses_world_coordinates = false;
@@ -120,9 +116,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
- actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
- actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture;
actions.usage_flag_pointers["DISCARD"] = &uses_discard;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
@@ -151,6 +144,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
depth_test = DepthTest(depth_testi);
cull_mode = Cull(cull_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
@@ -607,9 +603,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "color_buffer";
- actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -674,7 +667,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
@@ -707,10 +699,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps
- actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]";
- actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter
-
actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
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 78d29e2a41..816248567b 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -251,7 +251,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
Size2i target_size = render_buffers->get_target_size();
Size2i internal_size = render_buffers->get_internal_size();
- // can't do our blit pass if resolutions don't match
+ // can't do our blit pass if resolutions don't match, this should already have been checked.
ERR_FAIL_COND_V(target_size != internal_size, RID());
// - opaque pass
@@ -715,20 +715,26 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// setup rendering to render buffer
screen_size = p_render_data->render_buffers->get_internal_size();
- if (rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) {
- // can't do blit subpass
+ if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
+ // can't do blit subpass because we're scaling
using_subpass_post_process = false;
} else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
- // can't do blit subpass
+ // can't do blit subpass because we're using post processes
using_subpass_post_process = false;
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
- // can't use our last two subpasses
+ // can't use our last two subpasses because we're reading from screen texture or depth texture
using_subpass_transparent = false;
using_subpass_post_process = false;
}
+ // We do this last because our get_color_fbs creates and caches the framebuffer if we need it.
+ if (using_subpass_post_process && rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) {
+ // can't do blit subpass because we don't have all subpasses
+ using_subpass_post_process = false;
+ }
+
if (using_subpass_post_process) {
// all as subpasses
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
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 ee4c8001eb..3d1d78c63d 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
@@ -46,7 +46,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
- uses_screen_texture = false;
if (code.is_empty()) {
return; //just invalid, but no error
@@ -74,9 +73,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
uses_vertex = false;
uses_sss = false;
uses_transmittance = false;
- uses_screen_texture = false;
- uses_depth_texture = false;
- uses_normal_texture = false;
uses_time = false;
writes_modelview_or_projection = false;
uses_world_coordinates = false;
@@ -121,9 +117,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
// actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
// actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
- actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
- actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture;
actions.usage_flag_pointers["DISCARD"] = &uses_discard;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
@@ -152,6 +145,10 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
depth_test = DepthTest(depth_testi);
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
#if 0
print_line("**compiling shader:");
@@ -498,9 +495,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "color_buffer";
- actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -565,7 +559,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 1f92697ecc..6f1f00cedc 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -128,6 +128,7 @@ public:
bool uses_screen_texture = false;
bool uses_depth_texture = false;
bool uses_normal_texture = false;
+ bool uses_screen_texture_mipmaps = false;
bool uses_time = false;
bool uses_vertex_time = false;
bool uses_fragment_time = false;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 0c6dcb553a..462b925134 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -525,10 +525,12 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ push_constant.flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ push_constant.flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
@@ -2034,7 +2036,6 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
actions.usage_flag_pointers["TIME"] = &uses_time;
@@ -2046,6 +2047,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
@@ -2423,7 +2425,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "screen_texture";
actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
@@ -2444,7 +2445,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
@@ -2459,7 +2459,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = MATERIAL_UNIFORM_SET;
@@ -2632,8 +2631,10 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a > 0.0001) {
c.rgb /= c.a;
@@ -2657,8 +2658,10 @@ void fragment() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
COLOR.rgb = c.rgb;
}
)");
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 266083fc49..7dea4a1a65 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -86,6 +86,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
+
+ FLAGS_FLIP_H = (1 << 30),
+ FLAGS_FLIP_V = (1 << 31),
};
enum {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 1d45db8eaf..2a87c4fa8d 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -539,7 +539,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.view_count = rb->get_view_count();
RID dest_fb;
- if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
+ if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
// If we use FSR to upscale we need to write our result into an intermediate buffer.
// Note that this is cached so we only create the texture the first time.
RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
@@ -556,10 +556,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RD::get_singleton()->draw_command_end_label();
}
- if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
- // TODO Investigate? Does this work? We never write into our render target and we've already done so up above in our tonemapper.
- // I think FSR should either work before our tonemapper or as an alternative of our tonemapper.
-
+ if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale");
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index eb5f68849e..1fb8b28b15 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -502,6 +502,12 @@ void main() {
if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(draw_data.flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(draw_data.flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 1b627a3e81..a904f4e0a6 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -27,6 +27,9 @@
#define FLAGS_USE_MSDF (1 << 28)
#define FLAGS_USE_LCD (1 << 29)
+#define FLAGS_FLIP_H (1 << 30)
+#define FLAGS_FLIP_V (1 << 31)
+
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
@@ -134,7 +137,7 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture;
layout(set = 0, binding = 5) uniform sampler shadow_sampler;
-layout(set = 0, binding = 6) uniform texture2D screen_texture;
+layout(set = 0, binding = 6) uniform texture2D color_buffer;
layout(set = 0, binding = 7) uniform texture2D sdf_texture;
layout(set = 0, binding = 8) uniform sampler material_samplers[12];
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 66ae1e8d1a..d631a89dd2 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -2685,6 +2685,14 @@ void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
ERR_FAIL_COND(!material);
+ // Need to clear texture arrays to prevent spin locking of their RID's.
+ // This happens when the app is being closed.
+ for (KeyValue<StringName, Variant> &E : material->params) {
+ if (E.value.get_type() == Variant::ARRAY) {
+ Array(E.value).clear();
+ }
+ }
+
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 6401d0f5d0..e4149f6bbd 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -1415,7 +1415,6 @@ void ParticlesStorage::update_particles() {
}
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
- bool updated = false;
if (particles->clear && particles->pre_process_time > 0.0) {
double frame_time;
@@ -1430,7 +1429,6 @@ void ParticlesStorage::update_particles() {
while (todo >= 0) {
_particles_process(particles, frame_time);
todo -= frame_time;
- updated = true;
}
}
@@ -1452,10 +1450,9 @@ void ParticlesStorage::update_particles() {
}
double todo = particles->frame_remainder + delta;
- while (todo >= frame_time || (particles->clear && !updated)) {
+ while (todo >= frame_time || particles->clear) {
_particles_process(particles, frame_time);
todo -= decr;
- updated = true;
}
particles->frame_remainder = todo;
@@ -1463,16 +1460,16 @@ void ParticlesStorage::update_particles() {
} else {
if (zero_time_scale) {
_particles_process(particles, 0.0);
- updated = true;
} else {
_particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
- updated = true;
}
}
- //copy particles to instance buffer
+ // Ensure that memory is initialized (the code above should ensure that _particles_process is always called at least once upon clearing).
+ DEV_ASSERT(!particles->clear);
- if (updated && particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ // Copy particles to instance buffer.
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
//does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
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 d67a848a40..31377a10a0 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
@@ -96,7 +96,7 @@ void RenderSceneBuffersRD::cleanup() {
named_textures.clear();
}
-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) {
+void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, 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) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@@ -104,12 +104,7 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
target_size = p_target_size;
internal_size = p_internal_size;
-
- // FIXME, right now we do this because only our clustered renderer supports FSR upscale
- // this does mean that with linear upscale if we use subpasses, we could get into trouble.
- if (!can_be_storage) {
- internal_size = target_size;
- }
+ scaling_3d_mode = p_scaling_3d_mode;
if (p_use_taa) {
// Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
@@ -193,6 +188,7 @@ void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_s
target_size = p_reflection_size;
internal_size = p_reflection_size;
render_target = RID();
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
fsr_sharpness = 0.0;
msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
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 ff946f410f..dc849fd56a 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
@@ -73,6 +73,7 @@ private:
// The internal size of the textures we render 3D to in case we render at a lower resolution and upscale
Size2i internal_size = Size2i(0, 0);
+ RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
float fsr_sharpness = 0.2f;
// Aliassing settings
@@ -139,7 +140,7 @@ public:
void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
void cleanup();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
void configure_for_reflections(const Size2i p_reflection_size);
virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
@@ -172,6 +173,7 @@ public:
_FORCE_INLINE_ uint32_t get_view_count() const { return view_count; }
_FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; }
_FORCE_INLINE_ Size2i get_target_size() const { return target_size; }
+ _FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
_FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; }
_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 2ea813aab0..218bb7b736 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -748,6 +748,10 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
switch (instance->base_type) {
case RS::INSTANCE_LIGHT: {
InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
+ if (instance->visible && RSG::light_storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
+ instance->scenario->dynamic_lights.erase(light->instance);
+ }
+
#ifdef DEBUG_ENABLED
if (light->geometries.size()) {
ERR_PRINT("BUG, indexing did not unpair geometries from light.");
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index e2e6ea5aa2..a389e3e767 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -84,7 +84,7 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count
Transform3D main_transform_inv = main_transform.inverse();
// 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters
- Vector3 far_center = (planes[0][Projection::PLANE_FAR].center() + planes[1][Projection::PLANE_FAR].center()) * 0.5;
+ Vector3 far_center = (planes[0][Projection::PLANE_FAR].get_center() + planes[1][Projection::PLANE_FAR].get_center()) * 0.5;
Plane far(-z, far_center);
/////////////////////////////////////////////////////////////////////////////
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 05a3fccf1c..3886f5b379 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -115,9 +115,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
p_viewport->render_buffers.unref();
} else {
- const float scaling_3d_scale = p_viewport->scaling_3d_scale;
+ float scaling_3d_scale = p_viewport->scaling_3d_scale;
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
- bool scaling_enabled = true;
if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) {
// FSR is not designed for downsampling.
@@ -133,7 +132,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
}
if (scaling_3d_scale == 1.0) {
- scaling_enabled = false;
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
}
int width;
@@ -141,36 +140,37 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
int render_width;
int render_height;
- if (scaling_enabled) {
- switch (scaling_3d_mode) {
- case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
- // Clamp 3D rendering resolution to reasonable values supported on most hardware.
- // This prevents freezing the engine or outright crashing on lower-end GPUs.
- width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
- height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
- render_width = width;
- render_height = height;
- break;
- case RS::VIEWPORT_SCALING_3D_MODE_FSR:
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
- render_height = MAX(height * scaling_3d_scale, 1.0);
- break;
- default:
- // This is an unknown mode.
- WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = width;
- render_height = height;
- break;
- }
- } else {
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = width;
- render_height = height;
+ switch (scaling_3d_mode) {
+ case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
+ // Clamp 3D rendering resolution to reasonable values supported on most hardware.
+ // This prevents freezing the engine or outright crashing on lower-end GPUs.
+ width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
+ height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
+ render_width = width;
+ render_height = height;
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_FSR:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
+ render_height = MAX(height * scaling_3d_scale, 1.0);
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_OFF:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
+ default:
+ // This is an unknown mode.
+ WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+ scaling_3d_scale = 1.0;
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
}
p_viewport->internal_size = Size2(render_width, render_height);
@@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// to compensate for the loss of sharpness.
const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
- p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), scaling_3d_mode, p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
}
}
}
@@ -1138,6 +1138,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport
void RendererViewport::viewport_set_use_taa(RID p_viewport, bool p_use_taa) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ ERR_FAIL_COND_EDMSG(OS::get_singleton()->get_current_rendering_method() != "forward_plus", "TAA is only available when using the Forward+ renderer.");
if (viewport->use_taa == p_use_taa) {
return;
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index 5967835d03..3678b70254 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -31,6 +31,8 @@
#include "rendering_device_binds.h"
Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) {
+ ERR_FAIL_NULL_V(RenderingDevice::get_singleton(), ERR_UNAVAILABLE);
+
Vector<String> lines = p_text.split("\n");
bool reading_versions = false;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index d053c60b85..8ac522bafe 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -854,7 +854,7 @@ public:
FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float)
FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &)
FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
- FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
+ FUNC5(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
FUNC9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int)
FUNC5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 626da90168..68542f32af 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -909,9 +909,6 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (p_default_actions.renames.has(vnode->name)) {
code = p_default_actions.renames[vnode->name];
- if (vnode->name == "SCREEN_TEXTURE") {
- r_gen_code.uses_screen_texture_mipmaps = true;
- }
} else {
if (shader->uniforms.has(vnode->name)) {
//its a uniform!
@@ -919,29 +916,22 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (u.texture_order >= 0) {
StringName name = vnode->name;
if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
- name = "SCREEN_TEXTURE";
+ name = "color_buffer";
if (u.filter >= ShaderLanguage::FILTER_NEAREST_MIPMAP) {
r_gen_code.uses_screen_texture_mipmaps = true;
}
+ r_gen_code.uses_screen_texture = true;
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
- name = "NORMAL_ROUGHNESS_TEXTURE";
+ name = "normal_roughness_buffer";
+ r_gen_code.uses_normal_roughness_texture = true;
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- name = "DEPTH_TEXTURE";
+ name = "depth_buffer";
+ r_gen_code.uses_depth_texture = true;
} else {
name = _mkid(vnode->name); //texture, use as is
}
- if (p_default_actions.renames.has(name)) {
- code = p_default_actions.renames[name];
- } else {
- code = name;
- }
-
- if (p_actions.usage_flag_pointers.has(name) && !used_flag_pointers.has(name)) {
- *p_actions.usage_flag_pointers[name] = true;
- used_flag_pointers.insert(name);
- }
-
+ code = name;
} else {
//a scalar or vector
if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
@@ -1251,16 +1241,20 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
if (correct_texture_uniform) {
- //TODO Needs to detect screen_texture hint as well
- is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
-
String sampler_name;
+ bool is_normal_roughness_texture = false;
if (actions.custom_samplers.has(texture_uniform)) {
sampler_name = actions.custom_samplers[texture_uniform];
} else {
if (shader->uniforms.has(texture_uniform)) {
- sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[texture_uniform];
+ if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
+ is_screen_texture = true;
+ } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
+ is_normal_roughness_texture = true;
+ }
+ sampler_name = _get_sampler_name(u.filter, u.repeat);
} else {
bool found = false;
@@ -1287,7 +1281,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
String data_type_name = "";
- if (texture_uniform == "NORMAL_ROUGHNESS_TEXTURE") {
+ if (is_normal_roughness_texture) {
data_type_name = "multiviewSampler";
normal_roughness_texture_used = true;
} else {
@@ -1515,6 +1509,9 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
r_gen_code.uses_screen_texture_mipmaps = false;
+ r_gen_code.uses_screen_texture = false;
+ r_gen_code.uses_depth_texture = false;
+ r_gen_code.uses_normal_roughness_texture = false;
used_name_defines.clear();
used_rmode_defines.clear();
diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h
index eeb2916160..43bea213da 100644
--- a/servers/rendering/shader_compiler.h
+++ b/servers/rendering/shader_compiler.h
@@ -81,6 +81,9 @@ public:
bool uses_fragment_time;
bool uses_vertex_time;
bool uses_screen_texture_mipmaps;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_roughness_texture;
};
struct DefaultIdentifierActions {
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 59a2ff66f3..5ecc38a63b 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5399,6 +5399,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
} else {
if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
+ if (identifier == "SCREEN_TEXTURE" || identifier == "DEPTH_TEXTURE" || identifier == "NORMAL_ROUGHNESS_TEXTURE") {
+ String name = String(identifier);
+ String name_lower = name.to_lower();
+ _set_error(vformat(RTR("%s has been removed in favor of using hint_%s with a uniform.\nTo continue with minimal code changes add 'uniform sampler2D %s : hint_%s, filter_linear_mipmaps;' near the top of your shader."), name, name_lower, name, name_lower));
+ return nullptr;
+ }
_set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier)));
return nullptr;
}
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 38dc806370..ba39328b2e 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -138,9 +138,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
@@ -267,7 +264,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true;
diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
index 1320199833..6369139aa6 100644
--- a/servers/rendering/storage/render_scene_buffers.cpp
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -34,8 +34,8 @@ void RenderSceneBuffers::_bind_methods() {
ClassDB::bind_method(D_METHOD("configure", "render_target", "internal_size", "target_size", "fsr_sharpness", "texture_mipmap_bias", "msaa", "screen_space_aa", "use_taa", "use_debanding", "view_count"), &RenderSceneBuffers::configure);
}
-void RenderSceneBuffers::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) {
- GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
+void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, 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) {
+ GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_scaling_3d_mode, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
};
void RenderSceneBuffers::set_fsr_sharpness(float p_fsr_sharpness) {
diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h
index 83fc78ca1c..cf96a9f372 100644
--- a/servers/rendering/storage/render_scene_buffers.h
+++ b/servers/rendering/storage/render_scene_buffers.h
@@ -40,7 +40,7 @@ class RenderSceneBuffers : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL10(_configure, RID, Size2i, Size2i, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
+ GDVIRTUAL11(_configure, RID, Size2i, Size2i, RS::ViewportScaling3DMode, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
GDVIRTUAL1(_set_fsr_sharpness, float)
GDVIRTUAL1(_set_texture_mipmap_bias, float)
GDVIRTUAL1(_set_use_debanding, bool)
@@ -49,7 +49,7 @@ public:
RenderSceneBuffers(){};
virtual ~RenderSceneBuffers(){};
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count);
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, 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);
// for those settings that are unlikely to require buffers to be recreated, we'll add setters
virtual void set_fsr_sharpness(float p_fsr_sharpness);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 14d8d035e2..c3bd3d277f 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -996,6 +996,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
if (index_array_len) {
List<Variant> keys;
p_lods.get_key_list(&keys);
+ keys.sort(); // otherwise lod levels may get skipped
for (const Variant &E : keys) {
float distance = E;
ERR_CONTINUE(distance <= 0.0);
@@ -1826,6 +1827,7 @@ void RenderingServer::_bind_methods() {
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+ BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY);
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
@@ -2592,7 +2594,7 @@ void RenderingServer::_bind_methods() {
/* Primitives */
- ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(-1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
@@ -2601,7 +2603,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_primitive);
ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()));
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 6efe28a847..4b51099ef0 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -802,7 +802,8 @@ public:
enum ViewportScaling3DMode {
VIEWPORT_SCALING_3D_MODE_BILINEAR,
VIEWPORT_SCALING_3D_MODE_FSR,
- VIEWPORT_SCALING_3D_MODE_MAX
+ VIEWPORT_SCALING_3D_MODE_MAX,
+ VIEWPORT_SCALING_3D_MODE_OFF = 255, // for internal use only
};
virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0;
@@ -1333,9 +1334,9 @@ public:
NINE_PATCH_TILE_FIT,
};
- virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0;
+ virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
- virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0) = 0;
virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0;
@@ -1343,7 +1344,7 @@ public:
virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0) = 0;
virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0;
- virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) = 0;
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()) = 0;
virtual void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1) = 0;
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID()) = 0;
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 997b83e32d..cbf37f25d6 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -1373,8 +1373,8 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
return p_string;
}
-TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- TypedArray<Vector2i> ret;
+TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector3i> ret;
GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
return ret;
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index fb784f5471..8536836983 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -521,8 +521,8 @@ public:
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
- TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
- GDVIRTUAL3RC(TypedArray<Vector2i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
+ TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index d339533688..027109b67d 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -483,6 +483,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(DIRECTION_AUTO);
BIND_ENUM_CONSTANT(DIRECTION_LTR);
BIND_ENUM_CONSTANT(DIRECTION_RTL);
+ BIND_ENUM_CONSTANT(DIRECTION_INHERITED);
/* Orientation */
BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL);
@@ -599,7 +600,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST);
- BIND_ENUM_CONSTANT(STRUCTURED_TEXT_NONE);
+ BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM);
}
@@ -1692,22 +1693,22 @@ String TextServer::strip_diacritics(const String &p_string) const {
return result;
}
-TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- TypedArray<Vector2i> ret;
+TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector3i> ret;
switch (p_parser_type) {
case STRUCTURED_TEXT_URI: {
int prev = 0;
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) {
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_FILE: {
@@ -1715,14 +1716,14 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) {
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_EMAIL: {
@@ -1731,19 +1732,19 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '@') && local) { // Add full "local" as single context.
local = false;
- ret.push_back(Vector2i(prev, i));
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
} else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_LIST: {
@@ -1752,18 +1753,97 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
int prev = 0;
for (int i = 0; i < tags.size(); i++) {
if (prev != i) {
- ret.push_back(Vector2i(prev, prev + tags[i].length()));
+ ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED));
}
- ret.push_back(Vector2i(prev + tags[i].length(), prev + tags[i].length() + 1));
+ ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED));
prev = prev + tags[i].length() + 1;
}
}
} break;
+ case STRUCTURED_TEXT_GDSCRIPT: {
+ bool in_string_literal = false;
+ bool in_string_literal_single = false;
+ bool in_id = false;
+
+ int prev = 0;
+ for (int i = 0; i < p_text.length(); i++) {
+ char32_t c = p_text[i];
+ if (in_string_literal) {
+ if (c == '\\') {
+ i++;
+ continue; // Skip escaped chars.
+ } else if (c == '\"') {
+ // String literal end, push string and ".
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal = false;
+ }
+ } else if (in_string_literal_single) {
+ if (c == '\\') {
+ i++;
+ continue; // Skip escaped chars.
+ } else if (c == '\'') {
+ // String literal end, push string and '.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal_single = false;
+ }
+ } else if (in_id) {
+ if (!is_unicode_identifier_continue(c)) {
+ // End of id, push id.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i;
+ in_id = false;
+ }
+ } else if (is_unicode_identifier_start(c)) {
+ // Start of new id, push prev element.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i;
+ in_id = true;
+ } else if (c == '\"') {
+ // String literal start, push prev element and ".
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal = true;
+ } else if (c == '\'') {
+ // String literal start, push prev element and '.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal_single = true;
+ } else if (c == '#') {
+ // Start of comment, push prev element and #, skip the rest of the text.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ break;
+ }
+ }
+ if (prev < p_text.length()) {
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
+ }
+ } break;
case STRUCTURED_TEXT_CUSTOM:
- case STRUCTURED_TEXT_NONE:
case STRUCTURED_TEXT_DEFAULT:
default: {
- ret.push_back(Vector2i(0, p_text.length()));
+ ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED));
}
}
return ret;
diff --git a/servers/text_server.h b/servers/text_server.h
index a56c7d8b23..a91d367e97 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -65,7 +65,8 @@ public:
enum Direction {
DIRECTION_AUTO,
DIRECTION_LTR,
- DIRECTION_RTL
+ DIRECTION_RTL,
+ DIRECTION_INHERITED,
};
enum Orientation {
@@ -198,7 +199,7 @@ public:
STRUCTURED_TEXT_FILE,
STRUCTURED_TEXT_EMAIL,
STRUCTURED_TEXT_LIST,
- STRUCTURED_TEXT_NONE,
+ STRUCTURED_TEXT_GDSCRIPT,
STRUCTURED_TEXT_CUSTOM
};
@@ -505,7 +506,7 @@ public:
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
- TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
virtual void cleanup() {}
diff --git a/tests/core/io/test_xml_parser.h b/tests/core/io/test_xml_parser.h
index f4e3f34be2..40cbea2dab 100644
--- a/tests/core/io/test_xml_parser.h
+++ b/tests/core/io/test_xml_parser.h
@@ -54,7 +54,7 @@ TEST_CASE("[XMLParser] End-to-end") {
CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT);
CHECK(parser.get_node_name() == "top");
CHECK(parser.has_attribute("attr"));
- CHECK(parser.get_attribute_value("attr") == "attr value");
+ CHECK(parser.get_named_attribute_value("attr") == "attr value");
CHECK(parser.read() == OK);
CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_TEXT);
diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h
index b2b857ca69..f784a29a17 100644
--- a/tests/core/math/test_plane.h
+++ b/tests/core/math/test_plane.h
@@ -87,8 +87,8 @@ TEST_CASE("[Plane] Plane-point operations") {
const Plane y_facing_plane = Plane(0, 1, 0, 4);
CHECK_MESSAGE(
- plane.center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)),
- "center() should return a vector pointing to the center of the plane.");
+ plane.get_center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)),
+ "get_center() should return a vector pointing to the center of the plane.");
CHECK_MESSAGE(
y_facing_plane.is_point_over(Vector3(0, 5, 0)),
diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h
index 4d9feeb4fa..b2a2ecc3bf 100644
--- a/tests/scene/test_arraymesh.h
+++ b/tests/scene/test_arraymesh.h
@@ -114,6 +114,17 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
CHECK(mesh->get_blend_shape_count() == 0);
}
+ SUBCASE("Can't add surface with incorrect number of blend shapes.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ ERR_PRINT_OFF
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+ ERR_PRINT_ON
+ CHECK(mesh->get_surface_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);
@@ -121,7 +132,15 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
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);
+ Array blend_shape{};
+ blend_shape.resize(Mesh::ARRAY_MAX);
+ blend_shape[Mesh::ARRAY_VERTEX] = cylinder_array[Mesh::ARRAY_VERTEX];
+ blend_shape[Mesh::ARRAY_NORMAL] = cylinder_array[Mesh::ARRAY_NORMAL];
+ blend_shape[Mesh::ARRAY_TANGENT] = cylinder_array[Mesh::ARRAY_TANGENT];
+ Array blend_shapes{};
+ blend_shapes.push_back(blend_shape);
+ blend_shapes.push_back(blend_shape);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend_shapes);
ERR_PRINT_OFF
mesh->clear_blend_shapes();
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index c68560000c..e98aece305 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -1954,7 +1954,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(false);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\t");
code_edit->unindent_lines();
@@ -1963,16 +1963,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(true);
/* Simple unindent. */
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "");
- /* Should inindent inplace. */
- code_edit->set_text("");
- code_edit->insert_text_at_caret("test\t");
-
- code_edit->do_unindent();
- CHECK(code_edit->get_line(0) == "test");
-
/* Backspace does a simple unindent. */
code_edit->set_text("");
code_edit->insert_text_at_caret("\t");
@@ -1987,7 +1980,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Caret on col zero unindent line. */
code_edit->set_text("\t\ttest");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\ttest");
/* Check input action. */
@@ -1998,34 +1991,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Selection does entire line. */
code_edit->set_text("\t\ttest");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\ttest");
/* Handles multiple lines. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Do not unindent line if last col is zero. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select(0, 0, 1, 0);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "\ttext");
/* Unindent even if last column of first line. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select(0, 5, 1, 1);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Check selection is adjusted. */
code_edit->set_text("\ttest");
code_edit->select(0, 1, 0, 2);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_selection_from_column() == 0);
CHECK(code_edit->get_selection_to_column() == 1);
CHECK(code_edit->get_line(0) == "test");
@@ -2041,7 +2034,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(false);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " ");
code_edit->unindent_lines();
@@ -2050,16 +2043,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(true);
/* Simple unindent. */
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "");
- /* Should inindent inplace. */
- code_edit->set_text("");
- code_edit->insert_text_at_caret("test ");
-
- code_edit->do_unindent();
- CHECK(code_edit->get_line(0) == "test");
-
/* Backspace does a simple unindent. */
code_edit->set_text("");
code_edit->insert_text_at_caret(" ");
@@ -2080,12 +2066,12 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Caret on col zero unindent line. */
code_edit->set_text(" test");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Only as far as needed */
code_edit->set_text(" test");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Check input action. */
@@ -2096,34 +2082,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Selection does entire line. */
code_edit->set_text(" test");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Handles multiple lines. */
code_edit->set_text(" test\n text");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Do not unindent line if last col is zero. */
code_edit->set_text(" test\n text");
code_edit->select(0, 0, 1, 0);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == " text");
/* Unindent even if last column of first line. */
code_edit->set_text(" test\n text");
code_edit->select(0, 5, 1, 1);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Check selection is adjusted. */
code_edit->set_text(" test");
code_edit->select(0, 4, 0, 5);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_selection_from_column() == 0);
CHECK(code_edit->get_selection_to_column() == 1);
CHECK(code_edit->get_line(0) == "test");
@@ -2930,7 +2916,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
code_edit->update_code_completion_options();
code_edit->confirm_code_completion();
- CHECK(code_edit->get_line(0) == "\"\"test\"\"");
+ CHECK(code_edit->get_line(0) == "\"\"test\"");
CHECK(code_edit->get_caret_column() == 7);
code_edit->undo();
diff --git a/tests/scene/test_curve_2d.h b/tests/scene/test_curve_2d.h
new file mode 100644
index 0000000000..fc141f3d09
--- /dev/null
+++ b/tests/scene/test_curve_2d.h
@@ -0,0 +1,228 @@
+/**************************************************************************/
+/* test_curve_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_CURVE_2D_H
+#define TEST_CURVE_2D_H
+
+#include "core/math/math_funcs.h"
+#include "scene/resources/curve.h"
+
+#include "tests/test_macros.h"
+
+namespace TestCurve2D {
+
+void add_sample_curve_points(Ref<Curve2D> &curve) {
+ Vector2 p0 = Vector2(0, 0);
+ Vector2 p1 = Vector2(50, 0);
+ Vector2 p2 = Vector2(50, 50);
+ Vector2 p3 = Vector2(0, 50);
+
+ Vector2 control0 = p1 - p0;
+ Vector2 control1 = p3 - p2;
+
+ curve->add_point(p0, Vector2(), control0);
+ curve->add_point(p3, control1, Vector2());
+}
+
+TEST_CASE("[Curve2D] Default curve is empty") {
+ const Ref<Curve2D> curve = memnew(Curve2D);
+ CHECK(curve->get_point_count() == 0);
+}
+
+TEST_CASE("[Curve2D] Point management") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+
+ SUBCASE("Functions for adding/removing points should behave as expected") {
+ curve->set_point_count(2);
+ CHECK(curve->get_point_count() == 2);
+
+ curve->remove_point(0);
+ CHECK(curve->get_point_count() == 1);
+
+ curve->add_point(Vector2());
+ CHECK(curve->get_point_count() == 2);
+
+ curve->clear_points();
+ CHECK(curve->get_point_count() == 0);
+ }
+
+ SUBCASE("Functions for changing single point properties should behave as expected") {
+ Vector2 new_in = Vector2(1, 1);
+ Vector2 new_out = Vector2(1, 1);
+ Vector2 new_pos = Vector2(1, 1);
+
+ curve->add_point(Vector2());
+
+ CHECK(curve->get_point_in(0) != new_in);
+ curve->set_point_in(0, new_in);
+ CHECK(curve->get_point_in(0) == new_in);
+
+ CHECK(curve->get_point_out(0) != new_out);
+ curve->set_point_out(0, new_out);
+ CHECK(curve->get_point_out(0) == new_out);
+
+ CHECK(curve->get_point_position(0) != new_pos);
+ curve->set_point_position(0, new_pos);
+ CHECK(curve->get_point_position(0) == new_pos);
+ }
+}
+
+TEST_CASE("[Curve2D] Baked") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+
+ SUBCASE("Single Point") {
+ curve->add_point(Vector2());
+
+ CHECK(curve->get_baked_length() == 0);
+ CHECK(curve->get_baked_points().size() == 1);
+ }
+
+ SUBCASE("Straight line") {
+ curve->add_point(Vector2());
+ curve->add_point(Vector2(0, 50));
+
+ CHECK(Math::is_equal_approx(curve->get_baked_length(), 50));
+ CHECK(curve->get_baked_points().size() == 15);
+ }
+
+ SUBCASE("BeziƩr Curve") {
+ add_sample_curve_points(curve);
+
+ real_t len = curve->get_baked_length();
+ real_t n_points = curve->get_baked_points().size();
+ // Curve length should be bigger than a straight between points
+ CHECK(len > 50);
+
+ SUBCASE("Increase bake interval") {
+ curve->set_bake_interval(10.0);
+ // Lower resolution should imply less points and smaller length
+ CHECK(curve->get_baked_length() < len);
+ CHECK(curve->get_baked_points().size() < n_points);
+ }
+ }
+}
+
+TEST_CASE("[Curve2D] Sampling") {
+ // Sampling over a simple straight line to make assertions simpler
+ Ref<Curve2D> curve = memnew(Curve2D);
+ curve->add_point(Vector2());
+ curve->add_point(Vector2(0, 50));
+
+ SUBCASE("sample") {
+ CHECK(curve->sample(0, 0) == Vector2(0, 0));
+ CHECK(curve->sample(0, 0.5) == Vector2(0, 25));
+ CHECK(curve->sample(0, 1) == Vector2(0, 50));
+ }
+
+ SUBCASE("samplef") {
+ CHECK(curve->samplef(0) == Vector2(0, 0));
+ CHECK(curve->samplef(0.5) == Vector2(0, 25));
+ CHECK(curve->samplef(1) == Vector2(0, 50));
+ }
+
+ SUBCASE("sample_baked") {
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 0))) == Vector2(0, 0));
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 25))) == Vector2(0, 25));
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 50))) == Vector2(0, 50));
+ }
+
+ SUBCASE("sample_baked_with_rotation") {
+ const real_t pi = 3.14159;
+ Transform2D t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 0)));
+ CHECK(t.get_origin() == Vector2(0, 0));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+
+ t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 25)));
+ CHECK(t.get_origin() == Vector2(0, 25));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+
+ t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 50)));
+ CHECK(t.get_origin() == Vector2(0, 50));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+ }
+
+ SUBCASE("get_closest_point") {
+ CHECK(curve->get_closest_point(Vector2(0, 0)) == Vector2(0, 0));
+ CHECK(curve->get_closest_point(Vector2(0, 25)) == Vector2(0, 25));
+ CHECK(curve->get_closest_point(Vector2(50, 25)) == Vector2(0, 25));
+ CHECK(curve->get_closest_point(Vector2(0, 50)) == Vector2(0, 50));
+ CHECK(curve->get_closest_point(Vector2(50, 50)) == Vector2(0, 50));
+ CHECK(curve->get_closest_point(Vector2(0, 100)) == Vector2(0, 50));
+ }
+}
+
+TEST_CASE("[Curve2D] Tessellation") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+ add_sample_curve_points(curve);
+
+ const int default_size = curve->tessellate().size();
+
+ SUBCASE("Increase to max stages should increase num of points") {
+ CHECK(curve->tessellate(6).size() > default_size);
+ }
+
+ SUBCASE("Decrease to max stages should decrease num of points") {
+ CHECK(curve->tessellate(4).size() < default_size);
+ }
+
+ SUBCASE("Increase to tolerance should decrease num of points") {
+ CHECK(curve->tessellate(5, 5).size() < default_size);
+ }
+
+ SUBCASE("Decrease to tolerance should increase num of points") {
+ CHECK(curve->tessellate(5, 3).size() > default_size);
+ }
+
+ SUBCASE("Adding a straight segment should only add the last point to tessellate return array") {
+ curve->add_point(Vector2(0, 100));
+ PackedVector2Array tes = curve->tessellate();
+ CHECK(tes.size() == default_size + 1);
+ CHECK(tes[tes.size() - 1] == Vector2(0, 100));
+ CHECK(tes[tes.size() - 2] == Vector2(0, 50));
+ }
+}
+
+TEST_CASE("[Curve2D] Even length tessellation") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+ add_sample_curve_points(curve);
+
+ const int default_size = curve->tessellate_even_length().size();
+
+ // Default tessellate_even_length tolerance_length is 20.0, by adding a 100 units
+ // straight, we expect the total size to be increased by more than 5,
+ // that is, the algo will pick a length < 20.0 and will divide the straight as
+ // well as the curve as opposed to tessellate() which only adds the final point
+ curve->add_point(Vector2(0, 150));
+ CHECK(curve->tessellate_even_length().size() > default_size + 5);
+}
+
+} // namespace TestCurve2D
+
+#endif // TEST_CURVE_2D_H
diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h
index 20c42d9fc2..0ddf027970 100644
--- a/tests/scene/test_node.h
+++ b/tests/scene/test_node.h
@@ -37,7 +37,7 @@
namespace TestNode {
-TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
+TEST_CASE("[SceneTree][Node] Testing node operations with a very simple scene tree") {
Node *node = memnew(Node);
// Check initial scene tree setup.
@@ -135,10 +135,30 @@ TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
CHECK(node->is_inside_tree());
}
+ SUBCASE("Node should be possible to reparent") {
+ node->reparent(SceneTree::get_singleton()->get_root());
+
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ CHECK(node->is_inside_tree());
+ }
+
+ SUBCASE("Node should be possible to duplicate") {
+ node->set_name("MyName");
+
+ Node *duplicate = node->duplicate();
+
+ CHECK_FALSE(node == duplicate);
+ CHECK_FALSE(duplicate->is_inside_tree());
+ CHECK_EQ(duplicate->get_name(), node->get_name());
+
+ memdelete(duplicate);
+ }
+
memdelete(node);
}
-TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
+TEST_CASE("[SceneTree][Node] Testing node operations with a more complex simple scene tree") {
Node *node1 = memnew(Node);
Node *node2 = memnew(Node);
Node *node1_1 = memnew(Node);
@@ -209,7 +229,7 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(child2, node1);
}
- SUBCASE("Nodes should be in the expected order when reparented") {
+ SUBCASE("Nodes should be in the expected order when reparented (remove/add)") {
CHECK_EQ(node2->get_child_count(), 0);
node1->remove_child(node1_1);
@@ -227,6 +247,22 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
}
+ SUBCASE("Nodes should be in the expected order when reparented") {
+ CHECK_EQ(node2->get_child_count(), 0);
+
+ node1_1->reparent(node2);
+
+ CHECK_EQ(node1->get_child_count(), 0);
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node1_1->get_parent(), node2);
+
+ Node *child = node2->get_child(0);
+ CHECK_EQ(child, node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+ }
+
SUBCASE("Nodes should be possible to find") {
Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
CHECK_EQ(child, nullptr);
@@ -315,6 +351,70 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(E->get(), node1_1);
}
+ SUBCASE("Nodes added as siblings of another node should be right next to it") {
+ node1->remove_child(node1_1);
+
+ node1->add_sibling(node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 3);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(0), node1);
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(1), node1_1);
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(2), node2);
+ }
+
+ SUBCASE("Replaced nodes should be be removed and the replacing node added") {
+ SceneTree::get_singleton()->get_root()->remove_child(node2);
+
+ node1->replace_by(node2);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
+
+ CHECK_FALSE(node1->is_inside_tree());
+ CHECK(node2->is_inside_tree());
+
+ CHECK_EQ(node1->get_parent(), nullptr);
+ CHECK_EQ(node2->get_parent(), SceneTree::get_singleton()->get_root());
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node2->get_child(0), node1_1);
+ }
+
+ SUBCASE("Replacing nodes should keep the groups of the replaced nodes") {
+ SceneTree::get_singleton()->get_root()->remove_child(node2);
+
+ node1->add_to_group("nodes");
+ node1->replace_by(node2, true);
+
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node2);
+ }
+
+ SUBCASE("Duplicating a node should also duplicate the children") {
+ node1->set_name("MyName1");
+ node1_1->set_name("MyName1_1");
+ Node *duplicate1 = node1->duplicate();
+
+ CHECK_EQ(duplicate1->get_child_count(), node1->get_child_count());
+ Node *duplicate1_1 = duplicate1->get_child(0);
+
+ CHECK_EQ(duplicate1_1->get_child_count(), node1_1->get_child_count());
+
+ CHECK_EQ(duplicate1->get_name(), node1->get_name());
+ CHECK_EQ(duplicate1_1->get_name(), node1_1->get_name());
+
+ CHECK_FALSE(duplicate1->is_inside_tree());
+ CHECK_FALSE(duplicate1_1->is_inside_tree());
+
+ memdelete(duplicate1_1);
+ memdelete(duplicate1);
+ }
+
memdelete(node1_1);
memdelete(node1);
memdelete(node2);
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
index 6cdb5fb0a5..9232a3020d 100644
--- a/tests/scene/test_primitives.h
+++ b/tests/scene/test_primitives.h
@@ -734,7 +734,7 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") {
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST ||
- text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_NONE ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_GDSCRIPT ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM));
CHECK(text->get_structured_text_bidi_override_options().size() >= 0);
CHECK(text->get_width() > 0);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 85a271fc9c..8c563f94ac 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -91,6 +91,7 @@
#include "tests/scene/test_bit_map.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_curve.h"
+#include "tests/scene/test_curve_2d.h"
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_node.h"
#include "tests/scene/test_path_2d.h"