summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.travis.yml2
-rw-r--r--AUTHORS.md2
-rw-r--r--CHANGELOG.md2
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--DONORS.md43
-rw-r--r--README.md6
-rw-r--r--SConstruct9
-rw-r--r--core/bind/core_bind.cpp15
-rw-r--r--core/bind/core_bind.h2
-rw-r--r--core/class_db.cpp36
-rw-r--r--core/class_db.h4
-rw-r--r--core/color.cpp2
-rw-r--r--core/color.h2
-rw-r--r--core/global_constants.cpp5
-rw-r--r--core/hash_map.h4
-rw-r--r--core/io/file_access_network.cpp4
-rw-r--r--core/io/file_access_network.h1
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/logger.cpp4
-rw-r--r--core/io/resource_format_binary.cpp9
-rw-r--r--core/io/resource_loader.cpp10
-rw-r--r--core/io/resource_loader.h4
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/resource_saver.h2
-rw-r--r--core/math/expression.cpp4
-rw-r--r--core/math/math_funcs.h10
-rw-r--r--core/message_queue.cpp1
-rw-r--r--core/object.cpp31
-rw-r--r--core/object.h12
-rw-r--r--core/os/input.cpp2
-rw-r--r--core/os/input.h2
-rw-r--r--core/project_settings.cpp86
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/resource.cpp4
-rw-r--r--core/script_debugger_remote.cpp2
-rw-r--r--core/script_language.cpp3
-rw-r--r--core/set.h1
-rw-r--r--core/ustring.cpp18
-rw-r--r--doc/classes/@GDScript.xml16
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationNodeAnimation.xml6
-rw-r--r--doc/classes/AnimationPlayer.xml6
-rw-r--r--doc/classes/AnimationTreePlayer.xml2
-rw-r--r--doc/classes/AudioServer.xml4
-rw-r--r--doc/classes/AudioStream.xml2
-rw-r--r--doc/classes/AudioStreamPlayer.xml4
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml4
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml4
-rw-r--r--doc/classes/BakedLightmap.xml2
-rw-r--r--doc/classes/Basis.xml4
-rw-r--r--doc/classes/CPUParticles.xml4
-rw-r--r--doc/classes/CPUParticles2D.xml4
-rw-r--r--doc/classes/CanvasItem.xml4
-rw-r--r--doc/classes/CanvasItemMaterial.xml8
-rw-r--r--doc/classes/CanvasLayer.xml4
-rw-r--r--doc/classes/CollisionShape.xml2
-rw-r--r--doc/classes/CollisionShape2D.xml2
-rw-r--r--doc/classes/Control.xml4
-rw-r--r--doc/classes/DirectionalLight.xml2
-rw-r--r--doc/classes/Directory.xml2
-rw-r--r--doc/classes/EditorImportPlugin.xml2
-rw-r--r--doc/classes/EditorInspector.xml8
-rw-r--r--doc/classes/EditorPlugin.xml8
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/Environment.xml4
-rw-r--r--doc/classes/Expression.xml23
-rw-r--r--doc/classes/File.xml2
-rw-r--r--doc/classes/GIProbe.xml2
-rw-r--r--doc/classes/Gradient.xml2
-rw-r--r--doc/classes/GridContainer.xml10
-rw-r--r--doc/classes/HTTPClient.xml4
-rw-r--r--doc/classes/HTTPRequest.xml2
-rw-r--r--doc/classes/Input.xml8
-rw-r--r--doc/classes/InputEvent.xml4
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventJoypadButton.xml2
-rw-r--r--doc/classes/InputEventJoypadMotion.xml2
-rw-r--r--doc/classes/InputEventKey.xml2
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/InputEventMouseMotion.xml2
-rw-r--r--doc/classes/InputEventScreenDrag.xml2
-rw-r--r--doc/classes/InputEventScreenTouch.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml2
-rw-r--r--doc/classes/InputMap.xml2
-rw-r--r--doc/classes/ItemList.xml18
-rw-r--r--doc/classes/JavaScript.xml2
-rw-r--r--doc/classes/KinematicBody.xml2
-rw-r--r--doc/classes/KinematicBody2D.xml2
-rw-r--r--doc/classes/Light.xml2
-rw-r--r--doc/classes/MeshDataTool.xml6
-rw-r--r--doc/classes/MeshInstance.xml6
-rw-r--r--doc/classes/NavigationPolygon.xml33
-rw-r--r--doc/classes/NetworkedMultiplayerPeer.xml4
-rw-r--r--doc/classes/Node.xml20
-rw-r--r--doc/classes/Node2D.xml2
-rw-r--r--doc/classes/OS.xml7
-rw-r--r--doc/classes/OmniLight.xml2
-rw-r--r--doc/classes/PackedScene.xml19
-rw-r--r--doc/classes/Particles2D.xml6
-rw-r--r--doc/classes/ParticlesMaterial.xml5
-rw-r--r--doc/classes/PathFollow2D.xml1
-rw-r--r--doc/classes/Physics2DDirectSpaceState.xml22
-rw-r--r--doc/classes/Physics2DServer.xml36
-rw-r--r--doc/classes/PhysicsBody.xml9
-rw-r--r--doc/classes/PhysicsBody2D.xml9
-rw-r--r--doc/classes/PhysicsDirectSpaceState.xml2
-rw-r--r--doc/classes/PhysicsServer.xml2
-rw-r--r--doc/classes/Plane.xml2
-rw-r--r--doc/classes/ProjectSettings.xml17
-rw-r--r--doc/classes/Quat.xml4
-rw-r--r--doc/classes/Rect2.xml2
-rw-r--r--doc/classes/ReflectionProbe.xml2
-rw-r--r--doc/classes/ResourceSaver.xml2
-rw-r--r--doc/classes/RichTextLabel.xml5
-rw-r--r--doc/classes/RigidBody.xml2
-rw-r--r--doc/classes/SceneTree.xml4
-rw-r--r--doc/classes/Script.xml2
-rw-r--r--doc/classes/Shader.xml2
-rw-r--r--doc/classes/Shape.xml2
-rw-r--r--doc/classes/Shape2D.xml2
-rw-r--r--doc/classes/SoftBody.xml7
-rw-r--r--doc/classes/Spatial.xml2
-rw-r--r--doc/classes/SpatialMaterial.xml4
-rw-r--r--doc/classes/SpotLight.xml2
-rw-r--r--doc/classes/StreamPeerSSL.xml2
-rw-r--r--doc/classes/StreamPeerTCP.xml3
-rw-r--r--doc/classes/SurfaceTool.xml4
-rw-r--r--doc/classes/TileMap.xml2
-rw-r--r--doc/classes/Transform.xml4
-rw-r--r--doc/classes/Tween.xml2
-rw-r--r--doc/classes/Vector2.xml6
-rw-r--r--doc/classes/Vector3.xml8
-rw-r--r--doc/classes/Viewport.xml4
-rw-r--r--doc/classes/VisualServer.xml11
-rw-r--r--doc/classes/World.xml2
-rw-r--r--doc/classes/World2D.xml2
-rw-r--r--doc/classes/WorldEnvironment.xml2
-rw-r--r--doc/classes/YSort.xml1
-rw-r--r--doc/tools/doc_merge.py2
-rw-r--r--doc/tools/doc_status.py4
-rwxr-xr-xdoc/tools/makerst.py8
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp5
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp5
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp12
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp70
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h1
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp7
-rw-r--r--drivers/gles2/shader_gles2.cpp14
-rw-r--r--drivers/gles2/shaders/canvas.glsl3
-rw-r--r--drivers/gles2/shaders/copy.glsl22
-rw-r--r--drivers/gles2/shaders/scene.glsl9
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp11
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp5
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp38
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp174
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h7
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp3
-rw-r--r--drivers/gles3/shaders/canvas.glsl19
-rw-r--r--drivers/gles3/shaders/scene.glsl2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp18
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h1
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.cpp11
-rw-r--r--drivers/unix/net_socket_posix.cpp2
-rw-r--r--drivers/unix/os_unix.cpp6
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp5
-rw-r--r--drivers/windows/file_access_windows.cpp4
-rw-r--r--editor/animation_track_editor.cpp29
-rw-r--r--editor/code_editor.cpp21
-rw-r--r--editor/code_editor.h2
-rw-r--r--editor/dependency_editor.cpp14
-rw-r--r--editor/dependency_editor.h10
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_autoload_settings.cpp2
-rw-r--r--editor/editor_export.cpp25
-rw-r--r--editor/editor_export.h8
-rw-r--r--editor/editor_file_dialog.cpp29
-rw-r--r--editor/editor_file_system.cpp6
-rw-r--r--editor/editor_file_system.h2
-rw-r--r--editor/editor_folding.cpp175
-rw-r--r--editor/editor_folding.h25
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_inspector.cpp124
-rw-r--r--editor/editor_inspector.h11
-rw-r--r--editor/editor_node.cpp113
-rw-r--r--editor/editor_node.h8
-rw-r--r--editor/editor_plugin.cpp1
-rw-r--r--editor/editor_properties.cpp17
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/fileserver/editor_file_server.cpp10
-rw-r--r--editor/filesystem_dock.cpp138
-rw-r--r--editor/filesystem_dock.h10
-rw-r--r--editor/find_in_files.cpp57
-rw-r--r--editor/icons/icon_script_extend.svg8
-rw-r--r--editor/import/resource_importer_texture.cpp6
-rw-r--r--editor/import_dock.cpp51
-rw-r--r--editor/import_dock.h1
-rw-r--r--editor/inspector_dock.cpp1
-rw-r--r--editor/plugin_config_dialog.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp24
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp6
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp3
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.cpp2
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.h2
-rw-r--r--editor/plugins/camera_editor_plugin.cpp12
-rw-r--r--editor/plugins/camera_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp420
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h25
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp54
-rw-r--r--editor/plugins/gi_probe_editor_plugin.cpp2
-rw-r--r--editor/plugins/gi_probe_editor_plugin.h2
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp2
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp30
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp22
-rw-r--r--editor/plugins/particles_2d_editor_plugin.h3
-rw-r--r--editor/plugins/particles_editor_plugin.cpp1
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp38
-rw-r--r--editor/plugins/script_editor_plugin.cpp27
-rw-r--r--editor/plugins/script_text_editor.cpp8
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/skeleton_editor_plugin.cpp1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp179
-rw-r--r--editor/plugins/spatial_editor_plugin.h3
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp22
-rw-r--r--editor/plugins/text_editor.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp3
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp296
-rw-r--r--editor/plugins/tile_map_editor_plugin.h20
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp70
-rw-r--r--editor/plugins/tile_set_editor_plugin.h8
-rw-r--r--editor/progress_dialog.cpp6
-rw-r--r--editor/project_export.cpp179
-rw-r--r--editor/project_export.h10
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/property_editor.cpp2
-rw-r--r--editor/property_selector.cpp2
-rw-r--r--editor/quick_open.cpp2
-rw-r--r--editor/scene_tree_dock.cpp64
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--editor/scene_tree_editor.cpp7
-rw-r--r--editor/script_editor_debugger.cpp43
-rw-r--r--editor/spatial_editor_gizmos.cpp3
-rw-r--r--gles_builders.py4
-rw-r--r--main/input_default.cpp40
-rw-r--r--main/input_default.h3
-rw-r--r--main/main.cpp59
-rw-r--r--methods.py2
-rw-r--r--misc/dist/document_icon.svg12
-rw-r--r--misc/dist/linux/org.godotengine.Godot.appdata.xml4
-rwxr-xr-xmisc/dist/osx_tools.app/Contents/Info.plist83
-rw-r--r--misc/dist/osx_tools.app/Contents/Resources/Document.icnsbin0 -> 143464 bytes
-rw-r--r--modules/csg/csg_shape.cpp9
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml2
-rw-r--r--modules/freetype/SCsub2
-rw-r--r--modules/gdnative/gdnative.cpp19
-rw-r--r--modules/gdnative/gdnative/array.cpp32
-rw-r--r--modules/gdnative/gdnative/basis.cpp9
-rw-r--r--modules/gdnative/gdnative/color.cpp41
-rw-r--r--modules/gdnative/gdnative/node_path.cpp9
-rw-r--r--modules/gdnative/gdnative/quat.cpp6
-rw-r--r--modules/gdnative/gdnative/rect2.cpp21
-rw-r--r--modules/gdnative/gdnative/string.cpp58
-rw-r--r--modules/gdnative/gdnative_api.json177
-rw-r--r--modules/gdnative/include/gdnative/array.h8
-rw-r--r--modules/gdnative/include/gdnative/basis.h2
-rw-r--r--modules/gdnative/include/gdnative/color.h14
-rw-r--r--modules/gdnative/include/gdnative/node_path.h2
-rw-r--r--modules/gdnative/include/gdnative/quat.h2
-rw-r--r--modules/gdnative/include/gdnative/rect2.h6
-rw-r--r--modules/gdnative/include/gdnative/string.h6
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp11
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/gdscript.cpp12
-rw-r--r--modules/gdscript/gdscript_compiler.cpp20
-rw-r--r--modules/gdscript/gdscript_compiler.h10
-rw-r--r--modules/gdscript/gdscript_editor.cpp60
-rw-r--r--modules/gdscript/gdscript_function.cpp49
-rw-r--r--modules/gdscript/gdscript_function.h10
-rw-r--r--modules/gdscript/gdscript_functions.cpp51
-rw-r--r--modules/gdscript/gdscript_functions.h3
-rw-r--r--modules/gdscript/gdscript_parser.cpp87
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml2
-rw-r--r--modules/gridmap/grid_map.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp22
-rw-r--r--modules/mono/SCsub111
-rw-r--r--modules/mono/config.py6
-rw-r--r--modules/mono/csharp_script.cpp139
-rw-r--r--modules/mono/csharp_script.h8
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj6
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs16
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs41
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs58
-rw-r--r--modules/mono/editor/GodotSharpTools/StringExtensions.cs4
-rw-r--r--modules/mono/editor/GodotSharpTools/packages.config4
-rw-r--r--modules/mono/editor/bindings_generator.cpp369
-rw-r--r--modules/mono/editor/bindings_generator.h35
-rw-r--r--modules/mono/editor/csharp_project.cpp129
-rw-r--r--modules/mono/editor/csharp_project.h3
-rw-r--r--modules/mono/editor/dotnet_solution.cpp (renamed from modules/mono/editor/net_solution.cpp)63
-rw-r--r--modules/mono/editor/dotnet_solution.h (renamed from modules/mono/editor/net_solution.h)23
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp121
-rw-r--r--modules/mono/editor/godotsharp_builds.h4
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp51
-rw-r--r--modules/mono/editor/godotsharp_editor.h2
-rw-r--r--modules/mono/editor/godotsharp_export.cpp21
-rw-r--r--modules/mono/editor/godotsharp_export.h2
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp6
-rw-r--r--modules/mono/editor/script_class_parser.cpp542
-rw-r--r--modules/mono/editor/script_class_parser.h79
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs16
-rw-r--r--modules/mono/glue/gd_glue.cpp10
-rw-r--r--modules/mono/godotsharp_defs.h3
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp67
-rw-r--r--modules/mono/mono_gd/gd_mono.h3
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp14
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp318
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h10
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp317
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h285
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp20
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h10
-rw-r--r--modules/mono/signal_awaiter_utils.cpp2
-rw-r--r--modules/mono/utils/macros.h9
-rw-r--r--modules/mono/utils/path_utils.cpp10
-rw-r--r--modules/mono/utils/string_utils.cpp28
-rw-r--r--modules/mono/utils/string_utils.h2
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml6
-rw-r--r--modules/recast/navigation_mesh_editor_plugin.cpp19
-rw-r--r--modules/recast/navigation_mesh_editor_plugin.h4
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/visual_script.cpp4
-rw-r--r--modules/visual_script/visual_script_editor.cpp21
-rw-r--r--modules/visual_script/visual_script_editor.h2
-rw-r--r--modules/websocket/emws_server.cpp3
-rw-r--r--modules/websocket/lws_client.cpp25
-rw-r--r--modules/websocket/websocket_client.cpp2
-rw-r--r--modules/websocket/websocket_multiplayer.cpp2
-rw-r--r--platform/android/build.gradle.template2
-rw-r--r--platform/android/detect.py4
-rw-r--r--platform/android/export/export.cpp81
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotView.java188
-rw-r--r--platform/android/os_android.cpp10
-rw-r--r--platform/haiku/os_haiku.cpp13
-rw-r--r--platform/iphone/detect.py2
-rw-r--r--platform/iphone/export/export.cpp6
-rw-r--r--platform/iphone/os_iphone.cpp10
-rw-r--r--platform/javascript/detect.py4
-rw-r--r--platform/javascript/engine.js3
-rw-r--r--platform/javascript/export/export.cpp8
-rw-r--r--platform/javascript/os_javascript.cpp18
-rw-r--r--platform/javascript/os_javascript.h4
-rw-r--r--platform/javascript/pre.js3
-rw-r--r--platform/osx/detect.py2
-rw-r--r--platform/osx/export/export.cpp16
-rw-r--r--platform/osx/os_osx.h4
-rw-r--r--platform/osx/os_osx.mm47
-rw-r--r--platform/server/SCsub15
-rw-r--r--platform/server/detect.py12
-rw-r--r--platform/server/os_server.cpp8
-rw-r--r--platform/server/os_server.h10
-rw-r--r--platform/server/platform_config.h5
-rw-r--r--platform/uwp/detect.py2
-rw-r--r--platform/uwp/export/export.cpp6
-rw-r--r--platform/uwp/os_uwp.cpp8
-rw-r--r--platform/windows/context_gl_win.cpp24
-rw-r--r--platform/windows/joypad.cpp4
-rw-r--r--platform/windows/os_windows.cpp118
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--platform/x11/detect.py12
-rw-r--r--platform/x11/os_x11.cpp10
-rw-r--r--scene/2d/animated_sprite.cpp20
-rw-r--r--scene/2d/area_2d.cpp16
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/canvas_item.cpp129
-rw-r--r--scene/2d/canvas_item.h27
-rw-r--r--scene/2d/collision_object_2d.cpp16
-rw-r--r--scene/2d/collision_polygon_2d.cpp4
-rw-r--r--scene/2d/collision_shape_2d.cpp6
-rw-r--r--scene/2d/cpu_particles_2d.cpp91
-rw-r--r--scene/2d/cpu_particles_2d.h14
-rw-r--r--scene/2d/line_2d.cpp12
-rw-r--r--scene/2d/line_builder.cpp1
-rw-r--r--scene/2d/mesh_instance_2d.cpp4
-rw-r--r--scene/2d/node_2d.cpp18
-rw-r--r--scene/2d/node_2d.h2
-rw-r--r--scene/2d/particles_2d.cpp36
-rw-r--r--scene/2d/particles_2d.h8
-rw-r--r--scene/2d/path_2d.cpp4
-rw-r--r--scene/2d/physics_body_2d.cpp35
-rw-r--r--scene/2d/physics_body_2d.h1
-rw-r--r--scene/2d/sprite.cpp24
-rw-r--r--scene/2d/tile_map.cpp11
-rw-r--r--scene/3d/arvr_nodes.cpp4
-rw-r--r--scene/3d/arvr_nodes.h4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp2
-rw-r--r--scene/3d/cpu_particles.cpp10
-rw-r--r--scene/3d/cpu_particles.h2
-rw-r--r--scene/3d/light.cpp9
-rw-r--r--scene/3d/mesh_instance.cpp6
-rw-r--r--scene/3d/mesh_instance.h1
-rw-r--r--scene/3d/path.cpp39
-rw-r--r--scene/3d/path.h4
-rw-r--r--scene/3d/physics_body.cpp36
-rw-r--r--scene/3d/physics_body.h1
-rw-r--r--scene/3d/soft_body.cpp19
-rw-r--r--scene/3d/soft_body.h1
-rw-r--r--scene/3d/spatial.cpp6
-rw-r--r--scene/3d/sprite_3d.cpp6
-rw-r--r--scene/3d/voxel_light_baker.cpp8
-rw-r--r--scene/animation/animation_blend_tree.cpp21
-rw-r--r--scene/animation/animation_blend_tree.h7
-rw-r--r--scene/animation/animation_node_state_machine.cpp1
-rw-r--r--scene/audio/audio_player.cpp1
-rw-r--r--scene/gui/base_button.cpp8
-rw-r--r--scene/gui/button.cpp6
-rw-r--r--scene/gui/control.cpp46
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/graph_edit.cpp12
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/item_list.cpp66
-rw-r--r--scene/gui/item_list.h4
-rw-r--r--scene/gui/label.cpp12
-rw-r--r--scene/gui/line_edit.cpp22
-rw-r--r--scene/gui/link_button.cpp6
-rw-r--r--scene/gui/nine_patch_rect.cpp18
-rw-r--r--scene/gui/popup_menu.cpp25
-rw-r--r--scene/gui/rich_text_label.cpp5
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/tabs.cpp83
-rw-r--r--scene/gui/tabs.h2
-rw-r--r--scene/gui/text_edit.cpp19
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/gui/texture_button.cpp18
-rw-r--r--scene/gui/texture_progress.cpp14
-rw-r--r--scene/gui/texture_rect.cpp6
-rw-r--r--scene/gui/tree.cpp2
-rw-r--r--scene/gui/video_player.cpp57
-rw-r--r--scene/main/canvas_layer.cpp15
-rw-r--r--scene/main/node.cpp28
-rw-r--r--scene/main/node.h2
-rw-r--r--scene/main/scene_tree.cpp3
-rw-r--r--scene/main/viewport.cpp74
-rw-r--r--scene/main/viewport.h6
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/convex_polygon_shape.cpp3
-rw-r--r--scene/resources/dynamic_font.cpp32
-rw-r--r--scene/resources/dynamic_font.h2
-rw-r--r--scene/resources/material.cpp14
-rw-r--r--scene/resources/material.h4
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--scene/resources/mesh_data_tool.cpp2
-rw-r--r--scene/resources/packed_scene.cpp20
-rw-r--r--scene/resources/particles_material.cpp9
-rw-r--r--scene/resources/particles_material.h1
-rw-r--r--scene/resources/primitive_meshes.cpp5
-rw-r--r--scene/resources/scene_format_text.cpp8
-rw-r--r--scene/resources/shape.cpp2
-rw-r--r--scene/resources/style_box.cpp34
-rw-r--r--scene/resources/visual_shader.cpp2
-rw-r--r--servers/audio/audio_stream.cpp16
-rw-r--r--servers/audio/audio_stream.h2
-rw-r--r--servers/audio/effects/reverb.cpp24
-rw-r--r--servers/audio_server.cpp11
-rw-r--r--servers/audio_server.h1
-rw-r--r--servers/physics/area_pair_sw.cpp4
-rw-r--r--servers/physics/collision_solver_sat.cpp1
-rw-r--r--servers/physics/space_sw.cpp29
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp4
-rw-r--r--servers/physics_2d/body_2d_sw.cpp3
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp4
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp1
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h4
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp41
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h6
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h6
-rw-r--r--servers/physics_2d/space_2d_sw.cpp102
-rw-r--r--servers/physics_2d/space_2d_sw.h3
-rw-r--r--servers/physics_2d_server.cpp26
-rw-r--r--servers/physics_2d_server.h10
-rw-r--r--servers/visual/rasterizer.h2
-rw-r--r--servers/visual/shader_language.cpp37
-rw-r--r--servers/visual/shader_language.h1
-rw-r--r--servers/visual/shader_types.cpp1
-rw-r--r--servers/visual/visual_server_canvas.cpp6
-rw-r--r--servers/visual/visual_server_canvas.h2
-rw-r--r--servers/visual/visual_server_raster.h4
-rw-r--r--servers/visual/visual_server_scene.cpp5
-rw-r--r--servers/visual/visual_server_viewport.cpp10
-rw-r--r--servers/visual/visual_server_viewport.h19
-rw-r--r--servers/visual/visual_server_wrap_mt.h4
-rw-r--r--servers/visual_server.cpp5
-rw-r--r--servers/visual_server.h4
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/libwebsockets/core/context.c25
-rw-r--r--thirdparty/libwebsockets/core/libwebsockets.c55
-rw-r--r--thirdparty/libwebsockets/core/output.c12
-rw-r--r--thirdparty/libwebsockets/core/private.h33
-rw-r--r--thirdparty/libwebsockets/libwebsockets.h44
-rw-r--r--thirdparty/libwebsockets/lws_config.h2
-rw-r--r--thirdparty/libwebsockets/lws_config_private.h2
-rw-r--r--thirdparty/libwebsockets/misc/lejp.c25
-rw-r--r--thirdparty/libwebsockets/plat/lws-plat-unix.c10
-rw-r--r--thirdparty/libwebsockets/plat/lws-plat-win.c34
-rw-r--r--thirdparty/libwebsockets/roles/h1/ops-h1.c14
-rw-r--r--thirdparty/libwebsockets/roles/http/client/client-handshake.c10
-rw-r--r--thirdparty/libwebsockets/roles/http/client/client.c38
-rw-r--r--thirdparty/libwebsockets/roles/http/header.c76
-rw-r--r--thirdparty/libwebsockets/roles/http/private.h1
-rw-r--r--thirdparty/libwebsockets/roles/http/server/lejp-conf.c64
-rw-r--r--thirdparty/libwebsockets/roles/http/server/parsers.c26
-rw-r--r--thirdparty/libwebsockets/roles/http/server/server.c50
-rw-r--r--thirdparty/libwebsockets/roles/ws/client-parser-ws.c11
-rw-r--r--thirdparty/libwebsockets/roles/ws/ops-ws.c26
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c2
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/ssl.c2
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h4
-rw-r--r--thirdparty/libwebsockets/uwp_fixes.diff10
-rw-r--r--thirdparty/libwebsockets/win32helpers/getopt.c306
-rw-r--r--thirdparty/libwebsockets/win32helpers/getopt_long.c480
-rw-r--r--thirdparty/libwebsockets/win32helpers/gettimeofday.c70
527 files changed, 8123 insertions, 3679 deletions
diff --git a/.gitignore b/.gitignore
index 52937b8679..fe504482b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -238,6 +238,7 @@ ClientBin/
*.pfx
*.publishsettings
node_modules/
+__pycache__/
# KDE
.directory
@@ -310,5 +311,8 @@ platform/windows/godot_res.res
/.vs
/.vscode
+# Visual Studio Code workspace file
+*.code-workspace
+
# Scons progress indicator
.scons_node_count
diff --git a/.travis.yml b/.travis.yml
index a5217c1d9c..a8bc8289e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,7 +38,7 @@ matrix:
- mono
packages:
- &linux_deps [libasound2-dev, libfreetype6-dev, libgl1-mesa-dev, libglu1-mesa-dev, libx11-dev, libxcursor-dev, libxi-dev, libxinerama-dev, libxrandr-dev]
- - &linux_mono_deps [mono-devel, msbuild]
+ - &linux_mono_deps [mono-devel, msbuild, nuget]
coverity_scan:
project:
diff --git a/AUTHORS.md b/AUTHORS.md
index 13a67ce3f5..2f109aff6e 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -73,7 +73,7 @@ name is available.
J08nY
Jakub Grzesik (kubecz3k)
Jérôme GULLY (Nutriz)
- JFonS
+ Joan Fons Sanchez (JFonS)
Johan Manuel (29jm)
Joshua Grams (JoshuaGrams)
Juan Linietsky (reduz)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 533968886e..6a0310f904 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,7 +47,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Setters and getters for node properties.
- Underscores in number literals are now allowed for improved readability (for example,`1_000_000`).
- Improved performance (+20% to +40%, based on various benchmarks).
-- [Feature tags](http://docs.godotengine.org/en/latest/learning/workflow/export/feature_tags.html) in the Project Settings, for custom per-platform settings.
+- [Feature tags](http://docs.godotengine.org/en/latest/getting_started/workflow/export/feature_tags.html) in the Project Settings, for custom per-platform settings.
- Full support for the [glTF 2.0](https://www.khronos.org/gltf/) 3D interchange format.
- Freelook and fly navigation to the 3D editor.
- Built-in editor logging (logging standard output to a file), disabled by default.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2ea2ed6bba..a8e4650710 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -71,7 +71,7 @@ discuss the implementation in the bug report first if you are not 100% about
what would be the best fix.
In addition to the following tips, also take a look at the
-[Engine development guide](http://docs.godotengine.org/en/latest/development/cpp/)
+[Engine development guide](https://docs.godotengine.org/en/latest/development/cpp/)
for an introduction to developing on Godot.
#### Be nice to the git history
diff --git a/DONORS.md b/DONORS.md
index 6fdb02e3fa..2c9bb1eb73 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -13,30 +13,29 @@ generous deed immortalized in the next stable release of Godot Engine.
## Platinum sponsors
Enjin Coin <https://enjincoin.io>
- GameDev.TV <https://gdev.tv/godot>
## Gold sponsors
Gamblify <https://www.gamblify.com>
+ GameDev.TV <https://gdev.tv/godot>
+ Image Campus <https://www.imagecampus.edu.ar>
## Mini sponsors
Andrew Dunai
Brandon Lamb
Christian Uldall Pedersen
- Christopher Igoe
Christoph Woinke
+ David Graham
GameDev.net
Hein-Pieter van Braam
iDev.Network Studios
Jamal Alyafei
- Jay Sistar
Leona Eden
Matthieu Huvé
Mike King
Nathan Warden
Neal Gompa (Conan Kudo)
- Pascal Julien
Patrick Aarstad
Ruslan Mustakov
Slobodan Milnovic
@@ -67,7 +66,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Gary Oberbrunner
Jay Horton
Johannes Wuensch
- Josep G. Camarasa
Joshua Lesperance
Krzysztof Dluzniewski
Kyle Szklenski
@@ -77,7 +75,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Ranoller
Sergey
Svenne Krap
- Timothy Hagberg
+ Xananax
BanjoNode2D
Beliar
@@ -92,6 +90,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Justo Delgado Baudí
KTL
Laurence Bannister
+ Markus Wiesner
paul gruenbacher
Rami
Robert Willes
@@ -106,7 +105,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Alessandra Pereyra
Alexey Dyadchenko
Amanda Haldy
- Branwen Danielle Zakariasen
Chau Siu Hung
Chris Brown
Chris Petrich
@@ -130,9 +128,8 @@ generous deed immortalized in the next stable release of Godot Engine.
joe513
Juraj Móza
Justin Arnold
- Lars Wuethrich
Leandro Voltolino
- Markus Wiesner
+ Marius Kamm
Marvin
Nahuel Sacchetti
Nick Nikitin
@@ -140,8 +137,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Pete Goodwin
ray-tracer
Ruben Soares Luis
- Rufus Xavier Sarsaparilla
- Sindre Sømme
Sofox
Stoned Xander
Trent McPheron
@@ -167,7 +162,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Bailey
Bastian Böhm
Benedikt
- Benjamin Beshara
Ben Vercammen
Blair Allen
Brandon
@@ -178,7 +172,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Chris Chapin
Christian Baune
Christian Winter
- Christopher Schmitt
Collin Shooltz
Daniel Johnson
Daniel Kaplan
@@ -192,11 +185,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Edward Herbert
Elias Nykrem
Eric Martini
+ Eric Williams
Eugenio Hugo Salgüero Jáñez
Fabian Becker
fengjiongmax
Foomf
G3Dev sàrl
+ George Lesica
Gerrit Großkopf
Gilberto K. Otubo
Greg Olson
@@ -206,6 +201,7 @@ generous deed immortalized in the next stable release of Godot Engine.
ialex32x
Jahn Johansen
Jaime Ruiz-Borau Vizárraga
+ Jako Danar
Jeff Hungerford
Joel Fivat
Johan Lindberg
@@ -213,9 +209,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Jonas Yamazaki
Jonathan Martin
Jonathan Nieto
- Jonathon
Jon Bonazza
Jon Sully
+ Jose Malheiro
Josh 'Cheeseness' Bush
Juanfran
Juan Negrier
@@ -227,14 +223,16 @@ generous deed immortalized in the next stable release of Godot Engine.
Kevin Kamper Meejach Petersen
Klavdij Voncina
Krzysztof Jankowski
+ Krzysztof Sierszecki
+ KsyTek Games
Linus Lind Lundgren
Loreshaper Games
- Luc Magitem
Luis Moraes
Macil
magodev
- Manolis Makris
+ Malcolm
Martin Eigel
+ Matt Welke
Max R.R. Collada
Maxwell
Mertcan Mermerkaya
@@ -245,17 +243,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Mikael Olsson
MoM
Moritz Laass
+ Moritz Weissenberger
Natrim
nee
Neil Blakey-Milner
Nick Pavlica
Niclas Eriksen
+ Nicolás Montaña
Nicolas SAN AGUSTIN
- Niko Leopold
+ Nik
Noi Sek
Pan Ip
Pascal Grüter
- Pat LaBine
Patrick Nafarrete
Paul E Hansen
Paul Gieske
@@ -273,10 +272,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Roman Tinkov
Sasori Olkof
Sootstone
- Stefan Butucea
- The K-B
Theo Cranmore
- Thibaud Galloy
Thibault Barbaroux
Thomas Bell
Thomas Holmes
@@ -284,18 +280,15 @@ generous deed immortalized in the next stable release of Godot Engine.
tiansheng li
Tim
Tom Larrow
- Tristan Crawford
- Tryggve Sollid
Trym Nilsen
+ Tyggve Sollid
Tyler Stafos
UltyX
Vaiktorg
Victor
Viktor Ferenczi
waka nya
- werner mendizabal
Wout Standaert
- Yu He
## Bronze donors
diff --git a/README.md b/README.md
index b34b9e8702..06380b5e0a 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ Official binaries for the Godot editor and the export templates can be found
#### Compiling from source
-[See the official docs](http://docs.godotengine.org/en/latest/development/compiling/)
+[See the official docs](https://docs.godotengine.org/en/latest/development/compiling/)
for compilation instructions for every supported platform.
### Community and contributing
@@ -53,10 +53,10 @@ To get started contributing to the project, see the [contributing guide](CONTRIB
### Documentation and demos
-The official documentation is hosted on [ReadTheDocs](http://docs.godotengine.org).
+The official documentation is hosted on [ReadTheDocs](https://docs.godotengine.org).
It is maintained by the Godot community in its own [GitHub repository](https://github.com/godotengine/godot-docs).
-The [class reference](http://docs.godotengine.org/en/latest/classes/)
+The [class reference](https://docs.godotengine.org/en/latest/classes/)
is also accessible from within the engine.
The official demos are maintained in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
diff --git a/SConstruct b/SConstruct
index f8c1c82961..628aac42af 100644
--- a/SConstruct
+++ b/SConstruct
@@ -349,7 +349,10 @@ if selected_platform in platform_list:
else: # always enable those errors
env.Append(CCFLAGS=['-Werror=return-type'])
- suffix = "." + selected_platform
+ if (hasattr(detect, 'get_program_suffix')):
+ suffix = "." + detect.get_program_suffix()
+ else:
+ suffix = "." + selected_platform
if (env["target"] == "release"):
if env["tools"]:
@@ -544,7 +547,7 @@ if 'env' in locals():
[os.remove(f) for f in files]
def file_list(self):
- if self.path == None:
+ if self.path is None:
# Nothing to do
return []
# Gather a list of (filename, (size, atime)) within the
@@ -569,7 +572,7 @@ if 'env' in locals():
if sum > self.limit:
mark = i
break
- if mark == None:
+ if mark is None:
return []
else:
return [x[0] for x in file_stat[mark:]]
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 02b8c71465..cd28081f76 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -180,6 +180,7 @@ void _ResourceSaver::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES);
BIND_ENUM_CONSTANT(FLAG_SAVE_BIG_ENDIAN);
BIND_ENUM_CONSTANT(FLAG_COMPRESS);
+ BIND_ENUM_CONSTANT(FLAG_REPLACE_SUBRESOURCE_PATHS);
}
_ResourceSaver::_ResourceSaver() {
@@ -1019,6 +1020,11 @@ void _OS::center_window() {
OS::get_singleton()->center_window();
}
+void _OS::move_window_to_foreground() {
+
+ OS::get_singleton()->move_window_to_foreground();
+}
+
bool _OS::is_debug_build() const {
#ifdef DEBUG_ENABLED
@@ -1120,6 +1126,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_attention"), &_OS::request_attention);
ClassDB::bind_method(D_METHOD("get_real_window_size"), &_OS::get_real_window_size);
ClassDB::bind_method(D_METHOD("center_window"), &_OS::center_window);
+ ClassDB::bind_method(D_METHOD("move_window_to_foreground"), &_OS::move_window_to_foreground);
ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window);
ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window);
@@ -2859,10 +2866,10 @@ void JSONParseResult::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line);
ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line");
- ADD_PROPERTYNZ(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line");
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result");
}
void JSONParseResult::set_error(Error p_error) {
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 3a913e01ed..437d7515c6 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -80,6 +80,7 @@ public:
FLAG_OMIT_EDITOR_PROPERTIES = 8,
FLAG_SAVE_BIG_ENDIAN = 16,
FLAG_COMPRESS = 32,
+ FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
};
static _ResourceSaver *get_singleton() { return singleton; }
@@ -184,6 +185,7 @@ public:
virtual bool is_window_always_on_top() const;
virtual void request_attention();
virtual void center_window();
+ virtual void move_window_to_foreground();
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window() const;
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 71809d5454..6565d242a2 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -1367,6 +1367,41 @@ void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p
}
}
+HashMap<StringName, HashMap<StringName, Variant> > ClassDB::default_values;
+
+Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property) {
+
+ if (!default_values.has(p_class)) {
+
+ default_values[p_class] = HashMap<StringName, Variant>();
+
+ if (ClassDB::can_instance(p_class)) {
+
+ Object *c = ClassDB::instance(p_class);
+ List<PropertyInfo> plist;
+ c->get_property_list(&plist);
+ for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
+ if (E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
+
+ Variant v = c->get(E->get().name);
+ default_values[p_class][E->get().name] = v;
+ }
+ }
+ memdelete(c);
+ }
+ }
+
+ if (!default_values.has(p_class)) {
+ return Variant();
+ }
+
+ if (!default_values[p_class].has(p_property)) {
+ return Variant();
+ }
+
+ return default_values[p_class][p_property];
+}
+
RWLock *ClassDB::lock = NULL;
void ClassDB::init() {
@@ -1393,6 +1428,7 @@ void ClassDB::cleanup() {
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();
+ default_values.clear();
memdelete(lock);
}
diff --git a/core/class_db.h b/core/class_db.h
index 11cc3033cf..75f9e8d6a7 100644
--- a/core/class_db.h
+++ b/core/class_db.h
@@ -161,6 +161,8 @@ public:
static void _add_class2(const StringName &p_class, const StringName &p_inherits);
+ static HashMap<StringName, HashMap<StringName, Variant> > default_values;
+
public:
// DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!!
template <class T>
@@ -352,6 +354,8 @@ public:
static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false);
static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false);
+ static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property);
+
static StringName get_category(const StringName &p_node);
static void set_class_enabled(StringName p_class, bool p_enable);
diff --git a/core/color.cpp b/core/color.cpp
index 55dd1ec6b9..ac314417ec 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -468,7 +468,7 @@ String Color::to_html(bool p_alpha) const {
return txt;
}
-Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) {
+Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
p_h = Math::fmod(p_h * 360.0f, 360.0f);
if (p_h < 0.0)
diff --git a/core/color.h b/core/color.h
index add61343ff..d6ad5f91c5 100644
--- a/core/color.h
+++ b/core/color.h
@@ -194,7 +194,7 @@ struct Color {
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
String to_html(bool p_alpha = true) const;
- Color from_hsv(float p_h, float p_s, float p_v, float p_a);
+ Color from_hsv(float p_h, float p_s, float p_v, float p_a) const;
static Color from_rgbe9995(uint32_t p_color);
_FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index c70f960a66..7e9b8b393c 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -547,8 +547,9 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
+ //deprecated, replaced by ClassDB function to check default value
+ //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO);
+ //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
diff --git a/core/hash_map.h b/core/hash_map.h
index 8620edba73..3869cd3c36 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -150,7 +150,7 @@ private:
if (new_hash_table_power == -1)
return;
- Element **new_hash_table = memnew_arr(Element *, (1 << new_hash_table_power));
+ Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power));
if (!new_hash_table) {
ERR_PRINT("Out of Memory");
@@ -230,7 +230,7 @@ private:
if (!p_t.hash_table || p_t.hash_table_power == 0)
return; /* not copying from empty table */
- hash_table = memnew_arr(Element *, 1 << p_t.hash_table_power);
+ hash_table = memnew_arr(Element *, (uint64_t)1 << p_t.hash_table_power);
hash_table_power = p_t.hash_table_power;
elements = p_t.elements;
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 6b6856dcc8..b9544ac166 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -500,8 +500,9 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
void FileAccessNetwork::configure() {
GLOBAL_DEF("network/remote_fs/page_size", 65536);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_size", PropertyInfo(Variant::INT, "network/remote_fs/page_size", PROPERTY_HINT_RANGE, "1,65536,1,or_greater")); //is used as denominator and can't be zero
GLOBAL_DEF("network/remote_fs/page_read_ahead", 4);
- GLOBAL_DEF("network/remote_fs/max_pages", 20);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_read_ahead", PropertyInfo(Variant::INT, "network/remote_fs/page_read_ahead", PROPERTY_HINT_RANGE, "0,8,1,or_greater"));
}
FileAccessNetwork::FileAccessNetwork() {
@@ -519,7 +520,6 @@ FileAccessNetwork::FileAccessNetwork() {
nc->unlock_mutex();
page_size = GLOBAL_GET("network/remote_fs/page_size");
read_ahead = GLOBAL_GET("network/remote_fs/page_read_ahead");
- max_pages = GLOBAL_GET("network/remote_fs/max_pages");
last_activity_val = 0;
waiting_on_page = -1;
last_page = -1;
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index e32dcea990..c929e8446d 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -98,7 +98,6 @@ class FileAccessNetwork : public FileAccess {
int page_size;
int read_ahead;
- int max_pages;
mutable int waiting_on_page;
mutable int last_activity_val;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 40f756ba9a..3823285792 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -455,7 +455,7 @@ String DirAccessPack::get_current_dir() {
while (pd->parent) {
pd = pd->parent;
- p = pd->name + "/" + p;
+ p = pd->name.plus_file(p);
}
return "res://" + p;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 051c02ab32..01755c8ee9 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -45,6 +45,10 @@
#endif
#endif
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define sprintf sprintf_s
+#endif
+
bool Logger::should_log(bool p_err) {
return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
}
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index e5741014a4..6f3a8c3d2e 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1309,7 +1309,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
case Variant::INT: {
int64_t val = p_property;
- if (val > 0x7FFFFFFF || val < -0x80000000) {
+ if (val > 0x7FFFFFFF || val < -(int64_t)0x80000000) {
f->store_32(VARIANT_INT64);
f->store_64(val);
@@ -1813,8 +1813,13 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
Property p;
p.name_idx = get_string_index(F->get().name);
p.value = E->get()->get(F->get().name);
- if (((F->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && p.value.is_zero()) || ((F->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && p.value.is_one()))
+
+ Variant default_value = ClassDB::class_get_default_property_value(E->get()->get_class(), F->get().name);
+
+ if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p.value, default_value))) {
continue;
+ }
+
p.pi = F->get();
rd.properties.push_back(p);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index d156a9f4bd..71b01aa94a 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -259,6 +259,10 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
}
#endif
+ if (_loaded_callback) {
+ _loaded_callback(res, p_path);
+ }
+
return res;
}
@@ -635,6 +639,12 @@ void ResourceLoader::clear_path_remaps() {
path_remaps.clear();
}
+void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) {
+ _loaded_callback = p_callback;
+}
+
+ResourceLoadedCallback ResourceLoader::_loaded_callback = NULL;
+
ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
void *ResourceLoader::err_notify_ud = NULL;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 96bc6fa8dd..7ade4a2dfc 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -78,6 +78,7 @@ typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text);
typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type);
typedef Error (*ResourceLoaderImport)(const String &p_path);
+typedef void (*ResourceLoadedCallback)(RES p_resource, const String &p_path);
class ResourceLoader {
@@ -106,6 +107,8 @@ class ResourceLoader {
//internal load function
static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error);
+ static ResourceLoadedCallback _loaded_callback;
+
public:
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
@@ -150,6 +153,7 @@ public:
static void load_translation_remaps();
static void clear_translation_remaps();
+ static void set_load_callback(ResourceLoadedCallback p_callback);
static ResourceLoaderImport import;
};
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 5c8188f735..097e81e308 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -90,7 +90,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t
rwcopy->set_path(old_path);
if (save_callback && p_path.begins_with("res://"))
- save_callback(p_path);
+ save_callback(p_resource, p_path);
return OK;
} else {
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 7ed580f2d6..6134d9db57 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -46,7 +46,7 @@ public:
virtual ~ResourceFormatSaver() {}
};
-typedef void (*ResourceSavedCallback)(const String &p_path);
+typedef void (*ResourceSavedCallback)(Ref<Resource> p_resource, const String &p_path);
class ResourceSaver {
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index a16267cf0a..0cfb54234c 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -2120,6 +2120,10 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
}
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
+ if (error_set) {
+ ERR_EXPLAIN("There was previously a parse error: " + error_str);
+ ERR_FAIL_V(Variant());
+ }
execution_error = false;
Variant output;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 9a486a49d0..65c318448c 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -305,16 +305,6 @@ public:
return b;
}
-#if defined(__GNUC__)
-
- static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
- static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename
-#else
-
- static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
- static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename
-#endif
-
static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) {
uint16_t h_exp, h_sig;
uint32_t f_sgn, f_exp, f_sig;
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 7f788c90a7..abfc73407a 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -338,6 +338,7 @@ MessageQueue::MessageQueue() {
buffer_end = 0;
buffer_max_used = 0;
buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "0,2048,1,or_greater"));
buffer_size *= 1024;
buffer = memnew_arr(uint8_t, buffer_size);
}
diff --git a/core/object.cpp b/core/object.cpp
index 946040ba34..6a6749f3b8 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -440,16 +440,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
if (r_valid)
*r_valid = true;
return;
-#ifdef TOOLS_ENABLED
- } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) {
- Array arr = p_value;
- for (int i = 0; i < arr.size(); i++) {
- editor_section_folding.insert(arr[i]);
- }
- if (r_valid)
- *r_valid = true;
- return;
-#endif
}
//something inside the object... :|
@@ -520,16 +510,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
if (r_valid)
*r_valid = true;
return ret;
-#ifdef TOOLS_ENABLED
- } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) {
- Array array;
- for (Set<String>::Element *E = editor_section_folding.front(); E; E = E->next()) {
- array.push_back(E->get());
- }
- if (r_valid)
- *r_valid = true;
- return array;
-#endif
+
} else {
//something inside the object... :|
bool success = _getv(p_name, ret);
@@ -655,15 +636,11 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
#ifdef TOOLS_ENABLED
p_list->push_back(PropertyInfo(Variant::NIL, "Script", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
#endif
- p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
-#ifdef TOOLS_ENABLED
- if (editor_section_folding.size()) {
- p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ if (!metadata.empty()) {
+ p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
-#endif
- if (!metadata.empty())
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORE_IF_NONZERO));
if (script_instance && !p_reversed) {
p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
diff --git a/core/object.h b/core/object.h
index b23160c1df..25d41140aa 100644
--- a/core/object.h
+++ b/core/object.h
@@ -103,8 +103,9 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings
PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor
PROPERTY_USAGE_CATEGORY = 256,
- PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero
- PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false
+ //those below are deprecated thanks to ClassDB's now class value cache
+ //PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero
+ //PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false
PROPERTY_USAGE_NO_INSTANCE_STATE = 2048,
PROPERTY_USAGE_RESTART_IF_CHANGED = 4096,
PROPERTY_USAGE_SCRIPT_VARIABLE = 8192,
@@ -126,10 +127,6 @@ enum PropertyUsageFlags {
#define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_PROPERTY(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter))
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index)
-#define ADD_PROPERTYNZ(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter))
-#define ADD_PROPERTYINZ(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter), m_index)
-#define ADD_PROPERTYNO(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter))
-#define ADD_PROPERTYINO(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter), m_index)
#define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
struct PropertyInfo {
@@ -723,6 +720,9 @@ public:
#ifdef TOOLS_ENABLED
void editor_set_section_unfold(const String &p_section, bool p_unfolded);
bool editor_is_section_unfolded(const String &p_section);
+ const Set<String> &editor_get_section_folding() const { return editor_section_folding; }
+ void editor_clear_section_folding() { editor_section_folding.clear(); }
+
#endif
//used by script languages to store binding data
diff --git a/core/os/input.cpp b/core/os/input.cpp
index 4cd1f0b24a..1a24258a10 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -86,7 +86,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
- ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);
+ ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press);
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
diff --git a/core/os/input.h b/core/os/input.h
index db523d6789..dc2c213db2 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -113,7 +113,7 @@ public:
virtual Vector3 get_magnetometer() const = 0;
virtual Vector3 get_gyroscope() const = 0;
- virtual void action_press(const StringName &p_action) = 0;
+ virtual void action_press(const StringName &p_action, float p_strength = 1.f) = 0;
virtual void action_release(const StringName &p_action) = 0;
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 99a23bbee1..407bb78375 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -288,9 +288,28 @@ void ProjectSettings::_convert_to_last_version() {
}
}
+/*
+ * This method is responsible for loading a project.godot file and/or data file
+ * using the following merit order:
+ * - If using NetworkClient, try to lookup project file or fail.
+ * - If --main-pack was passed by the user (`p_main_pack`), load it or fail.
+ * - Search for .pck file matching binary name. There are two possibilities:
+ * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck')
+ * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck')
+ * For each tentative, if the file exists, load it or fail.
+ * - On relevant platforms (Android/iOS), lookup project file in OS resource path.
+ * If found, load it or fail.
+ * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we
+ * are running from source code.
+ * If not found and `p_upwards` is true (--upwards passed by the user), look for
+ * project files in parent folders up to the system root (used to run a game
+ * from command line while in a subfolder).
+ * If a project file is found, load it or fail.
+ * If nothing was found, error out.
+ */
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) {
- //If looking for files in network, just use network!
+ // If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -302,9 +321,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- String exec_path = OS::get_singleton()->get_executable_path();
-
- //Attempt with a passed main pack first
+ // Attempt with a user-defined main pack first
if (p_main_pack != "") {
@@ -320,25 +337,39 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Attempt with execname.pck
+ // Attempt with exec_name.pck
+ // (This is the usual case when distributing a Godot game.)
+
+ // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
+ // or the exec path's basename + '.pck' (Windows).
+ // We need to test both possibilities as extensions for Linux binaries are optional
+ // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
+
+ String exec_path = OS::get_singleton()->get_executable_path();
+
if (exec_path != "") {
bool found = false;
- // get our filename without our path (note, using exec_path.get_file before get_basename anymore because not all file systems have dots in their file names!)
- String filebase_name = exec_path.get_file().get_basename();
+ String exec_dir = exec_path.get_base_dir();
+ String exec_filename = exec_path.get_file();
+ String exec_basename = exec_filename.get_basename();
+
+ // Try to load data pack at the location of the executable
+ // As mentioned above, we have two potential names to attempt
- // try to open at the location of executable
- String datapack_name = exec_path.get_base_dir().plus_file(filebase_name) + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ if (_load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) ||
+ _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"))) {
found = true;
} else {
- datapack_name = filebase_name + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ // If we couldn't find them next to the executable, we attempt
+ // the current working directory. Same story, two tests.
+ if (_load_resource_pack(exec_basename + ".pck") ||
+ _load_resource_pack(exec_filename + ".pck")) {
found = true;
}
}
- // if we opened our package, try and load our project...
+ // If we opened our package, try and load our project
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -350,17 +381,15 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
}
- //Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
- if (OS::get_singleton()->get_resource_dir() != "") {
- //OS will call Globals->get_resource_path which will be empty if not overridden!
- //if the OS would rather use somewhere else, then it will not be empty.
+ // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
+ if (OS::get_singleton()->get_resource_dir() != "") {
+ // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
+ // If the OS would rather use a specific location, then it will not be empty.
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
- if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
+ if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
-
- // data.pck and data.zip are deprecated and no longer supported, apologies.
- // make sure this is loaded from the resource path
+ }
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -371,21 +400,19 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Nothing was found, try to find a project.godot somewhere!
+ // Nothing was found, try to find a project file in provided path (`p_path`)
+ // or, if requested (`p_upwards`) in parent directories.
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!d, ERR_CANT_CREATE);
-
d->change_dir(p_path);
- String candidate = d->get_current_dir();
String current_dir = d->get_current_dir();
-
+ String candidate = current_dir;
bool found = false;
Error err;
while (true) {
-
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
// Optional, we don't mind if it fails
@@ -396,10 +423,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
if (p_upwards) {
- // Try to load settings ascending through dirs shape!
+ // Try to load settings ascending through parent directories
d->change_dir("..");
if (d->get_current_dir() == current_dir)
- break; //not doing anything useful
+ break; // not doing anything useful
current_dir = d->get_current_dir();
} else {
break;
@@ -416,6 +443,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
+ // If we're loading a project.godot from source code, we can operate some
+ // ProjectSettings conversions if need be.
_convert_to_last_version();
return OK;
@@ -1133,6 +1162,7 @@ ProjectSettings::ProjectSettings() {
custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
+ custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
//assigning here, because using GLOBAL_GET on every block for compressing can be slow
Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index b0023b4c26..430004bb96 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -199,6 +199,7 @@ void register_core_types() {
void register_core_settings() {
//since in register core types, globals may not e present
GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/packet_peer_stream/max_buffer_po2", PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater"));
}
void register_core_singletons() {
diff --git a/core/resource.cpp b/core/resource.cpp
index 4dcd338e94..a76e16232e 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -379,9 +379,9 @@ void Resource::_bind_methods() {
ClassDB::bind_method(D_METHOD("duplicate", "subresources"), &Resource::duplicate, DEFVAL(false));
ADD_SIGNAL(MethodInfo("changed"));
ADD_GROUP("Resource", "resource_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name");
BIND_VMETHOD(MethodInfo("_setup_local_to_scene"));
}
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 3e984fae32..621a94ab1a 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -1100,7 +1100,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
eh.userdata = this;
add_error_handler(&eh);
- profile_info.resize(CLAMP(int(ProjectSettings::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535));
+ profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions"));
profile_info_ptrs.resize(profile_info.size());
}
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 5b65da9ef1..496521486e 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -563,7 +563,8 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam
PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
owner(p_owner),
language(p_language),
- script(p_script) {
+ script(p_script),
+ build_failed(false) {
}
PlaceHolderScriptInstance::~PlaceHolderScriptInstance() {
diff --git a/core/set.h b/core/set.h
index 744019d5b4..59aa54128e 100644
--- a/core/set.h
+++ b/core/set.h
@@ -595,6 +595,7 @@ public:
return e;
}
+ inline bool empty() const { return _data.size_cache == 0; }
inline int size() const { return _data.size_cache; }
int calculate_depth() const {
diff --git a/core/ustring.cpp b/core/ustring.cpp
index b55607946d..3f017fa985 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -49,7 +49,7 @@
#endif
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
-#define snprintf _snprintf
+#define snprintf _snprintf_s
#endif
#define MAX_DIGITS 6
@@ -2774,16 +2774,13 @@ String String::format(const Variant &values, String placeholder) const {
if (value_arr.size() == 2) {
Variant v_key = value_arr[0];
- String key;
-
- key = v_key.get_construct_string();
+ String key = v_key;
if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") {
key = key.substr(1, key.length() - 2);
}
Variant v_val = value_arr[1];
- String val;
- val = v_val.get_construct_string();
+ String val = v_val;
if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") {
val = val.substr(1, val.length() - 2);
@@ -2795,8 +2792,7 @@ String String::format(const Variant &values, String placeholder) const {
}
} else { //Array structure ["RobotGuy","Logis","rookie"]
Variant v_val = values_arr[i];
- String val;
- val = v_val.get_construct_string();
+ String val = v_val;
if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") {
val = val.substr(1, val.length() - 2);
@@ -2815,8 +2811,8 @@ String String::format(const Variant &values, String placeholder) const {
d.get_key_list(&keys);
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- String key = E->get().get_construct_string();
- String val = d[E->get()].get_construct_string();
+ String key = E->get();
+ String val = d[E->get()];
if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") {
key = key.substr(1, key.length() - 2);
@@ -4039,7 +4035,7 @@ String String::sprintf(const Array &values, bool *error) const {
str = str.pad_decimals(min_decimals);
// Show sign
- if (show_sign && value >= 0) {
+ if (show_sign && str.left(1) != "-") {
str = str.insert(0, "+");
}
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 493f55e89b..20ec9141c6 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -745,6 +745,22 @@
[/codeblock]
</description>
</method>
+ <method name="push_error">
+ <return type="void">
+ </return>
+ <argument index="0" name="message" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="push_warning">
+ <return type="void">
+ </return>
+ <argument index="0" name="message" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="rad2deg">
<return type="float">
</return>
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 65d339c0d5..e05af0f1ac 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1298,10 +1298,6 @@
</constant>
<constant name="PROPERTY_USAGE_CATEGORY" value="256" enum="PropertyUsageFlags">
</constant>
- <constant name="PROPERTY_USAGE_STORE_IF_NONZERO" value="512" enum="PropertyUsageFlags">
- </constant>
- <constant name="PROPERTY_USAGE_STORE_IF_NONONE" value="1024" enum="PropertyUsageFlags">
- </constant>
<constant name="PROPERTY_USAGE_NO_INSTANCE_STATE" value="2048" enum="PropertyUsageFlags">
</constant>
<constant name="PROPERTY_USAGE_RESTART_IF_CHANGED" value="4096" enum="PropertyUsageFlags">
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index b9061e0b87..2e0d0c15b2 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -7,7 +7,7 @@
AABB consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index bb161cd87c..f189e6451d 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -17,7 +17,7 @@
Animations are just data containers, and must be added to nodes such as an [AnimationPlayer] or [AnimationTreePlayer] to be played back.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/animation/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml
index 22f5e0838e..de8e918f68 100644
--- a/doc/classes/AnimationNodeAnimation.xml
+++ b/doc/classes/AnimationNodeAnimation.xml
@@ -9,12 +9,6 @@
<demos>
</demos>
<methods>
- <method name="get_playback_time" qualifiers="const">
- <return type="float">
- </return>
- <description>
- </description>
- </method>
</methods>
<members>
<member name="animation" type="String" setter="set_animation" getter="get_animation">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 6dc91a234a..3b3638a4f3 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -7,8 +7,8 @@
An animation player is used for general purpose playback of [Animation] resources. It contains a dictionary of animations (referenced by name) and custom blend times between their transitions. Additionally, animations can be played and blended in different channels.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/animations.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/animation/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/animations.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
</tutorials>
<demos>
</demos>
@@ -238,7 +238,7 @@
The default time in which to blend animations. Ranges from 0 to 4096 with 0.01 precision. Default value: [code]0[/code].
</member>
<member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationPlayer.AnimationProcessMode">
- The process notification in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE].
+ The process notification in which to update animations. Default value: [code]ANIMATION_PROCESS_IDLE[/code].
</member>
<member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale">
The speed scaling ratio. For instance, if this value is 1 then the animation plays at normal speed. If it's 0.5 then it plays at half speed. If it's 2 then it plays at double speed. Default value: [code]1[/code].
diff --git a/doc/classes/AnimationTreePlayer.xml b/doc/classes/AnimationTreePlayer.xml
index 8c32d5f6a3..a081c64f6d 100644
--- a/doc/classes/AnimationTreePlayer.xml
+++ b/doc/classes/AnimationTreePlayer.xml
@@ -618,7 +618,7 @@
Once set, Animation nodes can be added to the AnimationTreePlayer.
</member>
<member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationTreePlayer.AnimationProcessMode">
- The thread in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE].
+ The thread in which to update animations. Default value: [code]ANIMATION_PROCESS_IDLE[/code].
</member>
</members>
<constants>
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 37756bcfd8..3ae5454e65 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -7,7 +7,7 @@
AudioServer is a low level server interface for audio access. It is in charge of creating sample data (playable audio) as well as its playback via a voice interface.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/audio/audio_buses.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html</link>
</tutorials>
<demos>
</demos>
@@ -385,6 +385,8 @@
<constant name="SPEAKER_MODE_STEREO" value="0" enum="SpeakerMode">
Two or fewer speakers are detected.
</constant>
+ <constant name="SPEAKER_SURROUND_31" value="1" enum="SpeakerMode">
+ </constant>
<constant name="SPEAKER_SURROUND_51" value="2" enum="SpeakerMode">
A 5.1 channel surround setup detected.
</constant>
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml
index 753a506058..96ce53b14f 100644
--- a/doc/classes/AudioStream.xml
+++ b/doc/classes/AudioStream.xml
@@ -7,7 +7,7 @@
Base class for audio streams. Audio streams are used for music playback, or other types of streamed sounds that don't fit or require more flexibility than a [Sample].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/audio/audio_streams.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index 26d0b1a83d..be4e4f137a 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -7,8 +7,8 @@
Plays background audio.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/audio/audio_streams.html</link>
+ <link>https://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index 5cc87e0e7a..3b81894c14 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -7,8 +7,8 @@
Plays audio that dampens with distance from screen center.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/audio/audio_streams.html</link>
+ <link>https://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index e61515ffc0..5841f1f6dc 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -7,8 +7,8 @@
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/audio/audio_streams.html</link>
+ <link>https://docs.godotengine.org/en/latest/learning/features/audio/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml
index 966b6dd7c4..8e27dc8d5d 100644
--- a/doc/classes/BakedLightmap.xml
+++ b/doc/classes/BakedLightmap.xml
@@ -7,7 +7,7 @@
Baked lightmaps are an alternative workflow for adding indirect (or baked) lighting to a scene. Unlike the [GIProbe] approach, baked lightmaps work fine on low-end PCs and mobile devices as they consume almost no resources in run-time.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/baked_lightmaps.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/baked_lightmaps.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index fe8debe1a9..95f6346321 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -8,8 +8,8 @@
For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S).
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
- <link>http://docs.godotengine.org/en/latest/tutorials/math/rotations.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/rotations.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/CPUParticles.xml b/doc/classes/CPUParticles.xml
index 9d3dc5d70a..c778cd56b3 100644
--- a/doc/classes/CPUParticles.xml
+++ b/doc/classes/CPUParticles.xml
@@ -39,8 +39,6 @@
</member>
<member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness">
</member>
- <member name="anim_loop" type="bool" setter="set_particle_flag" getter="get_particle_flag">
- </member>
<member name="anim_offset" type="float" setter="set_param" getter="get_param">
</member>
<member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
@@ -181,7 +179,7 @@
</constant>
<constant name="FLAG_ROTATE_Y" value="1" enum="Flags">
</constant>
- <constant name="FLAG_MAX" value="4" enum="Flags">
+ <constant name="FLAG_MAX" value="3" enum="Flags">
</constant>
<constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
</constant>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 6d115e2650..bae725d47c 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -39,8 +39,6 @@
</member>
<member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness">
</member>
- <member name="anim_loop" type="bool" setter="set_particle_flag" getter="get_particle_flag">
- </member>
<member name="anim_offset" type="float" setter="set_param" getter="get_param">
</member>
<member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
@@ -177,7 +175,7 @@
</constant>
<constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags">
</constant>
- <constant name="FLAG_MAX" value="2" enum="Flags">
+ <constant name="FLAG_MAX" value="1" enum="Flags">
</constant>
<constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
</constant>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 60f097f3f9..4bae656740 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -11,8 +11,8 @@
Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/2d_transforms.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml
index fe7194dcfe..69d873f446 100644
--- a/doc/classes/CanvasItemMaterial.xml
+++ b/doc/classes/CanvasItemMaterial.xml
@@ -19,6 +19,14 @@
<member name="light_mode" type="int" setter="set_light_mode" getter="get_light_mode" enum="CanvasItemMaterial.LightMode">
The manner in which material reacts to lighting.
</member>
+ <member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
+ </member>
+ <member name="particles_anim_loop" type="bool" setter="set_particles_anim_loop" getter="get_particles_anim_loop">
+ </member>
+ <member name="particles_anim_v_frames" type="int" setter="set_particles_anim_v_frames" getter="get_particles_anim_v_frames">
+ </member>
+ <member name="particles_animation" type="bool" setter="set_particles_animation" getter="get_particles_animation">
+ </member>
</members>
<constants>
<constant name="BLEND_MODE_MIX" value="0" enum="BlendMode">
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index d4412e15c9..c39b47ab07 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -7,8 +7,8 @@
Canvas drawing layer. [CanvasItem] nodes that are direct or indirect children of a [code]CanvasLayer[/code] will be drawn in that layer. The layer is a numeric index that defines the draw order. The default 2D scene renders with index 0, so a [code]CanvasLayer[/code] with index -1 will be drawn below, and one with index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or above), or backgrounds (in layer -1 or below).
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/2d_transforms.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/canvas_layers.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/canvas_layers.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/CollisionShape.xml b/doc/classes/CollisionShape.xml
index 5639c14192..740a6b7ab1 100644
--- a/doc/classes/CollisionShape.xml
+++ b/doc/classes/CollisionShape.xml
@@ -7,7 +7,7 @@
Editor facility for creating and editing collision shapes in 3D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area] to give it a detection shape, or add it to a [PhysicsBody] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject.shape_owner_get_shape] to get the actual shape.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index 713cb8d098..d3c616ee3d 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -7,7 +7,7 @@
Editor facility for creating and editing collision shapes in 2D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area2D] to give it a detection shape, or add it to a [PhysicsBody2D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject2D.shape_owner_get_shape] to get the actual shape.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index ee82afd592..76a475e49d 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -13,8 +13,8 @@
[Theme] resources change the Control's appearance. If you change the [Theme] on a [code]Control[/code] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_*_override[/code] methods, like [method add_font_override]. You can override the theme with the inspector.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/gui/index.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/gui/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml
index 2dc522083d..86c8f2f03a 100644
--- a/doc/classes/DirectionalLight.xml
+++ b/doc/classes/DirectionalLight.xml
@@ -7,7 +7,7 @@
A directional light is a type of [Light] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight transform (origin) is ignored. Only the basis is used do determine light direction.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index d8ad208fa7..57301f954f 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -23,7 +23,7 @@
[/codeblock]
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/filesystem.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index aaba30ccc9..24201c39b9 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -49,7 +49,7 @@
[/codeblock]
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/plugins/editor/import_plugins.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index a2a39fc8b6..5601f9b5ae 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -41,6 +41,14 @@
<description>
</description>
</signal>
+ <signal name="property_toggled">
+ <argument index="0" name="property" type="String">
+ </argument>
+ <argument index="1" name="checked" type="bool">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="resource_selected">
<argument index="0" name="res" type="Object">
</argument>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index ac139f18c9..feaa24b0ab 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -7,7 +7,7 @@
Plugins are used by the editor to extend functionality. The most common types of plugins are those which edit a given node or resource type, import plugins and export plugins. Also see [EditorScript] to add functions to the editor.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/development/plugins/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/development/plugins/index.html</link>
</tutorials>
<demos>
</demos>
@@ -453,7 +453,7 @@
<argument index="0" name="screen_name" type="String">
</argument>
<description>
- Emitted when user change the workspace (2D, 3D, Script, AssetLib). Also works with custom screens defined by plugins.
+ Emitted when user changes the workspace (2D, 3D, Script, AssetLib). Also works with custom screens defined by plugins.
</description>
</signal>
<signal name="resource_saved">
@@ -466,14 +466,14 @@
<argument index="0" name="scene_root" type="Node">
</argument>
<description>
- Emitted when user change scene. The argument is a root node of freshly opened scene.
+ Emitted when the scene is changed in the editor. The argument will return the root node of the scene that has just become active. If this scene is new and empty, the argument will be null.
</description>
</signal>
<signal name="scene_closed">
<argument index="0" name="filepath" type="String">
</argument>
<description>
- Emitted when user close scene. The argument is file path to a closed scene.
+ Emitted when user closes a scene. The argument is file path to a closed scene.
</description>
</signal>
</signals>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 76c105dd25..0c5de68d98 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -26,7 +26,7 @@
[/codeblock]
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 566322e6c5..4c2c83e55f 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -13,8 +13,8 @@
- Adjustments
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/environment_and_post_processing.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/high_dynamic_range.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/high_dynamic_range.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index d5b831a61a..c5f71fe55e 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -1,8 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Expression" inherits="Reference" category="Core" version="3.1">
<brief_description>
+ A class that stores an expression you can execute.
</brief_description>
<description>
+ An expression can be made of any arithmetic operation, built-in math function call, method call of a passed instance, or built-in type construction call.
+ An example expression text using the built-in math functions could be [code]sqrt(pow(3,2) + pow(4,2))[/code].
+ In the following example we use a [LineEdit] node to write our expression and show the result.
+ [codeblock]
+ onready var expression = Expression.new()
+
+ func _ready():
+ $LineEdit.connect("text_entered", self, "_on_text_entered")
+
+ func _on_text_entered(command):
+ var error = expression.parse(command, [])
+ if error != OK:
+ print(get_error_text())
+ return
+ var result = expression.execute([], null, true)
+ if not expression.has_execute_failed():
+ $LineEdit.text = str(result)
+ [/codeblock]
</description>
<tutorials>
</tutorials>
@@ -19,18 +38,21 @@
<argument index="2" name="show_error" type="bool" default="true">
</argument>
<description>
+ Executes the expression that was previously parsed by [method parse] and returns the result. Before you use the returned object, you should check if the method failed by calling [method has_execute_failed].
</description>
</method>
<method name="get_error_text" qualifiers="const">
<return type="String">
</return>
<description>
+ Returns the error text if [method parse] has failed.
</description>
</method>
<method name="has_execute_failed" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if [method execute] has failed.
</description>
</method>
<method name="parse">
@@ -41,6 +63,7 @@
<argument index="1" name="input_names" type="PoolStringArray" default="PoolStringArray( )">
</argument>
<description>
+ Parses the expression and returns a [enum @GlobalScope.Error].
</description>
</method>
</methods>
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index 20054ac9dc..6c900385f7 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -22,7 +22,7 @@
[/codeblock]
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/filesystem.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/GIProbe.xml b/doc/classes/GIProbe.xml
index 77dea73564..5fb0ccc33d 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/GIProbe.xml
@@ -5,7 +5,7 @@
<description>
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/gi_probes.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Gradient.xml b/doc/classes/Gradient.xml
index df4a507b65..bf3f125e48 100644
--- a/doc/classes/Gradient.xml
+++ b/doc/classes/Gradient.xml
@@ -4,7 +4,7 @@
Color interpolator node.
</brief_description>
<description>
- Given a set of colors, this node will interpolate them in order, meaning, that if you have color 1, color 2 and color3, the ramp will interpolate (generate the colors between two colors) from color 1 to color 2 and from color 2 to color 3. Initially the ramp will have 2 colors (black and white), one (black) at ramp lower offset offset 0 and the other (white) at the ramp higher offset 1.
+ Given a set of colors, this node will interpolate them in order, meaning, that if you have color 1, color 2 and color 3, the ramp will interpolate (generate the colors between two colors) from color 1 to color 2 and from color 2 to color 3. Initially the ramp will have 2 colors (black and white), one (black) at ramp lower offset 0 and the other (white) at the ramp higher offset 1.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml
index 8a8a9a2d24..346ab9d357 100644
--- a/doc/classes/GridContainer.xml
+++ b/doc/classes/GridContainer.xml
@@ -11,16 +11,6 @@
<demos>
</demos>
<methods>
- <method name="get_child_control_at_cell">
- <return type="Control">
- </return>
- <argument index="0" name="row" type="int">
- </argument>
- <argument index="1" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
</methods>
<members>
<member name="columns" type="int" setter="set_columns" getter="get_columns">
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 08e2f649a0..2f21505757 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -10,8 +10,8 @@
For more information on HTTP, see https://developer.mozilla.org/en-US/docs/Web/HTTP (or read RFC 2616 to get it straight from the source: https://tools.ietf.org/html/rfc2616).
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/http_client_class.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/ssl_certificates.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/http_client_class.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index c5bb10a23a..3916eb2b5b 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -8,7 +8,7 @@
Can be used to make HTTP requests, i.e. download or upload files or web content via HTTP.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/ssl_certificates.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 10ec15b99d..25a2f45773 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -7,7 +7,7 @@
A Singleton that deals with inputs. This includes key presses, mouse buttons and movement, joypads, and input actions. Actions and their events can be set in the Project Settings / Input Map tab. Or be set with [InputMap].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/index.html</link>
</tutorials>
<demos>
</demos>
@@ -17,8 +17,10 @@
</return>
<argument index="0" name="action" type="String">
</argument>
+ <argument index="1" name="strength" type="float" default="1.0f">
+ </argument>
<description>
- This will simulate pressing the specified action.
+ This will simulate pressing the specified action. The strength can be used for non-boolean actions.
</description>
</method>
<method name="action_release">
@@ -123,7 +125,7 @@
<argument index="0" name="button_index" type="int">
</argument>
<description>
- Receives a [code]JOY_BUTTON_*[/code] Enum and returns it's equivalent name as a string.
+ Receives a [code]JOY_BUTTON_*[/code] Enum and returns its equivalent name as a string.
</description>
</method>
<method name="get_joy_guid" qualifiers="const">
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index 993d62d188..c880823aee 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -7,8 +7,8 @@
Base class of all sort of input event. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/2d_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 16000231cb..8a10dc6ab9 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -7,7 +7,7 @@
Contains a generic action which can be targeted from several type of inputs. Actions can be created from the project settings menu [code]Project &gt; Project Settings &gt; Input Map[/code]. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html#actions</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#actions</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml
index adaeae685e..18e33c2131 100644
--- a/doc/classes/InputEventJoypadButton.xml
+++ b/doc/classes/InputEventJoypadButton.xml
@@ -7,7 +7,7 @@
Input event type for gamepad buttons. For joysticks see [InputEventJoypadMotion].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml
index f86aec4ce0..0c73f53158 100644
--- a/doc/classes/InputEventJoypadMotion.xml
+++ b/doc/classes/InputEventJoypadMotion.xml
@@ -7,7 +7,7 @@
Stores information about joystick motions. One [code]InputEventJoypadMotion[/code] represents one axis at a time.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index a013ee6266..0118fda2df 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -7,7 +7,7 @@
Stores key presses on the keyboard. Supports key presses, key releases and [member echo] events.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index 06de96890a..27e8d17407 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -7,7 +7,7 @@
Stores general mouse events information.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index a3a9055087..1342c7bf7e 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -7,7 +7,7 @@
Contains mouse click information. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/mouse_and_input_coordinates.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml
index 05e3e79d26..f7f6358910 100644
--- a/doc/classes/InputEventMouseMotion.xml
+++ b/doc/classes/InputEventMouseMotion.xml
@@ -7,7 +7,7 @@
Contains mouse motion information. Supports relative, absolute positions and speed. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/mouse_and_input_coordinates.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml
index f777d90ccb..a320c0a028 100644
--- a/doc/classes/InputEventScreenDrag.xml
+++ b/doc/classes/InputEventScreenDrag.xml
@@ -8,7 +8,7 @@
Contains screen drag information. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index 39cd0a9657..55f04cdd94 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -8,7 +8,7 @@
Stores multi-touch press/release information. Supports touch press, touch release and [member index] for multi-touch count and order.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index 9c1814fedd..fcf2fd545e 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -7,7 +7,7 @@
Contains keys events information with modifiers support like [code]SHIFT[/code] or [code]ALT[/code]. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index 7fd1d7e8ac..8c25f851db 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -7,7 +7,7 @@
Manages all [InputEventAction] which can be created/modified from the project settings menu [code]Project &gt; Project Settings &gt; Input Map[/code] or in code with [method add_action] and [method action_add_event]. See [method Node._input].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/inputs/inputevent.html#inputmap</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#inputmap</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index 4e4947de6c..0b8ede92d5 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -166,6 +166,14 @@
Returns whether or not the item at the specified index is disabled
</description>
</method>
+ <method name="is_item_icon_transposed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="is_item_selectable" qualifiers="const">
<return type="bool">
</return>
@@ -289,6 +297,16 @@
<description>
</description>
</method>
+ <method name="set_item_icon_transposed">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="rect" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_item_metadata">
<return type="void">
</return>
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScript.xml
index 17588717c2..fa3aaed684 100644
--- a/doc/classes/JavaScript.xml
+++ b/doc/classes/JavaScript.xml
@@ -7,7 +7,7 @@
The JavaScript singleton is implemented only in HTML5 export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml
index d5d8ebe712..df8fb251ba 100644
--- a/doc/classes/KinematicBody.xml
+++ b/doc/classes/KinematicBody.xml
@@ -9,7 +9,7 @@
Kinematic Characters: KinematicBody also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/kinematic_character_2d.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index db775042cf..8a644447ca 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -116,7 +116,7 @@
</argument>
<description>
Moves the body while keeping it attached to slopes. Similar to [method move_and_slide].
- As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting[code]snap[/code] to[code](0, 0)[/code] or by using [method move_and_slide] instead.
+ As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0)[/code] or by using [method move_and_slide] instead.
</description>
</method>
<method name="test_move">
diff --git a/doc/classes/Light.xml b/doc/classes/Light.xml
index 04191136a8..cf873e5b28 100644
--- a/doc/classes/Light.xml
+++ b/doc/classes/Light.xml
@@ -7,7 +7,7 @@
Light is the abstract base class for light nodes, so it shouldn't be used directly (It can't be instanced). Other types of light nodes inherit from it. Light contains the common variables and parameters used for lighting.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml
index 5c3af3e2e1..c90dba1561 100644
--- a/doc/classes/MeshDataTool.xml
+++ b/doc/classes/MeshDataTool.xml
@@ -104,7 +104,7 @@
</argument>
<description>
Returns specified edge associated with given face.
- Edge argument must 2 or less becuase a face only has three edges.
+ Edge argument must 2 or less because a face only has three edges.
</description>
</method>
<method name="get_face_meta" qualifiers="const">
@@ -134,14 +134,14 @@
</argument>
<description>
Returns specified vertex of given face.
- Vertex argument must be 2 or less becuase faces contain three vertices.
+ Vertex argument must be 2 or less because faces contain three vertices.
</description>
</method>
<method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
- Returns format of [Mesh]. Format is an integer made up of [Mesh] format flags combined together. For example, a mesh containing both vertices and normals would return a format of [code]3[/code] becuase [code]ARRAY_FORMAT_VERTEX[/code] is [code]1[/code] and [code]ARRAY_FORMAT_NORMAL[/code] is [code]2[/code].
+ Returns format of [Mesh]. Format is an integer made up of [Mesh] format flags combined together. For example, a mesh containing both vertices and normals would return a format of [code]3[/code] because [code]ARRAY_FORMAT_VERTEX[/code] is [code]1[/code] and [code]ARRAY_FORMAT_NORMAL[/code] is [code]2[/code].
For list of format flags see [ArrayMesh].
</description>
</method>
diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml
index ef42726ca9..bcc9a7cad9 100644
--- a/doc/classes/MeshInstance.xml
+++ b/doc/classes/MeshInstance.xml
@@ -41,6 +41,12 @@
Returns the [Material] for a surface of the [Mesh] resource.
</description>
</method>
+ <method name="get_surface_material_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="set_surface_material">
<return type="void">
</return>
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index b29e19e5d8..4ede80b98c 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -1,8 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationPolygon" inherits="Resource" category="Core" version="3.1">
<brief_description>
+ A node that has methods to draw outlines or use indices of vertices to create navigation polygons.
</brief_description>
<description>
+ There are two ways to create polygons. Either by using the [method add_outline] method or using the [method add_polygon] method.
+ Using [method add_outline]:
+ [code]
+ var polygon = NavigationPolygon.new()
+ var outline = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ polygon.add_outline(outline)
+ polygon.make_polygons_from_outlines()
+ $NavigationPolygonInstance.navpoly = polygon
+ [/code]
+ Using [method add_polygon] and indices of the vertices array.
+ [code]
+ var polygon = NavigationPolygon.new()
+ var vertices = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ polygon.set_vertices(vertices)
+ var indices = PoolIntArray(0, 3, 1)
+ polygon.add_polygon(indices)
+ $NavigationPolygonInstance.navpoly = polygon
+ [/code]
</description>
<tutorials>
</tutorials>
@@ -15,6 +34,7 @@
<argument index="0" name="outline" type="PoolVector2Array">
</argument>
<description>
+ Appends a [PoolVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_outline_at_index">
@@ -25,6 +45,7 @@
<argument index="1" name="index" type="int">
</argument>
<description>
+ Adds a [PoolVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_polygon">
@@ -33,18 +54,21 @@
<argument index="0" name="polygon" type="PoolIntArray">
</argument>
<description>
+ Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
</method>
<method name="clear_outlines">
<return type="void">
</return>
<description>
+ Clears the array of the outlines, but it doesn't clear the vertices and the polygons that were created by them.
</description>
</method>
<method name="clear_polygons">
<return type="void">
</return>
<description>
+ Clears the array of polygons, but it doesn't clear the array of outlines and vertices.
</description>
</method>
<method name="get_outline" qualifiers="const">
@@ -53,12 +77,14 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns a [PoolVector2Array] containing the vertices of an outline that was created in the editor or by script.
</description>
</method>
<method name="get_outline_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of outlines that were created in the editor or by script.
</description>
</method>
<method name="get_polygon">
@@ -67,24 +93,28 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns a [PoolIntArray] containing the indices of the vertices of a created polygon.
</description>
</method>
<method name="get_polygon_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the count of all polygons.
</description>
</method>
<method name="get_vertices" qualifiers="const">
<return type="PoolVector2Array">
</return>
<description>
+ Returns a [PoolVector2Array] containing all the vertices being used to create the polygons.
</description>
</method>
<method name="make_polygons_from_outlines">
<return type="void">
</return>
<description>
+ Creates polygons from the outlines added in the editor or by script.
</description>
</method>
<method name="remove_outline">
@@ -93,6 +123,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Removes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_outline">
@@ -103,6 +134,7 @@
<argument index="1" name="outline" type="PoolVector2Array">
</argument>
<description>
+ Changes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_vertices">
@@ -111,6 +143,7 @@
<argument index="0" name="vertices" type="PoolVector2Array">
</argument>
<description>
+ Sets the vertices that can be then indexed to create polygons with the [method add_polygon] method.
</description>
</method>
</methods>
diff --git a/doc/classes/NetworkedMultiplayerPeer.xml b/doc/classes/NetworkedMultiplayerPeer.xml
index ea6fe6d11c..990f928b25 100644
--- a/doc/classes/NetworkedMultiplayerPeer.xml
+++ b/doc/classes/NetworkedMultiplayerPeer.xml
@@ -7,7 +7,7 @@
Manages the connection to network peers. Assigns unique IDs to each client connected to the server.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/high_level_multiplayer.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
</tutorials>
<demos>
</demos>
@@ -92,7 +92,7 @@
</signals>
<constants>
<constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode">
- Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [code]TRANSFER_MODE_UNRELIABLE_ORDERED[/code]. Use for non-critical data, and always consider whether the order matters.
+ Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [code]TRANSFER_MODE_UNRELIABLE_ORDERED[/code]. Use for non-critical data, and always consider whether the order matters.
</constant>
<constant name="TRANSFER_MODE_UNRELIABLE_ORDERED" value="1" enum="TransferMode">
Packets are not acknowledged, no resend attempts are made for lost packets. Packets are received in the order they were sent in. Potentially faster than [code]TRANSFER_MODE_RELIABLE[/code]. Use for non-critical data or data that would be outdated if received late due to resend attempt(s) anyway, for example movement and positional data.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index a33ee5c363..dcdb6d0500 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -17,7 +17,7 @@
[b]Networking with nodes:[/b] After connecting to a server (or making one, see [NetworkedMultiplayerENet]) it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call Godot will use its [NodePath] (make sure node names are the same on all peers). Also take a look at the high-level networking tutorial and corresponding demos.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/scenes_and_nodes.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scenes_and_nodes.html</link>
</tutorials>
<demos>
</demos>
@@ -179,6 +179,15 @@
If [code]owned[/code] is [code]true[/code], this method only finds nodes whose owner is this node. This is especially important for scenes instantiated through script, because those scenes don't have an owner.
</description>
</method>
+ <method name="find_parent" qualifiers="const">
+ <return type="Node">
+ </return>
+ <argument index="0" name="mask" type="String">
+ </argument>
+ <description>
+ Finds the first parent of the current node whose name matches [code]mask[/code] as in [method String.match] (i.e. case sensitive, but '*' matches zero or more characters and '?' matches any single character except '.'). Note that it does not match against the full path, just against individual node names.
+ </description>
+ </method>
<method name="get_child" qualifiers="const">
<return type="Node">
</return>
@@ -267,15 +276,6 @@
Returns the parent node of the current node, or an empty [code]Node[/code] if the node lacks a parent.
</description>
</method>
- <method name="find_parent" qualifiers="const">
- <return type="Node">
- </return>
- <argument index="0" name="mask" type="String">
- </argument>
- <description>
- Finds the first parent of the current node whose name matches [code]mask[/code] as in [method String.match] (i.e. case sensitive, but '*' matches zero or more characters and '?' matches any single character except '.'). Note that it does not match against the full path, just against individual node names.
- </description>
- </method>
<method name="get_path" qualifiers="const">
<return type="NodePath">
</return>
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index 13eabeca17..e955f6bb7d 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -7,7 +7,7 @@
A 2D game object, with a position, rotation and scale. All 2D physics nodes and sprites inherit from Node2D. Use Node2D as a parent node to move, scale and rotate children in a 2D project. Also gives control on the node's render order.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 26684836ea..e218949757 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -556,6 +556,13 @@
Note that this method can also be used to kill processes that were not spawned by the game.
</description>
</method>
+ <method name="move_window_to_foreground">
+ <return type="void">
+ </return>
+ <description>
+ Moves the window to the front.
+ </description>
+ </method>
<method name="native_video_is_playing">
<return type="bool">
</return>
diff --git a/doc/classes/OmniLight.xml b/doc/classes/OmniLight.xml
index 5ed058bb06..8d67cb626b 100644
--- a/doc/classes/OmniLight.xml
+++ b/doc/classes/OmniLight.xml
@@ -7,7 +7,7 @@
An Omnidirectional light is a type of [Light] that emits light in all directions. The light is attenuated by distance and this attenuation can be configured by changing its energy, radius, and attenuation parameters.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 08df3f0ad6..7dea004b90 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -6,10 +6,23 @@
<description>
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]). Note that the node doesn't need to own itself.
- Example of saving a node:
+ Example of saving a node with different owners: The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
[codeblock]
+ # create the objects
+ var node = Node2D.new()
+ var rigid = RigidBody2D.new()
+ var collision = CollisionShape2D.new()
+
+ # create the object hierarchy
+ rigid.add_child(collision)
+ node.add_child(rigid)
+
+ # change owner of rigid, but not of collision
+ rigid.set_owner(node)
+
var scene = PackedScene.new()
- var result = scene.pack(child)
+ # only node and rigid are now packed
+ var result = scene.pack(node)
if result == OK:
ResourceSaver.save("res://path/name.scn", scene) # or user://...
[/codeblock]
@@ -39,7 +52,7 @@
<argument index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0">
</argument>
<description>
- Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers the [enum Node.NOTIFICATION_INSTANCED] notification on the root node.
+ Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers [Node]'s [code]NOTIFICATION_INSTANCED[/code] notification on the root node.
</description>
</method>
<method name="pack">
diff --git a/doc/classes/Particles2D.xml b/doc/classes/Particles2D.xml
index f872552a49..6416e409a3 100644
--- a/doc/classes/Particles2D.xml
+++ b/doc/classes/Particles2D.xml
@@ -42,9 +42,6 @@
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta">
</member>
- <member name="h_frames" type="int" setter="set_h_frames" getter="get_h_frames">
- Number of horizontal frames in [code]texture[/code].
- </member>
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime">
Amount of time each particle will exist. Default value: [code]1[/code].
</member>
@@ -71,9 +68,6 @@
<member name="texture" type="Texture" setter="set_texture" getter="get_texture">
Particle texture. If [code]null[/code] particles will be squares.
</member>
- <member name="v_frames" type="int" setter="set_v_frames" getter="get_v_frames">
- Number of vertical frames in [code]texture[/code].
- </member>
<member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect">
Editor visibility helper.
</member>
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index 354b98485e..2904d4c578 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -32,9 +32,6 @@
<member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness">
Angular velocity randomness ratio. Default value: [code]0[/code].
</member>
- <member name="anim_loop" type="bool" setter="set_flag" getter="get_flag">
- If [code]true[/code] animation will loop. Default value: [code]false[/code].
- </member>
<member name="anim_offset" type="float" setter="set_param" getter="get_param">
Particle animation offset.
</member>
@@ -216,7 +213,7 @@
<constant name="FLAG_ROTATE_Y" value="1" enum="Flags">
Use with [method set_flag] to set [member flag_rotate_y]
</constant>
- <constant name="FLAG_MAX" value="4" enum="Flags">
+ <constant name="FLAG_MAX" value="3" enum="Flags">
</constant>
<constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
All particles will be emitted from a single point.
diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml
index f9940dab2f..515c921d0d 100644
--- a/doc/classes/PathFollow2D.xml
+++ b/doc/classes/PathFollow2D.xml
@@ -23,6 +23,7 @@
The node's offset along the curve.
</member>
<member name="lookahead" type="float" setter="set_lookahead" getter="get_lookahead">
+ How far to look ahead of the curve to calculate the tangent if the node is rotating. E.g. shorter lookaheads will lead to faster rotations. Default value: [code]4[/code].
</member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop">
If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
diff --git a/doc/classes/Physics2DDirectSpaceState.xml b/doc/classes/Physics2DDirectSpaceState.xml
index aa54d9a11a..81db70f435 100644
--- a/doc/classes/Physics2DDirectSpaceState.xml
+++ b/doc/classes/Physics2DDirectSpaceState.xml
@@ -7,7 +7,7 @@
Direct access object to a space in the [Physics2DServer]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/ray-casting.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<demos>
</demos>
@@ -75,6 +75,26 @@
Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody]s or [Area]s, respectively.
</description>
</method>
+ <method name="intersect_point_on_canvas">
+ <return type="Array">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <argument index="1" name="canvas_instance_id" type="int">
+ </argument>
+ <argument index="2" name="max_results" type="int" default="32">
+ </argument>
+ <argument index="3" name="exclude" type="Array" default="[ ]">
+ </argument>
+ <argument index="4" name="collision_layer" type="int" default="2147483647">
+ </argument>
+ <argument index="5" name="collide_with_bodies" type="bool" default="true">
+ </argument>
+ <argument index="6" name="collide_with_areas" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="intersect_ray">
<return type="Dictionary">
</return>
diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml
index a473de4ce8..84e15d3b26 100644
--- a/doc/classes/Physics2DServer.xml
+++ b/doc/classes/Physics2DServer.xml
@@ -24,6 +24,16 @@
Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
</description>
</method>
+ <method name="area_attach_canvas_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="area_attach_object_instance_id">
<return type="void">
</return>
@@ -51,6 +61,14 @@
Creates an [Area2D].
</description>
</method>
+ <method name="area_get_canvas_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int">
</return>
@@ -377,6 +395,16 @@
<description>
</description>
</method>
+ <method name="body_attach_canvas_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="body_attach_object_instance_id">
<return type="void">
</return>
@@ -404,6 +432,14 @@
Creates a physics body. The first parameter can be any value from constants BODY_MODE*, for the type of body created. Additionally, the body can be created in sleeping state to save processing time.
</description>
</method>
+ <method name="body_get_canvas_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="body_get_collision_layer" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/PhysicsBody.xml b/doc/classes/PhysicsBody.xml
index af00027ed3..2658732f84 100644
--- a/doc/classes/PhysicsBody.xml
+++ b/doc/classes/PhysicsBody.xml
@@ -7,7 +7,7 @@
PhysicsBody is an abstract base class for implementing a physics body. All *Body types inherit from it.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
@@ -21,6 +21,13 @@
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
+ <method name="get_collision_exceptions">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an array of nodes that were added as collision exceptions for this body.
+ </description>
+ </method>
<method name="get_collision_layer_bit" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 4278979049..f848b6df70 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -7,7 +7,7 @@
PhysicsBody2D is an abstract base class for implementing a physics body. All *Body2D types inherit from it.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
@@ -21,6 +21,13 @@
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
+ <method name="get_collision_exceptions">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an array of nodes that were added as collision exceptions for this body.
+ </description>
+ </method>
<method name="get_collision_layer_bit" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/PhysicsDirectSpaceState.xml b/doc/classes/PhysicsDirectSpaceState.xml
index 1fd00fa21c..350a9ed3ce 100644
--- a/doc/classes/PhysicsDirectSpaceState.xml
+++ b/doc/classes/PhysicsDirectSpaceState.xml
@@ -7,7 +7,7 @@
Direct access object to a space in the [PhysicsServer]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/ray-casting.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml
index f79baea0be..c836414dd2 100644
--- a/doc/classes/PhysicsServer.xml
+++ b/doc/classes/PhysicsServer.xml
@@ -1260,7 +1260,7 @@
The higher, the stronger.
</constant>
<constant name="PIN_JOINT_IMPULSE_CLAMP" value="2" enum="PinJointParam">
- If above 0, this value is the maximum value for an impulse that this Joint puts on it's ends.
+ If above 0, this value is the maximum value for an impulse that this Joint puts on its ends.
</constant>
<constant name="HINGE_JOINT_BIAS" value="0" enum="HingeJointParam">
The speed with which the two bodies get pulled together when they move in different directions.
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index 3d5eada066..a57659abda 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -7,7 +7,7 @@
Plane represents a normalized plane equation. Basically, "normal" is the normal of the plane (a,b,c normalized), and "d" is the distance from the origin to the plane (in the direction of "normal"). "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4516fc522a..3b7356ab39 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -182,7 +182,7 @@
Name of the project. It is used from both project manager and by the exporters. Overriding this as name.locale allows setting it in multiple languages.
</member>
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="">
- Allow the project to save to it's own custom user dir (in AppData on windows or ~/.config on unixes). This setting only works for desktop exporters. A name must be set in the "custom_user_dir_name" setting for this to take effect.
+ Allow the project to save to its own custom user dir (in AppData on windows or ~/.config on unixes). This setting only works for desktop exporters. A name must be set in the "custom_user_dir_name" setting for this to take effect.
</member>
<member name="application/run/disable_stderr" type="bool" setter="" getter="">
Disable printing to stderr on exported build.
@@ -213,6 +213,8 @@
<member name="audio/mix_rate" type="int" setter="" getter="">
Mix rate used for audio. In general, it's better to not touch this and leave it to the host operating system.
</member>
+ <member name="audio/output_latency" type="int" setter="" getter="">
+ </member>
<member name="audio/video_delay_compensation_ms" type="int" setter="" getter="">
Setting to hardcode audio delay when playing video. Best to leave this untouched unless you know what you are doing.
</member>
@@ -230,6 +232,8 @@
</member>
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="">
</member>
+ <member name="debug/gdscript/completion/autocomplete_setters_and_getters" type="bool" setter="" getter="">
+ </member>
<member name="debug/gdscript/warnings/constant_used_as_function" type="bool" setter="" getter="">
</member>
<member name="debug/gdscript/warnings/deprecated_keyword" type="bool" setter="" getter="">
@@ -372,7 +376,7 @@
<member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="">
Timer setting for incremental search in Tree, IntemList, etc. controls.
</member>
- <member name="gui/timers/text_edit_idle_detect_sec" type="int" setter="" getter="">
+ <member name="gui/timers/text_edit_idle_detect_sec" type="float" setter="" getter="">
Timer for detecting idle in the editor.
</member>
<member name="input/ui_accept" type="Dictionary" setter="" getter="">
@@ -604,9 +608,6 @@
<member name="network/limits/packet_peer_stream/max_buffer_po2" type="int" setter="" getter="">
Default size of packet peer stream for deserializing godot data. Over this size, data is dropped.
</member>
- <member name="network/remote_fs/max_pages" type="int" setter="" getter="">
- Maximum amount of pages used for remote filesystem (used by debugging).
- </member>
<member name="network/remote_fs/page_read_ahead" type="int" setter="" getter="">
Amount of read ahead used by remote filesystem. Improves latency.
</member>
@@ -652,7 +653,7 @@
<member name="rendering/limits/rendering/max_renderable_elements" type="int" setter="" getter="">
Max amount of elements renderable in a frame. If more than this are visible per frame, they will be dropped. Keep in mind elements refer to mesh surfaces and not mesh themselves.
</member>
- <member name="rendering/limits/time/time_rollover_secs" type="int" setter="" getter="">
+ <member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="">
Shaders have a time variable that constantly increases. At some point it needs to be rolled back to zero to avoid numerical errors on shader animations. This setting specifies when.
</member>
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="">
@@ -691,7 +692,7 @@
<member name="rendering/quality/reflections/high_quality_ggx.mobile" type="bool" setter="" getter="">
</member>
<member name="rendering/quality/reflections/texture_array_reflections" type="bool" setter="" getter="">
- For reflection probes and panorama backgrounds (sky), use a texure array instead of mipmaps. This reduces jitter noise on reflections, but costs more performance and memory.
+ For reflection probes and panorama backgrounds (sky), use a texture array instead of mipmaps. This reduces jitter noise on reflections, but costs more performance and memory.
</member>
<member name="rendering/quality/reflections/texture_array_reflections.mobile" type="bool" setter="" getter="">
</member>
@@ -704,7 +705,7 @@
<member name="rendering/quality/shading/force_lambert_over_burley.mobile" type="bool" setter="" getter="">
</member>
<member name="rendering/quality/shading/force_vertex_shading" type="bool" setter="" getter="">
- Force vertex shading for all rendering. This can increase performance a lot, but also reduces quality inmensely. Can work to optimize on very low end mobile.
+ Force vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can work to optimize on very low end mobile.
</member>
<member name="rendering/quality/shading/force_vertex_shading.mobile" type="bool" setter="" getter="">
</member>
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index 67631bbc92..468839dfba 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -9,8 +9,8 @@
Quaternions need to be (re)normalized.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
- <link>http://docs.godotengine.org/en/latest/tutorials/math/rotations.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/rotations.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 1eea940da9..1392e53f8d 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -7,7 +7,7 @@
Rect2 consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index a9a897ebaf..7662f72eca 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -5,7 +5,7 @@
<description>
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/reflection_probes.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index bf3ea95bce..f388667891 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -47,5 +47,7 @@
</constant>
<constant name="FLAG_COMPRESS" value="32" enum="SaverFlags">
</constant>
+ <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 357d2e7a15..145ce7537b 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -8,7 +8,7 @@
Note that assignments to [member bbcode_text] clear the tag stack and reconstruct it from the property's contents. Any edits made to [member bbcode_text] will erase previous edits made from other manual sources such as [method append_bbcode] and the [code]push_*[/code] / [method pop] methods.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/gui/bbcode_in_richtextlabel.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
</tutorials>
<demos>
</demos>
@@ -111,7 +111,7 @@
<argument index="0" name="align" type="int" enum="RichTextLabel.Align">
</argument>
<description>
- Adds a [code][right][/code] tag to the tag stack.
+ Adds an alignment tag based on the given [code]align[/code] value. See [enum Align] for possible values.
</description>
</method>
<method name="push_cell">
@@ -170,6 +170,7 @@
<return type="void">
</return>
<description>
+ Adds a [code][s][/code] tag to the tag stack.
</description>
</method>
<method name="push_table">
diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml
index 0977b7ea01..4ff332402b 100644
--- a/doc/classes/RigidBody.xml
+++ b/doc/classes/RigidBody.xml
@@ -10,7 +10,7 @@
If you need to override the default physics behavior, you can write a custom force integration. See [member custom_integrator].
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index b89ecd1de9..dd94ee66d2 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -7,8 +7,8 @@
As one of the most important classes, the [code]SceneTree[/code] manages the hierarchy of nodes in a scene as well as scenes themselves. Nodes can be added, retrieved and removed. The whole scene tree (and thus the current scene) can be paused. Scenes can be loaded, switched and reloaded. You can also use the SceneTree to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. a "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/scene_tree.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/viewports/multiple_resolutions.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scene_tree.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/viewports/multiple_resolutions.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 128d7475cc..ec1d544c03 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -8,7 +8,7 @@
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/step_by_step/scripting.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 7f9a124683..dd6a023af4 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -7,7 +7,7 @@
This class allows you to define a custom shader program that can be used for various materials to render objects.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/shading/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/shading/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Shape.xml b/doc/classes/Shape.xml
index bc1a429418..6e51d3156f 100644
--- a/doc/classes/Shape.xml
+++ b/doc/classes/Shape.xml
@@ -7,7 +7,7 @@
Base class for all 3D shape resources. Nodes that inherit from this can be used as shapes for a [PhysicsBody] or [Area] objects.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 2772538cec..96b8a77d9e 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -7,7 +7,7 @@
Base class for all 2D Shapes. All 2D shape types inherit from this.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/SoftBody.xml b/doc/classes/SoftBody.xml
index 196d29fc60..6c3929d65b 100644
--- a/doc/classes/SoftBody.xml
+++ b/doc/classes/SoftBody.xml
@@ -20,6 +20,13 @@
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
+ <method name="get_collision_exceptions">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an array of nodes that were added as collision exceptions for this body.
+ </description>
+ </method>
<method name="get_collision_layer_bit" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml
index 7fd7b5deed..6f9d779737 100644
--- a/doc/classes/Spatial.xml
+++ b/doc/classes/Spatial.xml
@@ -8,7 +8,7 @@
Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the Spatial object is set as top level. Affine operations in this coordinate system correspond to direct affine operations on the Spatial's transform. The word local below refers to this coordinate system. The coordinate system that is attached to the Spatial object itself is referred to as object-local coordinate system.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/introduction_to_3d.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml
index 57fb267e91..392a550ee4 100644
--- a/doc/classes/SpatialMaterial.xml
+++ b/doc/classes/SpatialMaterial.xml
@@ -7,7 +7,7 @@
This provides a default material with a wide variety of rendering features and properties without the need to write shader code. See the tutorial below for details.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/spatial_material.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html</link>
</tutorials>
<demos>
</demos>
@@ -180,7 +180,7 @@
<member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
The number of horizontal frames in the particle spritesheet. Only enabled when using [code]BillboardMode.BILLBOARD_PARTICLES[/code]. See [member params_billboard_mode].
</member>
- <member name="particles_anim_loop" type="int" setter="set_particles_anim_loop" getter="get_particles_anim_loop">
+ <member name="particles_anim_loop" type="bool" setter="set_particles_anim_loop" getter="get_particles_anim_loop">
If [code]true[/code] particle animations are looped. Only enabled when using [code]BillboardMode.BILLBOARD_PARTICLES[/code]. See [member params_billboard_mode].
</member>
<member name="particles_anim_v_frames" type="int" setter="set_particles_anim_v_frames" getter="get_particles_anim_v_frames">
diff --git a/doc/classes/SpotLight.xml b/doc/classes/SpotLight.xml
index 1f81e9e5c2..11f914aac2 100644
--- a/doc/classes/SpotLight.xml
+++ b/doc/classes/SpotLight.xml
@@ -7,7 +7,7 @@
A SpotLight light is a type of [Light] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. TODO: Image of a spotlight.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml
index 33948df509..40a4e04a80 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerSSL.xml
@@ -7,7 +7,7 @@
SSL Stream peer. This object can be used to connect to SSL servers.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/ssl_certificates.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index 664ffc60c3..9a0fceddab 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -4,7 +4,7 @@
TCP Stream peer.
</brief_description>
<description>
- TCP Stream peer. This object can be used to connect to TCP servers, or also is returned by a tcp server.
+ TCP Stream peer. This object can be used to connect to TCP servers, or also is returned by a TCP server.
</description>
<tutorials>
</tutorials>
@@ -54,6 +54,7 @@
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if this peer is currently connected to a host, [code]false[code] otherwise.
</description>
</method>
<method name="set_no_delay">
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 4f9ac68e47..2e5d5d81c9 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -149,7 +149,7 @@
<argument index="2" name="transform" type="Transform">
</argument>
<description>
- Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform].
+ Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform].
</description>
</method>
<method name="begin">
@@ -187,7 +187,7 @@
<argument index="1" name="surface" type="int">
</argument>
<description>
- Creates a vertex array from an existing [Mesh].
+ Creates a vertex array from an existing [Mesh].
</description>
</method>
<method name="deindex">
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 6f8c76d1ea..7034d75473 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -7,7 +7,7 @@
Node for 2D tile-based maps. Tilemaps use a [TileSet] which contain a list of tiles (textures plus optional collision, navigation, and/or occluder shapes) which are used to create grid-based maps.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/using_tilemaps.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml
index 09edfe4235..b3168ef129 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform.xml
@@ -7,8 +7,8 @@
Represents one or many transformations in 3D space such as translation, rotation, or scaling. It consists of a [Basis] "basis" and an [Vector3] "origin". It is similar to a 3x4 matrix.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
- <link>http://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 1dc03ed314..e792835605 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -14,7 +14,7 @@
tween.start()
[/codeblock]
Many methods require a property name, such as "position" above. You can find the correct property name by hovering over the property in the Inspector.
- Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [code]http://easings.net/[/code] for some examples). The second accepts an [enum EaseType] constant, and controls the where [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [enum EASE_IN_OUT], and use the one that looks best.
+ Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [code]http://easings.net/[/code] for some examples). The second accepts an [enum EaseType] constant, and controls the where [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [code]EASE_IN_OUT[/code], and use the one that looks best.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index c323cf6992..006a843c32 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -7,7 +7,7 @@
2-element structure that can be used to represent positions in 2d space or any other pair of numeric values.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<demos>
</demos>
@@ -259,10 +259,10 @@
</methods>
<members>
<member name="x" type="float" setter="" getter="">
- The vector's x component.
+ The vector's x component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="float" setter="" getter="">
- The vector's y component.
+ The vector's y component. Also accessible by using the index position [code][1][/code].
</member>
</members>
<constants>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 8c4e08778d..48856875e7 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -7,7 +7,7 @@
Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vector math operations.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/math/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<demos>
</demos>
@@ -260,13 +260,13 @@
</methods>
<members>
<member name="x" type="float" setter="" getter="">
- The vector's x component.
+ The vector's x component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="float" setter="" getter="">
- The vector's y component.
+ The vector's y component. Also accessible by using the index position [code][1][/code].
</member>
<member name="z" type="float" setter="" getter="">
- The vector's z component.
+ The vector's z component. Also accessible by using the index position [code][2][/code].
</member>
</members>
<constants>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 9cd501630e..2cdd8c407f 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -12,8 +12,8 @@
Finally, viewports can also behave as render targets, in which case they will not be visible unless the associated texture is used to draw.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/2d/2d_transforms.html</link>
- <link>http://docs.godotengine.org/en/3.0/tutorials/viewports/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/viewports/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml
index 225a1f2bba..46a06d63d4 100644
--- a/doc/classes/VisualServer.xml
+++ b/doc/classes/VisualServer.xml
@@ -239,10 +239,6 @@
</argument>
<argument index="3" name="normal_map" type="RID">
</argument>
- <argument index="4" name="h_frames" type="int">
- </argument>
- <argument index="5" name="v_frames" type="int">
- </argument>
<description>
Adds a particles system to the [CanvasItem]'s draw commands.
</description>
@@ -3613,7 +3609,7 @@
If [code]true[/code] sets the viewport active, else sets it inactive.
</description>
</method>
- <method name="viewport_set_canvas_layer">
+ <method name="viewport_set_canvas_stacking">
<return type="void">
</return>
<argument index="0" name="viewport" type="RID">
@@ -3622,8 +3618,11 @@
</argument>
<argument index="2" name="layer" type="int">
</argument>
+ <argument index="3" name="sublayer" type="int">
+ </argument>
<description>
- Sets the renderlayer for a viewport's canvas.
+ Sets the stacking order for a viewport's canvas.
+ [code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] specifies the stacking order of the canvas among those in the same layer.
</description>
</method>
<method name="viewport_set_canvas_transform">
diff --git a/doc/classes/World.xml b/doc/classes/World.xml
index 540848e40a..4e954acd48 100644
--- a/doc/classes/World.xml
+++ b/doc/classes/World.xml
@@ -7,7 +7,7 @@
Class that has everything pertaining to a world. A physics space, a visual scenario and a sound space. Spatial nodes register their resources into the current world.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/ray-casting.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index 780cdd181a..9c3d66dade 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -7,7 +7,7 @@
Class that has everything pertaining to a 2D world. A physics space, a visual scenario and a sound space. 2D nodes register their resources into the current 2D world.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/physics/ray-casting.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index e68ad2800e..45e1af4e42 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -9,7 +9,7 @@
The [code]WorldEnvironment[/code] allows the user to specify default lighting parameters (e.g. ambient lighting), various post-processing effects (e.g. SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, skybox). Usually, these are added in order to improve the realism/color balance of the scene.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/environment_and_post_processing.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
</tutorials>
<demos>
</demos>
diff --git a/doc/classes/YSort.xml b/doc/classes/YSort.xml
index 12b9cb623f..45ae8645b1 100644
--- a/doc/classes/YSort.xml
+++ b/doc/classes/YSort.xml
@@ -14,6 +14,7 @@
</methods>
<members>
<member name="sort_enabled" type="bool" setter="set_sort_enabled" getter="is_sort_enabled">
+ If [code]true[/code] child nodes are sorted, otherwise sorting is disabled. Default: [code]true[/code].
</member>
</members>
<constants>
diff --git a/doc/tools/doc_merge.py b/doc/tools/doc_merge.py
index 57ac4bdcdd..496d5dcb74 100644
--- a/doc/tools/doc_merge.py
+++ b/doc/tools/doc_merge.py
@@ -82,7 +82,7 @@ def find_signal_descr(old_class, name):
def find_constant_descr(old_class, name):
- if (old_class == None):
+ if (old_class is None):
return None
constants = old_class.find("constants")
if(constants != None and len(list(constants)) > 0):
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index ab74c0b9d6..4bb4342d5f 100644
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -229,11 +229,11 @@ class ClassStatus:
output['overall'] = (description_progress + items_progress).to_colored_string('{percent}%', '{pad_percent}{s}')
if self.name.startswith('Total'):
- output['url'] = color('url', 'http://docs.godotengine.org/en/latest/classes/')
+ output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/')
if flags['s']:
output['comment'] = color('part_good', 'ALL OK')
else:
- output['url'] = color('url', 'http://docs.godotengine.org/en/latest/classes/class_{name}.html'.format(name=self.name.lower()))
+ output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/class_{name}.html'.format(name=self.name.lower()))
if flags['s'] and not flags['g'] and self.is_ok():
output['comment'] = color('part_good', 'ALL OK')
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index b3d6d32c26..7b7cc52547 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -375,7 +375,7 @@ def make_method(
event=False,
pp=None
):
- if (declare or pp == None):
+ if (declare or pp is None):
t = '- '
else:
t = ""
@@ -405,7 +405,7 @@ def make_method(
t += 'void'
t += ' '
- if declare or pp == None:
+ if declare or pp is None:
s = '**' + method_data.attrib['name'] + '** '
else:
@@ -577,7 +577,7 @@ def make_rst_class(node):
make_method(f, name, m, True, True)
f.write('\n')
d = m.find('description')
- if d == None or d.text.strip() == '':
+ if d is None or d.text.strip() == '':
continue
f.write(rstize_text(d.text.strip(), name))
f.write("\n\n")
@@ -676,7 +676,7 @@ def make_rst_class(node):
make_method(f, name, m, True)
f.write('\n')
d = m.find('description')
- if d == None or d.text.strip() == '':
+ if d is None or d.text.strip() == '':
continue
f.write(rstize_text(d.text.strip(), name))
f.write("\n\n")
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index aaec63d7ff..850b90d59b 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -145,9 +145,6 @@ Error AudioDriverCoreAudio::init() {
unsigned int buffer_size = buffer_frames * channels;
samples_in.resize(buffer_size);
input_buf.resize(buffer_size);
- input_buffer.resize(buffer_size * 8);
- input_position = 0;
- input_size = 0;
print_verbose("CoreAudio: detected " + itos(channels) + " channels");
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
@@ -487,6 +484,8 @@ void AudioDriverCoreAudio::capture_finish() {
Error AudioDriverCoreAudio::capture_start() {
+ input_buffer_init(buffer_frames);
+
OSStatus result = AudioOutputUnitStart(input_unit);
if (result != noErr) {
ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result));
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 18b5dd3483..9227c04e71 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -1111,6 +1111,7 @@ void RasterizerCanvasGLES2::initialize() {
// polygon buffer
{
uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
poly_size *= 1024;
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
@@ -1122,6 +1123,7 @@ void RasterizerCanvasGLES2::initialize() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
index_size *= 1024; // kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 848ac8b78f..175587b1bb 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -74,6 +74,10 @@
#include <EGL/eglext.h>
#endif
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define strcpy strcpy_s
+#endif
+
#ifndef IPHONE_ENABLED
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
@@ -84,6 +88,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
return; //these are ultimately annoying, so removing for now
char debSource[256], debType[256], debSev[256];
+
if (source == _EXT_DEBUG_SOURCE_API_ARB)
strcpy(debSource, "OpenGL");
else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB)
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index fbcbebc88c..c4b6c607a2 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2455,13 +2455,20 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, true);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, true);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false);
storage->shaders.copy.bind();
storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy);
+ if (asymmetrical) {
+ // pack the bits we need from our projection matrix
+ storage->shaders.copy.set_uniform(CopyShaderGLES2::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]);
+ ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here.
+ storage->shaders.copy.set_uniform(CopyShaderGLES2::PANO_TRANSFORM, p_transform);
+ }
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -2469,6 +2476,8 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
}
@@ -3037,6 +3046,7 @@ void RasterizerSceneGLES2::initialize() {
{
uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
glGenBuffers(1, &state.immediate_buffer);
glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index d5865064cf..5011794735 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -613,8 +613,72 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
return Ref<Image>(img);
#else
- ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES");
- ERR_FAIL_V(Ref<Image>());
+ Image::Format real_format;
+ GLenum gl_format;
+ GLenum gl_internal_format;
+ GLenum gl_type;
+ bool compressed;
+ _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed);
+
+ PoolVector<uint8_t> data;
+
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ PoolVector<uint8_t>::Write wb = data.write();
+
+ GLuint temp_framebuffer;
+ glGenFramebuffers(1, &temp_framebuffer);
+
+ GLuint temp_color_texture;
+ glGenTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, temp_color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture->tex_id);
+
+ glViewport(0, 0, texture->alloc_width, texture->alloc_height);
+
+ shaders.copy.bind();
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ bind_quad_array();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]);
+
+ glDeleteTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &temp_framebuffer);
+
+ wb = PoolVector<uint8_t>::Write();
+
+ data.resize(data_size);
+
+ Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data));
+ if (!texture->compressed) {
+ img->convert(real_format);
+ }
+
+ return Ref<Image>(img);
+
#endif
}
@@ -1538,7 +1602,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) {
if (p_material->shader && p_material->shader->mode == VS::SHADER_SPATIAL) {
if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX &&
- (!p_material->shader->spatial.uses_alpha || (p_material->shader->spatial.uses_alpha && p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) {
+ (!p_material->shader->spatial.uses_alpha || p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) {
can_cast_shadow = true;
}
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index c928f753b1..04a6f72710 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -429,6 +429,7 @@ public:
int light_mode;
*/
+
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 082c520480..723c44f2f6 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -80,11 +80,8 @@ static String _opstr(SL::Operator p_op) {
static String _mkid(const String &p_id) {
- StringBuffer<> id;
- id += "m_";
- id += p_id;
-
- return id.as_string();
+ String id = "m_" + p_id;
+ return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl
}
static String f2sp0(float p_float) {
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index 628a57c06d..c5a67d4e75 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -196,6 +196,12 @@ static void _display_error_with_code(const String &p_error, const Vector<const c
ERR_PRINTS(p_error);
}
+static String _mkid(const String &p_id) {
+
+ String id = "m_" + p_id;
+ return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl
+}
+
ShaderGLES2::Version *ShaderGLES2::get_current_version() {
Version *_v = version_map.getptr(conditional_version);
@@ -492,15 +498,15 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
if (cc) {
// uniforms
for (int i = 0; i < cc->custom_uniforms.size(); i++) {
- StringName native_uniform_name = "m_" + cc->custom_uniforms[i];
- GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data());
+ String native_uniform_name = _mkid(cc->custom_uniforms[i]);
+ GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
v.custom_uniform_locations[cc->custom_uniforms[i]] = location;
}
// textures
for (int i = 0; i < cc->texture_uniforms.size(); i++) {
- StringName native_uniform_name = "m_" + cc->texture_uniforms[i];
- GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data());
+ String native_uniform_name = _mkid(cc->texture_uniforms[i]);
+ GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
}
}
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index b990384949..79d4eb2243 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -148,7 +148,10 @@ void main() {
vec4 color = color_interp;
+#if !defined(COLOR_USED)
+ //default behavior, texture by color
color *= texture2D(color_texture, uv_interp);
+#endif
#ifdef SCREEN_UV_USED
vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl
index 16bbde196d..0b8da4f875 100644
--- a/drivers/gles2/shaders/copy.glsl
+++ b/drivers/gles2/shaders/copy.glsl
@@ -35,6 +35,8 @@ void main() {
#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
cube_interp = cube_in;
+#elif defined(USE_ASYM_PANO)
+ uv_interp = vertex_attrib.xy;
#else
uv_interp = uv_in;
#endif
@@ -68,6 +70,11 @@ varying vec2 uv_interp;
#endif
/* clang-format on */
+#ifdef USE_ASYM_PANO
+uniform highp mat4 pano_transform;
+uniform highp vec4 asym_proj;
+#endif
+
#ifdef USE_CUBEMAP
uniform samplerCube source_cube; // texunit:0
#else
@@ -108,6 +115,21 @@ void main() {
vec4 color = texturePanorama(source, normalize(cube_interp));
+#elif defined(USE_ASYM_PANO)
+
+ // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result.
+ // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1.
+ // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image.
+
+ vec3 cube_normal;
+ cube_normal.z = -1000000.0;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y;
+ cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a;
+ cube_normal = mat3(pano_transform) * cube_normal;
+ cube_normal.z = -cube_normal.z;
+
+ vec4 color = texturePanorama(source, normalize(cube_normal.xyz));
+
#elif defined(USE_CUBEMAP)
vec4 color = textureCube(source_cube, normalize(cube_interp));
#else
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 7b57f5d497..2a781605d1 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -359,7 +359,7 @@ void main() {
normal = normalize((world_matrix * vec4(normal, 0.0)).xyz);
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent = normalize((world_matrix * vec4(tangent, 0.0)), xyz);
+ tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz);
binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz);
#endif
#endif
@@ -1307,8 +1307,7 @@ LIGHT_SHADER_CODE
#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r)
#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r)
-float sample_shadow(
- highp sampler2D shadow, highp vec4 spos) {
+float sample_shadow(highp sampler2D shadow, highp vec4 spos) {
#ifdef SHADOW_MODE_PCF_13
@@ -1923,12 +1922,12 @@ FRAGMENT_SHADER_CODE
highp vec4 splane = shadow_coord;
splane.xyz /= splane.w;
- float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z);
+ float shadow = sample_shadow(light_shadow_atlas, splane);
light_att *= shadow;
}
#endif
-#endif
+#endif // LIGHT_MODE_SPOT
#ifdef USE_VERTEX_LIGHTING
//vertex lighting
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index a9b46baf53..0c6893d419 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -967,7 +967,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
//enable instancing
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
//reset shader and force rebind
state.using_texture_rect = true;
@@ -976,10 +975,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
if (texture) {
- Size2 texpixel_size(1.0 / (texture->width / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames));
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
- } else {
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
}
if (!particles->use_local_coords) {
@@ -993,9 +990,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
}
- state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames);
-
glBindVertexArray(data.particle_quad_array); //use particle quad array
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
@@ -1073,7 +1067,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
state.using_texture_rect = true;
_set_texture_rect_mode(false);
@@ -2027,6 +2020,7 @@ void RasterizerCanvasGLES3::initialize() {
{
uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
poly_size *= 1024; //kb
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
@@ -2074,6 +2068,7 @@ void RasterizerCanvasGLES3::initialize() {
glGenVertexArrays(1, &data.polygon_buffer_pointer_array);
uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
index_size *= 1024; //kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 2b3be9d0bd..2f6a556773 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -73,6 +73,10 @@ RasterizerScene *RasterizerGLES3::get_scene() {
#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148
#define _EXT_DEBUG_OUTPUT 0x92E0
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define strcpy strcpy_s
+#endif
+
#ifdef GLAD_ENABLED
// Restricting to GLAD as only used in initialize() with GLAD_GL_ARB_debug_output
#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED)
@@ -432,6 +436,7 @@ void RasterizerGLES3::register_config() {
GLOBAL_DEF("rendering/quality/filters/anisotropic_filter_level", 4);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/anisotropic_filter_level", PropertyInfo(Variant::INT, "rendering/quality/filters/anisotropic_filter_level", PROPERTY_HINT_RANGE, "1,16,1"));
GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"));
}
RasterizerGLES3::RasterizerGLES3() {
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index ed2b39a17d..792e9eb238 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1246,14 +1246,11 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
case ShaderLanguage::TYPE_SAMPLER3D: {
target = GL_TEXTURE_3D;
+ tex = storage->resources.white_tex_3d;
- switch (texture_hints[i]) {
-
- // TODO
- default: {
- tex = storage->resources.white_tex_3d;
- } break;
- }
+ //switch (texture_hints[i]) {
+ // TODO
+ //}
} break;
@@ -1431,7 +1428,16 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo
if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->particle_valid_histories[1]) {
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer, this was used 2 frames ago so it should be good enough for flushing
- RasterizerGLES3Particle *particle_array = (RasterizerGLES3Particle *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
+ RasterizerGLES3Particle *particle_array;
+#ifndef __EMSCRIPTEN__
+ particle_array = static_cast<RasterizerGLES3Particle *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+#else
+ PoolVector<RasterizerGLES3Particle> particle_vector;
+ particle_vector.resize(particles->amount);
+ PoolVector<RasterizerGLES3Particle>::Write w = particle_vector.write();
+ particle_array = w.ptr();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), particle_array);
+#endif
SortArray<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> sorter;
@@ -1443,7 +1449,17 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo
sorter.sort(particle_array, particles->amount);
+#ifndef __EMSCRIPTEN__
glUnmapBuffer(GL_ARRAY_BUFFER);
+#else
+ w = PoolVector<RasterizerGLES3Particle>::Write();
+ particle_array = NULL;
+ {
+ PoolVector<RasterizerGLES3Particle>::Read r = particle_vector.read();
+ glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), r.ptr());
+ }
+ particle_vector = PoolVector<RasterizerGLES3Particle>();
+#endif
#ifdef DEBUG_ENABLED
if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) {
glBindVertexArray(s->instancing_array_wireframe_id); // use the wireframe instancing array ID
@@ -4855,10 +4871,7 @@ void RasterizerSceneGLES3::initialize() {
glBindBuffer(GL_UNIFORM_BUFFER, 0);
render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS);
- if (render_list.max_elements > 1000000)
- render_list.max_elements = 1000000;
- if (render_list.max_elements < 1024)
- render_list.max_elements = 1024;
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,1000000,1"));
{
//quad buffers
@@ -5057,6 +5070,7 @@ void RasterizerSceneGLES3::initialize() {
{
uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
glGenBuffers(1, &state.immediate_buffer);
glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index a9aa152f10..649449a891 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -101,6 +101,28 @@
#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#ifdef __EMSCRIPTEN__
+#include <emscripten/emscripten.h>
+
+void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) {
+
+ /* clang-format off */
+ EM_ASM({
+ GLctx.getBufferSubData($0, $1, HEAPU8, $2, $3);
+ }, target, offset, data, size);
+ /* clang-format on */
+}
+
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) {
+
+ /* clang-format off */
+ EM_ASM({
+ GLctx.bufferSubData($0, $1, HEAPU8, $2, $3);
+ }, target, offset, data, size);
+ /* clang-format on */
+}
+#endif
+
void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) {
#ifdef GLES_OVER_GL
@@ -1094,8 +1116,78 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
return Ref<Image>(img);
#else
- ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES");
- ERR_FAIL_V(Ref<Image>());
+ Image::Format real_format;
+ GLenum gl_format;
+ GLenum gl_internal_format;
+ GLenum gl_type;
+ bool compressed;
+ bool srgb;
+ _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb);
+
+ PoolVector<uint8_t> data;
+
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ PoolVector<uint8_t>::Write wb = data.write();
+
+ GLuint temp_framebuffer;
+ glGenFramebuffers(1, &temp_framebuffer);
+
+ GLuint temp_color_texture;
+ glGenTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, temp_color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ print_line(itos(texture->alloc_width) + " xx " + itos(texture->alloc_height) + " -> " + itos(real_format));
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture->tex_id);
+
+ glViewport(0, 0, texture->alloc_width, texture->alloc_height);
+
+ shaders.copy.bind();
+
+ shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindVertexArray(resources.quadie_array);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindVertexArray(0);
+
+ glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]);
+
+ shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false);
+
+ glDeleteTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &temp_framebuffer);
+
+ wb = PoolVector<uint8_t>::Write();
+
+ data.resize(data_size);
+
+ Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data));
+ if (!texture->compressed) {
+ img->convert(real_format);
+ }
+
+ return Ref<Image>(img);
#endif
}
@@ -2738,7 +2830,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
if (material->shader && material->shader->mode == VS::SHADER_SPATIAL) {
if (material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX &&
- (!material->shader->spatial.uses_alpha || (material->shader->spatial.uses_alpha && material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) {
+ (!material->shader->spatial.uses_alpha || material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) {
can_cast_shadow = true;
}
@@ -3494,21 +3586,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, i
Surface *surface = mesh->surfaces[p_surface];
- glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id);
- void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT);
-
- ERR_FAIL_COND_V(!data, PoolVector<uint8_t>());
-
PoolVector<uint8_t> ret;
ret.resize(surface->array_byte_size);
+ glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id);
+#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
+ {
+ PoolVector<uint8_t>::Write w = ret.write();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, surface->array_byte_size, w.ptr());
+ }
+#else
+ void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, PoolVector<uint8_t>());
{
-
PoolVector<uint8_t>::Write w = ret.write();
copymem(w.ptr(), data, surface->array_byte_size);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
+#endif
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
return ret;
}
@@ -3521,22 +3618,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_m
ERR_FAIL_COND_V(surface->index_array_len == 0, PoolVector<uint8_t>());
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id);
- void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT);
-
- ERR_FAIL_COND_V(!data, PoolVector<uint8_t>());
-
PoolVector<uint8_t> ret;
ret.resize(surface->index_array_byte_size);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id);
+#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
+ {
+ PoolVector<uint8_t>::Write w = ret.write();
+ glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr());
+ }
+#else
+ void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, PoolVector<uint8_t>());
{
-
PoolVector<uint8_t>::Write w = ret.write();
copymem(w.ptr(), data, surface->index_array_byte_size);
}
-
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+#endif
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return ret;
}
@@ -3577,23 +3678,26 @@ Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shap
for (int i = 0; i < mesh->surfaces[p_surface]->blend_shapes.size(); i++) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id);
- void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT);
-
- ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >());
-
PoolVector<uint8_t> ret;
ret.resize(mesh->surfaces[p_surface]->array_byte_size);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id);
+#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
+ {
+ PoolVector<uint8_t>::Write w = ret.write();
+ glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, w.ptr());
+ }
+#else
+ void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT);
+ ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >());
{
-
PoolVector<uint8_t>::Write w = ret.write();
copymem(w.ptr(), data, mesh->surfaces[p_surface]->array_byte_size);
}
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+#endif
bsarr.push_back(ret);
-
- glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
}
return bsarr;
@@ -6001,9 +6105,21 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
const Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, AABB());
+ const float *data;
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]);
- float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT);
+#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
+ PoolVector<uint8_t> vector;
+ vector.resize(particles->amount * 16 * 6);
+ {
+ PoolVector<uint8_t>::Write w = vector.write();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, w.ptr());
+ }
+ PoolVector<uint8_t>::Read r = vector.read();
+ data = reinterpret_cast<const float *>(r.ptr());
+#else
+ data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT);
+#endif
AABB aabb;
Transform inv = particles->emission_transform.affine_inverse();
@@ -6020,7 +6136,13 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
aabb.expand_to(pos);
}
+#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
+ r = PoolVector<uint8_t>::Read();
+ vector = PoolVector<uint8_t>();
+#else
glUnmapBuffer(GL_ARRAY_BUFFER);
+#endif
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
float longest_axis = 0;
@@ -7686,6 +7808,8 @@ void RasterizerStorageGLES3::initialize() {
{
//transform feedback buffers
uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/blend_shape_max_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/blend_shape_max_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
+
for (int i = 0; i < 2; i++) {
glGenBuffers(1, &resources.transform_feedback_buffers[i]);
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 9a4798ac2a..773b149e0b 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -43,6 +43,12 @@
#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/particles.glsl.gen.h"
+// WebGL 2.0 has no MapBufferRange/UnmapBuffer, but offers a non-ES style BufferSubData API instead.
+#ifdef __EMSCRIPTEN__
+void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+#endif
+
class RasterizerCanvasGLES3;
class RasterizerSceneGLES3;
@@ -443,6 +449,7 @@ public:
};
int light_mode;
+
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index be36b41417..03619b941c 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -167,7 +167,8 @@ static String _opstr(SL::Operator p_op) {
static String _mkid(const String &p_id) {
- return "m_" + p_id;
+ String id = "m_" + p_id;
+ return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl
}
static String f2sp0(float p_float) {
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 8e8b693eb2..52746e0862 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -92,11 +92,6 @@ const bool at_light_pass = true;
const bool at_light_pass = false;
#endif
-#ifdef USE_PARTICLES
-uniform int h_frames;
-uniform int v_frames;
-#endif
-
#if defined(USE_MATERIAL)
/* clang-format off */
@@ -143,20 +138,6 @@ void main() {
highp vec4 outvec = vec4(vertex, 0.0, 1.0);
#endif
-#ifdef USE_PARTICLES
- //scale by texture size
- outvec.xy /= color_texpixel_size;
-
- //compute h and v frames and adjust UV interp for animation
- int total_frames = h_frames * v_frames;
- int frame = min(int(float(total_frames) * instance_custom.z), total_frames - 1);
- float frame_w = 1.0 / float(h_frames);
- float frame_h = 1.0 / float(v_frames);
- uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames);
- uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / h_frames);
-
-#endif
-
#define extra_matrix extra_matrix_instance
{
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 8388b15edb..91ab34f775 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -2053,7 +2053,7 @@ FRAGMENT_SHADER_CODE
emission = emission * rev_amount + fog_color * fog_amount;
ambient_light *= rev_amount;
- specular_light *rev_amount;
+ specular_light *= rev_amount;
diffuse_light *= rev_amount;
}
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 9c02549e39..d78316945f 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -613,20 +613,18 @@ Error AudioDriverPulseAudio::capture_init_device() {
break;
}
- print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
-
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
spec.channels = pa_rec_map.channels;
spec.rate = mix_rate;
- int latency = 30;
- input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
- int buffer_size = input_buffer_frames * spec.channels;
+ int input_latency = 30;
+ int input_buffer_frames = closest_power_of_2(input_latency * mix_rate / 1000);
+ int input_buffer_size = input_buffer_frames * spec.channels;
pa_buffer_attr attr;
- attr.fragsize = buffer_size * sizeof(int16_t);
+ attr.fragsize = input_buffer_size * sizeof(int16_t);
pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
if (pa_rec_str == NULL) {
@@ -642,9 +640,10 @@ Error AudioDriverPulseAudio::capture_init_device() {
ERR_FAIL_V(ERR_CANT_OPEN);
}
- input_buffer.resize(input_buffer_frames * 8);
- input_position = 0;
- input_size = 0;
+ input_buffer_init(input_buffer_frames);
+
+ print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
+ print_verbose("PulseAudio: input buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms");
return OK;
}
@@ -760,7 +759,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
mix_rate = 0;
buffer_frames = 0;
- input_buffer_frames = 0;
pa_buffer_size = 0;
channels = 0;
pa_ready = 0;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index f8358a452b..d8bab841ff 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -64,7 +64,6 @@ class AudioDriverPulseAudio : public AudioDriver {
unsigned int mix_rate;
unsigned int buffer_frames;
- unsigned int input_buffer_frames;
unsigned int pa_buffer_size;
int channels;
int pa_ready;
diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp
index 10ba0663f2..bc6ceb1e7e 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.cpp
+++ b/drivers/rtaudio/audio_driver_rtaudio.cpp
@@ -114,11 +114,12 @@ Error AudioDriverRtAudio::init() {
unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
print_verbose("Audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- short int tries = 2;
+ short int tries = 4;
- while (tries >= 0) {
+ while (tries > 0) {
switch (speaker_mode) {
case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break;
+ case SPEAKER_SURROUND_31: parameters.nChannels = 4; break;
case SPEAKER_SURROUND_51: parameters.nChannels = 6; break;
case SPEAKER_SURROUND_71: parameters.nChannels = 8; break;
};
@@ -128,12 +129,14 @@ Error AudioDriverRtAudio::init() {
active = true;
break;
- } catch (RtAudioError &e) {
+ } catch (RtAudioError) {
// try with less channels
ERR_PRINT("Unable to open audio, retrying with fewer channels...");
switch (speaker_mode) {
- case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_MODE_STEREO; break;
+ case SPEAKER_MODE_STEREO: break; // Required to silence unhandled enum value warning.
+ case SPEAKER_SURROUND_31: speaker_mode = SPEAKER_MODE_STEREO; break;
+ case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_SURROUND_31; break;
case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break;
}
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 2cc2032cbb..f981be66ce 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -55,7 +55,7 @@
#include <netinet/tcp.h>
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(__APPLE__)
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 7ff27be501..279274734f 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -288,6 +288,11 @@ uint64_t OS_Unix::get_ticks_usec() const {
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+#ifdef __EMSCRIPTEN__
+ // Don't compile this code at all to avoid undefined references.
+ // Actual virtual call goes to OS_JavaScript.
+ ERR_FAIL_V(ERR_BUG);
+#else
if (p_blocking && r_pipe) {
String argss;
@@ -354,6 +359,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo
}
return OK;
+#endif
}
Error OS_Unix::kill(const ProcessID &p_pid) {
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index a91e41b008..8665f701b1 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -336,10 +336,7 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) {
HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- // Set the buffer size
- input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS);
- input_position = 0;
- input_size = 0;
+ input_buffer_init(max_frames);
return OK;
}
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index b4492a2022..2582478259 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -114,7 +114,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
path = path + ".tmp";
}
- f = _wfopen(path.c_str(), mode_string);
+ _wfopen_s(&f, path.c_str(), mode_string);
if (f == NULL) {
last_error = ERR_FILE_CANT_OPEN;
@@ -278,7 +278,7 @@ bool FileAccessWindows::file_exists(const String &p_name) {
FILE *g;
//printf("opening file %s\n", p_fname.c_str());
String filename = fix_path(p_name);
- g = _wfopen(filename.c_str(), L"rb");
+ _wfopen_s(&g, filename.c_str(), L"rb");
if (g == NULL) {
return false;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 77be561477..f65825e395 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1253,14 +1253,14 @@ void AnimationTrackEdit::_notification(int p_what) {
float offset = animation->track_get_key_time(track, i) - timeline->get_value();
if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
- offset += editor->get_moving_selection_offset();
+ offset = editor->snap_time(offset + editor->get_moving_selection_offset());
}
offset = offset * scale + limit;
if (i < animation->track_get_key_count(track) - 1) {
float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value();
if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) {
- offset_n += editor->get_moving_selection_offset();
+ offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset());
}
offset_n = offset_n * scale + limit;
@@ -1685,15 +1685,10 @@ void AnimationTrackEdit::_zoom_changed() {
}
void AnimationTrackEdit::_path_entered(const String &p_text) {
-
- *block_animation_update_ptr = true;
undo_redo->create_action("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));
undo_redo->commit_action();
- *block_animation_update_ptr = false;
- update();
- path->hide();
}
String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
@@ -3192,7 +3187,8 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
case Animation::TYPE_ANIMATION: {
value = p_id.value;
} break;
- default: {}
+ default: {
+ }
}
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, value);
@@ -3881,9 +3877,7 @@ void AnimationTrackEditor::_move_selection_begin() {
void AnimationTrackEditor::_move_selection(float p_offset) {
moving_selection_offset = p_offset;
- if (snap->is_pressed() && step->get_value() != 0) {
- moving_selection_offset = Math::stepify(moving_selection_offset, step->get_value());
- }
+
for (int i = 0; i < track_edits.size(); i++) {
track_edits[i]->update();
}
@@ -4003,7 +3997,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 2- remove overlapped keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
- float newtime = E->get().pos + motion;
+ float newtime = snap_time(E->get().pos + motion);
int idx = animation->track_find_key(E->key().track, newtime, true);
if (idx == -1)
continue;
@@ -4027,7 +4021,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 3-move the keys (re insert them)
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = E->get().pos + motion;
+ float newpos = snap_time(E->get().pos + motion);
/*
if (newpos<0)
continue; //no add at the beginning
@@ -4038,7 +4032,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 4-(undo) remove inserted keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = E->get().pos + motion;
+ float newpos = snap_time(E->get().pos + motion);
/*
if (newpos<0)
continue; //no remove what no inserted
@@ -4074,7 +4068,7 @@ void AnimationTrackEditor::_move_selection_commit() {
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float oldpos = E->get().pos;
- float newpos = oldpos + motion;
+ float newpos = snap_time(oldpos + motion);
//if (newpos>=0)
undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
@@ -4086,6 +4080,8 @@ void AnimationTrackEditor::_move_selection_commit() {
for (int i = 0; i < track_edits.size(); i++) {
track_edits[i]->update();
}
+
+ _update_key_edit();
}
void AnimationTrackEditor::_move_selection_cancel() {
@@ -4349,7 +4345,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case Animation::TYPE_METHOD: text += " (Methods)"; break;
case Animation::TYPE_BEZIER: text += " (Bezier)"; break;
case Animation::TYPE_AUDIO: text += " (Audio)"; break;
- default: {};
+ default: {
+ };
}
TreeItem *it = track_copy_select->create_item(troot);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index aeb304d3b9..3136b0f012 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1060,7 +1060,7 @@ void CodeTextEditor::delete_lines() {
text_editor->end_complex_operation();
}
-void CodeTextEditor::code_lines_down() {
+void CodeTextEditor::clone_lines_down() {
int from_line = text_editor->cursor_get_line();
int to_line = text_editor->cursor_get_line();
int column = text_editor->cursor_get_column();
@@ -1072,22 +1072,21 @@ void CodeTextEditor::code_lines_down() {
}
int next_line = to_line + 1;
- if (to_line >= text_editor->get_line_count() - 1) {
- text_editor->set_line(to_line, text_editor->get_line(to_line) + "\n");
- }
-
+ bool caret_at_start = text_editor->cursor_get_line() == from_line;
text_editor->begin_complex_operation();
for (int i = from_line; i <= to_line; i++) {
-
text_editor->unfold_line(i);
- if (i >= text_editor->get_line_count() - 1) {
- text_editor->set_line(i, text_editor->get_line(i) + "\n");
- }
- String line_clone = text_editor->get_line(i);
- text_editor->insert_at(line_clone, next_line);
+ text_editor->set_line(next_line - 1, text_editor->get_line(next_line - 1) + "\n");
+ text_editor->set_line(next_line, text_editor->get_line(i));
next_line++;
}
+ if (caret_at_start) {
+ text_editor->cursor_set_line(to_line + 1);
+ } else {
+ text_editor->cursor_set_line(next_line - 1);
+ }
+
text_editor->cursor_set_column(column);
if (text_editor->is_selection_active()) {
text_editor->select(to_line + 1, text_editor->get_selection_from_column(), next_line - 1, text_editor->get_selection_to_column());
diff --git a/editor/code_editor.h b/editor/code_editor.h
index ee47eff9a8..2f9403843e 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -203,7 +203,7 @@ public:
void move_lines_up();
void move_lines_down();
void delete_lines();
- void code_lines_down();
+ void clone_lines_down();
void goto_line(int p_line);
void goto_line_selection(int p_line, int p_begin, int p_end);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index d64b02a605..99b6955160 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -557,8 +557,9 @@ DependencyRemoveDialog::DependencyRemoveDialog() {
//////////////
-void DependencyErrorDialog::show(const String &p_for_file, const Vector<String> &report) {
+void DependencyErrorDialog::show(Mode p_mode, const String &p_for_file, const Vector<String> &report) {
+ mode = p_mode;
for_file = p_for_file;
set_title(TTR("Error loading:") + " " + p_for_file.get_file());
files->clear();
@@ -584,7 +585,14 @@ void DependencyErrorDialog::show(const String &p_for_file, const Vector<String>
void DependencyErrorDialog::ok_pressed() {
- EditorNode::get_singleton()->load_scene(for_file, true);
+ switch (mode) {
+ case MODE_SCENE:
+ EditorNode::get_singleton()->load_scene(for_file, true);
+ break;
+ case MODE_RESOURCE:
+ EditorNode::get_singleton()->load_resource(for_file, true);
+ break;
+ }
}
void DependencyErrorDialog::custom_action(const String &) {
@@ -599,7 +607,7 @@ DependencyErrorDialog::DependencyErrorDialog() {
files = memnew(Tree);
files->set_hide_root(true);
- vb->add_margin_child(TTR("Scene failed to load due to missing dependencies:"), files, true);
+ vb->add_margin_child(TTR("Load failed due to missing dependencies:"), files, true);
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_custom_minimum_size(Size2(1, 200));
get_ok()->set_text(TTR("Open Anyway"));
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 4f268de748..e46df4c837 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -134,7 +134,15 @@ public:
class DependencyErrorDialog : public ConfirmationDialog {
GDCLASS(DependencyErrorDialog, ConfirmationDialog);
+public:
+ enum Mode {
+ MODE_SCENE,
+ MODE_RESOURCE,
+ };
+
+private:
String for_file;
+ Mode mode;
Button *fdep;
Label *text;
Tree *files;
@@ -142,7 +150,7 @@ class DependencyErrorDialog : public ConfirmationDialog {
void custom_action(const String &);
public:
- void show(const String &p_for_file, const Vector<String> &report);
+ void show(Mode p_mode, const String &p_for_file, const Vector<String> &report);
DependencyErrorDialog();
};
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index cdf0e4b829..2f2840192a 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -47,7 +47,9 @@ void EditorAbout::_notification(int p_what) {
Control *base = EditorNode::get_singleton()->get_gui_base();
Ref<Font> font = base->get_font("source", "EditorFonts");
_tpl_text->add_font_override("normal_font", font);
+ _tpl_text->add_constant_override("line_separation", 6 * EDSCALE);
_license_text->add_font_override("normal_font", font);
+ _license_text->add_constant_override("line_separation", 6 * EDSCALE);
_logo->set_texture(base->get_icon("Logo", "EditorIcons"));
} break;
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 1374c8c9aa..64742ff74c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -185,6 +185,7 @@ void EditorAutoloadSettings::_autoload_edited() {
if (path.begins_with("*"))
path = path.substr(1, path.length());
+ // Singleton autoloads are represented with a leading "*" in their path.
if (checked)
path = "*" + path;
@@ -651,6 +652,7 @@ void EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("Add AutoLoad"));
+ // Singleton autoloads are represented with a leading "*" in their path.
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, "*" + path);
if (ProjectSettings::get_singleton()->has_setting(name)) {
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 1a6188862f..209a006a06 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -144,6 +144,17 @@ String EditorExportPreset::get_include_filter() const {
return include_filter;
}
+void EditorExportPreset::set_export_path(const String &p_path) {
+
+ export_path = p_path;
+ EditorExport::singleton->save_presets();
+}
+
+String EditorExportPreset::get_export_path() const {
+
+ return export_path;
+}
+
void EditorExportPreset::set_exclude_filter(const String &p_exclude) {
exclude_filter = p_exclude;
@@ -213,6 +224,7 @@ String EditorExportPreset::get_custom_features() const {
EditorExportPreset::EditorExportPreset() {
+ export_path = "";
export_filter = EXPORT_ALL_RESOURCES;
runnable = false;
}
@@ -1034,6 +1046,7 @@ void EditorExport::_save() {
}
config->set_value(section, "include_filter", preset->get_include_filter());
config->set_value(section, "exclude_filter", preset->get_exclude_filter());
+ config->set_value(section, "export_path", preset->get_export_path());
config->set_value(section, "patch_list", preset->get_patches());
String option_section = "preset." + itos(i) + ".options";
@@ -1189,6 +1202,7 @@ void EditorExport::load_config() {
preset->set_include_filter(config->get_value(section, "include_filter"));
preset->set_exclude_filter(config->get_value(section, "exclude_filter"));
+ preset->set_export_path(config->get_value(section, "export_path", ""));
Vector<String> patch_list = config->get_value(section, "patch_list");
@@ -1337,18 +1351,21 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset,
return valid;
}
-String EditorExportPlatformPC::get_binary_extension(const Ref<EditorExportPreset> &p_preset) const {
+List<String> EditorExportPlatformPC::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
for (Map<String, String>::Element *E = extensions.front(); E; E = E->next()) {
if (p_preset->get(E->key())) {
- return extensions[E->key()];
+ list.push_back(extensions[E->key()]);
+ return list;
}
}
if (extensions.has("default")) {
- return extensions["default"];
+ list.push_back(extensions["default"]);
+ return list;
}
- return "";
+ return list;
}
Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
diff --git a/editor/editor_export.h b/editor/editor_export.h
index b4ee5b89e7..380b33cd17 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -57,6 +57,7 @@ private:
ExportFilter export_filter;
String include_filter;
String exclude_filter;
+ String export_path;
String exporter;
Set<String> selected_files;
@@ -114,6 +115,9 @@ public:
void set_custom_features(const String &p_custom_features);
String get_custom_features() const;
+ void set_export_path(const String &p_path);
+ String get_export_path() const;
+
const List<PropertyInfo> &get_properties() const { return properties; }
EditorExportPreset();
@@ -241,7 +245,7 @@ public:
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const = 0;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0;
virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
@@ -388,7 +392,7 @@ public:
virtual Ref<Texture> get_logo() const;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
void set_extension(const String &p_extension, const String &p_feature_key = "default");
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index f425d0a995..b39f910182 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -580,7 +580,7 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p
if (single_item_selected) {
item_menu->add_separator();
Dictionary item_meta = item_list->get_item_metadata(p_item);
- String item_text = item_meta["dir"] ? TTR("Open In File Manager") : TTR("Show In File Manager");
+ String item_text = item_meta["dir"] ? TTR("Open in File Manager") : TTR("Show in File Manager");
item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
}
@@ -605,7 +605,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) {
}
item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5);
item_menu->add_separator();
- item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
item_menu->set_position(item_list->get_global_position() + p_pos);
item_menu->popup();
@@ -1135,14 +1135,10 @@ void EditorFileDialog::_update_drives() {
}
void EditorFileDialog::_favorite_selected(int p_idx) {
-
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
- ERR_FAIL_INDEX(p_idx, favorited.size());
-
- dir_access->change_dir(favorited[p_idx]);
+ dir_access->change_dir(favorites->get_item_metadata(p_idx));
file->set_text("");
- invalidate();
update_dir();
+ invalidate();
_push_history();
}
@@ -1192,7 +1188,7 @@ void EditorFileDialog::_update_favorites() {
bool res = access == ACCESS_RESOURCES;
String current = get_current_dir();
- Ref<Texture> star = get_icon("Favorites", "EditorIcons");
+ Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
favorites->clear();
favorite->set_pressed(false);
@@ -1203,16 +1199,23 @@ void EditorFileDialog::_update_favorites() {
if (cres != res)
continue;
String name = favorited[i];
-
- bool setthis = name == current;
+ bool setthis = false;
if (res && name == "res://") {
+ if (name == current)
+ setthis = true;
name = "/";
+ } else if (name.ends_with("/")) {
+ if (name == current)
+ setthis = true;
+ name = name.substr(0, name.length() - 1);
+ name = name.get_file();
+
+ favorites->add_item(name, folder_icon);
} else {
- name = name.get_file() + "/";
+ continue; // We don't handle favorite files here
}
- favorites->add_item(name, star);
favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]);
if (setthis) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d73bf86f64..a99c9656ba 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1305,11 +1305,6 @@ void EditorFileSystem::_save_late_updated_files() {
}
}
-void EditorFileSystem::_resource_saved(const String &p_path) {
-
- EditorFileSystem::get_singleton()->update_file(p_path);
-}
-
Vector<String> EditorFileSystem::_get_dependencies(const String &p_path) {
List<String> deps;
@@ -1772,7 +1767,6 @@ EditorFileSystem::EditorFileSystem() {
abort_scan = false;
scanning_changes = false;
scanning_changes_done = false;
- ResourceSaver::set_save_callback(_resource_saved);
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da->change_dir("res://.import") != OK) {
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 47077425a1..f6eef2a152 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -204,8 +204,6 @@ class EditorFileSystem : public Node {
bool _update_scan_actions();
- static void _resource_saved(const String &p_path);
-
void _update_extensions();
void _reimport_file(const String &p_file);
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
new file mode 100644
index 0000000000..eec4438f96
--- /dev/null
+++ b/editor/editor_folding.cpp
@@ -0,0 +1,175 @@
+#include "editor_folding.h"
+
+#include "core/os/file_access.h"
+#include "editor_settings.h"
+
+PoolVector<String> EditorFolding::_get_unfolds(const Object *p_object) {
+
+ PoolVector<String> sections;
+ sections.resize(p_object->editor_get_section_folding().size());
+ if (sections.size()) {
+ PoolVector<String>::Write w = sections.write();
+ int idx = 0;
+ for (const Set<String>::Element *E = p_object->editor_get_section_folding().front(); E; E = E->next()) {
+ w[idx++] = E->get();
+ }
+ }
+
+ return sections;
+}
+
+void EditorFolding::save_resource_folding(const RES &p_resource, const String &p_path) {
+ Ref<ConfigFile> config;
+ config.instance();
+ PoolVector<String> unfolds = _get_unfolds(p_resource.ptr());
+ config->set_value("folding", "sections_unfolded", unfolds);
+
+ String path = EditorSettings::get_singleton()->get_project_settings_dir();
+ String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
+ file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file);
+ config->save(file);
+}
+
+void EditorFolding::_set_unfolds(Object *p_object, const PoolVector<String> &p_unfolds) {
+
+ int uc = p_unfolds.size();
+ PoolVector<String>::Read r = p_unfolds.read();
+ p_object->editor_clear_section_folding();
+ for (int i = 0; i < uc; i++) {
+ p_object->editor_set_section_unfold(r[i], true);
+ }
+}
+
+void EditorFolding::load_resource_folding(RES p_resource, const String &p_path) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+
+ String path = EditorSettings::get_singleton()->get_project_settings_dir();
+ String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
+ file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file);
+
+ if (config->load(file) != OK) {
+ return;
+ }
+
+ PoolVector<String> unfolds;
+
+ if (config->has_section_key("folding", "sections_unfolded")) {
+ unfolds = config->get_value("folding", "sections_unfolded");
+ }
+ _set_unfolds(p_resource.ptr(), unfolds);
+}
+
+void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Set<RES> &resources) {
+ if (p_root != p_node) {
+ if (!p_node->get_owner()) {
+ return; //not owned, bye
+ }
+ if (p_node->get_owner() != p_root && !p_root->is_editable_instance(p_node)) {
+ return;
+ }
+ }
+
+ PoolVector<String> unfolds = _get_unfolds(p_node);
+
+ if (unfolds.size()) {
+ p_folds.push_back(p_root->get_path_to(p_node));
+ p_folds.push_back(unfolds);
+ }
+
+ List<PropertyInfo> plist;
+ p_node->get_property_list(&plist);
+ for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
+ if (E->get().type == Variant::OBJECT) {
+ RES res = p_node->get(E->get().name);
+ if (res.is_valid() && !resources.has(res) && res->get_path() != String() && !res->get_path().is_resource_file()) {
+
+ PoolVector<String> res_unfolds = _get_unfolds(res.ptr());
+ resource_folds.push_back(res->get_path());
+ resource_folds.push_back(res_unfolds);
+ resources.insert(res);
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _fill_folds(p_root, p_node->get_child(i), p_folds, resource_folds, resources);
+ }
+}
+void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+
+ Array unfolds, res_unfolds;
+ Set<RES> resources;
+ _fill_folds(p_scene, p_scene, unfolds, res_unfolds, resources);
+
+ config->set_value("folding", "node_unfolds", unfolds);
+ config->set_value("folding", "resource_unfolds", res_unfolds);
+
+ String path = EditorSettings::get_singleton()->get_project_settings_dir();
+ String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
+ file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file);
+ config->save(file);
+}
+void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+
+ String path = EditorSettings::get_singleton()->get_project_settings_dir();
+ String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
+ file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file);
+
+ if (config->load(file) != OK) {
+ return;
+ }
+
+ Array unfolds;
+ if (config->has_section_key("folding", "node_unfolds")) {
+ unfolds = config->get_value("folding", "node_unfolds");
+ }
+ Array res_unfolds;
+ if (config->has_section_key("folding", "resource_unfolds")) {
+ res_unfolds = config->get_value("folding", "resource_unfolds");
+ }
+
+ ERR_FAIL_COND(unfolds.size() & 1);
+ ERR_FAIL_COND(res_unfolds.size() & 1);
+
+ for (int i = 0; i < unfolds.size(); i += 2) {
+ NodePath path = unfolds[i];
+ PoolVector<String> un = unfolds[i + 1];
+ Node *node = p_scene->get_node(path);
+ if (!node) {
+ continue;
+ }
+ _set_unfolds(node, un);
+ }
+
+ for (int i = 0; i < res_unfolds.size(); i += 2) {
+ String path = res_unfolds[i];
+ RES res;
+ if (ResourceCache::has(path)) {
+ res = RES(ResourceCache::get(path));
+ }
+ if (res.is_null()) {
+ continue;
+ }
+
+ PoolVector<String> unfolds = res_unfolds[i + 1];
+ _set_unfolds(res.ptr(), unfolds);
+ }
+}
+
+bool EditorFolding::has_folding_data(const String &p_path) {
+ String path = EditorSettings::get_singleton()->get_project_settings_dir();
+ String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
+ file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file);
+ return FileAccess::exists(file);
+}
+
+EditorFolding::EditorFolding() {
+}
diff --git a/editor/editor_folding.h b/editor/editor_folding.h
new file mode 100644
index 0000000000..cfd4b5466d
--- /dev/null
+++ b/editor/editor_folding.h
@@ -0,0 +1,25 @@
+#ifndef EDITOR_FOLDING_H
+#define EDITOR_FOLDING_H
+
+#include "scene/main/node.h"
+
+class EditorFolding {
+
+ PoolVector<String> _get_unfolds(const Object *p_object);
+ void _set_unfolds(Object *p_object, const PoolVector<String> &p_unfolds);
+
+ void _fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Set<RES> &resources);
+
+public:
+ void save_resource_folding(const RES &p_resource, const String &p_path);
+ void load_resource_folding(RES p_resource, const String &p_path);
+
+ void save_scene_folding(const Node *p_scene, const String &p_path);
+ void load_scene_folding(Node *p_scene, const String &p_path);
+
+ bool has_folding_data(const String &p_path);
+
+ EditorFolding();
+};
+
+#endif // EDITOR_FOLDING_H
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 80dd5aa114..3ee8d9c6c5 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -36,7 +36,7 @@
#include "editor_node.h"
#include "editor_settings.h"
-#define CONTRIBUTE_URL "http://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html"
+#define CONTRIBUTE_URL "https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html"
#define CONTRIBUTE2_URL "https://github.com/godotengine/godot-docs"
#define REQUEST_URL "https://github.com/godotengine/godot-docs/issues/new"
@@ -252,6 +252,8 @@ void EditorHelpSearch::_notification(int p_what) {
connect("confirmed", this, "_confirmed");
_update_search();
+ } else if (p_what == NOTIFICATION_EXIT_TREE) {
+ disconnect("confirmed", this, "_confirmed");
} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
if (is_visible_in_tree()) {
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a90f15004a..d6f337cc20 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -374,14 +374,24 @@ bool EditorProperty::_get_instanced_node_original_property(const StringName &p_p
node = node->get_owner();
}
+ if (!found) {
+ //if not found, try default class value
+ Variant attempt = ClassDB::class_get_default_property_value(object->get_class_name(), property);
+ if (attempt.get_type() != Variant::NIL) {
+ found = true;
+ value = attempt;
+ }
+ }
+
return found;
}
-bool EditorProperty::_is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage) {
+bool EditorProperty::_is_property_different(const Variant &p_current, const Variant &p_orig) {
// this is a pretty difficult function, because a property may not be saved but may have
// the flag to not save if one or if zero
+ //make sure there is an actual state
{
Node *node = Object::cast_to<Node>(object);
if (!node)
@@ -415,15 +425,6 @@ bool EditorProperty::_is_property_different(const Variant &p_current, const Vari
return false; //pointless to check if we are not comparing against anything.
}
- if (p_orig.get_type() == Variant::NIL) {
- // not found (was not saved)
- // check if it was not saved due to being zero or one
- if (p_current.is_zero() && property_usage & PROPERTY_USAGE_STORE_IF_NONZERO)
- return false;
- if (p_current.is_one() && property_usage & PROPERTY_USAGE_STORE_IF_NONONE)
- return false;
- }
-
if (p_current.get_type() == Variant::REAL && p_orig.get_type() == Variant::REAL) {
float a = p_current;
float b = p_orig;
@@ -434,23 +435,6 @@ bool EditorProperty::_is_property_different(const Variant &p_current, const Vari
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));
}
-bool EditorProperty::_is_instanced_node_with_original_property_different() {
-
- bool mbi = _might_be_in_instance();
- if (mbi) {
- Variant vorig;
- int usage = property_usage & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO);
- if (_get_instanced_node_original_property(property, vorig) || usage) {
- Variant v = object->get(property);
-
- if (_is_property_different(v, vorig, usage)) {
- return true;
- }
- }
- }
- return false;
-}
-
void EditorProperty::update_reload_status() {
if (property == StringName())
@@ -458,8 +442,22 @@ void EditorProperty::update_reload_status() {
bool has_reload = false;
- if (_is_instanced_node_with_original_property_different()) {
- has_reload = true;
+ if (_might_be_in_instance()) {
+ //check for difference including instantiation
+ Variant vorig;
+ if (_get_instanced_node_original_property(property, vorig)) {
+ Variant v = object->get(property);
+
+ if (_is_property_different(v, vorig)) {
+ has_reload = true;
+ }
+ }
+ } else {
+ //check for difference against default class value instead
+ Variant default_value = ClassDB::class_get_default_property_value(object->get_class_name(), property);
+ if (default_value != Variant() && default_value != object->get(property)) {
+ has_reload = true;
+ }
}
if (object->call("property_can_revert", property).operator bool()) {
@@ -628,7 +626,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
}
if (keying_rect.has_point(mb->get_position())) {
- emit_signal("property_keyed", property);
+ emit_signal("property_keyed", property, use_keying_next());
if (use_keying_next()) {
call_deferred("emit_signal", "property_changed", property, object->get(property).operator int64_t() + 1);
@@ -651,6 +649,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
Variant rev = object->call("property_get_revert", property);
emit_signal("property_changed", property, rev);
update_property();
+ return;
}
if (!object->get_script().is_null()) {
@@ -659,8 +658,16 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
if (scr->get_property_default_value(property, orig_value)) {
emit_signal("property_changed", property, orig_value);
update_property();
+ return;
}
}
+
+ Variant default_value = ClassDB::class_get_default_property_value(object->get_class_name(), property);
+ if (default_value != Variant()) {
+ emit_signal("property_changed", property, default_value);
+ update_property();
+ return;
+ }
}
if (check_rect.has_point(mb->get_position())) {
checked = !checked;
@@ -738,9 +745,9 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
- help_bit->get_rich_text()->set_fixed_size_to_width(300);
+ help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
- String text = TTR("Property: ") + "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
+ String text = TTR("Property:") + " [u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
text += p_text.get_slice("::", 1).strip_edges();
help_bit->set_text(text);
help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
@@ -960,7 +967,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
- help_bit->get_rich_text()->set_fixed_size_to_width(300);
+ help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
String text = "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
text += p_text.get_slice("::", 1).strip_edges();
@@ -1082,10 +1089,8 @@ void EditorInspectorSection::_notification(int p_what) {
Color color = get_color("font_color", "Tree");
draw_string(font, Point2(hs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width);
- int ofs = 0;
if (arrow.is_valid()) {
draw_texture(arrow, Point2(get_size().width - arrow->get_width(), (h - arrow->get_height()) / 2).floor());
- ofs += hs + arrow->get_width();
}
}
}
@@ -1370,6 +1375,28 @@ void EditorInspector::update_tree() {
// TreeItem *current_category = NULL;
+ bool unfold_if_edited = false;
+
+ if (use_folding && auto_unfold_edited && get_tree()->get_edited_scene_root()) {
+ String path;
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ path = get_tree()->get_edited_scene_root()->get_filename();
+ }
+ Resource *res = Object::cast_to<Resource>(object);
+ if (res) {
+ if (res->get_path().is_resource_file()) {
+ path = res->get_path();
+ } else if (res->get_path().begins_with("res://")) { //internal resource
+ path = get_tree()->get_edited_scene_root()->get_filename();
+ }
+ }
+
+ if (!EditorNode::get_singleton()->get_editor_folding().has_folding_data(path)) {
+ unfold_if_edited = true;
+ }
+ }
+
String filter = search_box ? search_box->get_text() : "";
String group;
String group_base;
@@ -1380,6 +1407,8 @@ void EditorInspector::update_tree() {
object->get_property_list(&plist, true);
HashMap<String, VBoxContainer *> item_path;
+ Map<VBoxContainer *, EditorInspectorSection *> section_map;
+
item_path[""] = main_vbox;
Color sscolor = get_color("prop_subsection", "Editor");
@@ -1542,7 +1571,9 @@ void EditorInspector::update_tree() {
c.a /= level;
section->setup(acc_path, path_name, object, c, use_folding);
- item_path[acc_path] = section->get_vbox();
+ VBoxContainer *vb = section->get_vbox();
+ item_path[acc_path] = vb;
+ section_map[vb] = section;
}
current_vbox = item_path[acc_path];
level = (MIN(level + 1, 4));
@@ -1685,6 +1716,13 @@ void EditorInspector::update_tree() {
if (current_selected && ep->property == current_selected) {
ep->select(current_focusable);
}
+
+ if (unfold_if_edited && ep->can_revert_to_default()) {
+ //if edited and there is a parent section, unfold it.
+ if (current_vbox && section_map.has(current_vbox)) {
+ section_map[current_vbox]->unfold();
+ }
+ }
}
}
@@ -1992,20 +2030,20 @@ void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array
changing--;
}
-void EditorInspector::_property_keyed(const String &p_path) {
+void EditorInspector::_property_keyed(const String &p_path, bool p_advance) {
if (!object)
return;
- emit_signal("property_keyed", p_path, object->get(p_path), true); //second param is deprecated
+ emit_signal("property_keyed", p_path, object->get(p_path), p_advance); //second param is deprecated
}
-void EditorInspector::_property_keyed_with_value(const String &p_path, const Variant &p_value) {
+void EditorInspector::_property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance) {
if (!object)
return;
- emit_signal("property_keyed", p_path, p_value, false); //second param is deprecated
+ emit_signal("property_keyed", p_path, p_value, p_advance); //second param is deprecated
}
void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
@@ -2181,6 +2219,10 @@ String EditorInspector::get_object_class() const {
return object_class;
}
+void EditorInspector::set_auto_unfold_edited(bool p_enable) {
+ auto_unfold_edited = p_enable;
+}
+
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed, DEFVAL(false));
@@ -2205,6 +2247,7 @@ void EditorInspector::_bind_methods() {
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "res"), PropertyInfo(Variant::STRING, "prop")));
ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("property_edited", PropertyInfo(Variant::STRING, "property")));
+ ADD_SIGNAL(MethodInfo("property_toggled", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::BOOL, "checked")));
ADD_SIGNAL(MethodInfo("restart_requested"));
}
@@ -2236,6 +2279,7 @@ EditorInspector::EditorInspector() {
set_process(true);
property_focusable = -1;
use_sub_inspector_bg = false;
+ auto_unfold_edited = false;
get_v_scrollbar()->connect("value_changed", this, "_vscroll_changed");
update_scroll_request = -1;
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index dccbdb9a73..00841178bd 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -71,8 +71,7 @@ private:
bool draw_top_bg;
bool _might_be_in_instance();
- bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage);
- bool _is_instanced_node_with_original_property_different();
+ bool _is_property_different(const Variant &p_current, const Variant &p_orig);
bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value);
void _focusable_focused(int p_index);
@@ -152,6 +151,8 @@ public:
void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; }
+ bool can_revert_to_default() const { return can_revert; }
+
EditorProperty();
};
@@ -271,6 +272,7 @@ class EditorInspector : public ScrollContainer {
bool read_only;
bool keying;
bool use_sub_inspector_bg;
+ bool auto_unfold_edited;
float refresh_countdown;
bool update_tree_pending;
@@ -293,8 +295,8 @@ class EditorInspector : public ScrollContainer {
void _property_changed(const String &p_path, const Variant &p_value, bool changing = false);
void _property_changed_update_all(const String &p_path, const Variant &p_value);
void _multiple_properties_changed(Vector<String> p_paths, Array p_values);
- void _property_keyed(const String &p_path);
- void _property_keyed_with_value(const String &p_path, const Variant &p_value);
+ void _property_keyed(const String &p_path, bool p_advance);
+ void _property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance);
void _property_checked(const String &p_path, bool p_checked);
@@ -365,6 +367,7 @@ public:
String get_object_class() const;
void set_use_sub_inspector_bg(bool p_enable);
+ void set_auto_unfold_edited(bool p_enable);
EditorInspector();
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 18dd85617b..dbbf5d08b8 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -574,13 +574,29 @@ void EditorNode::_editor_select_prev() {
_editor_select(editor);
}
-Error EditorNode::load_resource(const String &p_scene) {
+Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_deps) {
- RES res = ResourceLoader::load(p_scene);
+ dependency_errors.clear();
+
+ Error err;
+ RES res = ResourceLoader::load(p_resource, "", false, &err);
ERR_FAIL_COND_V(!res.is_valid(), ERR_CANT_OPEN);
- inspector_dock->edit_resource(res);
+ if (!p_ignore_broken_deps && dependency_errors.has(p_resource)) {
+
+ //current_option = -1;
+ Vector<String> errors;
+ for (Set<String>::Element *E = dependency_errors[p_resource].front(); E; E = E->next()) {
+ errors.push_back(E->get());
+ }
+ dependency_error->show(DependencyErrorDialog::MODE_RESOURCE, p_resource, errors);
+ dependency_errors.erase(p_resource);
+
+ return ERR_FILE_MISSING_DEPENDENCIES;
+ }
+
+ inspector_dock->edit_resource(res);
return OK;
}
@@ -1061,6 +1077,9 @@ void EditorNode::_save_scene(String p_file, int idx) {
set_current_version(editor_data.get_undo_redo().get_version());
else
editor_data.set_edited_scene_version(0, idx);
+
+ editor_folding.save_scene_folding(scene, p_file);
+
_update_title();
_update_scene_tabs();
} else {
@@ -2251,7 +2270,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
emit_signal("request_help_search", "");
} break;
case HELP_DOCS: {
- OS::get_singleton()->shell_open("http://docs.godotengine.org/");
+ OS::get_singleton()->shell_open("https://docs.godotengine.org/");
} break;
case HELP_QA: {
OS::get_singleton()->shell_open("https://godotengine.org/qa/");
@@ -2842,7 +2861,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
errors.push_back(E->get());
}
- dependency_error->show(lpath, errors);
+ dependency_error->show(DependencyErrorDialog::MODE_SCENE, lpath, errors);
opening_prev = false;
if (prev != -1) {
@@ -2907,6 +2926,8 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
_update_scene_tabs();
_add_to_recent_scenes(lpath);
+ editor_folding.load_scene_folding(new_scene, lpath);
+
prev_scene->set_disabled(previous_scenes.size() == 0);
opening_prev = false;
@@ -3129,34 +3150,33 @@ Ref<Texture> EditorNode::get_object_icon(const Object *p_object, const String &p
script = p_object;
}
- StringName name;
- String icon_path;
if (script.is_valid()) {
- name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
- icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
- name = script->get_instance_base_type();
+ StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
+ if (icon_path.length())
+ return ResourceLoader::load(icon_path);
+
+ // should probably be deprecated in 4.x
+ StringName base = script->get_instance_base_type();
+ if (base != StringName()) {
+ const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
+ for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
+ const Vector<EditorData::CustomType> &ct = E->value();
+ for (int i = 0; i < ct.size(); ++i) {
+ if (ct[i].name == base && ct[i].icon.is_valid()) {
+ return ct[i].icon;
+ }
+ }
+ }
+ }
}
- if (gui_base->has_icon(p_object->get_class(), "EditorIcons"))
- return gui_base->get_icon(p_object->get_class(), "EditorIcons");
-
- if (icon_path.length())
- return ResourceLoader::load(icon_path);
-
+ // should probably be deprecated in 4.x
if (p_object->has_meta("_editor_icon"))
return p_object->get_meta("_editor_icon");
- if (name != StringName()) {
- const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
- for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
- const Vector<EditorData::CustomType> &ct = E->value();
- for (int i = 0; i < ct.size(); ++i) {
- if (ct[i].name == name && ct[i].icon.is_valid()) {
- return ct[i].icon;
- }
- }
- }
- }
+ if (gui_base->has_icon(p_object->get_class(), "EditorIcons"))
+ return gui_base->get_icon(p_object->get_class(), "EditorIcons");
if (p_fallback.length())
return gui_base->get_icon(p_fallback, "EditorIcons");
@@ -3892,7 +3912,9 @@ void EditorNode::_scene_tab_hover(int p_tab) {
tab_preview_panel->hide();
} else {
String path = editor_data.get_scene_path(p_tab);
- EditorResourcePreview::get_singleton()->queue_resource_preview(path, this, "_thumbnail_done", p_tab);
+ if (path != String()) {
+ EditorResourcePreview::get_singleton()->queue_resource_preview(path, this, "_thumbnail_done", p_tab);
+ }
}
}
@@ -3928,7 +3950,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_all_scenes"), FILE_SAVE_ALL_SCENES);
if (scene_tabs->get_hovered_tab() >= 0) {
scene_tabs_context_menu->add_separator();
- scene_tabs_context_menu->add_item(TTR("Show in filesystem"), FILE_SHOW_IN_FILESYSTEM);
+ scene_tabs_context_menu->add_item(TTR("Show in FileSystem"), FILE_SHOW_IN_FILESYSTEM);
scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE);
scene_tabs_context_menu->add_item(TTR("Close Tab"), FILE_CLOSE);
}
@@ -4542,6 +4564,19 @@ void EditorNode::_video_driver_selected(int p_which) {
_update_video_driver_color();
}
+void EditorNode::_resource_saved(RES p_resource, const String &p_path) {
+ if (EditorFileSystem::get_singleton()) {
+ EditorFileSystem::get_singleton()->update_file(p_path);
+ }
+
+ singleton->editor_folding.save_resource_folding(p_resource, p_path);
+}
+
+void EditorNode::_resource_loaded(RES p_resource, const String &p_path) {
+
+ singleton->editor_folding.load_resource_folding(p_resource, p_path);
+}
+
void EditorNode::_bind_methods() {
ClassDB::bind_method("_menu_option", &EditorNode::_menu_option);
@@ -4842,6 +4877,7 @@ EditorNode::EditorNode() {
EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true);
EDITOR_DEF_RST("interface/inspector/capitalize_properties", true);
EDITOR_DEF_RST("interface/inspector/disable_folding", false);
+ EDITOR_DEF_RST("interface/inspector/auto_unfold_edited", true);
EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
@@ -4981,7 +5017,7 @@ EditorNode::EditorNode() {
dock_select_rect_over = -1;
dock_popup_selected = -1;
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- dock_slot[i]->set_custom_minimum_size(Size2(230, 220) * EDSCALE);
+ dock_slot[i]->set_custom_minimum_size(Size2(170, 0) * EDSCALE);
dock_slot[i]->set_v_size_flags(Control::SIZE_EXPAND_FILL);
dock_slot[i]->set_popup(dock_select_popup);
dock_slot[i]->connect("pre_popup_pressed", this, "_dock_pre_popup", varray(i));
@@ -5158,7 +5194,7 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/save_scene", TTR("Save Scene"), KEY_MASK_CMD + KEY_S), FILE_SAVE_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/save_scene_as", TTR("Save Scene As..."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_S), FILE_SAVE_AS_SCENE);
- p->add_shortcut(ED_SHORTCUT("editor/save_all_scenes", TTR("Save all Scenes"), KEY_MASK_ALT + KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_S), FILE_SAVE_ALL_SCENES);
+ p->add_shortcut(ED_SHORTCUT("editor/save_all_scenes", TTR("Save All Scenes"), KEY_MASK_ALT + KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_S), FILE_SAVE_ALL_SCENES);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/close_scene", TTR("Close Scene"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_W), FILE_CLOSE);
p->add_separator();
@@ -5249,10 +5285,13 @@ EditorNode::EditorNode() {
p->add_check_item(TTR("Visible Navigation"), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
p->add_separator();
+ //those are now on by default, since they are harmless
p->add_check_item(TTR("Sync Scene Changes"), RUN_LIVE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
+ p->set_item_checked(p->get_item_count() - 1, true);
p->add_check_item(TTR("Sync Script Changes"), RUN_RELOAD_SCRIPTS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
+ p->set_item_checked(p->get_item_count() - 1, true);
p->connect("id_pressed", this, "_menu_option");
menu_hb->add_spacer();
@@ -5497,8 +5536,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(40 * EDSCALE);
- main_hsplit->set_split_offset(-40 * EDSCALE);
+ left_r_hsplit->set_split_offset(70 * EDSCALE);
+ main_hsplit->set_split_offset(-70 * EDSCALE);
// Define corresponding default layout
@@ -5513,8 +5552,8 @@ EditorNode::EditorNode() {
for (int i = 0; i < vsplits.size(); i++)
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", 40 * EDSCALE);
- default_layout->set_value(docks_section, "dock_hsplit_3", -40 * EDSCALE);
+ 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_4", 0);
_update_layouts_menu();
@@ -5827,6 +5866,9 @@ EditorNode::EditorNode() {
print_handler.userdata = this;
add_print_handler(&print_handler);
+ ResourceSaver::set_save_callback(_resource_saved);
+ ResourceLoader::set_load_callback(_resource_loaded);
+
#ifdef OSX_ENABLED
ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_ALT | KEY_1);
ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_ALT | KEY_2);
@@ -5855,6 +5897,7 @@ EditorNode::~EditorNode() {
memdelete(editor_plugins_force_input_forwarding);
memdelete(file_server);
memdelete(progress_hb);
+
EditorSettings::destroy();
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 0096748ed1..b828a4d7d5 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -38,6 +38,7 @@
#include "editor/editor_about.h"
#include "editor/editor_data.h"
#include "editor/editor_export.h"
+#include "editor/editor_folding.h"
#include "editor/editor_inspector.h"
#include "editor/editor_log.h"
#include "editor/editor_name_dialog.h"
@@ -385,6 +386,7 @@ private:
EditorSelection *editor_selection;
ProjectExportDialog *project_export;
EditorResourcePreview *resource_preview;
+ EditorFolding editor_folding;
EditorFileServer *file_server;
@@ -600,6 +602,9 @@ private:
PrintHandlerList print_handler;
static void _print_handler(void *p_this, const String &p_string, bool p_error);
+ static void _resource_saved(RES p_resource, const String &p_path);
+ static void _resource_loaded(RES p_resource, const String &p_path);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -682,7 +687,7 @@ public:
void fix_dependencies(const String &p_for_file);
void clear_scene() { _cleanup_scene(); }
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false);
- Error load_resource(const String &p_scene);
+ Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
bool is_scene_open(const String &p_path);
@@ -690,6 +695,7 @@ public:
void set_current_scene(int p_idx);
static EditorData &get_editor_data() { return singleton->editor_data; }
+ static EditorFolding &get_editor_folding() { return singleton->editor_folding; }
EditorHistory *get_editor_history() { return &editor_history; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index dd3a8aa307..86b2db877e 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -475,7 +475,6 @@ void EditorPlugin::set_force_draw_over_forwarding_enabled() {
}
void EditorPlugin::notify_scene_changed(const Node *scn_root) {
- if (scn_root == NULL) return;
emit_signal("scene_changed", scn_root);
}
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 96d482f47e..b68ec97406 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1802,8 +1802,13 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
NodePath path = p_path;
Node *base_node = Object::cast_to<Node>(get_edited_object());
- if (base_node == NULL && get_edited_object()->has_method("get_root_path")) {
- base_node = get_edited_object()->call("get_root_path");
+ if (base_node == NULL) {
+ if (Object::cast_to<Resource>(get_edited_object())) {
+ Node *to_node = get_node(p_path);
+ path = get_tree()->get_edited_scene_root()->get_path_to(to_node);
+ } else if (get_edited_object()->has_method("get_root_path")) {
+ base_node = get_edited_object()->call("get_root_path");
+ }
}
if (base_node) { // for AnimationTrackKeyEdit
path = base_node->get_path().rel_path_to(p_path);
@@ -1860,6 +1865,12 @@ void EditorPropertyNodePath::update_property() {
Node *target_node = base_node->get_node(p);
ERR_FAIL_COND(!target_node);
+ if (String(target_node->get_name()).find("@") != -1) {
+ assign->set_icon(Ref<Texture>());
+ assign->set_text(p);
+ return;
+ }
+
assign->set_text(target_node->get_name());
assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
}
@@ -2210,7 +2221,7 @@ void EditorPropertyResource::_update_menu() {
RES r = res;
if (r.is_valid() && r->get_path().is_resource_file()) {
menu->add_separator();
- menu->add_item(TTR("Show in File System"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
+ menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
}
} else {
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 1e97920f7e..34c273fbae 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -357,7 +357,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/theme/color_theme", "Adaptive");
hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom");
- _initial_set("text_editor/theme/line_spacing", 4);
+ _initial_set("text_editor/theme/line_spacing", 6);
_initial_set("text_editor/theme/selection_color", Color::html("40808080"));
_load_default_text_editor_theme();
@@ -410,7 +410,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/completion/add_type_hints", false);
_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);
- _initial_set("docks/scene_tree/draw_relationship_lines", false);
+ _initial_set("docks/scene_tree/draw_relationship_lines", true);
_initial_set("docks/scene_tree/relationship_line_color", Color::html("464646"));
_initial_set("editors/grid_map/pick_distance", 5000.0);
diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp
index 27fe716855..306f047860 100644
--- a/editor/fileserver/editor_file_server.cpp
+++ b/editor/fileserver/editor_file_server.cpp
@@ -150,13 +150,13 @@ void EditorFileServer::_subthread_start(void *s) {
s.parse_utf8(fileutf8.ptr());
if (cmd == FileAccessNetwork::COMMAND_FILE_EXISTS) {
- DEBUG_PRINT("FILE EXISTS: " + s);
+ print_verbose("FILE EXISTS: " + s);
}
if (cmd == FileAccessNetwork::COMMAND_GET_MODTIME) {
- DEBUG_PRINT("MOD TIME: " + s);
+ print_verbose("MOD TIME: " + s);
}
if (cmd == FileAccessNetwork::COMMAND_OPEN_FILE) {
- DEBUG_PRINT("OPEN: " + s);
+ print_verbose("OPEN: " + s);
}
if (!s.begins_with("res://")) {
@@ -243,7 +243,7 @@ void EditorFileServer::_subthread_start(void *s) {
int read = cd->files[id]->get_buffer(buf.ptrw(), blocklen);
ERR_CONTINUE(read < 0);
- DEBUG_PRINT("GET BLOCK - offset: " + itos(offset) + ", blocklen: " + itos(blocklen));
+ print_verbose("GET BLOCK - offset: " + itos(offset) + ", blocklen: " + itos(blocklen));
//not found, continue
encode_uint32(id, buf4);
@@ -259,7 +259,7 @@ void EditorFileServer::_subthread_start(void *s) {
} break;
case FileAccessNetwork::COMMAND_CLOSE: {
- DEBUG_PRINT("CLOSED");
+ print_verbose("CLOSED");
ERR_CONTINUE(!cd->files.has(id));
memdelete(cd->files[id]);
cd->files.erase(id);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 4d386c1af6..828e608fa4 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -225,16 +225,11 @@ void FileSystemDock::_update_tree(const Vector<String> p_uncollapsed_paths, bool
updating_tree = false;
}
-void FileSystemDock::_update_display_mode() {
+void FileSystemDock::_update_display_mode(bool p_force) {
// Compute the new display mode
- DisplayMode new_display_mode;
- if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) {
- new_display_mode = file_list_view ? DISPLAY_MODE_FILE_LIST_ONLY : DISPLAY_MODE_TREE_ONLY;
- } else {
- new_display_mode = DISPLAY_MODE_SPLIT;
- }
+ DisplayMode new_display_mode = (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) ? DISPLAY_MODE_TREE_ONLY : DISPLAY_MODE_SPLIT;
- if (new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) {
+ if (p_force || new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) {
display_mode = new_display_mode;
old_display_mode_setting = display_mode_setting;
button_toggle_display_mode->set_pressed(display_mode_setting == DISPLAY_MODE_SETTING_SPLIT ? true : false);
@@ -252,19 +247,9 @@ void FileSystemDock::_update_display_mode() {
file_list_vb->hide();
break;
- case DISPLAY_MODE_FILE_LIST_ONLY:
- tree->hide();
- tree_search_box->hide();
- button_tree->show();
-
- file_list_vb->show();
- _update_file_list(true);
- break;
-
case DISPLAY_MODE_SPLIT:
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- button_tree->hide();
tree->ensure_cursor_is_visible();
tree_search_box->hide();
_update_tree(_compute_uncollapsed_paths());
@@ -295,7 +280,6 @@ void FileSystemDock::_notification(int p_what) {
String ei = "EditorIcons";
button_reload->set_icon(get_icon("Reload", ei));
button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
- button_tree->set_icon(get_icon("Filesystem", ei));
_update_file_list_display_mode_button();
button_file_list_display_mode->connect("pressed", this, "_change_file_display");
@@ -312,7 +296,6 @@ void FileSystemDock::_notification(int p_what) {
file_list_popup->connect("id_pressed", this, "_file_list_rmb_option");
tree_popup->connect("id_pressed", this, "_tree_rmb_option");
- button_tree->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED);
current_path->connect("text_entered", this, "navigate_to_path");
display_mode_setting = DisplayModeSetting(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
@@ -352,14 +335,23 @@ void FileSystemDock::_notification(int p_what) {
tree->set_drop_mode_flags(0);
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ if (is_visible_in_tree()) {
+ _update_display_mode(true);
+ }
+ } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update icons
String ei = "EditorIcons";
button_reload->set_icon(get_icon("Reload", ei));
button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
- button_tree->set_icon(get_icon("Filesystem", ei));
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
+ if (button_file_list_display_mode->is_pressed()) {
+ button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
+ } else {
+ button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
+ }
tree_search_box->set_right_icon(get_icon("Search", ei));
tree_search_box->set_clear_button_enabled(true);
@@ -412,7 +404,7 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
TreeItem *favorites_item = tree->get_root()->get_children();
- if (selected->get_parent() == favorites_item) {
+ if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed
path = "Favorites";
} else {
@@ -474,20 +466,9 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
_set_current_path_text(path);
_push_to_history();
+ _update_tree(_compute_uncollapsed_paths());
if (display_mode == DISPLAY_MODE_SPLIT) {
- if (path.ends_with("/") || path == "Favorites") {
- _go_to_file_list();
- }
- _update_tree(_compute_uncollapsed_paths());
_update_file_list(false);
- } else if (display_mode == DISPLAY_MODE_TREE_ONLY) {
- if (path.ends_with("/") || path == "Favorites") {
- _go_to_file_list();
- } else {
- _update_tree(_compute_uncollapsed_paths());
- }
- } else { // DISPLAY_MODE_FILE_LIST_ONLY
- _update_file_list(true);
}
String file_name = p_path.get_file();
@@ -701,7 +682,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
_search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 128);
} else {
- if ((display_mode == DISPLAY_MODE_FILE_LIST_ONLY || display_mode == DISPLAY_MODE_TREE_ONLY) || always_show_folders) {
+ if (display_mode == DISPLAY_MODE_TREE_ONLY || always_show_folders) {
// Display folders in the list
if (directory != "res://") {
@@ -829,35 +810,16 @@ void FileSystemDock::_tree_activate_file() {
TreeItem *selected = tree->get_selected();
if (selected) {
call_deferred("_select_file", selected->get_metadata(0));
- }
-}
-void FileSystemDock::_file_list_activate_file(int p_idx) {
- _select_file(files->get_item_metadata(p_idx));
-}
-
-void FileSystemDock::_go_to_file_list() {
-
- if (display_mode == DISPLAY_MODE_TREE_ONLY) {
-
- file_list_view = true;
- _update_display_mode();
- } else {
- TreeItem *selected = tree->get_selected();
- if (selected) {
+ if (path.ends_with("/") || path == "Favorites") {
bool collapsed = selected->is_collapsed();
selected->set_collapsed(!collapsed);
}
- _update_file_list(false);
}
}
-void FileSystemDock::_go_to_tree() {
-
- file_list_view = false;
- tree->grab_focus();
- _update_display_mode();
- tree->ensure_cursor_is_visible();
+void FileSystemDock::_file_list_activate_file(int p_idx) {
+ _select_file(files->get_item_metadata(p_idx));
}
void FileSystemDock::_preview_invalidated(const String &p_path) {
@@ -1172,6 +1134,23 @@ void FileSystemDock::_update_project_settings_after_move(const Map<String, Strin
}
};
}
+
+ // Also search for the file in autoload, as they are stored differently from normal files.
+ List<PropertyInfo> property_list;
+ ProjectSettings::get_singleton()->get_property_list(&property_list);
+ for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ if (E->get().name.begins_with("autoload/")) {
+ // If the autoload resource paths has a leading "*", it indicates that it is a Singleton,
+ // so we have to handle both cases when updating.
+ String autoload = GLOBAL_GET(E->get().name);
+ String autoload_singleton = autoload.substr(1, autoload.length());
+ if (p_renames.has(autoload)) {
+ ProjectSettings::get_singleton()->set_setting(E->get().name, p_renames[autoload]);
+ } else if (autoload.begins_with("*") && p_renames.has(autoload_singleton)) {
+ ProjectSettings::get_singleton()->set_setting(E->get().name, "*" + p_renames[autoload_singleton]);
+ }
+ }
+ }
ProjectSettings::get_singleton()->save();
}
@@ -1200,7 +1179,8 @@ void FileSystemDock::_make_dir_confirm() {
if (dir_name.length() == 0) {
EditorNode::get_singleton()->show_warning(TTR("No name provided"));
return;
- } else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
+ } else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.find("*") != -1 ||
+ dir_name.find("|") != -1 || dir_name.find(">") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters"));
return;
}
@@ -1623,7 +1603,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> p_selected)
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- make_script_dialog_text->config("Node", fpath + "new_script.gd", false);
+ make_script_dialog_text->config("Node", fpath.plus_file("new_script.gd"), false);
make_script_dialog_text->popup_centered(Size2(300, 300) * EDSCALE);
} break;
@@ -1676,9 +1656,6 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
tree_search_box->set_text(searched_string);
switch (display_mode) {
- case DISPLAY_MODE_FILE_LIST_ONLY: {
- _update_file_list(false);
- } break;
case DISPLAY_MODE_TREE_ONLY: {
_update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>());
} break;
@@ -1707,12 +1684,6 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) {
void FileSystemDock::focus_on_filter() {
- if (display_mode == DISPLAY_MODE_FILE_LIST_ONLY && tree->is_visible()) {
- // Tree mode, switch to files list with search box
- tree->hide();
- file_list_vb->show();
- }
-
file_list_search_box->grab_focus();
}
@@ -1997,7 +1968,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
return;
}
-void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths) {
+void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options) {
// Add options for files and folders
ERR_FAIL_COND(p_paths.empty())
@@ -2084,12 +2055,14 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (p_paths.size() == 1) {
p_popup->add_separator();
- p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
- p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
- p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
+ if (p_display_path_dependent_options) {
+ p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
+ }
String fpath = p_paths[0];
- String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager");
+ String item_text = fpath.ends_with("/") ? TTR("Open in File Manager") : TTR("Show in File Manager");
p_popup->add_item(item_text, FILE_SHOW_IN_EXPLORER);
}
}
@@ -2100,8 +2073,8 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
if (paths.size() == 1) {
if (paths[0].ends_with("/")) {
- tree_popup->add_item(TTR("Expand all"), FOLDER_EXPAND_ALL);
- tree_popup->add_item(TTR("Collapse all"), FOLDER_COLLAPSE_ALL);
+ tree_popup->add_item(TTR("Expand All"), FOLDER_EXPAND_ALL);
+ tree_popup->add_item(TTR("Collapse All"), FOLDER_COLLAPSE_ALL);
tree_popup->add_separator();
}
}
@@ -2133,7 +2106,7 @@ void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) {
if (!paths.empty()) {
file_list_popup->clear();
file_list_popup->set_size(Size2(1, 1));
- _file_and_folders_fill_popup(file_list_popup, paths);
+ _file_and_folders_fill_popup(file_list_popup, paths, searched_string.length() == 0);
file_list_popup->set_position(files->get_global_position() + p_pos);
file_list_popup->popup();
}
@@ -2141,13 +2114,16 @@ void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) {
void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) {
// Right click on empty space for file list
+ if (searched_string.length() > 0)
+ return;
+
file_list_popup->clear();
file_list_popup->set_size(Size2(1, 1));
file_list_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
file_list_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
file_list_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
- file_list_popup->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
+ file_list_popup->add_item(TTR("Show in File Manager"), FILE_SHOW_IN_EXPLORER);
file_list_popup->set_position(files->get_global_position() + p_pos);
file_list_popup->popup();
}
@@ -2302,7 +2278,6 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_file_list_activate_file"), &FileSystemDock::_file_list_activate_file);
ClassDB::bind_method(D_METHOD("_tree_activate_file"), &FileSystemDock::_tree_activate_file);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
- ClassDB::bind_method(D_METHOD("_go_to_tree"), &FileSystemDock::_go_to_tree);
ClassDB::bind_method(D_METHOD("navigate_to_path"), &FileSystemDock::navigate_to_path);
ClassDB::bind_method(D_METHOD("_change_file_display"), &FileSystemDock::_change_file_display);
ClassDB::bind_method(D_METHOD("_fw_history"), &FileSystemDock::_fw_history);
@@ -2398,7 +2373,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
/*
button_open = memnew( Button );
button_open->set_flat(true);
- button_open->connect("pressed",this,"_go_to_file_list");
+ button_open->connect("pressed",this,"_tree_toggle_collapsed");
toolbar_hbc->add_child(button_open);
button_open->hide();
button_open->set_focus_mode(FOCUS_NONE);
@@ -2448,11 +2423,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
path_hb = memnew(HBoxContainer);
file_list_vb->add_child(path_hb);
- button_tree = memnew(ToolButton);
- button_tree->set_tooltip(TTR("Enter tree-view."));
- button_tree->hide();
- path_hb->add_child(button_tree);
-
file_list_search_box = memnew(LineEdit);
file_list_search_box->set_h_size_flags(SIZE_EXPAND_FILL);
file_list_search_box->set_placeholder(TTR("Search files"));
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index d964515572..df6fa5f9d2 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -73,7 +73,6 @@ private:
enum DisplayMode {
DISPLAY_MODE_TREE_ONLY,
- DISPLAY_MODE_FILE_LIST_ONLY,
DISPLAY_MODE_SPLIT,
};
@@ -109,7 +108,6 @@ private:
Button *button_toggle_display_mode;
Button *button_reload;
- Button *button_tree;
Button *button_file_list_display_mode;
Button *button_hist_next;
Button *button_hist_prev;
@@ -127,7 +125,6 @@ private:
DisplayMode display_mode;
DisplayModeSetting display_mode_setting;
DisplayModeSetting old_display_mode_setting;
- bool file_list_view;
PopupMenu *file_list_popup;
PopupMenu *tree_popup;
@@ -193,8 +190,7 @@ private:
void _change_file_display();
void _fs_changed();
- void _go_to_tree();
- void _go_to_file_list();
+ void _tree_toggle_collapsed();
void _select_file(const String p_path);
void _tree_activate_file();
@@ -237,7 +233,7 @@ private:
void _search_changed(const String &p_text, const Control *p_from);
- void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths);
+ void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options = true);
void _tree_rmb_select(const Vector2 &p_pos);
void _file_list_rmb_select(int p_item, const Vector2 &p_pos);
void _file_list_rmb_pressed(const Vector2 &p_pos);
@@ -268,7 +264,7 @@ private:
void _file_list_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
void _tree_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
- void _update_display_mode();
+ void _update_display_mode(bool p_force = false);
Vector<String> _tree_get_selected(bool remove_self_inclusion = true);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 0ccaa95fb7..705bb1d9c5 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "find_in_files.h"
+
#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "editor_node.h"
@@ -89,8 +90,6 @@ static bool find_next(const String &line, String pattern, int from, bool match_c
//--------------------------------------------------------------------------------
FindInFiles::FindInFiles() {
_root_prefix = ROOT_PREFIX;
- _extension_filter.insert("gd");
- _extension_filter.insert("cs");
_searching = false;
_whole_words = true;
_match_case = true;
@@ -301,8 +300,7 @@ const char *FindInFilesDialog::SIGNAL_REPLACE_REQUESTED = "replace_requested";
FindInFilesDialog::FindInFilesDialog() {
- set_custom_minimum_size(Size2(400, 190) * EDSCALE);
- set_resizable(true);
+ set_custom_minimum_size(Size2(500 * EDSCALE, 0));
set_title(TTR("Find in Files"));
VBoxContainer *vbc = memnew(VBoxContainer);
@@ -317,7 +315,7 @@ FindInFilesDialog::FindInFilesDialog() {
vbc->add_child(gc);
Label *find_label = memnew(Label);
- find_label->set_text(TTR("Find: "));
+ find_label->set_text(TTR("Find:"));
gc->add_child(find_label);
_search_text_line_edit = memnew(LineEdit);
@@ -326,10 +324,7 @@ FindInFilesDialog::FindInFilesDialog() {
_search_text_line_edit->connect("text_entered", this, "_on_search_text_entered");
gc->add_child(_search_text_line_edit);
- {
- Control *placeholder = memnew(Control);
- gc->add_child(placeholder);
- }
+ gc->add_child(memnew(Control)); // Space to mantain the grid aligned.
{
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -346,7 +341,7 @@ FindInFilesDialog::FindInFilesDialog() {
}
Label *folder_label = memnew(Label);
- folder_label->set_text(TTR("Folder: "));
+ folder_label->set_text(TTR("Folder:"));
gc->add_child(folder_label);
{
@@ -374,7 +369,7 @@ FindInFilesDialog::FindInFilesDialog() {
}
Label *filter_label = memnew(Label);
- filter_label->set_text(TTR("Filter: "));
+ filter_label->set_text(TTR("Filters:"));
gc->add_child(filter_label);
{
@@ -382,7 +377,8 @@ FindInFilesDialog::FindInFilesDialog() {
Vector<String> exts;
exts.push_back("gd");
- exts.push_back("cs");
+ if (Engine::get_singleton()->has_singleton("GodotSharp"))
+ exts.push_back("cs");
for (int i = 0; i < exts.size(); ++i) {
CheckBox *cb = memnew(CheckBox);
@@ -395,39 +391,14 @@ FindInFilesDialog::FindInFilesDialog() {
gc->add_child(hbc);
}
- {
- Control *placeholder = memnew(Control);
- placeholder->set_custom_minimum_size(Size2(0, EDSCALE * 16));
- vbc->add_child(placeholder);
- }
-
- {
- HBoxContainer *hbc = memnew(HBoxContainer);
- hbc->set_alignment(HBoxContainer::ALIGN_CENTER);
-
- _find_button = add_button(TTR("Find..."), false, "find");
- _find_button->set_disabled(true);
-
- {
- Control *placeholder = memnew(Control);
- placeholder->set_custom_minimum_size(Size2(EDSCALE * 16, 0));
- hbc->add_child(placeholder);
- }
-
- _replace_button = add_button(TTR("Replace..."), false, "replace");
- _replace_button->set_disabled(true);
+ _find_button = add_button(TTR("Find..."), false, "find");
+ _find_button->set_disabled(true);
- {
- Control *placeholder = memnew(Control);
- placeholder->set_custom_minimum_size(Size2(EDSCALE * 16, 0));
- hbc->add_child(placeholder);
- }
-
- Button *cancel_button = get_ok();
- cancel_button->set_text(TTR("Cancel"));
+ _replace_button = add_button(TTR("Replace..."), false, "replace");
+ _replace_button->set_disabled(true);
- vbc->add_child(hbc);
- }
+ Button *cancel_button = get_ok();
+ cancel_button->set_text(TTR("Cancel"));
}
void FindInFilesDialog::set_search_text(String text) {
diff --git a/editor/icons/icon_script_extend.svg b/editor/icons/icon_script_extend.svg
new file mode 100644
index 0000000000..ef3d48af9f
--- /dev/null
+++ b/editor/icons/icon_script_extend.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m6 1v1c-0.55228 0-1 0.44772-1 1v10h-1v-2h-2v2c2.826e-4 0.35698 0.19084 0.68674 0.5 0.86523 0.15194 0.088045 0.32439 0.13452 0.5 0.13477v1h7c0.73866 0 1.3763-0.40437 1.7227-1h-3.7227v-4h4v-5h3v-2c0-1.1046-0.89543-2-2-2z" fill="#e0e0e0"/>
+<path transform="translate(0 1036.4)" d="m6 1c-1.1046 0-2 0.89543-2 2v7h-2-1v1 2c0 1.1046 0.89543 2 2 2s2-0.89543 2-2v-10c0-0.55228 0.44772-1 1-1s1 0.44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-0.89543-2-2-2zm-4 10h2v2c0 0.55228-0.44772 1-1 1s-1-0.44772-1-1v-2z" fill="#b4b4b4"/>
+<circle cx="3" cy="1048.4" rx="1" ry="1" fill="#e0e0e0"/>
+<path d="m16 1048.4-3-3v2h-4v2h4v2z" fill="#68b6ff" fill-rule="evenodd"/>
+</g>
+</svg>
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 5eb1a42f9f..8e91a88adb 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -235,7 +235,7 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
if (p_streamable)
format |= StreamTexture::FORMAT_BIT_STREAM;
- if (p_mipmaps || p_compress_mode == COMPRESS_VIDEO_RAM) //VRAM always uses mipmaps
+ if (p_mipmaps)
format |= StreamTexture::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit
if (p_detect_3d)
format |= StreamTexture::FORMAT_BIT_DETECT_3D;
@@ -310,7 +310,9 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
case COMPRESS_VIDEO_RAM: {
Ref<Image> image = p_image->duplicate();
- image->generate_mipmaps(p_force_normal);
+ if (p_mipmaps) {
+ image->generate_mipmaps(p_force_normal);
+ }
if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) {
image->convert(Image::FORMAT_RGBE9995);
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 31eb193461..2e68609a56 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -38,11 +38,17 @@ public:
List<PropertyInfo> properties;
Ref<ResourceImporter> importer;
Vector<String> paths;
+ Set<StringName> checked;
+ bool checking;
bool _set(const StringName &p_name, const Variant &p_value) {
if (values.has(p_name)) {
values[p_name] = p_value;
+ if (checking) {
+ checked.insert(p_name);
+ _change_notify(String(p_name).utf8().get_data());
+ }
return true;
}
@@ -63,13 +69,24 @@ public:
for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
if (!importer->get_option_visibility(E->get().name, values))
continue;
- p_list->push_back(E->get());
+ PropertyInfo pi = E->get();
+ if (checking) {
+ pi.usage |= PROPERTY_USAGE_CHECKABLE;
+ if (checked.has(E->get().name)) {
+ pi.usage |= PROPERTY_USAGE_CHECKED;
+ }
+ }
+ p_list->push_back(pi);
}
}
void update() {
_change_notify();
}
+
+ ImportDockParameters() {
+ checking = false;
+ }
};
void ImportDock::set_edit_path(const String &p_path) {
@@ -125,6 +142,8 @@ void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
params->properties.clear();
params->values.clear();
+ params->checking = false;
+ params->checked.clear();
for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
@@ -205,6 +224,8 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
params->properties.clear();
params->values.clear();
+ params->checking = true;
+ params->checked.clear();
for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
@@ -360,11 +381,21 @@ void ImportDock::_reimport() {
Error err = config->load(params->paths[i] + ".import");
ERR_CONTINUE(err != OK);
- config->set_value("remap", "importer", params->importer->get_importer_name());
- config->erase_section("params");
+ if (params->checking) {
+ //update only what edited (checkboxes)
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
+ if (params->checked.has(E->get().name)) {
+ config->set_value("params", E->get().name, params->values[E->get().name]);
+ }
+ }
+ } else {
+ //override entirely
+ config->set_value("remap", "importer", params->importer->get_importer_name());
+ config->erase_section("params");
- for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
- config->set_value("params", E->get().name, params->values[E->get().name]);
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
+ config->set_value("params", E->get().name, params->values[E->get().name]);
+ }
}
config->save(params->paths[i] + ".import");
@@ -388,11 +419,20 @@ void ImportDock::_notification(int p_what) {
} break;
}
}
+
+void ImportDock::_property_toggled(const StringName &p_prop, bool p_checked) {
+ if (p_checked) {
+ params->checked.insert(p_prop);
+ } else {
+ params->checked.erase(p_prop);
+ }
+}
void ImportDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_reimport"), &ImportDock::_reimport);
ClassDB::bind_method(D_METHOD("_preset_selected"), &ImportDock::_preset_selected);
ClassDB::bind_method(D_METHOD("_importer_selected"), &ImportDock::_importer_selected);
+ ClassDB::bind_method(D_METHOD("_property_toggled"), &ImportDock::_property_toggled);
}
void ImportDock::initialize_import_options() const {
@@ -423,6 +463,7 @@ ImportDock::ImportDock() {
import_opts = memnew(EditorInspector);
add_child(import_opts);
import_opts->set_v_size_flags(SIZE_EXPAND_FILL);
+ import_opts->connect("property_toggled", this, "_property_toggled");
hb = memnew(HBoxContainer);
add_child(hb);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index 41c7298d9a..632fd39700 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -60,6 +60,7 @@ class ImportDock : public VBoxContainer {
void _importer_selected(int i_idx);
void _update_options(const Ref<ConfigFile> &p_config = Ref<ConfigFile>());
+ void _property_toggled(const StringName &p_prop, bool p_checked);
void _reimport();
enum {
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 750fca2852..2a8885c0a4 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -593,6 +593,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
inspector->set_undo_redo(&editor_data->get_undo_redo());
inspector->set_use_filter(true); // TODO: check me
+ inspector->set_auto_unfold_edited(bool(EDITOR_GET("interface/inspector/auto_unfold_edited")));
inspector->connect("resource_selected", this, "_resource_selected");
inspector->connect("property_keyed", this, "_property_keyed");
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index a334f79f5a..8e626e7111 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -180,7 +180,7 @@ PluginConfigDialog::PluginConfigDialog() {
grid->add_child(desc_lb);
desc_edit = memnew(TextEdit);
- desc_edit->set_custom_minimum_size(Size2(400.0f, 50.0f));
+ desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE);
grid->add_child(desc_edit);
Label *author_lb = memnew(Label);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index f7e59e2beb..71a5d73b2f 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -132,8 +132,8 @@ Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const {
void AbstractPolygon2DEditor::_commit_action() {
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
}
@@ -218,7 +218,7 @@ void AbstractPolygon2DEditor::_node_removed(Node *p_node) {
edit(NULL);
hide();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -334,7 +334,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos));
selected_point = closest;
edge_point = PosVertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
} else {
@@ -403,7 +403,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip_active = true;
_wip_changed();
edited_point = PosVertex(-1, 1, cpoint);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
hover_point = Vertex();
selected_point = Vertex(0);
edge_point = PosVertex();
@@ -424,7 +424,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_wip_changed();
edited_point = PosVertex(-1, wip.size(), cpoint);
selected_point = Vertex(wip.size() - 1);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -453,7 +453,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_set_polygon(edited_point.polygon, vertices);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
const PosVertex onEdgeVertex = closest_edge_point(gpoint);
@@ -462,20 +462,20 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
hover_point = Vertex();
edge_point = onEdgeVertex;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
if (edge_point.valid()) {
edge_point = PosVertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
const PosVertex new_hover_point = closest_point(gpoint);
if (hover_point != new_hover_point) {
hover_point = new_hover_point;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
}
@@ -494,7 +494,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip.remove(selected_point.vertex);
_wip_changed();
selected_point = wip.size() - 1;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
} else {
@@ -627,7 +627,7 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
hover_point = Vertex();
selected_point = Vertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 205458fb1d..eb3c432ee7 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -692,7 +692,9 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
Ref<Animation> anim = player->get_animation(an->get_animation());
if (anim.is_valid()) {
E->get()->set_max(anim->get_length());
- E->get()->set_value(an->get_playback_time());
+ //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E->get().input_node;
+ StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E->key()) + "/time";
+ E->get()->set_value(AnimationTreeEditor::get_singleton()->get_tree()->get(time_path));
}
}
}
@@ -833,8 +835,6 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
if (p_node.is_valid()) {
blend_tree = p_node;
- } else {
- blend_tree.unref();
}
if (blend_tree.is_null()) {
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 66770d98e5..138b8a491c 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -962,6 +962,9 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
HBoxContainer *hbc = memnew(HBoxContainer);
+ if (p_page_count < 2)
+ return hbc;
+
//do the mario
int from = p_page - 5;
if (from < 0)
diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp
index e65a697857..40e3bb5be2 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.cpp
+++ b/editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -108,7 +108,7 @@ void BakedLightmapEditorPlugin::_bind_methods() {
BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
editor = p_node;
- bake = memnew(Button);
+ bake = memnew(ToolButton);
bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake Lightmaps"));
bake->hide();
diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/baked_lightmap_editor_plugin.h
index a32b573851..8d3b5b1dd6 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.h
+++ b/editor/plugins/baked_lightmap_editor_plugin.h
@@ -42,7 +42,7 @@ class BakedLightmapEditorPlugin : public EditorPlugin {
BakedLightmap *lightmap;
- Button *bake;
+ ToolButton *bake;
EditorNode *editor;
static EditorProgress *tmp_progress;
diff --git a/editor/plugins/camera_editor_plugin.cpp b/editor/plugins/camera_editor_plugin.cpp
index 37fbb54c30..3d8b24ccc7 100644
--- a/editor/plugins/camera_editor_plugin.cpp
+++ b/editor/plugins/camera_editor_plugin.cpp
@@ -32,18 +32,6 @@
#include "spatial_editor_plugin.h"
-void CameraEditor::_notification(int p_what) {
-
- switch (p_what) {
-
- /* case NOTIFICATION_PROCESS: {
-
- if (preview->is_pressed() && node)
- node->call("make_current");
-
- } break;*/
- }
-}
void CameraEditor::_node_removed(Node *p_node) {
if (p_node == node) {
diff --git a/editor/plugins/camera_editor_plugin.h b/editor/plugins/camera_editor_plugin.h
index 275624beeb..0340808c9a 100644
--- a/editor/plugins/camera_editor_plugin.h
+++ b/editor/plugins/camera_editor_plugin.h
@@ -50,7 +50,6 @@ class CameraEditor : public Control {
void _pressed();
protected:
- void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index a9bc5e77ac..1add99bdcc 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -179,8 +179,21 @@ void CanvasItemEditor::_snap_if_closer_float(float p_value, float p_target_snap,
}
}
-bool CanvasItemEditor::_is_node_editable(const Node *p_node) {
- return (!(p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_")) && !(ClassDB::is_parent_class(p_node->get_parent()->get_class_name(), "Container") && ClassDB::is_parent_class(p_node->get_class_name(), "Control")));
+bool CanvasItemEditor::_is_node_locked(const Node *p_node) {
+ return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
+}
+
+bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning) {
+ if (_is_node_locked(p_node)) {
+ return false;
+ }
+ if (Object::cast_to<Control>(p_node) && Object::cast_to<Container>(p_node->get_parent())) {
+ if (p_popup_warning) {
+ _popup_warning_temporarily(warning_child_of_container, 3.0);
+ }
+ return false;
+ }
+ return true;
}
void CanvasItemEditor::_snap_if_closer_point(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) {
@@ -415,7 +428,7 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
}
}
- if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !_is_node_editable(canvas_item))) {
+ if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !_is_node_locked(canvas_item))) {
Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
Rect2 rect = canvas_item->_edit_get_rect();
if (r_first) {
@@ -437,7 +450,7 @@ Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
return rect;
}
-void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node)
return;
if (Object::cast_to<Viewport>(p_node))
@@ -449,16 +462,14 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
if (canvas_item) {
if (!canvas_item->is_set_as_toplevel()) {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
} else {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, canvas_item->get_transform(), p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, canvas_item->get_transform(), p_canvas_xform);
}
} else {
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
}
- if (p_limit != 0 && r_items.size() >= p_limit)
- return;
}
if (canvas_item && canvas_item->is_visible_in_tree()) {
@@ -478,11 +489,11 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
return;
}
-void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit) {
+void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) {
Node *scene = editor->get_edited_scene();
- _find_canvas_items_at_pos(p_pos, scene, r_items, p_limit);
+ _find_canvas_items_at_pos(p_pos, scene, r_items);
//Remove invalid results
for (int i = 0; i < r_items.size(); i++) {
@@ -513,7 +524,7 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
}
//Remove the item if invalid
- if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || !_is_node_editable(canvas_item)) {
+ if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || _is_node_locked(canvas_item)) {
r_items.remove(i);
i--;
} else {
@@ -614,7 +625,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner());
bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
- bool locked = !_is_node_editable(p_node);
+ bool locked = _is_node_locked(p_node);
if (!lock_children || !editable) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
@@ -681,7 +692,7 @@ List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retreive_lock
List<CanvasItem *> selection;
for (Map<Node *, Object *>::Element *E = editor_selection->get_selection().front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
- if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retreive_locked || _is_node_editable(canvas_item))) {
+ if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retreive_locked || !_is_node_locked(canvas_item))) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (se) {
selection.push_back(canvas_item);
@@ -1025,8 +1036,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Scroll or pan down
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else {
_zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position());
}
@@ -1037,8 +1047,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Scroll or pan up
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else {
_zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position());
}
@@ -1049,8 +1058,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Pan left
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1059,8 +1067,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Pan right
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1112,8 +1119,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
}
view_offset.x -= relative.x / zoom;
view_offset.y -= relative.y / zoom;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1131,8 +1137,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
view_offset.x += delta.x;
view_offset.y += delta.y;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
@@ -1293,18 +1298,28 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
- drag_selection = _get_edited_canvas_items();
- if (drag_selection.size() > 0 && ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE)) {
- drag_type = DRAG_ROTATE;
- drag_from = transform.affine_inverse().xform(b->get_position());
- CanvasItem *canvas_item = drag_selection[0];
- if (canvas_item->_edit_use_pivot()) {
- drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
- } else {
- drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
+ if ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
+ List<CanvasItem *> selection = _get_edited_canvas_items();
+
+ // Remove not movable nodes
+ for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
+ if (!_is_node_movable(E->get(), true))
+ selection.erase(E);
+ }
+
+ drag_selection = selection;
+ if (drag_selection.size() > 0) {
+ drag_type = DRAG_ROTATE;
+ drag_from = transform.affine_inverse().xform(b->get_position());
+ CanvasItem *canvas_item = drag_selection[0];
+ if (canvas_item->_edit_use_pivot()) {
+ drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
+ } else {
+ drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
+ }
+ _save_canvas_item_state(drag_selection);
+ return true;
}
- _save_canvas_item_state(drag_selection);
- return true;
}
}
}
@@ -1367,7 +1382,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
Control *control = Object::cast_to<Control>(selection[0]);
- if (control && !Object::cast_to<Container>(control->get_parent())) {
+ if (control && _is_node_movable(control)) {
Vector2 anchor_pos[4];
anchor_pos[0] = Vector2(control->get_anchor(MARGIN_LEFT), control->get_anchor(MARGIN_TOP));
anchor_pos[1] = Vector2(control->get_anchor(MARGIN_RIGHT), control->get_anchor(MARGIN_TOP));
@@ -1486,7 +1501,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
- if (canvas_item->_edit_use_rect()) {
+ if (canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
Rect2 rect = canvas_item->_edit_get_rect();
Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
@@ -1654,27 +1669,30 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
- Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
- Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
+ if (_is_node_movable(canvas_item)) {
- drag_type = DRAG_SCALE_BOTH;
+ Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
- Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
- drag_type = DRAG_SCALE_X;
- }
- Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
- drag_type = DRAG_SCALE_Y;
- }
+ drag_type = DRAG_SCALE_BOTH;
- drag_from = transform.affine_inverse().xform(b->get_position());
- drag_selection = List<CanvasItem *>();
- drag_selection.push_back(canvas_item);
- _save_canvas_item_state(drag_selection);
- return true;
+ Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
+ Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
+ drag_type = DRAG_SCALE_X;
+ }
+ Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
+ drag_type = DRAG_SCALE_Y;
+ }
+
+ drag_from = transform.affine_inverse().xform(b->get_position());
+ drag_selection = List<CanvasItem *>();
+ drag_selection.push_back(canvas_item);
+ _save_canvas_item_state(drag_selection);
+ return true;
+ }
}
}
}
@@ -1702,13 +1720,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_SCALE_BOTH) {
Size2 scale_factor = drag_to_local / drag_from_local;
if (uniform) {
- if (ABS(offset.x) > ABS(offset.y)) {
- scale.x *= scale_factor.x;
- scale.y = scale.x * ratio;
- } else {
- scale.y *= scale_factor.y;
- scale.x = scale.y / ratio;
- }
+ scale *= (scale_factor.x + scale_factor.y) / 2.0;
} else {
scale *= scale_factor;
}
@@ -1759,12 +1771,22 @@ 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() == BUTTON_LEFT && b->is_pressed()) {
- List<CanvasItem *> selection = _get_edited_canvas_items();
- if (((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) && selection.size() > 0) {
- drag_type = DRAG_MOVE;
- drag_from = transform.affine_inverse().xform(b->get_position());
- drag_selection = selection;
- _save_canvas_item_state(drag_selection);
+ if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
+ List<CanvasItem *> selection = _get_edited_canvas_items();
+
+ // Remove not movable nodes
+ for (int i = 0; i < selection.size(); i++) {
+ if (!_is_node_movable(selection[i], true)) {
+ selection.erase(selection[i]);
+ }
+ }
+
+ if (selection.size() > 0) {
+ drag_type = DRAG_MOVE;
+ drag_from = transform.affine_inverse().xform(b->get_position());
+ drag_selection = selection;
+ _save_canvas_item_state(drag_selection);
+ }
return true;
}
}
@@ -2014,7 +2036,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
Vector<_SelectResult> selection;
// Retrieve the items
- _get_canvas_items_at_pos(click, selection, editor_selection->get_selection().empty() ? 1 : 0);
+ _get_canvas_items_at_pos(click, selection);
// Retrieve the bones
_get_bones_at_pos(click, selection);
@@ -2042,10 +2064,19 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Drag the node(s) if requested
List<CanvasItem *> selection = _get_edited_canvas_items();
- drag_type = DRAG_MOVE;
- drag_selection = selection;
- drag_from = click;
- _save_canvas_item_state(drag_selection);
+ // Remove not movable nodes
+ for (int i = 0; i < selection.size(); i++) {
+ if (!_is_node_movable(selection[i], true)) {
+ selection.erase(selection[i]);
+ }
+ }
+
+ if (selection.size() > 0) {
+ drag_type = DRAG_MOVE;
+ drag_selection = selection;
+ drag_from = click;
+ _save_canvas_item_state(drag_selection);
+ }
}
// Select the item
return true;
@@ -2178,6 +2209,8 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
//printf("Zoom or pan\n");
} else if ((accepted = _gui_input_select(p_event))) {
//printf("Selection\n");
+ } else {
+ //printf("Not accepted\n");
}
if (accepted)
@@ -2708,12 +2741,12 @@ void CanvasItemEditor::_draw_selection() {
// Draw control-related helpers
Control *control = Object::cast_to<Control>(canvas_item);
- if (control) {
+ if (control && _is_node_movable(control)) {
_draw_control_helpers(control);
}
// Draw the resize handles
- if (tool == TOOL_SELECT && canvas_item->_edit_use_rect()) {
+ if (tool == TOOL_SELECT && canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
Rect2 rect = canvas_item->_edit_get_rect();
Vector2 endpoints[4] = {
xform.xform(rect.position),
@@ -2741,40 +2774,41 @@ void CanvasItemEditor::_draw_selection() {
bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
-
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
- Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
-
- Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
-
- if (drag_type == DRAG_SCALE_X) {
- scale_factor.x += offset.x;
- if (uniform) {
- scale_factor.y += offset.x;
- }
- } else if (drag_type == DRAG_SCALE_Y) {
- scale_factor.y -= offset.y;
- if (uniform) {
- scale_factor.x -= offset.y;
+ if (_is_node_movable(canvas_item)) {
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
+
+ Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
+ bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
+
+ if (drag_type == DRAG_SCALE_X) {
+ scale_factor.x += offset.x;
+ if (uniform) {
+ scale_factor.y += offset.x;
+ }
+ } else if (drag_type == DRAG_SCALE_Y) {
+ scale_factor.y -= offset.y;
+ if (uniform) {
+ scale_factor.x -= offset.y;
+ }
}
- }
- //scale_factor *= zoom;
+ //scale_factor *= zoom;
- viewport->draw_set_transform_matrix(simple_xform);
- Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- Color x_axis_color(1.0, 0.4, 0.4, 0.6);
- viewport->draw_rect(x_handle_rect, x_axis_color);
- viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), x_axis_color);
+ viewport->draw_set_transform_matrix(simple_xform);
+ Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ Color x_axis_color(1.0, 0.4, 0.4, 0.6);
+ viewport->draw_rect(x_handle_rect, x_axis_color);
+ viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), x_axis_color);
- Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- Color y_axis_color(0.4, 1.0, 0.4, 0.6);
- viewport->draw_rect(y_handle_rect, y_axis_color);
- viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), y_axis_color);
+ Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ Color y_axis_color(0.4, 1.0, 0.4, 0.6);
+ viewport->draw_rect(y_handle_rect, y_axis_color);
+ viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), y_axis_color);
- viewport->draw_set_transform_matrix(viewport->get_transform());
+ viewport->draw_set_transform_matrix(viewport->get_transform());
+ }
}
}
}
@@ -2950,7 +2984,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
_draw_invisible_nodes_positions(p_node->get_child(i), parent_xform, canvas_xform);
}
- if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || !_is_node_editable(canvas_item))) {
+ if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || _is_node_locked(canvas_item))) {
Transform2D xform = transform * canvas_xform * parent_xform;
// Draw the node's position
@@ -3139,6 +3173,8 @@ void CanvasItemEditor::_draw_viewport() {
group_button->set_disabled(selection.empty());
ungroup_button->set_visible(all_group);
+ info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+
_draw_grid();
_draw_selection();
_draw_axis();
@@ -3168,6 +3204,11 @@ void CanvasItemEditor::_draw_viewport() {
_draw_hover();
}
+void CanvasItemEditor::update_viewport() {
+ _update_scrollbars();
+ viewport->update();
+}
+
void CanvasItemEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
@@ -3362,11 +3403,14 @@ void CanvasItemEditor::_notification(int p_what) {
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
- drag_type = DRAG_NONE;
+ Array selection = editor_selection->get_selected_nodes();
+ if (selection.size() != 1 || (Node *)selection[0] != p_canvas_item) {
+ drag_type = DRAG_NONE;
- // Clear the selection
- editor_selection->clear(); //_clear_canvas_items();
- editor_selection->add_node(p_canvas_item);
+ // Clear the selection
+ editor_selection->clear(); //_clear_canvas_items();
+ editor_selection->add_node(p_canvas_item);
+ }
}
void CanvasItemEditor::_queue_update_bone_list() {
@@ -3498,6 +3542,35 @@ void CanvasItemEditor::_update_scrollbars() {
updating_scroll = false;
}
+void CanvasItemEditor::_popup_warning_depop(Control *p_control) {
+ ERR_FAIL_COND(!popup_temporarily_timers.has(p_control));
+
+ Timer *timer = popup_temporarily_timers[p_control];
+ p_control->hide();
+ remove_child(timer);
+ popup_temporarily_timers.erase(p_control);
+ memdelete(timer);
+ info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+}
+
+void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const float p_duration) {
+ Timer *timer;
+ if (!popup_temporarily_timers.has(p_control)) {
+ timer = memnew(Timer);
+ timer->connect("timeout", this, "_popup_warning_depop", varray(p_control));
+ timer->set_one_shot(true);
+ add_child(timer);
+
+ popup_temporarily_timers[p_control] = timer;
+ } else {
+ timer = popup_temporarily_timers[p_control];
+ }
+
+ timer->start(p_duration);
+ p_control->show();
+ info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+}
+
void CanvasItemEditor::_update_scroll(float) {
if (updating_scroll)
@@ -3574,8 +3647,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
view_offset.x = Math::round(view_offset.x + ofs.x);
view_offset.y = Math::round(view_offset.y + ofs.y);
- _update_scrollbars();
- viewport->update();
+ update_viewport();
}
void CanvasItemEditor::_button_zoom_minus() {
@@ -4172,8 +4244,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
view_offset.x -= offset.x / zoom;
view_offset.y -= offset.y / zoom;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else { // VIEW_FRAME_TO_SELECTION
@@ -4206,10 +4277,11 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed);
ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed);
-
+ ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop);
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
+ ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
ADD_SIGNAL(MethodInfo("item_group_status_changed"));
@@ -4391,7 +4463,22 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
viewport->update();
}
+void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) {
+ ERR_FAIL_COND(!p_control);
+
+ p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL);
+ info_overlay->add_child(p_control);
+ info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+}
+
+void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
+
+ info_overlay->remove_child(p_control);
+ info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+}
+
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
+ ERR_FAIL_COND(!p_control);
hb->add_child(p_control);
}
@@ -4417,6 +4504,46 @@ void CanvasItemEditor::focus_selection() {
CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
+ key_pos = true;
+ key_rot = true;
+ key_scale = false;
+
+ show_grid = false;
+ show_origin = true;
+ show_viewport = true;
+ show_helpers = false;
+ show_rulers = true;
+ show_guides = true;
+ show_edit_locks = true;
+ zoom = 1;
+ view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
+ previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
+ grid_offset = Point2();
+ grid_step = Point2(10, 10);
+ grid_step_multiplier = 0;
+ snap_rotation_offset = 0;
+ snap_rotation_step = 15 / (180 / Math_PI);
+ snap_active = false;
+ snap_node_parent = true;
+ snap_node_anchors = true;
+ snap_node_sides = true;
+ snap_node_center = true;
+ snap_other_nodes = true;
+ snap_grid = true;
+ snap_guides = true;
+ snap_rotation = false;
+ snap_pixel = false;
+
+ skeleton_show_bones = true;
+
+ drag_type = DRAG_NONE;
+ drag_from = Vector2();
+ drag_to = Vector2();
+ dragged_guide_pos = Point2();
+ dragged_guide_index = -1;
+
+ bone_last_frame = 0;
+
bone_list_dirty = false;
tool = TOOL_SELECT;
undo_redo = p_editor->get_undo_redo();
@@ -4460,6 +4587,28 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->connect("draw", this, "_draw_viewport");
viewport->connect("gui_input", this, "_gui_input_viewport");
+ info_overlay = memnew(VBoxContainer);
+ info_overlay->set_anchors_and_margins_preset(Control::PRESET_BOTTOM_LEFT);
+ info_overlay->set_margin(MARGIN_LEFT, 10);
+ info_overlay->set_margin(MARGIN_BOTTOM, -15);
+ info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
+ info_overlay->add_constant_override("separation", 10);
+ viewport_scrollable->add_child(info_overlay);
+
+ Theme *info_overlay_theme = memnew(Theme);
+ info_overlay_theme->copy_default_theme();
+ info_overlay->set_theme(info_overlay_theme);
+
+ StyleBoxFlat *info_overlay_label_stylebox = memnew(StyleBoxFlat);
+ info_overlay_label_stylebox->set_bg_color(Color(0.0, 0.0, 0.0, 0.2));
+ info_overlay_label_stylebox->set_expand_margin_size_all(4);
+ info_overlay_theme->set_stylebox("normal", "Label", info_overlay_label_stylebox);
+
+ warning_child_of_container = memnew(Label);
+ warning_child_of_container->hide();
+ warning_child_of_container->set_text("Warning: Children of a container get their position and size determined only by their parent");
+ add_control_to_info_overlay(warning_child_of_container);
+
h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
h_scroll->connect("value_changed", this, "_update_scroll");
@@ -4608,6 +4757,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
skeleton_menu = memnew(MenuButton);
hb->add_child(skeleton_menu);
+ skeleton_menu->set_tooltip(TTR("Skeleton Options"));
p = skeleton_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
@@ -4716,49 +4866,11 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY);
divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE);
- key_pos = true;
- key_rot = true;
- key_scale = false;
-
- show_grid = false;
- show_origin = true;
- show_viewport = true;
- show_helpers = false;
- show_rulers = true;
- show_guides = true;
- show_edit_locks = true;
- zoom = 1;
- view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
- previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
- grid_offset = Point2();
- grid_step = Point2(10, 10);
- grid_step_multiplier = 0;
- snap_rotation_offset = 0;
- snap_rotation_step = 15 / (180 / Math_PI);
- snap_active = false;
- snap_node_parent = true;
- snap_node_anchors = true;
- snap_node_sides = true;
- snap_node_center = true;
- snap_other_nodes = true;
- snap_grid = true;
- snap_guides = true;
- snap_rotation = false;
- snap_pixel = false;
- skeleton_show_bones = true;
skeleton_menu->get_popup()->set_item_checked(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES), true);
singleton = this;
set_process_unhandled_key_input(true);
- drag_type = DRAG_NONE;
- drag_from = Vector2();
- drag_to = Vector2();
- dragged_guide_pos = Point2();
- dragged_guide_index = -1;
-
- bone_last_frame = 0;
-
// Update the menus' checkboxes
call_deferred("set_state", get_state());
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 4f8cc6ab5e..f71eb1b605 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -64,7 +64,10 @@ public:
Dictionary undo_state;
- CanvasItemEditorSelectedItem() { prev_rot = 0; }
+ CanvasItemEditorSelectedItem() :
+ prev_anchors() {
+ prev_rot = 0;
+ }
};
class CanvasItemEditor : public VBoxContainer {
@@ -220,6 +223,11 @@ private:
ToolButton *zoom_reset;
ToolButton *zoom_plus;
+ Map<Control *, Timer *> popup_temporarily_timers;
+
+ Label *warning_child_of_container;
+ VBoxContainer *info_overlay;
+
Transform2D transform;
bool show_grid;
bool show_rulers;
@@ -369,9 +377,10 @@ private:
Ref<ShortCut> multiply_grid_step_shortcut;
Ref<ShortCut> divide_grid_step_shortcut;
- bool _is_node_editable(const Node *p_node);
- void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
- void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit = 0);
+ bool _is_node_locked(const Node *p_node);
+ bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
+ void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+ void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items);
void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items);
void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
@@ -477,6 +486,9 @@ private:
void _update_bone_list();
void _tree_changed(Node *);
+ void _popup_warning_temporarily(Control *p_control, const float p_duration);
+ void _popup_warning_depop(Control *p_control);
+
friend class CanvasItemEditorPlugin;
protected:
@@ -542,11 +554,16 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
+ void add_control_to_info_overlay(Control *p_control);
+ void remove_control_from_info_overlay(Control *p_control);
+
HSplitContainer *get_palette_split();
VSplitContainer *get_bottom_split();
Control *get_viewport_control() { return viewport; }
+ void update_viewport();
+
Tool get_current_tool() { return tool; }
void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index d1a94f5b49..313ba1ee6b 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -129,7 +129,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
capsule->set_height(parameter * 2 - capsule->get_radius() * 2);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -138,7 +138,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
Ref<CircleShape2D> circle = node->get_shape();
circle->set_radius(p_point.length());
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} break;
@@ -160,7 +160,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
line->set_normal(p_point.normalized());
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -170,7 +170,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
ray->set_length(Math::abs(p_point.y));
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} break;
@@ -183,7 +183,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
rect->set_extents(extents.abs());
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -198,16 +198,16 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
seg->set_b(p_point);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
}
+ node->get_shape()->_change_notify();
}
void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
- Control *c = canvas_item_editor->get_viewport_control();
undo_redo->create_action(TTR("Set Handle"));
switch (shape_type) {
@@ -216,14 +216,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
if (idx == 0) {
undo_redo->add_do_method(capsule.ptr(), "set_radius", capsule->get_radius());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(capsule.ptr(), "set_radius", p_org);
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
} else if (idx == 1) {
undo_redo->add_do_method(capsule.ptr(), "set_height", capsule->get_height());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(capsule.ptr(), "set_height", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -232,9 +232,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<CircleShape2D> circle = node->get_shape();
undo_redo->add_do_method(circle.ptr(), "set_radius", circle->get_radius());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(circle.ptr(), "set_radius", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -251,14 +251,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
if (idx == 0) {
undo_redo->add_do_method(line.ptr(), "set_d", line->get_d());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(line.ptr(), "set_d", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} else {
undo_redo->add_do_method(line.ptr(), "set_normal", line->get_normal());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(line.ptr(), "set_normal", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -267,9 +267,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<RayShape2D> ray = node->get_shape();
undo_redo->add_do_method(ray.ptr(), "set_length", ray->get_length());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(ray.ptr(), "set_length", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -277,9 +277,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<RectangleShape2D> rect = node->get_shape();
undo_redo->add_do_method(rect.ptr(), "set_extents", rect->get_extents());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(rect.ptr(), "set_extents", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -287,14 +287,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<SegmentShape2D> seg = node->get_shape();
if (idx == 0) {
undo_redo->add_do_method(seg.ptr(), "set_a", seg->get_a());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(seg.ptr(), "set_a", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} else if (idx == 1) {
undo_redo->add_do_method(seg.ptr(), "set_b", seg->get_b());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(seg.ptr(), "set_b", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -411,7 +411,7 @@ void CollisionShape2DEditor::_get_current_shape_type() {
shape_type = -1;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
@@ -538,7 +538,7 @@ void CollisionShape2DEditor::edit(Node *p_node) {
node = NULL;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void CollisionShape2DEditor::_bind_methods() {
diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp
index 06da64b181..5fc5cad1ef 100644
--- a/editor/plugins/gi_probe_editor_plugin.cpp
+++ b/editor/plugins/gi_probe_editor_plugin.cpp
@@ -90,7 +90,7 @@ void GIProbeEditorPlugin::_bind_methods() {
GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
editor = p_node;
- bake = memnew(Button);
+ bake = memnew(ToolButton);
bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake GI Probe"));
bake->hide();
diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h
index 017e9bd743..1b3b63f227 100644
--- a/editor/plugins/gi_probe_editor_plugin.h
+++ b/editor/plugins/gi_probe_editor_plugin.h
@@ -42,7 +42,7 @@ class GIProbeEditorPlugin : public EditorPlugin {
GIProbe *gi_probe;
- Button *bake;
+ ToolButton *bake;
EditorNode *editor;
static EditorProgress *tmp_progress;
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index 186e66f980..8df40232b0 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -350,8 +350,6 @@ ItemListEditor::ItemListEditor() {
selected_idx = -1;
- add_child(memnew(VSeparator));
-
toolbar_button = memnew(ToolButton);
toolbar_button->set_text(TTR("Items"));
add_child(toolbar_button);
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 2f2e1dae81..6a16cf0989 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -57,7 +57,7 @@ void LightOccluder2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = NULL;
hide();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -88,8 +88,8 @@ void LightOccluder2DEditor::_wip_close(bool p_closed) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_closed", node->get_occluder_polygon()->is_closed());
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_closed", p_closed);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
wip.clear();
wip_active = false;
@@ -139,7 +139,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
wip.push_back(cpoint);
wip_active = true;
edited_point_pos = cpoint;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
edited_point = 1;
return true;
} else {
@@ -158,7 +158,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
wip.push_back(cpoint);
edited_point = wip.size();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
//add wip point
@@ -183,8 +183,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
poly.push_back(cpoint);
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -217,7 +217,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
edited_point = closest_idx + 1;
edited_point_pos = xform.affine_inverse().xform(closest_pos);
node->get_occluder_polygon()->set_polygon(Variant(poly));
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
} else {
@@ -244,7 +244,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
pre_move_edit = poly;
edited_point = closest_idx;
edited_point_pos = xform.affine_inverse().xform(closest_pos);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -259,8 +259,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", pre_move_edit);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
edited_point = -1;
@@ -290,8 +290,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
poly.remove(closest_idx);
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -312,7 +312,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
cpoint = canvas_item_editor->snap_point(cpoint);
edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -369,7 +369,7 @@ void LightOccluder2DEditor::edit(Node *p_collision_polygon) {
wip.clear();
wip_active = false;
edited_point = -1;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
node = NULL;
}
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index 5dcbca2ed6..ab94258c44 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/io/image_loader.h"
+#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
#include "scene/resources/particles_material.h"
@@ -82,6 +83,25 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) {
emission_mask->popup_centered_minsize();
} break;
+ case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
+ cpu_particles->convert_from_particles(particles);
+ cpu_particles->set_name(particles->get_name());
+ cpu_particles->set_transform(particles->get_transform());
+ cpu_particles->set_visible(particles->is_visible());
+ cpu_particles->set_pause_mode(particles->get_pause_mode());
+
+ undo_redo->create_action("Replace Particles by CPUParticles");
+ undo_redo->add_do_method(particles, "replace_by", cpu_particles);
+ undo_redo->add_undo_method(cpu_particles, "replace_by", particles);
+ undo_redo->add_do_reference(cpu_particles);
+ undo_redo->add_undo_reference(particles);
+ undo_redo->commit_action();
+
+ } break;
}
}
@@ -355,6 +375,8 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
menu->get_popup()->add_separator();
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
// menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
+ menu->get_popup()->add_separator();
+ menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
menu->set_text(TTR("Particles"));
toolbar->add_child(menu);
diff --git a/editor/plugins/particles_2d_editor_plugin.h b/editor/plugins/particles_2d_editor_plugin.h
index 71ca8ef499..eaa96d84e9 100644
--- a/editor/plugins/particles_2d_editor_plugin.h
+++ b/editor/plugins/particles_2d_editor_plugin.h
@@ -46,7 +46,8 @@ class Particles2DEditorPlugin : public EditorPlugin {
MENU_GENERATE_VISIBILITY_RECT,
MENU_LOAD_EMISSION_MASK,
- MENU_CLEAR_EMISSION_MASK
+ MENU_CLEAR_EMISSION_MASK,
+ MENU_OPTION_CONVERT_TO_CPU_PARTICLES
};
enum EmissionMode {
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 6b41946918..f2dfae7a9f 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -453,6 +453,7 @@ void ParticlesEditor::_bind_methods() {
ParticlesEditor::ParticlesEditor() {
+ node = NULL;
particles_editor_hb = memnew(HBoxContainer);
SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
options = memnew(MenuButton);
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 88b3194490..c67c96798a 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -130,8 +130,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
undo_redo->add_undo_method(curve.ptr(), "add_point", curve->get_point_position(i), curve->get_point_in(i), curve->get_point_out(i), i);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
} else if (dist_to_p_out < grab_threshold) {
@@ -139,8 +139,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove Out-Control from Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_out", i, Vector2());
undo_redo->add_undo_method(curve.ptr(), "set_point_out", i, curve->get_point_out(i));
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
} else if (dist_to_p_in < grab_threshold) {
@@ -148,8 +148,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove In-Control from Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_in", i, Vector2());
undo_redo->add_undo_method(curve.ptr(), "set_point_in", i, curve->get_point_in(i));
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -165,8 +165,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Add Point to Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
action = ACTION_MOVING_POINT;
@@ -174,7 +174,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
moving_from = curve->get_point_position(action_point);
moving_screen_from = gpoint;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
@@ -196,8 +196,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Move Point in Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint);
undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -212,8 +212,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length));
undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length));
}
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -228,8 +228,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length));
undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_in_length));
}
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -280,7 +280,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
} break;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -331,7 +331,7 @@ void Path2DEditor::_node_visibility_changed() {
if (!node)
return;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void Path2DEditor::edit(Node *p_path2d) {
@@ -406,8 +406,8 @@ void Path2DEditor::_mode_selected(int p_mode) {
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());
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return;
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 7e11c4a253..085660b79e 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -210,6 +210,9 @@ void ScriptEditorQuickOpen::_notification(int p_what) {
search_box->set_right_icon(get_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
} break;
+ case NOTIFICATION_EXIT_TREE: {
+ disconnect("confirmed", this, "_confirmed");
+ } break;
}
}
@@ -490,7 +493,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
edit(text_file, true);
return;
}
- // if it's a path then its most likely a deleted file not help
+ // if it's a path then it's most likely a deleted file not help
} else if (path.find("::") != -1) {
// built-in script
Ref<Script> script = ResourceLoader::load(path);
@@ -978,7 +981,7 @@ void ScriptEditor::_menu_option(int p_option) {
} break;
case SEARCH_WEBSITE: {
- OS::get_singleton()->shell_open("http://docs.godotengine.org/");
+ OS::get_singleton()->shell_open("https://docs.godotengine.org/");
} break;
case WINDOW_NEXT: {
@@ -1363,7 +1366,9 @@ void ScriptEditor::_notification(int p_what) {
if (is_visible()) {
find_in_files_button->show();
} else {
- find_in_files->hide();
+ if (find_in_files->is_visible_in_tree()) {
+ editor->hide_bottom_panel();
+ }
find_in_files_button->hide();
}
@@ -2806,8 +2811,7 @@ void ScriptEditor::_start_find_in_files(bool with_replace) {
find_in_files->set_with_replace(with_replace);
find_in_files->start_search();
- find_in_files_button->set_pressed(true);
- find_in_files->show();
+ editor->make_bottom_panel_item_visible(find_in_files);
}
void ScriptEditor::_on_find_in_files_modified_files(PoolStringArray paths) {
@@ -2891,7 +2895,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
restoring_layout = false;
waiting_update_names = false;
pending_auto_reload = false;
- auto_reload_running_scripts = false;
+ auto_reload_running_scripts = true;
members_overview_enabled = EditorSettings::get_singleton()->get("text_editor/open_scripts/show_members_overview");
help_overview_enabled = EditorSettings::get_singleton()->get("text_editor/help/show_help_index");
editor = p_editor;
@@ -2912,7 +2916,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
script_list = memnew(ItemList);
list_split->add_child(script_list);
- script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 90)); //need to give a bit of limit to avoid it from disappearing
+ script_list->set_custom_minimum_size(Size2(150, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(140);
_sort_list_on_update = true;
@@ -2951,7 +2955,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
overview_vbox->add_child(members_overview);
members_overview->set_allow_reselect(true);
- members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
+ members_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
members_overview->set_v_size_flags(SIZE_EXPAND_FILL);
members_overview->set_allow_rmb_select(true);
members_overview->set_drag_forwarding(this);
@@ -2959,12 +2963,12 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
help_overview = memnew(ItemList);
overview_vbox->add_child(help_overview);
help_overview->set_allow_reselect(true);
- help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
+ help_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
help_overview->set_v_size_flags(SIZE_EXPAND_FILL);
tab_container = memnew(TabContainer);
tab_container->set_tabs_visible(false);
- tab_container->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
+ tab_container->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
script_split->add_child(tab_container);
tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -2997,7 +3001,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show In File System")), SHOW_IN_FILE_SYSTEM);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show in FileSystem")), SHOW_IN_FILE_SYSTEM);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Previous"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV);
@@ -3174,7 +3178,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
add_child(find_in_files_dialog);
find_in_files = memnew(FindInFilesPanel);
find_in_files_button = editor->add_bottom_panel_item(TTR("Search Results"), find_in_files);
- find_in_files_button->set_tooltip(TTR("Search in files"));
find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, this, "_on_find_in_files_result_selected");
find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, this, "_on_find_in_files_modified_files");
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 362b8543d4..c3e2aa86f0 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -179,7 +179,7 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("search_result_border_color", search_result_border_color);
text_edit->add_color_override("symbol_color", symbol_color);
- text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 4));
+ text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
colors_cache.symbol_color = symbol_color;
colors_cache.keyword_color = keyword_color;
@@ -773,7 +773,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case EDIT_CLONE_DOWN: {
- code_editor->code_lines_down();
+ code_editor->clone_lines_down();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
@@ -1583,8 +1583,8 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD | KEY_SPACE);
#endif
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T);
- ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent To Spaces"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Y);
- ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent To Tabs"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_I);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Y);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_I);
ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD | KEY_I);
#ifdef OSX_ENABLED
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 17f93b55a1..638de1b213 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -263,7 +263,7 @@ void ShaderEditor::_menu_option(int p_option) {
shader_editor->delete_lines();
} break;
case EDIT_CLONE_DOWN: {
- shader_editor->code_lines_down();
+ shader_editor->clone_lines_down();
} break;
case EDIT_TOGGLE_COMMENT: {
diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp
index e7d9f1b702..8b0beefb3e 100644
--- a/editor/plugins/skeleton_editor_plugin.cpp
+++ b/editor/plugins/skeleton_editor_plugin.cpp
@@ -151,6 +151,7 @@ void SkeletonEditor::_bind_methods() {
}
SkeletonEditor::SkeletonEditor() {
+ skeleton = NULL;
options = memnew(MenuButton);
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index f57614b3b3..fa2f54d0b3 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -952,8 +952,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
int mod = _get_key_modifier(b);
- if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
- set_freelook_active(true);
+ if (!orthogonal) {
+ if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
+ set_freelook_active(true);
+ }
}
} else {
set_freelook_active(false);
@@ -1134,7 +1136,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (clicked) {
_select_clicked(clicked_wants_append, true);
- //clickd processing was deferred
+ // Processing was deferred.
clicked = 0;
}
@@ -1241,7 +1243,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (!clicked_includes_current) {
_select_clicked(clicked_wants_append, true);
- //clickd processing was deferred
+ // Processing was deferred.
}
_compute_edit(_edit.mouse_pos);
@@ -1339,7 +1341,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1468,7 +1471,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1643,6 +1647,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
nav_mode = NAVIGATION_LOOK;
+ } else if (orthogonal) {
+ nav_mode = NAVIGATION_PAN;
}
} else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
@@ -1793,7 +1799,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
_menu_option(VIEW_CENTER_TO_SELECTION);
}
- if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
+ // Orthgonal mode doesn't work in freelook.
+ if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
_update_name();
}
@@ -1823,7 +1830,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(TTR("Animation Key Inserted."));
}
- if (ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
+ // Freelook doesn't work in orthogonal mode.
+ if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
set_freelook_active(!is_freelook_active());
} else if (k->get_scancode() == KEY_ESCAPE) {
@@ -1911,37 +1919,38 @@ void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, con
void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
- // Freelook only works properly in perspective.
- // It could technically work in ortho, but it's terrible for a user due to FOV being a fixed width.
- if (!orthogonal) {
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
-
- // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
- Transform prev_camera_transform = to_camera_transform(cursor);
+ if (orthogonal) {
+ _nav_pan(p_event, p_relative);
+ return;
+ }
- if (invert_y_axis) {
- cursor.x_rot -= p_relative.y * radians_per_pixel;
- } else {
- cursor.x_rot += p_relative.y * radians_per_pixel;
- }
- cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0)
- cursor.x_rot = Math_PI / 2.0;
- if (cursor.x_rot < -Math_PI / 2.0)
- cursor.x_rot = -Math_PI / 2.0;
+ real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
- // Look is like the opposite of Orbit: the focus point rotates around the camera
- Transform camera_transform = to_camera_transform(cursor);
- Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
- Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
- Vector3 diff = prev_pos - pos;
- cursor.pos += diff;
+ // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
+ Transform prev_camera_transform = to_camera_transform(cursor);
- name = "";
- _update_name();
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
}
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+ if (cursor.x_rot > Math_PI / 2.0)
+ cursor.x_rot = Math_PI / 2.0;
+ if (cursor.x_rot < -Math_PI / 2.0)
+ cursor.x_rot = -Math_PI / 2.0;
+
+ // Look is like the opposite of Orbit: the focus point rotates around the camera
+ Transform camera_transform = to_camera_transform(cursor);
+ Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 diff = prev_pos - pos;
+ cursor.pos += diff;
+
+ name = "";
+ _update_name();
}
void SpatialEditorViewport::set_freelook_active(bool active_now) {
@@ -2222,8 +2231,21 @@ void SpatialEditorViewport::_notification(int p_what) {
bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
info_label->set_visible(show_info);
+ Camera *current_camera;
+
+ if (previewing) {
+ current_camera = previewing;
+ } else {
+ current_camera = camera;
+ }
+
if (show_info) {
String text;
+ text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n";
+ text += "Y: " + rtos(current_camera->get_translation().y).pad_decimals(1) + "\n";
+ text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n";
+ text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n";
+ text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n";
text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n";
text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n";
text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n";
@@ -2250,6 +2272,11 @@ void SpatialEditorViewport::_notification(int p_what) {
float cinema_half_width = cinema_label->get_size().width / 2.0f;
cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width);
}
+
+ if (lock_rotation) {
+ float locked_half_width = locked_label->get_size().width / 2.0f;
+ locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width);
+ }
}
if (p_what == NOTIFICATION_ENTER_TREE) {
@@ -2260,27 +2287,36 @@ void SpatialEditorViewport::_notification(int p_what) {
surface->connect("mouse_exited", this, "_surface_mouse_exit");
surface->connect("focus_entered", this, "_surface_focus_enter");
surface->connect("focus_exited", this, "_surface_focus_exit");
- view_menu->set_flat(false);
- view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
+
_init_gizmo_instance(index);
}
+
if (p_what == NOTIFICATION_EXIT_TREE) {
_finish_gizmo_instances();
}
- if (p_what == NOTIFICATION_MOUSE_ENTER) {
- }
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+
+ view_menu->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons"));
+ preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
+
+ view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- if (p_what == NOTIFICATION_DRAW) {
+ preview_camera->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+
+ info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
}
}
@@ -2521,8 +2557,14 @@ void SpatialEditorViewport::_menu_option(int p_option) {
if (!se)
continue;
- Transform xform = camera_transform;
- xform.scale_basis(sp->get_scale());
+ Transform xform;
+ if (orthogonal) {
+ xform = sp->get_global_transform();
+ xform.basis.set_euler(camera_transform.basis.get_euler());
+ } else {
+ xform = camera_transform;
+ xform.scale_basis(sp->get_scale());
+ }
undo_redo->add_do_method(sp, "set_global_transform", xform);
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
@@ -2570,9 +2612,9 @@ void SpatialEditorViewport::_menu_option(int p_option) {
lock_rotation = !current;
view_menu->get_popup()->set_item_checked(idx, !current);
if (lock_rotation) {
- view_menu->set_icon(get_icon("Lock", "EditorIcons"));
+ locked_label->show();
} else {
- view_menu->set_icon(Ref<Texture>());
+ locked_label->hide();
}
} break;
@@ -2642,11 +2684,6 @@ void SpatialEditorViewport::_menu_option(int p_option) {
bool current = view_menu->get_popup()->is_item_checked(idx);
view_menu->get_popup()->set_item_checked(idx, !current);
- if (current)
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- else
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + fps_label->get_size().height);
-
} break;
case VIEW_DISPLAY_NORMAL: {
@@ -2760,7 +2797,7 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
if (!preview)
preview_camera->hide();
- view_menu->show();
+ view_menu->set_disabled(false);
surface->update();
} else {
@@ -2768,7 +2805,7 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
previewing = preview;
previewing->connect("tree_exiting", this, "_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
- view_menu->hide();
+ view_menu->set_disabled(true);
surface->update();
}
}
@@ -3425,8 +3462,10 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
surface->set_focus_mode(FOCUS_ALL);
view_menu = memnew(MenuButton);
+ view_menu->set_flat(false);
surface->add_child(view_menu);
- view_menu->set_position(Point2(4, 4) * EDSCALE);
+ view_menu->set_position(Point2(10, 10) * EDSCALE);
+
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
@@ -3477,12 +3516,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
- preview_camera = memnew(Button);
- preview_camera->set_toggle_mode(true);
- preview_camera->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- preview_camera->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
- preview_camera->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+ preview_camera = memnew(CheckBox);
+ preview_camera->set_position(Point2(10, 38) * EDSCALE); // Below the 'view_menu' MenuButton.
preview_camera->set_text(TTR("Preview"));
surface->add_child(preview_camera);
preview_camera->hide();
@@ -3502,7 +3537,6 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
surface->add_child(info_label);
info_label->hide();
- // FPS Counter.
fps_label = memnew(Label);
fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
@@ -3520,6 +3554,16 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
cinema_label->hide();
previewing_cinema = false;
+ locked_label = memnew(Label);
+ locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
+ locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
+ locked_label->set_h_grow_direction(GROW_DIRECTION_END);
+ locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
+ locked_label->set_align(Label::ALIGN_CENTER);
+ surface->add_child(locked_label);
+ locked_label->set_text(TTR("View Rotation Locked"));
+ locked_label->hide();
+
accept = NULL;
freelook_active = false;
@@ -5443,7 +5487,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
view_menu = memnew(MenuButton);
view_menu->set_text(TTR("View"));
- view_menu->set_position(Point2(212, 0));
hbc_menu->add_child(view_menu);
p = view_menu->get_popup();
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index c552f21e39..3cce76cc17 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -192,7 +192,7 @@ private:
EditorSelection *editor_selection;
UndoRedo *undo_redo;
- Button *preview_camera;
+ CheckBox *preview_camera;
ViewportContainer *viewport_container;
MenuButton *view_menu;
@@ -211,6 +211,7 @@ private:
Label *info_label;
Label *fps_label;
Label *cinema_label;
+ Label *locked_label;
struct _RayResult {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 30246147c2..40781908fd 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -548,7 +548,6 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
} else {
hide();
- //set_physics_process(false);
}
}
@@ -816,16 +815,26 @@ SpriteFramesEditor::SpriteFramesEditor() {
void SpriteFramesEditorPlugin::edit(Object *p_object) {
frames_editor->set_undo_redo(&get_undo_redo());
- SpriteFrames *s = Object::cast_to<SpriteFrames>(p_object);
- if (!s)
- return;
+
+ SpriteFrames *s;
+ AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object);
+ if (animated_sprite) {
+ s = *animated_sprite->get_sprite_frames();
+ } else {
+ s = Object::cast_to<SpriteFrames>(p_object);
+ }
frames_editor->edit(s);
}
bool SpriteFramesEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("SpriteFrames");
+ AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object);
+ if (animated_sprite && *animated_sprite->get_sprite_frames()) {
+ return true;
+ } else {
+ return p_object->is_class("SpriteFrames");
+ }
}
void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
@@ -833,14 +842,11 @@ void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
editor->make_bottom_panel_item_visible(frames_editor);
- //frames_editor->set_process(true);
} else {
button->hide();
if (frames_editor->is_visible_in_tree())
editor->hide_bottom_panel();
-
- //frames_editor->set_process(false);
}
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 4ff7046a35..4a8eae1ba4 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -131,7 +131,7 @@ void TextEditor::_load_theme_settings() {
text_edit->add_color_override("search_result_border_color", search_result_border_color);
text_edit->add_color_override("symbol_color", symbol_color);
- text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 4));
+ text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
colors_cache.font_color = text_color;
colors_cache.symbol_color = symbol_color;
@@ -360,7 +360,7 @@ void TextEditor::_edit_option(int p_op) {
} break;
case EDIT_CLONE_DOWN: {
- code_editor->code_lines_down();
+ code_editor->clone_lines_down();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 33e1f7c6a3..7c3e524d89 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -846,7 +846,8 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
p->set_item_checked(0, true);
p->connect("id_pressed", this, "_set_snap_mode");
hb_grid = memnew(HBoxContainer);
- hb_tools->add_child(hb_grid);
+ //hb_tools->add_child(hb_grid);
+ main_vb->add_child(hb_grid);
hb_grid->add_child(memnew(VSeparator));
hb_grid->add_child(memnew(Label(TTR("Offset:"))));
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 27c3ff960b..213cd2ce1a 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "tile_map_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "core/math/math_funcs.h"
#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
@@ -43,8 +44,8 @@ void TileMapEditor::_notification(int p_what) {
case NOTIFICATION_PROCESS: {
- if (bucket_queue.size() && canvas_item_editor_viewport) {
- canvas_item_editor_viewport->update();
+ if (bucket_queue.size()) {
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
@@ -65,13 +66,11 @@ void TileMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
- transp->set_icon(get_icon("Transpose", "EditorIcons"));
- mirror_x->set_icon(get_icon("MirrorX", "EditorIcons"));
- mirror_y->set_icon(get_icon("MirrorY", "EditorIcons"));
- rotate_0->set_icon(get_icon("Rotate0", "EditorIcons"));
- rotate_90->set_icon(get_icon("Rotate90", "EditorIcons"));
- rotate_180->set_icon(get_icon("Rotate180", "EditorIcons"));
- rotate_270->set_icon(get_icon("Rotate270", "EditorIcons"));
+ rotate_left_button->set_icon(get_icon("Rotate270", "EditorIcons"));
+ rotate_right_button->set_icon(get_icon("Rotate90", "EditorIcons"));
+ flip_horizontal_button->set_icon(get_icon("MirrorX", "EditorIcons"));
+ flip_vertical_button->set_icon(get_icon("MirrorY", "EditorIcons"));
+ clear_transform_button->set_icon(get_icon("Clear", "EditorIcons"));
search_box->set_right_icon(get_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
@@ -97,27 +96,27 @@ void TileMapEditor::_menu_option(int p_option) {
// immediately without pressing the left mouse button first
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_BUCKET: {
tool = TOOL_BUCKET;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_PICK_TILE: {
tool = TOOL_PICKING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_SELECT: {
tool = TOOL_SELECTING;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_COPY: {
@@ -126,7 +125,7 @@ void TileMapEditor::_menu_option(int p_option) {
if (selection_active) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
case OPTION_ERASE_SELECTION: {
@@ -141,7 +140,7 @@ void TileMapEditor::_menu_option(int p_option) {
selection_active = false;
copydata.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_FIX_INVALID: {
@@ -165,7 +164,7 @@ void TileMapEditor::_menu_option(int p_option) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
}
@@ -182,13 +181,13 @@ void TileMapEditor::_palette_multi_selected(int index, bool selected) {
void TileMapEditor::_canvas_mouse_enter() {
mouse_over = true;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_canvas_mouse_exit() {
mouse_over = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
Vector<int> TileMapEditor::get_selected_tiles() const {
@@ -301,7 +300,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
}
node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose);
- if (manual_autotile || node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE) {
+ if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) {
if (current != -1) {
node->set_cell_autotile_coord(p_pos.x, p_pos.y, position);
}
@@ -357,6 +356,10 @@ void TileMapEditor::_update_palette() {
if (!node)
return;
+ // Update the clear button
+ clear_transform_button->set_disabled(!flip_h && !flip_v && !transpose);
+
+ // Update the palette
Vector<int> selected = get_selected_tiles();
palette->clear();
manual_palette->clear();
@@ -429,9 +432,6 @@ void TileMapEditor::_update_palette() {
Ref<Texture> tex = tileset->tile_get_texture(entries[i].id);
if (tex.is_valid()) {
- Color color = tileset->tile_get_modulate(entries[i].id);
- palette->set_item_icon_modulate(palette->get_item_count() - 1, color);
-
Rect2 region = tileset->tile_get_region(entries[i].id);
if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) {
@@ -440,10 +440,25 @@ void TileMapEditor::_update_palette() {
region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id);
}
- if (!region.has_no_area())
+ // Transpose and flip
+ palette->set_item_icon_transposed(palette->get_item_count() - 1, transpose);
+ if (flip_h) {
+ region.size.x = -region.size.x;
+ }
+ if (flip_v) {
+ region.size.y = -region.size.y;
+ }
+
+ // Set region
+ if (region.size != Size2())
palette->set_item_icon_region(palette->get_item_count() - 1, region);
+ // Set icon
palette->set_item_icon(palette->get_item_count() - 1, tex);
+
+ // Modulation
+ Color color = tileset->tile_get_modulate(entries[i].id);
+ palette->set_item_icon_modulate(palette->get_item_count() - 1, color);
}
palette->set_item_metadata(palette->get_item_count() - 1, entries[i].id);
@@ -519,12 +534,12 @@ void TileMapEditor::_pick_tile(const Point2 &p_pos) {
selected.push_back(id);
set_selected_tiles(selected);
- mirror_x->set_pressed(node->is_cell_x_flipped(p_pos.x, p_pos.y));
- mirror_y->set_pressed(node->is_cell_y_flipped(p_pos.x, p_pos.y));
- transp->set_pressed(node->is_cell_transposed(p_pos.x, p_pos.y));
+ flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y);
+ flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y);
+ transpose = node->is_cell_transposed(p_pos.x, p_pos.y);
- _update_transform_buttons();
- canvas_item_editor_viewport->update();
+ _update_palette();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) {
@@ -671,7 +686,7 @@ void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) {
rectangle.position = begin;
rectangle.size = end - begin;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_erase_selection() {
@@ -978,7 +993,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
@@ -995,7 +1010,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
_finish_undo();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} else if (tool == TOOL_PASTING) {
@@ -1011,12 +1026,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
_finish_undo();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true; // We want to keep the Pasting tool
} else if (tool == TOOL_SELECTING) {
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} else if (tool == TOOL_BUCKET) {
@@ -1055,7 +1070,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1065,7 +1080,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
copydata.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1106,7 +1121,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_finish_undo();
if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
tool = TOOL_NONE;
@@ -1149,7 +1164,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (new_over_tile != over_tile) {
over_tile = new_over_tile;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
if (show_tile_info) {
@@ -1235,7 +1250,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_set_cell(points[i], invalid_cell);
}
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
return true;
@@ -1294,7 +1309,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1308,13 +1323,13 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// NOTE: We do not set tool = TOOL_PAINTING as this begins painting
// immediately without pressing the left mouse button first
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) {
tool = TOOL_BUCKET;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1327,7 +1342,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_SELECTING;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1337,7 +1352,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (selection_active) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1354,7 +1369,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
}
@@ -1366,23 +1381,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("tile_map_editor/mirror_x", p_event)) {
flip_h = !flip_h;
- mirror_x->set_pressed(flip_h);
- _update_transform_buttons();
- canvas_item_editor_viewport->update();
+ _update_palette();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/mirror_y", p_event)) {
flip_v = !flip_v;
- mirror_y->set_pressed(flip_v);
- _update_transform_buttons();
- canvas_item_editor_viewport->update();
+ _update_palette();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/transpose", p_event)) {
transpose = !transpose;
- transp->set_pressed(transpose);
- _update_transform_buttons();
- canvas_item_editor_viewport->update();
+ _update_palette();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
}
@@ -1643,9 +1655,7 @@ void TileMapEditor::edit(Node *p_tile_map) {
void TileMapEditor::_tileset_settings_changed() {
_update_palette();
-
- if (canvas_item_editor_viewport)
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_icon_size_changed(float p_value) {
@@ -1666,7 +1676,10 @@ void TileMapEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_canvas_mouse_enter"), &TileMapEditor::_canvas_mouse_enter);
ClassDB::bind_method(D_METHOD("_canvas_mouse_exit"), &TileMapEditor::_canvas_mouse_exit);
ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed);
- ClassDB::bind_method(D_METHOD("_update_transform_buttons"), &TileMapEditor::_update_transform_buttons);
+ ClassDB::bind_method(D_METHOD("_rotate"), &TileMapEditor::_rotate);
+ ClassDB::bind_method(D_METHOD("_flip_horizontal"), &TileMapEditor::_flip_horizontal);
+ ClassDB::bind_method(D_METHOD("_flip_vertical"), &TileMapEditor::_flip_vertical);
+ ClassDB::bind_method(D_METHOD("_clear_transform"), &TileMapEditor::_clear_transform);
ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected);
ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected);
@@ -1691,37 +1704,67 @@ TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) {
return op;
}
-void TileMapEditor::_update_transform_buttons(Object *p_button) {
- //ERR_FAIL_NULL(p_button);
- ToolButton *b = Object::cast_to<ToolButton>(p_button);
- //ERR_FAIL_COND(!b);
-
- if (b == rotate_0) {
- mirror_x->set_pressed(false);
- mirror_y->set_pressed(false);
- transp->set_pressed(false);
- } else if (b == rotate_90) {
- mirror_x->set_pressed(true);
- mirror_y->set_pressed(false);
- transp->set_pressed(true);
- } else if (b == rotate_180) {
- mirror_x->set_pressed(true);
- mirror_y->set_pressed(true);
- transp->set_pressed(false);
- } else if (b == rotate_270) {
- mirror_x->set_pressed(false);
- mirror_y->set_pressed(true);
- transp->set_pressed(true);
+void TileMapEditor::_rotate(int steps) {
+ const bool normal_rotation_matrix[][3] = {
+ { false, false, false },
+ { true, true, false },
+ { false, true, true },
+ { true, false, true }
+ };
+
+ const bool mirrored_rotation_matrix[][3] = {
+ { false, true, false },
+ { true, true, true },
+ { false, false, true },
+ { true, false, false }
+ };
+
+ if (transpose ^ flip_h ^ flip_v) {
+ // Odd number of flags activated = mirrored rotation
+ for (int i = 0; i < 4; i++) {
+ if (transpose == mirrored_rotation_matrix[i][0] &&
+ flip_h == mirrored_rotation_matrix[i][1] &&
+ flip_v == mirrored_rotation_matrix[i][2]) {
+ int new_id = Math::wrapi(i + steps, 0, 4);
+ transpose = mirrored_rotation_matrix[new_id][0];
+ flip_h = mirrored_rotation_matrix[new_id][1];
+ flip_v = mirrored_rotation_matrix[new_id][2];
+ break;
+ }
+ }
+ } else {
+ // Even number of flags activated = normal rotation
+ for (int i = 0; i < 4; i++) {
+ if (transpose == normal_rotation_matrix[i][0] &&
+ flip_h == normal_rotation_matrix[i][1] &&
+ flip_v == normal_rotation_matrix[i][2]) {
+ int new_id = Math::wrapi(i + steps, 0, 4);
+ transpose = normal_rotation_matrix[new_id][0];
+ flip_h = normal_rotation_matrix[new_id][1];
+ flip_v = normal_rotation_matrix[new_id][2];
+ break;
+ }
+ }
}
- flip_h = mirror_x->is_pressed();
- flip_v = mirror_y->is_pressed();
- transpose = transp->is_pressed();
+ _update_palette();
+}
+
+void TileMapEditor::_flip_horizontal() {
+ flip_h = !flip_h;
+ _update_palette();
+}
+
+void TileMapEditor::_flip_vertical() {
+ flip_v = !flip_v;
+ _update_palette();
+}
- rotate_0->set_pressed(!flip_h && !flip_v && !transpose);
- rotate_90->set_pressed(flip_h && !flip_v && transpose);
- rotate_180->set_pressed(flip_h && flip_v && !transpose);
- rotate_270->set_pressed(!flip_h && flip_v && transpose);
+void TileMapEditor::_clear_transform() {
+ transpose = false;
+ flip_h = false;
+ flip_v = false;
+ _update_palette();
}
TileMapEditor::TileMapEditor(EditorNode *p_editor) {
@@ -1754,10 +1797,8 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
ED_SHORTCUT("tile_map_editor/mirror_x", TTR("Mirror X"), KEY_A);
ED_SHORTCUT("tile_map_editor/mirror_y", TTR("Mirror Y"), KEY_S);
- HBoxContainer *tool_hb1 = memnew(HBoxContainer);
- add_child(tool_hb1);
- HBoxContainer *tool_hb2 = memnew(HBoxContainer);
- add_child(tool_hb2);
+ HBoxContainer *tool_hb = memnew(HBoxContainer);
+ add_child(tool_hb);
manual_button = memnew(CheckBox);
manual_button->set_text("Disable Autotile");
@@ -1842,52 +1883,37 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
p->connect("id_pressed", this, "_menu_option");
toolbar->add_child(options);
-
- transp = memnew(ToolButton);
- transp->set_toggle_mode(true);
- transp->set_tooltip(TTR("Transpose") + " (" + ED_GET_SHORTCUT("tile_map_editor/transpose")->get_as_text() + ")");
- transp->set_focus_mode(FOCUS_NONE);
- transp->connect("pressed", this, "_update_transform_buttons", make_binds(transp));
- tool_hb1->add_child(transp);
- mirror_x = memnew(ToolButton);
- mirror_x->set_toggle_mode(true);
- mirror_x->set_tooltip(TTR("Mirror X") + " (" + ED_GET_SHORTCUT("tile_map_editor/mirror_x")->get_as_text() + ")");
- mirror_x->set_focus_mode(FOCUS_NONE);
- mirror_x->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_x));
- tool_hb1->add_child(mirror_x);
- mirror_y = memnew(ToolButton);
- mirror_y->set_toggle_mode(true);
- mirror_y->set_tooltip(TTR("Mirror Y") + " (" + ED_GET_SHORTCUT("tile_map_editor/mirror_y")->get_as_text() + ")");
- mirror_y->set_focus_mode(FOCUS_NONE);
- mirror_y->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_y));
- tool_hb1->add_child(mirror_y);
-
- rotate_0 = memnew(ToolButton);
- rotate_0->set_toggle_mode(true);
- rotate_0->set_tooltip(TTR("Rotate 0 degrees"));
- rotate_0->set_focus_mode(FOCUS_NONE);
- rotate_0->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_0));
- tool_hb2->add_child(rotate_0);
- rotate_90 = memnew(ToolButton);
- rotate_90->set_toggle_mode(true);
- rotate_90->set_tooltip(TTR("Rotate 90 degrees"));
- rotate_90->set_focus_mode(FOCUS_NONE);
- rotate_90->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_90));
- tool_hb2->add_child(rotate_90);
- rotate_180 = memnew(ToolButton);
- rotate_180->set_toggle_mode(true);
- rotate_180->set_tooltip(TTR("Rotate 180 degrees"));
- rotate_180->set_focus_mode(FOCUS_NONE);
- rotate_180->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_180));
- tool_hb2->add_child(rotate_180);
- rotate_270 = memnew(ToolButton);
- rotate_270->set_toggle_mode(true);
- rotate_270->set_tooltip(TTR("Rotate 270 degrees"));
- rotate_270->set_focus_mode(FOCUS_NONE);
- rotate_270->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_270));
- tool_hb2->add_child(rotate_270);
-
- rotate_0->set_pressed(true);
+ rotate_left_button = memnew(ToolButton);
+ rotate_left_button->set_tooltip(TTR("Rotate left"));
+ rotate_left_button->set_focus_mode(FOCUS_NONE);
+ rotate_left_button->connect("pressed", this, "_rotate", varray(-1));
+ tool_hb->add_child(rotate_left_button);
+
+ rotate_right_button = memnew(ToolButton);
+ rotate_right_button->set_tooltip(TTR("Rotate right"));
+ rotate_right_button->set_focus_mode(FOCUS_NONE);
+ rotate_right_button->connect("pressed", this, "_rotate", varray(1));
+ tool_hb->add_child(rotate_right_button);
+
+ flip_horizontal_button = memnew(ToolButton);
+ flip_horizontal_button->set_tooltip(TTR("Flip horizontally"));
+ flip_horizontal_button->set_focus_mode(FOCUS_NONE);
+ flip_horizontal_button->connect("pressed", this, "_flip_horizontal");
+ tool_hb->add_child(flip_horizontal_button);
+
+ flip_vertical_button = memnew(ToolButton);
+ flip_vertical_button->set_tooltip(TTR("Flip vertically"));
+ flip_vertical_button->set_focus_mode(FOCUS_NONE);
+ flip_vertical_button->connect("pressed", this, "_flip_vertical");
+ tool_hb->add_child(flip_vertical_button);
+
+ clear_transform_button = memnew(ToolButton);
+ clear_transform_button->set_tooltip(TTR("Clear transform"));
+ clear_transform_button->set_focus_mode(FOCUS_NONE);
+ clear_transform_button->connect("pressed", this, "_clear_transform");
+ tool_hb->add_child(clear_transform_button);
+
+ clear_transform_button->set_disabled(true);
}
TileMapEditor::~TileMapEditor() {
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 3d44647a1b..68e5806ee5 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -93,13 +93,13 @@ class TileMapEditor : public VBoxContainer {
Label *tile_info;
MenuButton *options;
- ToolButton *transp;
- ToolButton *mirror_x;
- ToolButton *mirror_y;
- ToolButton *rotate_0;
- ToolButton *rotate_90;
- ToolButton *rotate_180;
- ToolButton *rotate_270;
+
+ ToolButton *flip_horizontal_button;
+ ToolButton *flip_vertical_button;
+ ToolButton *rotate_left_button;
+ ToolButton *rotate_right_button;
+ ToolButton *clear_transform_button;
+
CheckBox *manual_button;
Tool tool;
@@ -196,11 +196,15 @@ class TileMapEditor : public VBoxContainer {
void _tileset_settings_changed();
void _icon_size_changed(float p_value);
+ void _clear_transform();
+ void _flip_horizontal();
+ void _flip_vertical();
+ void _rotate(int steps);
+
protected:
void _notification(int p_what);
static void _bind_methods();
CellOp _get_op_from_cell(const Point2i &p_pos);
- void _update_transform_buttons(Object *p_button = NULL);
public:
HBoxContainer *get_toolbar() const { return toolbar; }
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 9988d82fb8..d0e0b3e006 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -483,6 +483,11 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
//---------------
helper = memnew(TilesetEditorContext(this));
tile_names_opacity = 0;
+
+ // config scale
+ max_scale = 10.0f;
+ min_scale = 0.1f;
+ scale_ratio = 1.2f;
}
TileSetEditor::~TileSetEditor() {
@@ -953,7 +958,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Ref<InputEventMouseMotion> mm = p_ie;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) {
if (!current_tile_region.has_point(mb->get_position())) {
List<int> *tiles = new List<int>();
tileset->get_tile_list(tiles);
@@ -972,6 +977,15 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
}
+
+ // Mouse Wheel Event
+ const int _mouse_button_index = mb->get_button_index();
+ if (_mouse_button_index == BUTTON_WHEEL_UP && mb->get_control()) {
+ _zoom_in();
+
+ } else if (_mouse_button_index == BUTTON_WHEEL_DOWN && mb->get_control()) {
+ _zoom_out();
+ }
}
// Drag Middle Mouse
if (mm.is_valid()) {
@@ -1448,23 +1462,11 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
}
}
} else if (p_tool == ZOOM_OUT) {
- float scale = workspace->get_scale().x;
- if (scale > 0.1) {
- scale /= 2;
- workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
- }
+ _zoom_out();
} else if (p_tool == ZOOM_1) {
- workspace->set_scale(Vector2(1, 1));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size);
+ _reset_zoom();
} else if (p_tool == ZOOM_IN) {
- float scale = workspace->get_scale().x;
- scale *= 2;
- workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
+ _zoom_in();
} else if (p_tool == TOOL_SELECT) {
if (creating_shape) {
// Cancel Creation
@@ -1503,6 +1505,31 @@ void TileSetEditor::_set_snap_sep(Vector2 p_val) {
workspace->update();
}
+void TileSetEditor::_zoom_in() {
+ float scale = workspace->get_scale().x;
+ if (scale < max_scale) {
+ scale *= scale_ratio;
+ workspace->set_scale(Vector2(scale, scale));
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
+ }
+}
+void TileSetEditor::_zoom_out() {
+
+ float scale = workspace->get_scale().x;
+ if (scale > min_scale) {
+ scale /= scale_ratio;
+ workspace->set_scale(Vector2(scale, scale));
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
+ }
+}
+void TileSetEditor::_reset_zoom() {
+ workspace->set_scale(Vector2(1, 1));
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size);
+}
+
void TileSetEditor::draw_highlight_current_tile() {
if (get_current_tile() >= 0) {
@@ -2084,13 +2111,24 @@ void TileSetEditor::update_texture_list() {
List<int> ids;
tileset->get_tile_list(&ids);
+ Vector<int> ids_to_remove;
for (List<int>::Element *E = ids.front(); E; E = E->next()) {
+ // Clear tiles referencing gone textures (user has been already given the chance to fix broken deps)
+ if (!tileset->tile_get_texture(E->get()).is_valid()) {
+ ids_to_remove.push_back(E->get());
+ ERR_CONTINUE(!tileset->tile_get_texture(E->get()).is_valid());
+ }
+
if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) {
texture_list->add_item(tileset->tile_get_texture(E->get())->get_path().get_file());
texture_map.insert(tileset->tile_get_texture(E->get())->get_rid(), tileset->tile_get_texture(E->get()));
texture_list->set_item_metadata(texture_list->get_item_count() - 1, tileset->tile_get_texture(E->get())->get_rid());
}
}
+ for (int i = 0; i < ids_to_remove.size(); i++) {
+ tileset->remove_tile(ids_to_remove[i]);
+ }
+
if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) {
texture_list->select(texture_list->find_metadata(selected_texture->get_rid()));
if (texture_list->get_selected_items().size() > 0)
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 23bf68b90f..bd8a2ddb98 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -141,6 +141,10 @@ class TileSetEditor : public Control {
EditMode edit_mode;
int current_tile;
+ float max_scale;
+ float min_scale;
+ float scale_ratio;
+
void update_texture_list();
void update_texture_list_icon();
@@ -178,6 +182,10 @@ private:
void _set_snap_off(Vector2 p_val);
void _set_snap_sep(Vector2 p_val);
+ void _zoom_in();
+ void _zoom_out();
+ void _reset_zoom();
+
void draw_highlight_current_tile();
void draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>());
void draw_tile_subdivision(int p_id, Color p_color) const;
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 29a780961e..4a98aa411d 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -39,7 +39,7 @@ void BackgroundProgress::_add_task(const String &p_task, const String &p_label,
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(tasks.has(p_task));
- Task t;
+ BackgroundProgress::Task t;
t.hb = memnew(HBoxContainer);
Label *l = memnew(Label);
l->set_text(p_label + " ");
@@ -112,7 +112,7 @@ void BackgroundProgress::add_task(const String &p_task, const String &p_label, i
void BackgroundProgress::task_step(const String &p_task, int p_step) {
//this code is weird, but it prevents deadlock.
- bool no_updates;
+ bool no_updates = true;
{
_THREAD_SAFE_METHOD_
no_updates = updates.empty();
@@ -167,7 +167,7 @@ void ProgressDialog::_popup() {
void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
ERR_FAIL_COND(tasks.has(p_task));
- Task t;
+ ProgressDialog::Task t;
t.vb = memnew(VBoxContainer);
VBoxContainer *vb2 = memnew(VBoxContainer);
t.vb->add_margin_child(p_label, vb2);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 3ec49e187f..f8ba6fd4e3 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -50,6 +50,7 @@ void ProjectExportDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
+ duplicate_preset->set_icon(get_icon("Duplicate", "EditorIcons"));
delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
connect("confirmed", this, "_export_pck_zip");
custom_feature_display->get_parent_control()->add_style_override("panel", get_stylebox("bg", "Tree"));
@@ -58,6 +59,7 @@ void ProjectExportDialog::_notification(int p_what) {
EditorSettings::get_singleton()->set("interface/dialogs/export_bounds", get_rect());
} break;
case NOTIFICATION_THEME_CHANGED: {
+ duplicate_preset->set_icon(get_icon("Duplicate", "EditorIcons"));
delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
Control *panel = custom_feature_display->get_parent_control();
if (panel)
@@ -163,14 +165,37 @@ void ProjectExportDialog::_update_presets() {
updating = false;
}
+void ProjectExportDialog::_update_export_all() {
+
+ bool can_export = EditorExport::get_singleton()->get_export_preset_count() > 0 ? true : false;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
+ bool needs_templates;
+ String error;
+ if (preset->get_export_path() == "" || !preset->get_platform()->can_export(preset, error, needs_templates)) {
+ can_export = false;
+ break;
+ }
+ }
+
+ if (can_export) {
+ export_all_button->set_disabled(false);
+ } else {
+ export_all_button->set_disabled(true);
+ }
+}
+
void ProjectExportDialog::_edit_preset(int p_index) {
if (p_index < 0 || p_index >= presets->get_item_count()) {
name->set_text("");
name->set_editable(false);
+ export_path->set_editable(false);
runnable->set_disabled(true);
parameters->edit(NULL);
presets->unselect_all();
+ duplicate_preset->set_disabled(true);
delete_preset->set_disabled(true);
sections->hide();
patches->clear();
@@ -188,8 +213,11 @@ void ProjectExportDialog::_edit_preset(int p_index) {
sections->show();
name->set_editable(true);
+ export_path->set_editable(true);
+ duplicate_preset->set_disabled(false);
delete_preset->set_disabled(false);
name->set_text(current->get_name());
+ export_path->set_text(current->get_export_path());
runnable->set_disabled(false);
runnable->set_pressed(current->is_runnable());
parameters->edit(current.ptr());
@@ -260,6 +288,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
custom_features->set_text(current->get_custom_features());
_update_feature_list();
+ _update_export_all();
updating = false;
}
@@ -428,6 +457,73 @@ void ProjectExportDialog::_name_changed(const String &p_string) {
_update_presets();
}
+void ProjectExportDialog::_export_path_changed(const String &p_string) {
+
+ if (updating)
+ return;
+
+ Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
+ ERR_FAIL_COND(current.is_null());
+
+ current->set_export_path(p_string);
+ _update_presets();
+}
+
+void ProjectExportDialog::_duplicate_preset() {
+
+ Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
+ if (current.is_null())
+ return;
+
+ Ref<EditorExportPreset> preset = current->get_platform()->create_preset();
+ ERR_FAIL_COND(!preset.is_valid());
+
+ String name = current->get_name() + "" + itos(1);
+ bool make_runnable = true;
+ int attempt = 2;
+ while (true) {
+
+ bool valid = true;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
+ if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
+ make_runnable = false;
+ }
+ if (p->get_name() == name) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid)
+ break;
+
+ attempt++;
+ name = current->get_name() + " " + itos(attempt);
+ }
+
+ preset->set_name(name);
+ if (make_runnable)
+ preset->set_runnable(make_runnable);
+ preset->set_export_filter(current->get_export_filter());
+ preset->set_include_filter(current->get_include_filter());
+ preset->set_exclude_filter(current->get_exclude_filter());
+ Vector<String> list = current->get_patches();
+ for (int i = 0; i < list.size(); i++) {
+ preset->add_patch(list[i]);
+ }
+ preset->set_custom_features(current->get_custom_features());
+
+ for (const List<PropertyInfo>::Element *E = current->get_properties().front(); E; E = E->next()) {
+ preset->set(E->get().name, current->get(E->get().name));
+ }
+
+ EditorExport::get_singleton()->add_export_preset(preset);
+ _update_presets();
+ _edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1);
+}
+
void ProjectExportDialog::_delete_preset() {
Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
@@ -745,12 +841,19 @@ void ProjectExportDialog::_export_project() {
export_project->set_access(FileDialog::ACCESS_FILESYSTEM);
export_project->clear_filters();
- String extension = platform->get_binary_extension(current);
- if (extension != String()) {
- export_project->add_filter("*." + extension + " ; " + platform->get_name() + " Export");
- export_project->set_current_file(default_filename + "." + extension);
+ List<String> extension_list = platform->get_binary_extensions(current);
+ for (int i = 0; i < extension_list.size(); i++) {
+ export_project->add_filter("*." + extension_list[i] + " ; " + platform->get_name() + " Export");
+ }
+
+ if (current->get_export_path() != "") {
+ export_project->set_current_path(current->get_export_path());
} else {
- export_project->set_current_file(default_filename);
+ if (extension_list.size() >= 1) {
+ export_project->set_current_file(default_filename + "." + extension_list[0]);
+ } else {
+ export_project->set_current_file(default_filename);
+ }
}
// Ensure that signal is connected if previous attempt left it disconnected with _validate_export_path
@@ -772,6 +875,7 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
ERR_FAIL_COND(current.is_null());
Ref<EditorExportPlatform> platform = current->get_platform();
ERR_FAIL_COND(platform.is_null());
+ current->set_export_path(p_path);
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
if (err != OK) {
@@ -782,6 +886,42 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
}
}
+void ProjectExportDialog::_export_all_dialog() {
+
+ export_all_dialog->show();
+ export_all_dialog->popup_centered_minsize(Size2(300, 80));
+}
+
+void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
+
+ export_all_dialog->hide();
+
+ _export_all(p_str == "release" ? false : true);
+}
+
+void ProjectExportDialog::_export_all(bool p_debug) {
+
+ String mode = p_debug ? TTR("Debug") : TTR("Release");
+ EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count());
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
+ ERR_FAIL_COND(preset.is_null());
+ Ref<EditorExportPlatform> platform = preset->get_platform();
+ ERR_FAIL_COND(platform.is_null());
+
+ ep.step(preset->get_name(), i);
+
+ Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
+ if (err != OK) {
+ error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
+ error_dialog->show();
+ error_dialog->popup_centered_minsize(Size2(300, 80));
+ ERR_PRINT("Failed to export project");
+ }
+ }
+}
+
void ProjectExportDialog::_bind_methods() {
ClassDB::bind_method("_add_preset", &ProjectExportDialog::_add_preset);
@@ -789,6 +929,7 @@ void ProjectExportDialog::_bind_methods() {
ClassDB::bind_method("_update_parameters", &ProjectExportDialog::_update_parameters);
ClassDB::bind_method("_runnable_pressed", &ProjectExportDialog::_runnable_pressed);
ClassDB::bind_method("_name_changed", &ProjectExportDialog::_name_changed);
+ ClassDB::bind_method("_duplicate_preset", &ProjectExportDialog::_duplicate_preset);
ClassDB::bind_method("_delete_preset", &ProjectExportDialog::_delete_preset);
ClassDB::bind_method("_delete_preset_confirm", &ProjectExportDialog::_delete_preset_confirm);
ClassDB::bind_method("get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
@@ -805,8 +946,12 @@ void ProjectExportDialog::_bind_methods() {
ClassDB::bind_method("_export_pck_zip_selected", &ProjectExportDialog::_export_pck_zip_selected);
ClassDB::bind_method("_open_export_template_manager", &ProjectExportDialog::_open_export_template_manager);
ClassDB::bind_method("_validate_export_path", &ProjectExportDialog::_validate_export_path);
+ ClassDB::bind_method("_export_path_changed", &ProjectExportDialog::_export_path_changed);
ClassDB::bind_method("_export_project", &ProjectExportDialog::_export_project);
ClassDB::bind_method("_export_project_to_path", &ProjectExportDialog::_export_project_to_path);
+ ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
+ ClassDB::bind_method("_export_all_dialog", &ProjectExportDialog::_export_all_dialog);
+ ClassDB::bind_method("_export_all_dialog_action", &ProjectExportDialog::_export_all_dialog_action);
ClassDB::bind_method("_custom_features_changed", &ProjectExportDialog::_custom_features_changed);
ClassDB::bind_method("_tab_changed", &ProjectExportDialog::_tab_changed);
}
@@ -842,6 +987,9 @@ ProjectExportDialog::ProjectExportDialog() {
presets->set_drag_forwarding(this);
mc->add_child(presets);
presets->connect("item_selected", this, "_edit_preset");
+ duplicate_preset = memnew(ToolButton);
+ preset_hb->add_child(duplicate_preset);
+ duplicate_preset->connect("pressed", this, "_duplicate_preset");
delete_preset = memnew(ToolButton);
preset_hb->add_child(delete_preset);
delete_preset->connect("pressed", this, "_delete_preset");
@@ -858,6 +1006,10 @@ ProjectExportDialog::ProjectExportDialog() {
runnable->connect("pressed", this, "_runnable_pressed");
settings_vb->add_child(runnable);
+ export_path = memnew(LineEdit);
+ settings_vb->add_margin_child(TTR("Export Path:"), export_path);
+ export_path->connect("text_changed", this, "_export_path_changed");
+
sections = memnew(TabContainer);
sections->set_tab_align(TabContainer::ALIGN_LEFT);
settings_vb->add_child(sections);
@@ -948,7 +1100,9 @@ ProjectExportDialog::ProjectExportDialog() {
//disable by default
name->set_editable(false);
+ export_path->set_editable(false);
runnable->set_disabled(true);
+ duplicate_preset->set_disabled(true);
delete_preset->set_disabled(true);
sections->hide();
parameters->edit(NULL);
@@ -967,6 +1121,19 @@ ProjectExportDialog::ProjectExportDialog() {
// Disable initially before we select a valid preset
export_button->set_disabled(true);
+ export_all_dialog = memnew(ConfirmationDialog);
+ add_child(export_all_dialog);
+ export_all_dialog->set_title("Export All");
+ export_all_dialog->set_text(TTR("Export mode?"));
+ export_all_dialog->get_ok()->hide();
+ export_all_dialog->add_button(TTR("Debug"), true, "debug");
+ export_all_dialog->add_button(TTR("Release"), true, "release");
+ export_all_dialog->connect("custom_action", this, "_export_all_dialog_action");
+
+ export_all_button = add_button(TTR("Export All"), !OS::get_singleton()->get_swap_ok_cancel(), "export");
+ export_all_button->connect("pressed", this, "_export_all_dialog");
+ export_all_button->set_disabled(true);
+
export_pck_zip = memnew(FileDialog);
export_pck_zip->add_filter("*.zip ; ZIP File");
export_pck_zip->add_filter("*.pck ; Godot Game Pack");
@@ -1030,6 +1197,8 @@ ProjectExportDialog::ProjectExportDialog() {
default_filename = "UnnamedProject";
}
}
+
+ _update_export_all();
}
ProjectExportDialog::~ProjectExportDialog() {
diff --git a/editor/project_export.h b/editor/project_export.h
index 552c6d7faf..7009968138 100644
--- a/editor/project_export.h
+++ b/editor/project_export.h
@@ -61,10 +61,12 @@ private:
TabContainer *sections;
MenuButton *add_preset;
+ Button *duplicate_preset;
Button *delete_preset;
ItemList *presets;
LineEdit *name;
+ LineEdit *export_path;
EditorInspector *parameters;
CheckButton *runnable;
@@ -91,6 +93,8 @@ private:
ConfirmationDialog *patch_erase;
Button *export_button;
+ Button *export_all_button;
+ AcceptDialog *export_all_dialog;
LineEdit *custom_features;
RichTextLabel *custom_feature_display;
@@ -106,10 +110,13 @@ private:
void _runnable_pressed();
void _update_parameters(const String &p_edited_property);
void _name_changed(const String &p_string);
+ void _export_path_changed(const String &p_string);
void _add_preset(int p_platform);
void _edit_preset(int p_index);
+ void _duplicate_preset();
void _delete_preset();
void _delete_preset_confirm();
+ void _update_export_all();
void _update_presets();
@@ -139,6 +146,9 @@ private:
void _validate_export_path(const String &p_path);
void _export_project();
void _export_project_to_path(const String &p_path);
+ void _export_all_dialog();
+ void _export_all_dialog_action(const String &p_str);
+ void _export_all(bool p_debug);
void _update_feature_list();
void _custom_features_changed(const String &p_text);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 83de5a646a..8c906e5f0b 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1312,7 +1312,7 @@ void ProjectManager::_load_recent_projects() {
show->set_modulate(Color(1, 1, 1, 0.5));
path_hb->add_child(show);
show->connect("pressed", this, "_show_project", varray(path));
- show->set_tooltip(TTR("Show In File Manager"));
+ show->set_tooltip(TTR("Show in File Manager"));
Label *fpath = memnew(Label(path));
fpath->set_name("path");
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 9ef6e4332c..8da75b7b3f 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -968,7 +968,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
RES r = v;
if (r.is_valid() && r->get_path().is_resource_file()) {
menu->add_separator();
- menu->add_item(TTR("Show in File System"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
+ menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
}
} else {
}
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index 9042bdc7c1..a8c97be936 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -394,6 +394,8 @@ void PropertySelector::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
connect("confirmed", this, "_confirmed");
+ } else if (p_what == NOTIFICATION_EXIT_TREE) {
+ disconnect("confirmed", this, "_confirmed");
}
}
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index e48a0022e8..8dacc3c142 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -261,6 +261,8 @@ void EditorQuickOpen::_notification(int p_what) {
search_box->set_right_icon(get_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
+ } else if (p_what == NOTIFICATION_EXIT_TREE) {
+ disconnect("confirmed", this, "_confirmed");
}
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 8925804710..fe438236c9 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -53,6 +53,13 @@ void SceneTreeDock::_nodes_drag_begin() {
}
}
+void SceneTreeDock::_quick_open() {
+ Vector<String> files = quick_open->get_selected_files();
+ for (int i = 0; i < files.size(); i++) {
+ instance(files[i]);
+ }
+}
+
void SceneTreeDock::_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> mb = p_event;
@@ -319,16 +326,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- List<String> extensions;
- ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
- file->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
-
- file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- }
-
- file->popup_centered_ratio();
+ quick_open->popup_dialog("PackedScene", true);
+ quick_open->set_title(TTR("Instance Child Scene"));
} break;
case TOOL_REPLACE: {
@@ -359,15 +358,12 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
ScriptLanguage *l = ScriptServer::get_language(i);
if (l->get_type() == existing->get_class()) {
String name = l->get_global_class_name(existing->get_path());
- if (ScriptServer::is_global_class(name)) {
- if (EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
- inherits = editor->get_editor_data().script_class_get_base(name);
- } else if (l->can_inherit_from_file()) {
- inherits = "\"" + existing->get_path() + "\"";
- }
- } else {
+ if (ScriptServer::is_global_class(name) && EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
+ inherits = name;
+ } else if (l->can_inherit_from_file()) {
inherits = "\"" + existing->get_path() + "\"";
}
+ break;
}
}
}
@@ -1307,6 +1303,13 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
+ // When edited_scene inherits from another one the root Node will be the parent Scene,
+ // we don't want to consider that Node a foreign one otherwise we would not be able to
+ // delete it
+ if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E->get()) {
+ continue;
+ }
+
if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) {
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
@@ -1497,6 +1500,7 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
editor_data->get_undo_redo().commit_action();
editor->push_item(p_script.operator->());
+ _update_script_button();
}
void SceneTreeDock::_toggle_editable_children() {
@@ -1612,9 +1616,17 @@ void SceneTreeDock::_delete_confirm() {
void SceneTreeDock::_update_script_button() {
if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size() == 1) {
- button_create_script->show();
+ Node *n = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list()[0];
+ if (n->get_script().is_null()) {
+ button_create_script->show();
+ button_clear_script->hide();
+ } else {
+ button_create_script->hide();
+ button_clear_script->show();
+ }
} else {
- button_create_script->hide();
+ button_create_script->show();
+ button_clear_script->hide();
}
}
@@ -2059,9 +2071,12 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
existing_script = selected->get_script();
}
- menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ if (!existing_script.is_valid()) {
+ menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ }
if (selection.size() > 1 || existing_script.is_valid()) {
menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
+ menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT);
}
menu->add_separator();
@@ -2288,6 +2303,7 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_new_scene_from"), &SceneTreeDock::_new_scene_from);
ClassDB::bind_method(D_METHOD("_nodes_dragged"), &SceneTreeDock::_nodes_dragged);
ClassDB::bind_method(D_METHOD("_files_dropped"), &SceneTreeDock::_files_dropped);
+ ClassDB::bind_method(D_METHOD("_quick_open"), &SceneTreeDock::_quick_open);
ClassDB::bind_method(D_METHOD("_script_dropped"), &SceneTreeDock::_script_dropped);
ClassDB::bind_method(D_METHOD("_tree_rmb"), &SceneTreeDock::_tree_rmb);
ClassDB::bind_method(D_METHOD("_filter_changed"), &SceneTreeDock::_filter_changed);
@@ -2324,6 +2340,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"));
ED_SHORTCUT("scene_tree/change_node_type", TTR("Change Type"));
ED_SHORTCUT("scene_tree/attach_script", TTR("Attach Script"));
+ ED_SHORTCUT("scene_tree/extend_script", TTR("Extend Script"));
ED_SHORTCUT("scene_tree/clear_script", TTR("Clear Script"));
ED_SHORTCUT("scene_tree/move_up", TTR("Move Up"), KEY_MASK_CMD | KEY_UP);
ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KEY_MASK_CMD | KEY_DOWN);
@@ -2355,6 +2372,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
filter->set_h_size_flags(SIZE_EXPAND_FILL);
filter->set_placeholder(TTR("Filter nodes"));
filter_hbc->add_child(filter);
+ filter->add_constant_override("minimum_spaces", 0);
filter->connect("text_changed", this, "_filter_changed");
tb = memnew(ToolButton);
@@ -2438,9 +2456,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
accept = memnew(AcceptDialog);
add_child(accept);
- file = memnew(EditorFileDialog);
- add_child(file);
- file->connect("file_selected", this, "instance");
+ quick_open = memnew(EditorQuickOpen);
+ add_child(quick_open);
+ quick_open->connect("quick_open", this, "_quick_open");
set_process_unhandled_key_input(true);
delete_dialog = memnew(ConfirmationDialog);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index eea34a3ec5..3939f4f361 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -36,6 +36,7 @@
#include "editor/editor_data.h"
#include "editor/editor_sub_scene.h"
#include "editor/groups_editor.h"
+#include "editor/quick_open.h"
#include "editor/rename_dialog.h"
#include "editor/reparent_dialog.h"
#include "editor/script_create_dialog.h"
@@ -125,7 +126,7 @@ class SceneTreeDock : public VBoxContainer {
ConfirmationDialog *editable_instance_remove_dialog;
ReparentDialog *reparent_dialog;
- EditorFileDialog *file;
+ EditorQuickOpen *quick_open;
EditorSubScene *import_subscene_dialog;
EditorFileDialog *new_scene_from_dialog;
@@ -194,6 +195,7 @@ class SceneTreeDock : public VBoxContainer {
void _nodes_dragged(Array p_nodes, NodePath p_to, int p_type);
void _files_dropped(Vector<String> p_files, NodePath p_to, int p_type);
void _script_dropped(String p_file, NodePath p_to);
+ void _quick_open();
void _tree_rmb(const Vector2 &p_menu_pos);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 848e4def6d..6614e24df7 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -665,6 +665,13 @@ void SceneTreeEditor::_renamed() {
Node *n = get_node(np);
ERR_FAIL_COND(!n);
+ // Empty node names are not allowed, so resets it to previous text and show warning
+ if (which->get_text(0).strip_edges().empty()) {
+ which->set_text(0, n->get_name());
+ EditorNode::get_singleton()->show_warning(TTR("No name provided"));
+ return;
+ }
+
String new_name = which->get_text(0);
if (!Node::_validate_node_name(new_name)) {
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 6fbac0d4b5..089ffa285d 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -123,8 +123,8 @@ protected:
if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/"))
return false;
- emit_signal("value_edited", p_name, p_value);
prop_values[p_name] = p_value;
+ emit_signal("value_edited", p_name, p_value);
return true;
}
@@ -355,7 +355,7 @@ void ScriptEditorDebugger::_video_mem_request() {
Size2 ScriptEditorDebugger::get_minimum_size() const {
Size2 ms = Control::get_minimum_size();
- ms.y = MAX(ms.y, 250);
+ ms.y = MAX(ms.y, 250 * EDSCALE);
return ms;
}
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
@@ -467,7 +467,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
String type = p_data[1];
Array properties = p_data[2];
- bool is_new_object = false;
if (remote_objects.has(id)) {
debugObj = remote_objects[id];
} else {
@@ -475,10 +474,14 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
debugObj->remote_object_id = id;
debugObj->type_name = type;
remote_objects[id] = debugObj;
- is_new_object = true;
debugObj->connect("value_edited", this, "_scene_tree_property_value_edited");
}
+ int old_prop_size = debugObj->prop_list.size();
+
+ debugObj->prop_list.clear();
+ int new_props_added = 0;
+ Set<String> changed;
for (int i = 0; i < properties.size(); i++) {
Array prop = properties[i];
@@ -511,18 +514,34 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
}
- if (is_new_object) {
- //don't update.. it's the same, instead refresh
- debugObj->prop_list.push_back(pinfo);
- }
+ //always add the property, since props may have been added or removed
+ debugObj->prop_list.push_back(pinfo);
- debugObj->prop_values[pinfo.name] = var;
+ if (!debugObj->prop_values.has(pinfo.name)) {
+ new_props_added++;
+ debugObj->prop_values[pinfo.name] = var;
+ } else {
+
+ if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, debugObj->prop_values[pinfo.name], var))) {
+ debugObj->prop_values[pinfo.name] = var;
+ changed.insert(pinfo.name);
+ }
+ }
}
if (editor->get_editor_history()->get_current() != debugObj->get_instance_id()) {
editor->push_item(debugObj, "");
} else {
- debugObj->update();
+
+ if (old_prop_size == debugObj->prop_list.size() && new_props_added == 0) {
+ //only some may have changed, if so, then update those, if exist
+ for (Set<String>::Element *E = changed.front(); E; E = E->next()) {
+ EditorNode::get_singleton()->get_inspector()->update_property(E->get());
+ }
+ } else {
+ //full update, because props were added or removed
+ debugObj->update();
+ }
}
} else if (p_msg == "message:video_mem") {
@@ -1272,7 +1291,7 @@ void ScriptEditorDebugger::stop() {
breaked = false;
server->stop();
-
+ _clear_remote_objects();
ppeer->set_stream_peer(Ref<StreamPeer>());
if (connection.is_valid()) {
@@ -2234,7 +2253,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
p_editor->get_undo_redo()->set_method_notify_callback(_method_changeds, this);
p_editor->get_undo_redo()->set_property_notify_callback(_property_changeds, this);
- live_debug = false;
+ live_debug = true;
last_path_id = false;
error_count = 0;
warning_count = 0;
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index a321cb16c5..881f20cecb 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -3454,10 +3454,9 @@ void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
if (points.size() > 3) {
- QuickHull qh;
Vector<Vector3> varr = Variant(points);
Geometry::MeshData md;
- Error err = qh.build(varr, md);
+ Error err = QuickHull::build(varr, md);
if (err == OK) {
Vector<Vector3> points;
points.resize(md.edges.size() * 2);
diff --git a/gles_builders.py b/gles_builders.py
index 1e63a53f1a..f9fd6d3fa2 100644
--- a/gles_builders.py
+++ b/gles_builders.py
@@ -59,11 +59,11 @@ def include_file_in_legacygl_header(filename, header_data, depth):
included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
header_data.vertex_included_files += [included_file]
- if include_file_in_legacygl_header(included_file, header_data, depth + 1) == None:
+ if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
header_data.fragment_included_files += [included_file]
- if include_file_in_legacygl_header(included_file, header_data, depth + 1) == None:
+ if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
line = fs.readline()
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 913c143025..b1084900d6 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -261,6 +261,13 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+ // Notes on mouse-touch emulation:
+ // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
+ // as true mouse events. The only difference is the situation is flagged as emulated so they are not
+ // emulated back to touch events in an endless loop.
+ // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
+ // require additional handling by this class.
+
_THREAD_SAFE_METHOD_
Ref<InputEventKey> k = p_event;
@@ -316,11 +323,21 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
}
}
- if (emulate_mouse_from_touch) {
+ Ref<InputEventScreenTouch> st = p_event;
+
+ if (st.is_valid()) {
+
+ if (st->is_pressed()) {
+ SpeedTrack &track = touch_speed_track[st->get_index()];
+ track.reset();
+ } else {
+ // Since a pointer index may not occur again (OSs may or may not reuse them),
+ // imperatively remove it from the map to keep no fossil entries in it
+ touch_speed_track.erase(st->get_index());
+ }
- Ref<InputEventScreenTouch> st = p_event;
+ if (emulate_mouse_from_touch) {
- if (st.is_valid()) {
bool translate = false;
if (st->is_pressed()) {
if (mouse_from_touch_index == -1) {
@@ -351,10 +368,18 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
_parse_input_event_impl(button_event, true);
}
}
+ }
+
+ Ref<InputEventScreenDrag> sd = p_event;
+
+ if (sd.is_valid()) {
+
+ SpeedTrack &track = touch_speed_track[sd->get_index()];
+ track.update(sd->get_relative());
+ sd->set_speed(track.speed);
- Ref<InputEventScreenDrag> sd = p_event;
+ if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
- if (sd.is_valid() && sd->get_index() == mouse_from_touch_index) {
Ref<InputEventMouseMotion> motion_event;
motion_event.instance();
@@ -404,6 +429,7 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.idle_frame = Engine::get_singleton()->get_idle_frames();
action.pressed = p_event->is_action_pressed(E->key());
+ action.strength = 0.f;
action_state[E->key()] = action;
}
action_state[E->key()].strength = p_event->get_action_strength(E->key());
@@ -530,13 +556,14 @@ Point2i InputDefault::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_moti
void InputDefault::iteration(float p_step) {
}
-void InputDefault::action_press(const StringName &p_action) {
+void InputDefault::action_press(const StringName &p_action, float p_strength) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.idle_frame = Engine::get_singleton()->get_idle_frames();
action.pressed = true;
+ action.strength = p_strength;
action_state[p_action] = action;
}
@@ -548,6 +575,7 @@ void InputDefault::action_release(const StringName &p_action) {
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.idle_frame = Engine::get_singleton()->get_idle_frames();
action.pressed = false;
+ action.strength = 0.f;
action_state[p_action] = action;
}
diff --git a/main/input_default.h b/main/input_default.h
index b420ec124b..b6767669f0 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -117,6 +117,7 @@ class InputDefault : public Input {
};
SpeedTrack mouse_speed_track;
+ Map<int, SpeedTrack> touch_speed_track;
Map<int, Joypad> joy_names;
int fallback_mapping;
@@ -226,7 +227,7 @@ public:
void set_main_loop(MainLoop *p_main_loop);
void set_mouse_position(const Point2 &p_posf);
- void action_press(const StringName &p_action);
+ void action_press(const StringName &p_action, float p_strength = 1.f);
void action_release(const StringName &p_action);
void iteration(float p_step);
diff --git a/main/main.cpp b/main/main.cpp
index 41ae368087..ca1b03392a 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -722,6 +722,29 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
I = N;
}
+ // Network file system needs to be configured before globals, since globals are based on the
+ // 'project.godot' file which will only be available through the network if this is enabled
+ FileAccessNetwork::configure();
+ if (remotefs != "") {
+
+ file_access_network_client = memnew(FileAccessNetworkClient);
+ int port;
+ if (remotefs.find(":") != -1) {
+ port = remotefs.get_slicec(':', 1).to_int();
+ remotefs = remotefs.get_slicec(':', 0);
+ } else {
+ port = 6010;
+ }
+
+ Error err = file_access_network_client->connect(remotefs, port, remotefs_pass);
+ if (err) {
+ OS::get_singleton()->printerr("Could not connect to remotefs: %s:%i.\n", remotefs.utf8().get_data(), port);
+ goto error;
+ }
+
+ FileAccess::make_default<FileAccessNetwork>(FileAccess::ACCESS_RESOURCES);
+ }
+
if (globals->setup(project_path, main_pack, upwards) == OK) {
found_project = true;
} else {
@@ -729,16 +752,22 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
editor = false;
#else
- OS::get_singleton()->print("Error: Could not load game path '%s'.\n", project_path.ascii().get_data());
+ String error_msg = "Error: Could not load game data at path '" + project_path + "'. Is the .pck file missing?\n";
+ OS::get_singleton()->print(error_msg.ascii().get_data());
+ OS::get_singleton()->alert(error_msg);
goto error;
#endif
}
GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc", PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1")); // No negative and limit to 500 due to crashes
GLOBAL_DEF("network/limits/debugger_stdout/max_chars_per_second", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_chars_per_second", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_chars_per_second", PROPERTY_HINT_RANGE, "0, 4096, 1, or_greater"));
GLOBAL_DEF("network/limits/debugger_stdout/max_messages_per_frame", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_messages_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_messages_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater"));
GLOBAL_DEF("network/limits/debugger_stdout/max_errors_per_frame", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_errors_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_errors_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater"));
if (debug_mode == "remote") {
@@ -762,28 +791,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
script_debugger = memnew(ScriptDebuggerLocal);
OS::get_singleton()->initialize_debugging();
}
-
- FileAccessNetwork::configure();
-
- if (remotefs != "") {
-
- file_access_network_client = memnew(FileAccessNetworkClient);
- int port;
- if (remotefs.find(":") != -1) {
- port = remotefs.get_slicec(':', 1).to_int();
- remotefs = remotefs.get_slicec(':', 0);
- } else {
- port = 6010;
- }
-
- Error err = file_access_network_client->connect(remotefs, port, remotefs_pass);
- if (err) {
- OS::get_singleton()->printerr("Could not connect to remotefs: %s:%i.\n", remotefs.utf8().get_data(), port);
- goto error;
- }
-
- FileAccess::make_default<FileAccessNetwork>(FileAccess::ACCESS_RESOURCES);
- }
if (script_debugger) {
//there is a debugger, parse breakpoints
@@ -811,6 +818,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
GLOBAL_DEF("logging/file_logging/log_path", "user://logs/log.txt");
GLOBAL_DEF("logging/file_logging/max_log_files", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files", PropertyInfo(Variant::INT, "logging/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater")); //no negative numbers
if (FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && GLOBAL_GET("logging/file_logging/enable_file_logging")) {
String base_path = GLOBAL_GET("logging/file_logging/log_path");
int max_files = GLOBAL_GET("logging/file_logging/max_log_files");
@@ -1001,6 +1009,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps", PropertyInfo(Variant::INT, "debug/settings/fps/force_fps", PROPERTY_HINT_RANGE, "0,120,1,or_greater"));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
@@ -1009,10 +1018,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (frame_delay == 0) {
frame_delay = GLOBAL_DEF("application/run/frame_delay_msec", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/frame_delay_msec", PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater")); // No negative numbers
}
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(GLOBAL_DEF("application/run/low_processor_mode_sleep_usec", 8000));
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/low_processor_mode_sleep_usec", PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater")); // No negative numbers
Engine::get_singleton()->set_frame_delay(frame_delay);
@@ -1641,7 +1652,7 @@ bool Main::start() {
GLOBAL_DEF("display/window/stretch/aspect", "ignore");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"));
GLOBAL_DEF("display/window/stretch/shrink", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::STRING, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1"));
+ ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
diff --git a/methods.py b/methods.py
index 0cf05751a8..111a2347be 100644
--- a/methods.py
+++ b/methods.py
@@ -330,7 +330,7 @@ def split_lib(self, libname, src_list = None, env_lib = None):
list = []
lib_list = []
- if src_list == None:
+ if src_list is None:
src_list = getattr(env, libname + "_sources")
if type(env_lib) == type(None):
diff --git a/misc/dist/document_icon.svg b/misc/dist/document_icon.svg
new file mode 100644
index 0000000000..2652110fa5
--- /dev/null
+++ b/misc/dist/document_icon.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024">
+<path d="M159.143 69.856v884.288h705.714v-665.51L646.08 69.856z" fill="#fff" stroke="#d2d2d2" stroke-width="20"/>
+<g stroke-width=".32">
+ <path d="M723.128 594.284s-.701-4.304-1.111-4.265l-78.083 7.534a12.691 12.691 0 0 0-11.474 11.78l-2.145 30.747-60.408 4.31-4.11-27.866c-.914-6.198-6.326-10.87-12.591-10.87h-82.412c-6.263 0-11.675 4.672-12.59 10.87l-4.111 27.865-60.408-4.31-2.145-30.745a12.692 12.692 0 0 0-11.475-11.783l-78.12-7.532c-.404-.039-.7 4.269-1.104 4.269l-.105 16.897 66.161 10.67 2.167 31.02c.438 6.28 5.505 11.357 11.79 11.808l83.194 5.935c.315.022.626.035.937.035 6.252 0 11.655-4.675 12.57-10.873l4.228-28.671h60.436l4.228 28.671c.913 6.196 6.323 10.87 12.583 10.87.307 0 .613-.01.913-.032l83.206-5.935c6.282-.45 11.351-5.528 11.79-11.808l2.164-31.02 66.133-10.717z" fill="#fff"/>
+ <path d="M300.84 466.87v127.413c.233.003.466.011.697.033l78.113 7.531a8.41 8.41 0 0 1 7.583 7.789l2.409 34.481 68.138 4.862 4.694-31.825a8.41 8.41 0 0 1 8.321-7.184h82.412a8.41 8.41 0 0 1 8.32 7.184l4.693 31.825 68.14-4.862 2.407-34.481a8.414 8.414 0 0 1 7.583-7.789l78.082-7.531c.231-.022.462-.03.695-.033v-10.166l.033-.01V466.87h.289c10.348-13.207 19.923-27.124 29.105-41.972-12.195-20.76-27.137-39.313-43.109-56.502-14.813 7.456-29.2 15.903-42.79 24.891-6.8-6.759-14.458-12.288-21.981-18.067-7.392-5.937-15.722-10.29-23.622-15.361 2.352-17.517 3.515-34.762 3.983-52.76-20.385-10.26-42.123-17.062-64.111-21.947-8.779 14.754-16.807 30.732-23.799 46.352-8.291-1.385-16.621-1.899-24.962-1.998v-.013c-.058 0-.112.013-.162.013-.052 0-.106-.013-.157-.013v.013c-8.356.1-16.68.613-24.973 1.998-6.988-15.62-15.012-31.598-23.804-46.352-21.977 4.885-43.717 11.688-64.1 21.947.466 17.998 1.63 35.243 3.988 52.76-7.916 5.071-16.235 9.424-23.629 15.36-7.512 5.78-15.184 11.31-21.986 18.068-13.589-8.988-27.972-17.435-42.79-24.89-15.971 17.188-30.905 35.74-43.104 56.501 9.178 14.848 18.76 28.765 29.105 41.972z" fill="#478cbf"/>
+ <path d="M653.052 617.91l-2.42 34.664a8.413 8.413 0 0 1-7.792 7.803l-83.204 5.937a8.412 8.412 0 0 1-8.92-7.165l-4.77-32.357h-67.89l-4.772 32.358c-.64 4.354-4.534 7.486-8.92 7.164l-83.203-5.937a8.413 8.413 0 0 1-7.792-7.803l-2.42-34.665-70.238-6.772c.033 7.55.13 15.819.13 17.465 0 74.181 94.102 109.836 211.016 110.246h.287c116.915-.41 210.984-36.065 210.984-110.246 0-1.676.101-9.912.136-17.465z" fill="#478cbf"/>
+ <path d="M448.344 518.591c0 26.01-21.074 47.078-47.074 47.078-25.987 0-47.067-21.069-47.067-47.078 0-25.991 21.08-47.05 47.067-47.05 26 0 47.074 21.059 47.074 47.05" fill="#fff"/>
+ <path d="M437.017 521.384c0 17.251-13.982 31.233-31.246 31.233-17.256 0-31.247-13.982-31.247-31.233 0-17.252 13.99-31.247 31.247-31.247 17.264 0 31.246 13.995 31.246 31.247" fill="#414042"/>
+ <path d="M511.997 569.952c-8.37 0-15.152-6.168-15.152-13.77v-43.336c0-7.596 6.783-13.77 15.152-13.77 8.368 0 15.166 6.174 15.166 13.77v43.336c0 7.602-6.798 13.77-15.166 13.77M575.657 518.591c0 26.01 21.074 47.078 47.078 47.078 25.985 0 47.063-21.069 47.063-47.078 0-25.991-21.078-47.05-47.063-47.05-26.004 0-47.078 21.059-47.078 47.05" fill="#fff"/>
+ <path d="M586.987 521.384c0 17.251 13.978 31.233 31.23 31.233 17.268 0 31.245-13.982 31.245-31.233 0-17.252-13.977-31.247-31.246-31.247-17.251 0-31.23 13.995-31.23 31.247" fill="#414042"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/misc/dist/linux/org.godotengine.Godot.appdata.xml b/misc/dist/linux/org.godotengine.Godot.appdata.xml
index 9f3f9e34af..c11317cd35 100644
--- a/misc/dist/linux/org.godotengine.Godot.appdata.xml
+++ b/misc/dist/linux/org.godotengine.Godot.appdata.xml
@@ -27,8 +27,8 @@
</screenshots>
<url type="homepage">https://godotengine.org</url>
<url type="bugtracker">https://github.com/godotengine/godot/issues</url>
- <url type="faq">http://docs.godotengine.org/en/latest/about/faq.html</url>
- <url type="help">http://docs.godotengine.org</url>
+ <url type="faq">https://docs.godotengine.org/en/latest/about/faq.html</url>
+ <url type="help">https://docs.godotengine.org</url>
<url type="donation">https://godotengine.org/donate</url>
<url type="translate">https://hosted.weblate.org/projects/godot-engine/godot</url>
<developer_name>The Godot Engine Community</developer_name>
diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist
index 828a40206d..faa929b818 100755
--- a/misc/dist/osx_tools.app/Contents/Info.plist
+++ b/misc/dist/osx_tools.app/Contents/Info.plist
@@ -38,31 +38,82 @@
<key>CFBundleDocumentTypes</key>
<array>
<dict>
- <key>CFBundleTypeExtensions</key>
- <array>
- <string>scn</string>
- <string>SCN</string>
- </array>
- <key>CFBundleTypeIconFile</key>
- <string>Godot.icns</string>
- <key>CFBundleTypeMIMETypes</key>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSItemContentTypes</key>
<array>
- <string>scene/x-scn</string>
+ <string>public.tscn</string>
</array>
- <key>CFBundleTypeName</key>
- <string>Godot Scene</string>
- <key>CFBundleTypeOSTypes</key>
+ <key>NSExportableTypes</key>
<array>
- <string>SCN </string>
+ <string>public.tscn</string>
</array>
+ </dict>
+ <dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
- <key>LSIsAppleDefaultForType</key>
- <true/>
<key>LSItemContentTypes</key>
<array>
- <string>org.godotengine.scn</string>
+ <string>public.godot</string>
+ </array>
+ <key>NSExportableTypes</key>
+ <array>
+ <string>public.godot</string>
+ </array>
+ </dict>
+ </array>
+ <key>UTExportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeIdentifier</key>
+ <string>public.tscn</string>
+ <key>UTTypeReferenceURL</key>
+ <string></string>
+ <key>UTTypeDescription</key>
+ <string>Godot Scene</string>
+ <key>UTTypeIconFile</key>
+ <string>Document.icns</string>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.data</string>
+ </array>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>com.apple.ostype</key>
+ <string>TSCN</string>
+ <key>public.filename-extension</key>
+ <array>
+ <string>scn</string>
+ <string>tscn</string>
+ </array>
+ <key>public.mime-type</key>
+ <string>scene/x-scn</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>UTTypeIdentifier</key>
+ <string>public.godot</string>
+ <key>UTTypeReferenceURL</key>
+ <string></string>
+ <key>UTTypeDescription</key>
+ <string>Godot Project</string>
+ <key>UTTypeIconFile</key>
+ <string>Document.icns</string>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.data</string>
</array>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>com.apple.ostype</key>
+ <string>GODP</string>
+ <key>public.filename-extension</key>
+ <array>
+ <string>godot</string>
+ </array>
+ <key>public.mime-type</key>
+ <string>project/x-godot</string>
+ </dict>
</dict>
</array>
</dict>
diff --git a/misc/dist/osx_tools.app/Contents/Resources/Document.icns b/misc/dist/osx_tools.app/Contents/Resources/Document.icns
new file mode 100644
index 0000000000..06d7c65298
--- /dev/null
+++ b/misc/dist/osx_tools.app/Contents/Resources/Document.icns
Binary files differ
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index d1ef08dc83..4eb798de11 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -521,6 +521,11 @@ CSGBrush *CSGMesh::_build_brush() {
Array arrays = mesh->surface_get_arrays(i);
+ if (arrays.size() == 0) {
+ _make_dirty();
+ ERR_FAIL_COND_V(arrays.size() == 0, NULL);
+ }
+
PoolVector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
if (avertices.size() == 0)
continue;
@@ -593,8 +598,8 @@ CSGBrush *CSGMesh::_build_brush() {
mw[j / 3] = mat;
}
} else {
- int is = vertices.size();
- int as = avertices.size();
+ int as = vertices.size();
+ int is = avertices.size();
vertices.resize(as + is);
smooth.resize((as + is) / 3);
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 6d990f6f6f..e057a435ac 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -7,7 +7,7 @@
A PacketPeer implementation that should be passed to [method SceneTree.set_network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/high_level_multiplayer.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
<link>http://enet.bespin.org/usergroup0.html</link>
</tutorials>
<demos>
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index 7ca40c1b8b..3e2068b8db 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -59,6 +59,8 @@ if env['builtin_freetype']:
if env['platform'] == 'uwp':
# Include header for UWP to fix build issues
env_freetype.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
+ # Globally too, as freetype is used in scene (see bottom)
+ env.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
sfnt = thirdparty_dir + 'src/sfnt/sfnt.c'
if env['platform'] == 'javascript':
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index ecde73ae1c..f07fdef488 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -243,12 +243,12 @@ void GDNativeLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix);
ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "reloadable"), "set_reloadable", "is_reloadable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reloadable"), "set_reloadable", "is_reloadable");
}
GDNative::GDNative() {
@@ -268,7 +268,7 @@ void GDNative::_bind_methods() {
ClassDB::bind_method(D_METHOD("call_native", "calling_type", "procedure_name", "arguments"), &GDNative::call_native);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
}
void GDNative::set_library(Ref<GDNativeLibrary> p_library) {
@@ -306,6 +306,13 @@ bool GDNative::initialize() {
#elif defined(UWP_ENABLED)
// On UWP we use a relative path from the app
String path = lib_path.replace("res://", "");
+#elif defined(OSX_ENABLED)
+ // On OSX the exported libraries are located under the Frameworks directory.
+ // So we need to replace the library path.
+ String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
+ if (!FileAccess::exists(path)) {
+ path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(lib_path.get_file());
+ }
#else
String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
#endif
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 1fb0ff0500..a30cc09bf6 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -318,6 +318,38 @@ void GDAPI godot_array_destroy(godot_array *p_self) {
((Array *)p_self)->~Array();
}
+godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep) {
+ const Array *self = (const Array *)p_self;
+ godot_array res;
+ Array *val = (Array *)&res;
+ memnew_placement(val, Array);
+ *val = self->duplicate(p_deep);
+ return res;
+}
+
+godot_variant GDAPI godot_array_max(const godot_array *p_self) {
+ const Array *self = (const Array *)p_self;
+ godot_variant v;
+ Variant *val = (Variant *)&v;
+ memnew_placement(val, Variant);
+ *val = self->max();
+ return v;
+}
+
+godot_variant GDAPI godot_array_min(const godot_array *p_self) {
+ const Array *self = (const Array *)p_self;
+ godot_variant v;
+ Variant *val = (Variant *)&v;
+ memnew_placement(val, Variant);
+ *val = self->min();
+ return v;
+}
+
+void GDAPI godot_array_shuffle(godot_array *p_self) {
+ Array *self = (Array *)p_self;
+ self->shuffle();
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index 70d2814577..d88499ade1 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -282,6 +282,15 @@ godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self
return raw_dest;
}
+godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t) {
+ godot_basis raw_dest;
+ Basis *dest = (Basis *)&raw_dest;
+ const Basis *self = (const Basis *)p_self;
+ const Basis *b = (const Basis *)p_b;
+ *dest = self->slerp(*b, p_t);
+ return raw_dest;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp
index 4089f4458a..79f0c71b5e 100644
--- a/modules/gdnative/gdnative/color.cpp
+++ b/modules/gdnative/gdnative/color.cpp
@@ -116,6 +116,26 @@ godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self) {
return self->to_rgba32();
}
+godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_abgr32();
+}
+
+godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_abgr64();
+}
+
+godot_int GDAPI godot_color_to_argb64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_argb64();
+}
+
+godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_rgba64();
+}
+
godot_int GDAPI godot_color_to_argb32(const godot_color *p_self) {
const Color *self = (const Color *)p_self;
return self->to_argb32();
@@ -156,6 +176,27 @@ godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color
return dest;
}
+godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->darkened(p_amount);
+ return dest;
+}
+
+godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->from_hsv(p_h, p_s, p_v, p_a);
+ return dest;
+}
+
+godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->lightened(p_amount);
+ return dest;
+}
+
godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha) {
godot_string dest;
const Color *self = (const Color *)p_self;
diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp
index f24facaae8..cf82940e09 100644
--- a/modules/gdnative/gdnative/node_path.cpp
+++ b/modules/gdnative/gdnative/node_path.cpp
@@ -110,6 +110,15 @@ godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, c
return *self == *b;
}
+godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self) {
+ const NodePath *self = (const NodePath *)p_self;
+ godot_node_path res;
+ NodePath *val = (NodePath *)&res;
+ memnew_placement(val, NodePath);
+ *val = self->get_as_property_path();
+ return res;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp
index ddec77edcd..2594759508 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quat.cpp
@@ -225,6 +225,12 @@ godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self) {
return raw_dest;
}
+void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle) {
+ Quat *self = (Quat *)p_self;
+ const Vector3 *axis = (const Vector3 *)p_axis;
+ self->set_axis_angle(*axis, p_angle);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 54b98fc4e5..5cbc2712c3 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -109,6 +109,27 @@ godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p
return dest;
}
+godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->grow_individual(p_left, p_top, p_right, p_bottom);
+ return dest;
+}
+
+godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->grow_margin((Margin)p_margin, p_by);
+ return dest;
+}
+
+godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->abs();
+ return dest;
+}
+
godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to) {
godot_rect2 dest;
const Rect2 *self = (const Rect2 *)p_self;
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 8ca57392a3..0996633b70 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -1285,6 +1285,64 @@ godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self) {
return self->is_valid_ip_address();
}
+godot_string GDAPI godot_string_dedent(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+ godot_string result;
+ String return_value = self->dedent();
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix) {
+ const String *self = (const String *)p_self;
+ String *prefix = (String *)p_prefix;
+ godot_string result;
+ String return_value = self->trim_prefix(*prefix);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix) {
+ const String *self = (const String *)p_self;
+ String *suffix = (String *)p_suffix;
+ godot_string result;
+ String return_value = self->trim_suffix(*suffix);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars) {
+ const String *self = (const String *)p_self;
+ String *chars = (String *)p_chars;
+ godot_string result;
+ String return_value = self->rstrip(*chars);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_pool_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor,
+ const godot_bool p_allow_empty, const godot_int p_maxsplit) {
+ const String *self = (const String *)p_self;
+ String *divisor = (String *)p_divisor;
+
+ godot_pool_string_array result;
+ memnew_placement(&result, PoolStringArray);
+ PoolStringArray *proxy = (PoolStringArray *)&result;
+ PoolStringArray::Write proxy_writer = proxy->write();
+ Vector<String> tmp_result = self->rsplit(*divisor, p_allow_empty, p_maxsplit);
+ proxy->resize(tmp_result.size());
+
+ for (int i = 0; i < tmp_result.size(); i++) {
+ proxy_writer[i] = tmp_result[i];
+ }
+
+ return result;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 16a34a9a33..c5a1fa139e 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -14,6 +14,183 @@
"next": null,
"api": [
{
+ "name": "godot_color_to_abgr32",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_abgr64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_argb64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_rgba64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_darkened",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_amount"]
+ ]
+ },
+ {
+ "name": "godot_color_from_hsv",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_h"],
+ ["const godot_real", "p_s"],
+ ["const godot_real", "p_v"],
+ ["const godot_real", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_color_lightened",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_amount"]
+ ]
+ },
+ {
+ "name": "godot_array_duplicate",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_array *", "p_self"],
+ ["const godot_bool", "p_deep"]
+ ]
+ },
+ {
+ "name": "godot_array_max",
+ "return_type": "godot_variant",
+ "arguments": [
+ ["const godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_array_min",
+ "return_type": "godot_variant",
+ "arguments": [
+ ["const godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_array_shuffle",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_basis_slerp",
+ "return_type": "godot_basis",
+ "arguments": [
+ ["const godot_basis *", "p_self"],
+ ["const godot_basis *", "p_b"],
+ ["const godot_real", "p_t"]
+ ]
+ },
+ {
+ "name": "godot_node_path_get_as_property_path",
+ "return_type": "godot_node_path",
+ "arguments": [
+ ["const godot_node_path *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_quat_set_axis_angle",
+ "return_type": "void",
+ "arguments": [
+ ["godot_quat *", "p_self"],
+ ["const godot_vector3 *", "p_axis"],
+ ["const godot_real", "p_angle"]
+ ]
+ },
+ {
+ "name": "godot_rect2_grow_individual",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"],
+ ["const godot_real", "p_left"],
+ ["const godot_real", "p_top"],
+ ["const godot_real", "p_right"],
+ ["const godot_real", "p_bottom"]
+ ]
+ },
+ {
+ "name": "godot_rect2_grow_margin",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"],
+ ["const godot_int", "p_margin"],
+ ["const godot_real", "p_by"]
+ ]
+ },
+ {
+ "name": "godot_rect2_abs",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_dedent",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_trim_prefix",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_prefix"]
+ ]
+ },
+ {
+ "name": "godot_string_trim_suffix",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_suffix"]
+ ]
+ },
+ {
+ "name": "godot_string_rstrip",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_chars"]
+ ]
+ },
+ {
+ "name": "godot_string_rsplit",
+ "return_type": "godot_pool_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_divisor"],
+ ["const godot_bool", "p_allow_empty"],
+ ["const godot_int", "p_maxsplit"]
+ ]
+ },
+ {
"name": "godot_basis_get_quat",
"return_type": "godot_quat",
"arguments": [
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index 1e66d133b9..876b8f8e8f 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -130,6 +130,14 @@ godot_int GDAPI godot_array_bsearch_custom(godot_array *p_self, const godot_vari
void GDAPI godot_array_destroy(godot_array *p_self);
+godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep);
+
+godot_variant GDAPI godot_array_max(const godot_array *p_self);
+
+godot_variant GDAPI godot_array_min(const godot_array *p_self);
+
+void GDAPI godot_array_shuffle(godot_array *p_self);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index ebe2b1125b..6128bf3ac3 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -127,6 +127,8 @@ godot_basis GDAPI godot_basis_operator_multiply_vector(const godot_basis *p_self
godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self, const godot_real p_b);
+godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 1f0ac8354d..3007dbc6e3 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -81,6 +81,14 @@ godot_string GDAPI godot_color_as_string(const godot_color *p_self);
godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self);
+godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_argb64(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self);
+
godot_int GDAPI godot_color_to_argb32(const godot_color *p_self);
godot_real GDAPI godot_color_gray(const godot_color *p_self);
@@ -93,6 +101,12 @@ godot_color GDAPI godot_color_linear_interpolate(const godot_color *p_self, cons
godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color *p_over);
+godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount);
+
+godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a);
+
+godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount);
+
godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha);
godot_bool GDAPI godot_color_operator_equal(const godot_color *p_self, const godot_color *p_b);
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 2b55e01d13..48fe5b4d3d 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -80,6 +80,8 @@ godot_bool GDAPI godot_node_path_is_empty(const godot_node_path *p_self);
godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, const godot_node_path *p_b);
+godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index b1290f745c..634f486e66 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -109,6 +109,8 @@ godot_bool GDAPI godot_quat_operator_equal(const godot_quat *p_self, const godot
godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self);
+void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 4adcb73e3d..47c15c80bd 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -77,6 +77,12 @@ godot_bool GDAPI godot_rect2_has_point(const godot_rect2 *p_self, const godot_ve
godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p_by);
+godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom);
+
+godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by);
+
+godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self);
+
godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to);
godot_bool GDAPI godot_rect2_operator_equal(const godot_rect2 *p_self, const godot_rect2 *p_b);
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index 73245160c1..95ae42a9ec 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -246,6 +246,12 @@ godot_bool GDAPI godot_string_is_valid_identifier(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_integer(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self);
+godot_string GDAPI godot_string_dedent(const godot_string *p_self);
+godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix);
+godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix);
+godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars);
+godot_pool_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor, const godot_bool p_allow_empty, const godot_int p_maxsplit);
+
void GDAPI godot_string_destroy(godot_string *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 37e72bf9f8..eb133502c4 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -72,11 +72,11 @@ void NativeScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation);
ClassDB::bind_method(D_METHOD("get_property_documentation", "path"), &NativeScript::get_property_documentation);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
ADD_GROUP("Script Class", "script_class_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new"));
}
@@ -1711,8 +1711,7 @@ void NativeReloadNode::_notification(int p_what) {
}
RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
- ResourceFormatLoaderText rsflt;
- return rsflt.load(p_path, p_original_path, r_error);
+ return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error);
}
void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 632970f8c0..4cefdbd7cb 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -8,7 +8,7 @@
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 48c1760662..159085df34 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -469,8 +469,15 @@ bool GDScript::_update_exports() {
for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
E->get()->set_build_failed(true);
}
+ return false;
}
} else {
+ if (!valid) {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->set_build_failed(true);
+ }
+ return false;
+ }
}
if (base_cache.is_valid()) {
@@ -2065,12 +2072,12 @@ GDScriptLanguage::GDScriptLanguage() {
_debug_call_stack_pos = 0;
int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/gdscript/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
+
if (ScriptDebugger::get_singleton()) {
//debugging enabled!
_debug_max_call_stack = dmcs;
- if (_debug_max_call_stack < 1024)
- _debug_max_call_stack = 1024;
_call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
} else {
@@ -2081,6 +2088,7 @@ GDScriptLanguage::GDScriptLanguage() {
#ifdef DEBUG_ENABLED
GLOBAL_DEF("debug/gdscript/warnings/enable", true);
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
+ GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_"));
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 310c4e21f2..45319c59e7 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1603,13 +1603,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
return OK;
}
-Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
+Error GDScriptCompiler::_parse_function(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
Vector<int> bytecode;
CodeGen codegen;
codegen.class_node = p_class;
- codegen.script = p_script;
+ codegen.script = p_script.ptr();
codegen.function_node = p_func;
codegen.stack_max = 0;
codegen.current_line = 0;
@@ -1853,7 +1853,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return OK;
}
-Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+Error GDScriptCompiler::_parse_class_level(Ref<GDScript> p_script, Ref<GDScript> p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
if (p_class->owner && p_class->owner->owner) {
// Owner is not root
@@ -1887,7 +1887,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->initializer = NULL;
p_script->subclasses.clear();
- p_script->_owner = p_owner;
+ p_script->_owner = p_owner.ptr();
p_script->tool = p_class->tool;
p_script->name = p_class->name;
@@ -1994,7 +1994,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
StringName name = p_class->_signals[i].name;
- GDScript *c = p_script;
+ GDScript *c = p_script.ptr();
while (c) {
@@ -2054,7 +2054,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
return OK;
}
-Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+Error GDScriptCompiler::_parse_class_blocks(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
//parse methods
bool has_initializer = false;
@@ -2159,7 +2159,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
return OK;
}
-void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+void GDScriptCompiler::_make_scripts(const Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
Map<StringName, Ref<GDScript> > old_subclasses;
@@ -2178,20 +2178,20 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
subclass.instance();
}
- subclass->_owner = const_cast<GDScript *>(p_script);
+ subclass->_owner = const_cast<GDScript *>(p_script.ptr());
class_map.insert(name, subclass);
_make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state);
}
}
-Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) {
+Error GDScriptCompiler::compile(const GDScriptParser *p_parser, Ref<GDScript> p_script, bool p_keep_state) {
err_line = -1;
err_column = -1;
error = "";
parser = p_parser;
- main_script = p_script;
+ main_script = p_script.ptr();
const GDScriptParser::Node *root = parser->get_parse_tree();
ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, ERR_INVALID_DATA);
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 55f5e2b48e..23c6450aa7 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -148,17 +148,17 @@ class GDScriptCompiler {
int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level);
int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false);
Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
- Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
- Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
- Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
- void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _parse_function(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
+ Error _parse_class_level(Ref<GDScript> p_script, Ref<GDScript> p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _parse_class_blocks(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ void _make_scripts(const Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line;
int err_column;
StringName source;
String error;
public:
- Error compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state = false);
+ Error compile(const GDScriptParser *p_parser, Ref<GDScript> p_script, bool p_keep_state = false);
String get_error() const;
int get_error_line() const;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index ddd9e6b01c..068e8d2d92 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1308,37 +1308,38 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c
return false;
}
- // Check ClassDB
- if (ClassDB::class_exists(p_identifier)) {
- r_type.type.has_type = true;
- r_type.type.kind = GDScriptParser::DataType::NATIVE;
- r_type.type.native_type = p_identifier;
- if (Engine::get_singleton()->has_singleton(p_identifier)) {
- r_type.type.is_meta_type = false;
- r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier);
- } else {
- r_type.type.is_meta_type = true;
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier];
- r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ for (int i = 0; i < 2; i++) {
+ StringName target_id;
+ switch (i) {
+ case 0:
+ // Check ClassDB
+ target_id = p_identifier;
+ break;
+ case 1:
+ // ClassDB again for underscore-prefixed classes
+ target_id = String("_") + p_identifier;
+ break;
}
- return true;
- }
- // ClassDB again for underscore-prefixed classes
- StringName under_id = String("_") + p_identifier;
- if (ClassDB::class_exists(under_id)) {
- r_type.type.has_type = true;
- r_type.type.kind = GDScriptParser::DataType::NATIVE;
- r_type.type.native_type = p_identifier;
- if (Engine::get_singleton()->has_singleton(p_identifier)) {
- r_type.type.is_meta_type = false;
- r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier);
- } else {
- r_type.type.is_meta_type = true;
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier];
- r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ if (ClassDB::class_exists(target_id)) {
+ r_type.type.has_type = true;
+ r_type.type.kind = GDScriptParser::DataType::NATIVE;
+ r_type.type.native_type = target_id;
+ if (Engine::get_singleton()->has_singleton(target_id)) {
+ r_type.type.is_meta_type = false;
+ r_type.value = Engine::get_singleton()->get_singleton_object(target_id);
+ } else {
+ r_type.type.is_meta_type = true;
+ const Map<StringName, int>::Element *target_elem = GDScriptLanguage::get_singleton()->get_global_map().find(target_id);
+ // Check because classes like EditorNode are in ClassDB by now, but unknown to GDScript
+ if (!target_elem) {
+ return false;
+ }
+ int idx = target_elem->get();
+ r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ }
+ return true;
}
- return true;
}
// Check autoload singletons
@@ -1999,7 +2000,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (!_static) {
List<MethodInfo> methods;
- ClassDB::get_method_list(type, &methods, false, true);
+ bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize();
+ ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
if (E->get().name.begins_with("_")) {
continue;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index f09ff224e8..31115a4bd9 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -275,7 +275,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
uint32_t alloca_size = 0;
- GDScript *_class;
+ GDScript *script;
int ip = 0;
int line = _initial_line;
@@ -286,7 +286,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
line = p_state->line;
ip = p_state->ip;
alloca_size = p_state->stack.size();
- _class = p_state->_class;
+ script = p_state->script.ptr();
p_instance = p_state->instance;
defarg = p_state->defarg;
self = p_state->self;
@@ -368,9 +368,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else {
self = p_instance->owner;
}
- _class = p_instance->script.ptr();
+ script = p_instance->script.ptr();
} else {
- _class = _script;
+ script = this->_script.ptr();
}
}
@@ -395,7 +395,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text); \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, stack, err_text); \
if (unlikely(!m_v)) \
OPCODE_BREAK;
@@ -404,7 +404,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text);
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, stack, err_text);
#endif
@@ -1185,7 +1185,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, argc + 3);
- const GDScript *gds = _script;
+ const GDScript *gds = _script.ptr();
const Map<StringName, GDScriptFunction *>::Element *E = NULL;
while (gds->base.ptr()) {
@@ -1256,11 +1256,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->state.stack_size = _stack_size;
gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
- gdfs->state._class = _class;
+ gdfs->state.script = _script;
gdfs->state.ip = ip + ipofs;
gdfs->state.line = line;
gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : 0;
- gdfs->state.script_id = _class->get_instance_id();
//gdfs->state.result_pos=ip+ipofs-1;
gdfs->state.defarg = defarg;
gdfs->state.instance = p_instance;
@@ -1549,8 +1548,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
String err_file;
if (p_instance)
err_file = p_instance->script->path;
- else if (_class)
- err_file = _class->path;
+ else if (script)
+ err_file = script->path;
if (err_file == "")
err_file = "<built-in>";
String err_func = name;
@@ -1765,15 +1764,20 @@ GDScriptFunction::~GDScriptFunction() {
Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
#ifdef DEBUG_ENABLED
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ // Checking this first since it's faster
+ if (!state.script.is_valid()) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
ERR_FAIL_V(Variant());
}
- if (state.script_id && !ObjectDB::get_instance(state.script_id)) {
- ERR_EXPLAIN("Resumed after yield, but script is gone");
+ if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
ERR_FAIL_V(Variant());
}
+#else
+ if (!is_valid()) {
+ return Variant();
+ }
#endif
Variant arg;
@@ -1841,12 +1845,12 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
return false;
if (p_extended_check) {
+ //script gone? (checking this first since it's faster)
+ if (!state.script.is_valid())
+ return false;
//class instance gone?
if (state.instance_id && !ObjectDB::get_instance(state.instance_id))
return false;
- //script gone?
- if (state.script_id && !ObjectDB::get_instance(state.script_id))
- return false;
}
return true;
@@ -1856,13 +1860,14 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
#ifdef DEBUG_ENABLED
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ // Checking this first since it's faster
+ if (!state.script.is_valid()) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
ERR_FAIL_V(Variant());
}
- if (state.script_id && !ObjectDB::get_instance(state.script_id)) {
- ERR_EXPLAIN("Resumed after yield, but script is gone");
+ if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
ERR_FAIL_V(Variant());
}
#endif
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index bfb6d673f1..a47070de4f 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -225,7 +225,7 @@ private:
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
- GDScript *_script;
+ Ref<GDScript> _script;
StringName name;
Vector<Variant> constants;
@@ -272,15 +272,13 @@ private:
public:
struct CallState {
- ObjectID instance_id; //by debug only
- ObjectID script_id;
-
+ ObjectID instance_id;
GDScriptInstance *instance;
Vector<uint8_t> stack;
int stack_size;
Variant self;
uint32_t alloca_size;
- GDScript *_class;
+ Ref<GDScript> script;
int ip;
int line;
int defarg;
@@ -299,7 +297,7 @@ public:
int get_default_argument_addr(int p_idx) const;
GDScriptDataType get_return_type() const;
GDScriptDataType get_argument_type(int p_idx) const;
- GDScript *get_script() const { return _script; }
+ GDScript *get_script() const { return const_cast<GDScript *>(_script.ptr()); }
StringName get_source() const { return source; }
void debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 5af9bbc05f..2f31d59c46 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -106,6 +106,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"printerr",
"printraw",
"print_debug",
+ "push_error",
+ "push_warning",
"var2str",
"str2var",
"var2bytes",
@@ -707,13 +709,40 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
ScriptLanguage *script = GDScriptLanguage::get_singleton();
if (script->debug_get_stack_level_count() > 0) {
- str += "\n\t";
- str += "At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)); // + " in function '" + script->debug_get_stack_level_function(0) + "'";
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
}
print_line(str);
r_ret = Variant();
} break;
+ case PUSH_ERROR: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = Variant();
+ break;
+ }
+
+ String message = *p_args[0];
+ ERR_PRINTS(message);
+ r_ret = Variant();
+ } break;
+ case PUSH_WARNING: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = Variant();
+ break;
+ }
+
+ String message = *p_args[0];
+ WARN_PRINTS(message);
+ r_ret = Variant();
+ } break;
case VAR_TO_STR: {
VALIDATE_ARG_COUNT(1);
String vars;
@@ -1754,11 +1783,25 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
+ case PUSH_ERROR: {
+
+ MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message"));
+ mi.return_val.type = Variant::NIL;
+ return mi;
+
+ } break;
+ case PUSH_WARNING: {
+
+ MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message"));
+ mi.return_val.type = Variant::NIL;
+ return mi;
+
+ } break;
case VAR_TO_STR: {
+
MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
mi.return_val.type = Variant::STRING;
return mi;
-
} break;
case STR_TO_VAR: {
@@ -1768,10 +1811,10 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
case VAR_TO_BYTES: {
+
MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
mi.return_val.type = Variant::POOL_BYTE_ARRAY;
return mi;
-
} break;
case BYTES_TO_VAR: {
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index e920dd4ece..33d5f27230 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -97,6 +97,8 @@ public:
TEXT_PRINTERR,
TEXT_PRINTRAW,
TEXT_PRINT_DEBUG,
+ PUSH_ERROR,
+ PUSH_WARNING,
VAR_TO_STR,
STR_TO_VAR,
VAR_TO_BYTES,
@@ -117,7 +119,6 @@ public:
LEN,
IS_INSTANCE_VALID,
FUNC_MAX
-
};
static const char *get_func_name(Function p_func);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 5f2655eb92..09b3a5631f 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -4353,6 +4353,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.type = Variant::INT;
current_export.hint = is_flags ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
+ current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
Dictionary enum_values = constant;
List<Variant> keys;
@@ -4839,6 +4840,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
if (tokenizer->is_token_literal(0, true)) {
enum_name = tokenizer->get_token_literal();
+
+ if (current_class->constant_expressions.has(enum_name)) {
+ _set_error("A constant named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[enum_name].expression->line) + ").");
+ return;
+ }
+
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == enum_name) {
+ _set_error("A variable named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
+
tokenizer->advance();
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CURLY_BRACKET_OPEN) {
@@ -4865,26 +4881,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
} else { // tokenizer->is_token_literal(0, true)
- ClassNode::Constant constant;
-
StringName const_id = tokenizer->get_token_literal();
- if (current_class->constant_expressions.has(const_id)) {
- _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->constant_expressions[const_id].expression->line) + ").");
- return;
- }
-
- for (int i = 0; i < current_class->variables.size(); i++) {
- if (current_class->variables[i].identifier == const_id) {
- _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->variables[i].line) + ").");
- return;
- }
- }
-
tokenizer->advance();
+ ConstantNode *enum_value_expr;
+
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
tokenizer->advance();
@@ -4901,23 +4903,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- ConstantNode *subexpr_const = static_cast<ConstantNode *>(subexpr);
+ enum_value_expr = static_cast<ConstantNode *>(subexpr);
- if (subexpr_const->value.get_type() != Variant::INT) {
+ if (enum_value_expr->value.get_type() != Variant::INT) {
_set_error("Expected an int value for enum");
return;
}
- last_assign = subexpr_const->value;
-
- constant.expression = subexpr_const;
+ last_assign = enum_value_expr->value;
} else {
last_assign = last_assign + 1;
- ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = last_assign;
- cn->datatype = _type_from_variant(cn->value);
- constant.expression = cn;
+ enum_value_expr = alloc_node<ConstantNode>();
+ enum_value_expr->value = last_assign;
+ enum_value_expr->datatype = _type_from_variant(enum_value_expr->value);
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -4925,14 +4924,29 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
if (enum_name != "") {
- const ConstantNode *cn = static_cast<const ConstantNode *>(constant.expression);
- enum_dict[const_id] = cn->value;
- }
+ enum_dict[const_id] = enum_value_expr->value;
+ } else {
+ if (current_class->constant_expressions.has(const_id)) {
+ _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[const_id].expression->line) + ").");
+ return;
+ }
- constant.type.has_type = true;
- constant.type.kind = DataType::BUILTIN;
- constant.type.builtin_type = Variant::INT;
- p_class->constant_expressions.insert(const_id, constant);
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == const_id) {
+ _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
+
+ ClassNode::Constant constant;
+ constant.type.has_type = true;
+ constant.type.kind = DataType::BUILTIN;
+ constant.type.builtin_type = Variant::INT;
+ constant.expression = enum_value_expr;
+ p_class->constant_expressions.insert(const_id, constant);
+ }
}
}
@@ -6709,9 +6723,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
}
}
+ bool rets = false;
return_type.has_type = true;
return_type.kind = DataType::BUILTIN;
- return_type.builtin_type = Variant::get_method_return_type(base_type.builtin_type, callee_name);
+ return_type.builtin_type = Variant::get_method_return_type(base_type.builtin_type, callee_name, &rets);
+ // If the method returns, but it might return any type, (Variant::NIL), pretend we don't know the type.
+ // At least make sure we know that it returns
+ if (rets && return_type.builtin_type == Variant::NIL) {
+ return_type.has_type = false;
+ }
break;
}
@@ -7074,7 +7094,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
DataType member_type;
for (int i = 0; i < current_class->variables.size(); i++) {
- ClassNode::Member m = current_class->variables[i];
if (current_class->variables[i].identifier == p_identifier) {
member_type = current_class->variables[i].data_type;
current_class->variables.write[i].usages += 1;
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index f13479940d..9b9088dd82 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -10,7 +10,7 @@
A GridMap is split into a sparse collection of octants for efficient rendering and physics processing. Every octant has the same dimensions and can contain several cells.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/using_gridmaps.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index a8fdf8cf1f..274a2f0249 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -892,7 +892,7 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", 0), "set_theme", "get_theme");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", 0), "set_theme", "get_theme");
#endif // DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index a49137ae73..24d40111cf 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -48,9 +48,9 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
const int image_width = decoder.get_width();
const int image_height = decoder.get_height();
- int comps = decoder.get_num_components();
- if (comps == 3)
- comps = 4; //weird
+ const int comps = decoder.get_num_components();
+ if (comps != 1 && comps != 3)
+ return ERR_FILE_CORRUPT;
if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS)
return ERR_FILE_CORRUPT;
@@ -73,7 +73,19 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
}
jpgd::uint8 *pDst = pImage_data + y * dst_bpl;
- memcpy(pDst, pScan_line, dst_bpl);
+
+ if (comps == 1) {
+ memcpy(pDst, pScan_line, dst_bpl);
+ } else {
+ // For images with more than 1 channel pScan_line will always point to a buffer
+ // containing 32-bit RGBA pixels. Alpha is always 255 and we ignore it.
+ for (int x = 0; x < image_width; x++) {
+ pDst[0] = pScan_line[x * 4 + 0];
+ pDst[1] = pScan_line[x * 4 + 1];
+ pDst[2] = pScan_line[x * 4 + 2];
+ pDst += 3;
+ }
+ }
}
//all good
@@ -82,7 +94,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
if (comps == 1)
fmt = Image::FORMAT_L8;
else
- fmt = Image::FORMAT_RGBA8;
+ fmt = Image::FORMAT_RGB8;
dw = PoolVector<uint8_t>::Write();
p_image->create(image_width, image_height, 0, fmt, data);
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index e4691ee5c8..0e5dd9b4cf 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -44,7 +44,7 @@ def make_cs_files_header(src, dst, version_dst):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
- inserted_files += '\tr_files.insert("' + filepath_src_rel + '", ' \
+ inserted_files += '\tr_files.insert("' + filepath_src_rel.replace('\\', '\\\\') + '", ' \
'CompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
@@ -88,9 +88,6 @@ vars.Update(env_mono)
if env_mono['mono_glue']:
env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
-if ARGUMENTS.get('yolo_copy', False):
- env_mono.Append(CPPDEFINES=['YOLO_COPY'])
-
# Configure TLS checks
import tls_configure
@@ -105,6 +102,75 @@ env_mono = conf.Finish()
import os
+def find_nuget_unix():
+ import os.path
+ import sys
+
+ hint_dirs = ['/opt/novell/mono/bin']
+ if sys.platform == 'darwin':
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, 'nuget')
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + '.exe'):
+ return hint_path + '.exe'
+
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, 'nuget')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
+ return hint_path + '.exe'
+
+ return None
+
+
+def find_nuget_windows():
+ import mono_reg_utils as monoreg
+
+ mono_root = ''
+ bits = env['bits']
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if mono_root:
+ mono_bin_dir = os.path.join(mono_root, 'bin')
+ nuget_mono = os.path.join(mono_bin_dir, 'nuget.bat')
+
+ if os.path.isfile(nuget_mono):
+ return nuget_mono
+
+ # Standalone NuGet
+
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, 'nuget.exe')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ if 'NUGET_PATH' in os.environ:
+ hint_path = os.environ['NUGET_PATH']
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ hint_path = os.path.join(hint_path, 'nuget.exe')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ return None
+
+
def find_msbuild_unix(filename):
import os.path
import sys
@@ -179,14 +245,17 @@ def mono_build_solution(source, target, env):
import mono_reg_utils as monoreg
from shutil import copyfile
- framework_path = ''
+ sln_path = os.path.abspath(str(source[0]))
+ target_path = os.path.abspath(str(target[0]))
+ framework_path = ''
msbuild_env = os.environ.copy()
# Needed when running from Developer Command Prompt for VS
if 'PLATFORM' in msbuild_env:
del msbuild_env['PLATFORM']
+ # Find MSBuild
if os.name == 'nt':
msbuild_info = find_msbuild_windows()
if msbuild_info is None:
@@ -216,11 +285,27 @@ def mono_build_solution(source, target, env):
print('MSBuild path: ' + msbuild_path)
+ # Find NuGet
+ nuget_path = find_nuget_windows() if os.name == 'nt' else find_nuget_unix()
+ if nuget_path is None:
+ raise RuntimeError('Cannot find NuGet executable')
+
+ print('NuGet path: ' + nuget_path)
+
+ # Do NuGet restore
+
+ try:
+ subprocess.check_call([nuget_path, 'restore', sln_path])
+ except subprocess.CalledProcessError:
+ raise RuntimeError('GodotSharpTools: NuGet restore failed')
+
+ # Build solution
+
build_config = 'Release'
msbuild_args = [
msbuild_path,
- os.path.abspath(str(source[0])),
+ sln_path,
'/p:Configuration=' + build_config,
]
@@ -230,20 +315,24 @@ def mono_build_solution(source, target, env):
try:
subprocess.check_call(msbuild_args, env=msbuild_env)
except subprocess.CalledProcessError:
- raise RuntimeError('GodotSharpTools build failed')
+ raise RuntimeError('GodotSharpTools: Build failed')
+
+ # Copy files
- src_dir = os.path.abspath(os.path.join(str(source[0]), os.pardir, 'bin', build_config))
- dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
+ src_dir = os.path.abspath(os.path.join(sln_path, os.pardir, 'bin', build_config))
+ dst_dir = os.path.abspath(os.path.join(target_path, os.pardir))
+ asm_file = 'GodotSharpTools.dll'
if not os.path.isdir(dst_dir):
if os.path.exists(dst_dir):
raise RuntimeError('Target directory is a file')
os.makedirs(dst_dir)
- asm_file = 'GodotSharpTools.dll'
-
copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
+ # Dependencies
+ copyfile(os.path.join(src_dir, "DotNet.Glob.dll"), os.path.join(dst_dir, "DotNet.Glob.dll"))
+
if env['tools']:
output_dir = Dir('#bin').abspath
editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools')
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 8427103ee7..189699cca8 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -265,11 +265,7 @@ def make_template_dir(env, mono_root):
template_dir_name = ''
- if platform == 'windows':
- template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
- elif platform == 'osx':
- template_dir_name = 'data.mono.%s.%s' % (platform, target)
- elif platform == 'x11':
+ if platform in ['windows', 'osx', 'x11']:
template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
else:
assert False
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 5160d42367..700e518cfc 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -32,6 +32,7 @@
#include <mono/metadata/threads.h>
+#include "core/io/json.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/os/thread.h"
@@ -42,7 +43,6 @@
#include "editor/csharp_project.h"
#include "editor/editor_node.h"
#include "editor/godotsharp_editor.h"
-#include "utils/string_utils.h"
#endif
#include "godotsharp_dirs.h"
@@ -50,6 +50,7 @@
#include "mono_gd/gd_mono_marshal.h"
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
+#include "utils/string_utils.h"
#include "utils/thread_local.h"
#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var)
@@ -370,6 +371,7 @@ bool CSharpLanguage::supports_builtin_mode() const {
return false;
}
+#ifdef TOOLS_ENABLED
static String variant_type_to_managed_name(const String &p_var_type_name) {
if (p_var_type_name.empty())
@@ -432,8 +434,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
return p_var_type_name;
}
-String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
-#ifdef TOOLS_ENABLED
+String CSharpLanguage::make_function(const String &, const String &p_name, const PoolStringArray &p_args) const {
// FIXME
// - Due to Godot's API limitation this just appends the function to the end of the file
// - Use fully qualified name if there is ambiguity
@@ -449,10 +450,12 @@ String CSharpLanguage::make_function(const String &p_class, const String &p_name
s += ")\n{\n // Replace with function body.\n}\n";
return s;
+}
#else
+String CSharpLanguage::make_function(const String &, const String &, const PoolStringArray &) const {
return String();
-#endif
}
+#endif
String CSharpLanguage::_get_indentation() const {
#ifdef TOOLS_ENABLED
@@ -822,6 +825,49 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
}
#endif
+void CSharpLanguage::project_assembly_loaded() {
+
+ scripts_metadata.clear();
+
+ String scripts_metadata_filename = "scripts_metadata.";
+
+#ifdef TOOLS_ENABLED
+ scripts_metadata_filename += Engine::get_singleton()->is_editor_hint() ? "editor" : "editor_player";
+#else
+#ifdef DEBUG_ENABLED
+ scripts_metadata_filename += "debug";
+#else
+ scripts_metadata_filename += "release";
+#endif
+#endif
+
+ String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file(scripts_metadata_filename);
+
+ if (FileAccess::exists(scripts_metadata_path)) {
+ String old_json;
+
+ Error ferr = read_all_file_utf8(scripts_metadata_path, old_json);
+ ERR_FAIL_COND(ferr != OK);
+
+ Variant old_dict_var;
+ String err_str;
+ int err_line;
+ Error json_err = JSON::parse(old_json, old_dict_var, err_str, err_line);
+ if (json_err != OK) {
+ ERR_PRINTS("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ")");
+ return;
+ }
+
+ scripts_metadata = old_dict_var.operator Dictionary();
+
+ print_verbose("Successfully loaded scripts metadata");
+ } else {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_PRINT("Missing scripts metadata file");
+ }
+ }
+}
+
void CSharpLanguage::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("cs");
@@ -1407,6 +1453,8 @@ bool CSharpInstance::_unreference_owner_unsafe() {
if (!unsafe_referenced)
return false; // Already unreferenced
+ unsafe_referenced = false;
+
// Called from CSharpInstance::mono_object_disposed() or ~CSharpInstance()
// Unsafe refcount decrement. The managed instance also counts as a reference.
@@ -2208,10 +2256,27 @@ bool CSharpScript::can_instance() const {
#endif
#ifdef TOOLS_ENABLED
- return valid && (tool || ScriptServer::is_scripting_enabled());
+ bool extra_cond = tool || ScriptServer::is_scripting_enabled();
#else
- return valid;
+ bool extra_cond = true;
#endif
+
+ // FIXME Need to think this through better.
+ // For tool scripts, this will never fire if the class is not found. That's because we
+ // don't know if it's a tool script if we can't find the class to access the attributes.
+ if (extra_cond && !script_class) {
+ if (GDMono::get_singleton()->get_project_assembly() == NULL) {
+ // The project assembly is not loaded
+ ERR_EXPLAIN("Cannot instance script because the project assembly is not loaded. Script: " + get_path());
+ ERR_FAIL_V(NULL);
+ } else {
+ // The project assembly is loaded, but the class could not found
+ ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path());
+ ERR_FAIL_V(NULL);
+ }
+ }
+
+ return valid && extra_cond;
}
StringName CSharpScript::get_instance_base_type() const {
@@ -2317,20 +2382,6 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
CRASH_COND(!valid);
#endif
- if (!script_class) {
- if (GDMono::get_singleton()->get_project_assembly() == NULL) {
- // The project assembly is not loaded
- ERR_EXPLAIN("Cannot instance script because the project assembly is not loaded. Script: " + get_path());
- ERR_FAIL_V(NULL);
- } else {
- // The project assembly is loaded, but the class could not found
- ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path());
- ERR_FAIL_V(NULL);
- }
- }
-
- ERR_FAIL_COND_V(!valid, NULL);
-
if (native) {
String native_name = native->get_name();
if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
@@ -2418,7 +2469,23 @@ Error CSharpScript::reload(bool p_keep_state) {
GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly();
if (project_assembly) {
- script_class = project_assembly->get_object_derived_class(name);
+ const Variant *script_metadata_var = CSharpLanguage::get_singleton()->get_scripts_metadata().getptr(get_path());
+ if (script_metadata_var) {
+ Dictionary script_metadata = script_metadata_var->operator Dictionary()["class"];
+ const Variant *namespace_ = script_metadata.getptr("namespace");
+ const Variant *class_name = script_metadata.getptr("class_name");
+ ERR_FAIL_NULL_V(namespace_, ERR_BUG);
+ ERR_FAIL_NULL_V(class_name, ERR_BUG);
+ GDMonoClass *klass = project_assembly->get_class(namespace_->operator String(), class_name->operator String());
+ if (klass) {
+ bool obj_type = CACHED_CLASS(GodotObject)->is_assignable_from(klass);
+ ERR_FAIL_COND_V(!obj_type, ERR_BUG);
+ script_class = klass;
+ }
+ } else {
+ // Missing script metadata. Fallback to legacy method
+ script_class = project_assembly->get_object_derived_class(name);
+ }
valid = script_class != NULL;
@@ -2546,29 +2613,14 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
Error CSharpScript::load_source_code(const String &p_path) {
- PoolVector<uint8_t> sourcef;
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V(err != OK, err);
-
- int len = f->get_len();
- sourcef.resize(len + 1);
- PoolVector<uint8_t>::Write w = sourcef.write();
- int r = f->get_buffer(w.ptr(), len);
- f->close();
- memdelete(f);
- ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
- w[len] = 0;
-
- String s;
- if (s.parse_utf8((const char *)w.ptr())) {
-
- ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
- ERR_FAIL_V(ERR_INVALID_DATA);
+ Error ferr = read_all_file_utf8(p_path, source);
+ if (ferr != OK) {
+ if (ferr == ERR_INVALID_DATA) {
+ ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
+ }
+ ERR_FAIL_V(ferr);
}
- source = s;
-
#ifdef TOOLS_ENABLED
source_changed_cache = true;
#endif
@@ -2718,7 +2770,8 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
"Compile",
ProjectSettings::get_singleton()->globalize_path(p_path));
} else {
- ERR_PRINTS("Cannot add " + p_path + " to the C# project because it could not be created.");
+ ERR_PRINTS("Failed to create C# project");
+ ERR_PRINTS("Cannot add " + p_path + " to the C# project");
}
}
#endif
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 8b0a095890..fc604df2a0 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -67,7 +67,7 @@ class CSharpScript : public Script {
friend class CSharpInstance;
friend class CSharpLanguage;
- friend class CSharpScriptDepSort;
+ friend struct CSharpScriptDepSort;
bool tool;
bool valid;
@@ -275,6 +275,8 @@ class CSharpLanguage : public ScriptLanguage {
int lang_idx;
+ Dictionary scripts_metadata;
+
public:
StringNameCache string_names;
@@ -295,6 +297,10 @@ public:
void reload_assemblies_if_needed(bool p_soft_reload);
#endif
+ void project_assembly_loaded();
+
+ _FORCE_INLINE_ const Dictionary &get_scripts_metadata() { return scripts_metadata; }
+
virtual String get_name() const;
/* LANGUAGE FUNCTIONS */
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
index fceb732426..f9e9f41977 100644
--- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
+++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
@@ -31,6 +31,9 @@
<Reference Include="System" />
<Reference Include="Microsoft.Build" />
<Reference Include="Microsoft.Build.Framework" />
+ <Reference Include="DotNet.Glob, Version=2.1.1.0, Culture=neutral, PublicKeyToken=b68cc888b4f632d1, processorArchitecture=MSIL">
+ <HintPath>packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="StringExtensions.cs" />
@@ -43,5 +46,8 @@
<Compile Include="Utils\OS.cs" />
<Compile Include="Editor\GodotSharpExport.cs" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
index f00ec5a2ad..647d9ac81d 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using DotNet.Globbing;
using Microsoft.Build.Construction;
namespace GodotSharpTools.Project
@@ -7,7 +8,10 @@ namespace GodotSharpTools.Project
{
public static bool HasItem(this ProjectRootElement root, string itemType, string include)
{
- string includeNormalized = include.NormalizePath();
+ GlobOptions globOptions = new GlobOptions();
+ globOptions.Evaluation.CaseInsensitive = false;
+
+ string normalizedInclude = include.NormalizePath();
foreach (var itemGroup in root.ItemGroups)
{
@@ -16,10 +20,14 @@ namespace GodotSharpTools.Project
foreach (var item in itemGroup.Items)
{
- if (item.ItemType == itemType)
+ if (item.ItemType != itemType)
+ continue;
+
+ var glob = Glob.Parse(item.Include.NormalizePath(), globOptions);
+
+ if (glob.IsMatch(normalizedInclude))
{
- if (item.Include.NormalizePath() == includeNormalized)
- return true;
+ return true;
}
}
}
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
index 1d863e6f61..2ce7837a27 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
@@ -6,18 +6,24 @@ namespace GodotSharpTools.Project
{
public static class ProjectGenerator
{
+ public const string CoreApiProjectName = "GodotSharp";
+ public const string EditorApiProjectName = "GodotSharpEditor";
+ const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}";
+ const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}";
+
public static string GenCoreApiProject(string dir, string[] compileItems)
{
- string path = Path.Combine(dir, CoreApiProject + ".csproj");
+ string path = Path.Combine(dir, CoreApiProjectName + ".csproj");
ProjectPropertyGroupElement mainGroup;
- var root = CreateLibraryProject(CoreApiProject, out mainGroup);
+ var root = CreateLibraryProject(CoreApiProjectName, out mainGroup);
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot");
+ mainGroup.SetProperty("ProjectGuid", CoreApiProjectGuid);
- GenAssemblyInfoFile(root, dir, CoreApiProject,
- new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" },
+ GenAssemblyInfoFile(root, dir, CoreApiProjectName,
+ new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]" },
new string[] { "System.Runtime.CompilerServices" });
foreach (var item in compileItems)
@@ -27,33 +33,33 @@ namespace GodotSharpTools.Project
root.Save(path);
- return root.GetGuid().ToString().ToUpper();
+ return CoreApiProjectGuid;
}
- public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems)
+ public static string GenEditorApiProject(string dir, string coreApiProjPath, string[] compileItems)
{
- string path = Path.Combine(dir, EditorApiProject + ".csproj");
+ string path = Path.Combine(dir, EditorApiProjectName + ".csproj");
ProjectPropertyGroupElement mainGroup;
- var root = CreateLibraryProject(EditorApiProject, out mainGroup);
+ var root = CreateLibraryProject(EditorApiProjectName, out mainGroup);
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot");
+ mainGroup.SetProperty("ProjectGuid", EditorApiProjectGuid);
- GenAssemblyInfoFile(root, dir, EditorApiProject);
+ GenAssemblyInfoFile(root, dir, EditorApiProjectName);
foreach (var item in compileItems)
{
root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
}
- var coreApiRef = root.AddItem("Reference", CoreApiProject);
- coreApiRef.AddMetadata("HintPath", coreApiHintPath);
+ var coreApiRef = root.AddItem("ProjectReference", coreApiProjPath.Replace("/", "\\"));
coreApiRef.AddMetadata("Private", "False");
root.Save(path);
- return root.GetGuid().ToString().ToUpper();
+ return EditorApiProjectGuid;
}
public static string GenGameProject(string dir, string name, string[] compileItems)
@@ -77,13 +83,13 @@ namespace GodotSharpTools.Project
toolsGroup.AddProperty("WarningLevel", "4");
toolsGroup.AddProperty("ConsolePause", "false");
- var coreApiRef = root.AddItem("Reference", CoreApiProject);
- coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll"));
+ var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
+ coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll"));
coreApiRef.AddMetadata("Private", "False");
- var editorApiRef = root.AddItem("Reference", EditorApiProject);
+ var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
- editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll"));
+ editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll"));
editorApiRef.AddMetadata("Private", "False");
GenAssemblyInfoFile(root, dir, name);
@@ -182,9 +188,6 @@ namespace GodotSharpTools.Project
}
}
- public const string CoreApiProject = "GodotSharp";
- public const string EditorApiProject = "GodotSharpEditor";
-
private const string assemblyInfoTemplate =
@"using System.Reflection;{0}
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
index 6889ea715f..a13f4fd6ef 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
@@ -1,5 +1,6 @@
-using System;
+using System.Collections.Generic;
using System.IO;
+using DotNet.Globbing;
using Microsoft.Build.Construction;
namespace GodotSharpTools.Project
@@ -10,8 +11,61 @@ namespace GodotSharpTools.Project
{
var dir = Directory.GetParent(projectPath).FullName;
var root = ProjectRootElement.Open(projectPath);
- if (root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\")))
+ var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\");
+
+ if (root.AddItemChecked(itemType, normalizedInclude))
root.Save();
}
+
+ private static string[] GetAllFilesRecursive(string rootDirectory, string mask)
+ {
+ string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories);
+
+ // We want relative paths
+ for (int i = 0; i < files.Length; i++) {
+ files[i] = files[i].RelativeToPath(rootDirectory);
+ }
+
+ return files;
+ }
+
+ public static string[] GetIncludeFiles(string projectPath, string itemType)
+ {
+ var result = new List<string>();
+ var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs");
+
+ GlobOptions globOptions = new GlobOptions();
+ globOptions.Evaluation.CaseInsensitive = false;
+
+ var root = ProjectRootElement.Open(projectPath);
+
+ foreach (var itemGroup in root.ItemGroups)
+ {
+ if (itemGroup.Condition.Length != 0)
+ continue;
+
+ foreach (var item in itemGroup.Items)
+ {
+ if (item.ItemType != itemType)
+ continue;
+
+ string normalizedInclude = item.Include.NormalizePath();
+
+ var glob = Glob.Parse(normalizedInclude, globOptions);
+
+ // TODO Check somehow if path has no blog to avoid the following loop...
+
+ foreach (var existingFile in existingFiles)
+ {
+ if (glob.IsMatch(existingFile))
+ {
+ result.Add(existingFile);
+ }
+ }
+ }
+ }
+
+ return result.ToArray();
+ }
}
}
diff --git a/modules/mono/editor/GodotSharpTools/StringExtensions.cs b/modules/mono/editor/GodotSharpTools/StringExtensions.cs
index b66c86f8ce..b0436d2f18 100644
--- a/modules/mono/editor/GodotSharpTools/StringExtensions.cs
+++ b/modules/mono/editor/GodotSharpTools/StringExtensions.cs
@@ -36,7 +36,9 @@ namespace GodotSharpTools
public static bool IsAbsolutePath(this string path)
{
- return path.StartsWith("/") || path.StartsWith("\\") || path.StartsWith(driveRoot);
+ return path.StartsWith("/", StringComparison.Ordinal) ||
+ path.StartsWith("\\", StringComparison.Ordinal) ||
+ path.StartsWith(driveRoot, StringComparison.Ordinal);
}
public static string CsvEscape(this string value, char delimiter = ',')
diff --git a/modules/mono/editor/GodotSharpTools/packages.config b/modules/mono/editor/GodotSharpTools/packages.config
new file mode 100644
index 0000000000..2c7cb0bd4b
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="DotNet.Glob" version="2.1.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index bcf08026bc..166b3e1324 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -47,7 +47,6 @@
#include "../utils/path_utils.h"
#include "../utils/string_utils.h"
#include "csharp_project.h"
-#include "net_solution.h"
#define CS_INDENT " " // 4 whitespaces
@@ -97,7 +96,7 @@
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(3)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(5)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
@@ -173,23 +172,74 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
return ret;
}
-String BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
+int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
CRASH_COND(p_ienum.constants.empty());
- const List<ConstantInterface>::Element *front = p_ienum.constants.front();
- int candidate_len = front->get().name.length();
+ const ConstantInterface &front_iconstant = p_ienum.constants.front()->get();
+ Vector<String> front_parts = front_iconstant.name.split("_", /* p_allow_empty: */ true);
+ int candidate_len = front_parts.size() - 1;
- for (const List<ConstantInterface>::Element *E = front->next(); E; E = E->next()) {
- int j = 0;
- for (j = 0; j < candidate_len && j < E->get().name.length(); j++) {
- if (front->get().name[j] != E->get().name[j])
- break;
+ if (candidate_len == 0)
+ return 0;
+
+ for (const List<ConstantInterface>::Element *E = p_ienum.constants.front()->next(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
+
+ Vector<String> parts = iconstant.name.split("_", /* p_allow_empty: */ true);
+
+ int i;
+ for (i = 0; i < candidate_len && i < parts.size(); i++) {
+ if (front_parts[i] != parts[i]) {
+ // HARDCODED: Some Flag enums have the prefix 'FLAG_' for everything except 'FLAGS_DEFAULT' (same for 'METHOD_FLAG_' and'METHOD_FLAGS_DEFAULT').
+ bool hardcoded_exc = (i == candidate_len - 1 && ((front_parts[i] == "FLAGS" && parts[i] == "FLAG") || (front_parts[i] == "FLAG" && parts[i] == "FLAGS")));
+ if (!hardcoded_exc)
+ break;
+ }
}
- candidate_len = j;
+ candidate_len = i;
+
+ if (candidate_len == 0)
+ return 0;
}
- return front->get().name.substr(0, candidate_len);
+ return candidate_len;
+}
+
+void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumInterface &p_ienum, int p_prefix_length) {
+
+ if (p_prefix_length > 0) {
+ for (List<ConstantInterface>::Element *E = p_ienum.constants.front(); E; E = E->next()) {
+ int curr_prefix_length = p_prefix_length;
+
+ ConstantInterface &curr_const = E->get();
+
+ String constant_name = curr_const.name;
+
+ Vector<String> parts = constant_name.split("_", /* p_allow_empty: */ true);
+
+ if (parts.size() <= curr_prefix_length)
+ continue;
+
+ if (parts[curr_prefix_length][0] >= '0' && parts[curr_prefix_length][0] <= '9') {
+ // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
+ // so we make the prefix for this constant one word shorter in those cases.
+ for (curr_prefix_length = curr_prefix_length - 1; curr_prefix_length > 0; curr_prefix_length--) {
+ if (parts[curr_prefix_length][0] < '0' || parts[curr_prefix_length][0] > '9')
+ break;
+ }
+ }
+
+ constant_name = "";
+ for (int i = curr_prefix_length; i < parts.size(); i++) {
+ if (i > curr_prefix_length)
+ constant_name += "_";
+ constant_name += parts[i];
+ }
+
+ curr_const.proxy_name = snake_to_pascal_case(constant_name, true);
+ }
+ }
}
void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
@@ -272,7 +322,7 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
}
p_output.push_back(MEMBER_BEGIN "public const int ");
- p_output.push_back(iconstant.name);
+ p_output.push_back(iconstant.proxy_name);
p_output.push_back(" = ");
p_output.push_back(itos(iconstant.value));
p_output.push_back(";");
@@ -334,25 +384,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
p_output.push_back(INDENT2 "/// </summary>\n");
}
- String constant_name = iconstant.name;
-
- if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
- constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
- }
-
- if (constant_name[0] >= '0' && constant_name[0] <= '9') {
- // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
- // so we make the prefix one word shorter in those cases.
- int i = 0;
- for (i = ienum.prefix.length() - 1; i >= 0; i--) {
- if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
- break;
- }
- constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
- }
-
p_output.push_back(INDENT2);
- p_output.push_back(constant_name);
+ p_output.push_back(iconstant.proxy_name);
p_output.push_back(" = ");
p_output.push_back(itos(iconstant.value));
p_output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
@@ -367,32 +400,29 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
p_output.push_back(CLOSE_BLOCK); // end of namespace
}
-Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) {
+Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
verbose_output = p_verbose_output;
+ String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
+
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
- if (!DirAccess::exists(p_output_dir)) {
- Error err = da->make_dir_recursive(p_output_dir);
+ if (!DirAccess::exists(proj_dir)) {
+ Error err = da->make_dir_recursive(proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
- da->change_dir(p_output_dir);
+ da->change_dir(proj_dir);
da->make_dir("Core");
da->make_dir("ObjectType");
- String core_dir = path_join(p_output_dir, "Core");
- String obj_type_dir = path_join(p_output_dir, "ObjectType");
+ String core_dir = path_join(proj_dir, "Core");
+ String obj_type_dir = path_join(proj_dir, "ObjectType");
Vector<String> compile_items;
- NETSolution solution(API_ASSEMBLY_NAME);
-
- if (!solution.set_path(p_output_dir))
- return ERR_FILE_NOT_FOUND;
-
// Generate source file for global scope constants and enums
{
List<String> constants_source;
@@ -496,15 +526,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
compile_items.push_back(internal_methods_file);
- String guid = CSharpProject::generate_core_api_project(p_output_dir, compile_items);
+ String guid = CSharpProject::generate_core_api_project(proj_dir, compile_items);
- solution.add_new_project(API_ASSEMBLY_NAME, guid);
+ DotNetSolution::ProjectInfo proj_info;
+ proj_info.guid = guid;
+ proj_info.relpath = String(CORE_API_ASSEMBLY_NAME).plus_file(CORE_API_ASSEMBLY_NAME ".csproj");
+ proj_info.configs.push_back("Debug");
+ proj_info.configs.push_back("Release");
- Error sln_error = solution.save();
- if (sln_error != OK) {
- ERR_PRINT("Could not to save .NET solution.");
- return sln_error;
- }
+ r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
if (verbose_output)
OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
@@ -512,32 +542,29 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
return OK;
}
-Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output) {
+Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
verbose_output = p_verbose_output;
+ String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
+
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
- if (!DirAccess::exists(p_output_dir)) {
- Error err = da->make_dir_recursive(p_output_dir);
+ if (!DirAccess::exists(proj_dir)) {
+ Error err = da->make_dir_recursive(proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
- da->change_dir(p_output_dir);
+ da->change_dir(proj_dir);
da->make_dir("Core");
da->make_dir("ObjectType");
- String core_dir = path_join(p_output_dir, "Core");
- String obj_type_dir = path_join(p_output_dir, "ObjectType");
+ String core_dir = path_join(proj_dir, "Core");
+ String obj_type_dir = path_join(proj_dir, "ObjectType");
Vector<String> compile_items;
- NETSolution solution(EDITOR_API_ASSEMBLY_NAME);
-
- if (!solution.set_path(p_output_dir))
- return ERR_FILE_NOT_FOUND;
-
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
const TypeInterface &itype = E.get();
@@ -598,19 +625,57 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
compile_items.push_back(internal_methods_file);
- String guid = CSharpProject::generate_editor_api_project(p_output_dir, p_core_dll_path, compile_items);
+ String guid = CSharpProject::generate_editor_api_project(proj_dir, "../" CORE_API_ASSEMBLY_NAME "/" CORE_API_ASSEMBLY_NAME ".csproj", compile_items);
+
+ DotNetSolution::ProjectInfo proj_info;
+ proj_info.guid = guid;
+ proj_info.relpath = String(EDITOR_API_ASSEMBLY_NAME).plus_file(EDITOR_API_ASSEMBLY_NAME ".csproj");
+ proj_info.configs.push_back("Debug");
+ proj_info.configs.push_back("Release");
+
+ r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
+
+ if (verbose_output)
+ OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
+
+ return OK;
+}
+
+Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) {
- solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, guid);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+
+ if (!DirAccess::exists(p_output_dir)) {
+ Error err = da->make_dir_recursive(p_output_dir);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
+ DotNetSolution solution(API_SOLUTION_NAME);
+
+ if (!solution.set_path(p_output_dir))
+ return ERR_FILE_NOT_FOUND;
+
+ Error proj_err;
+
+ proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output);
+ if (proj_err != OK) {
+ ERR_PRINT("Generation of the Core API C# project failed");
+ return proj_err;
+ }
+
+ proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output);
+ if (proj_err != OK) {
+ ERR_PRINT("Generation of the Editor API C# project failed");
+ return proj_err;
+ }
Error sln_error = solution.save();
if (sln_error != OK) {
- ERR_PRINT("Could not to save .NET solution.");
+ ERR_PRINT("Failed to save API solution");
return sln_error;
}
- if (verbose_output)
- OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
-
return OK;
}
@@ -646,8 +711,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
List<String> output;
output.push_back("using System;\n"); // IntPtr
+ output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
+
output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
"'Missing XML comment for publicly visible type or member'\n");
+
output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
const DocData::ClassDoc *class_doc = itype.class_doc;
@@ -717,7 +785,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
output.push_back(MEMBER_BEGIN "public const int ");
- output.push_back(iconstant.name);
+ output.push_back(iconstant.proxy_name);
output.push_back(" = ");
output.push_back(itos(iconstant.value));
output.push_back(";");
@@ -757,25 +825,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(INDENT3 "/// </summary>\n");
}
- String constant_name = iconstant.name;
-
- if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
- constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
- }
-
- if (constant_name[0] >= '0' && constant_name[0] <= '9') {
- // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
- // so we make the prefix one word shorter in those cases.
- int i = 0;
- for (i = ienum.prefix.length() - 1; i >= 0; i--) {
- if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
- break;
- }
- constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
- }
-
output.push_back(INDENT3);
- output.push_back(constant_name);
+ output.push_back(iconstant.proxy_name);
output.push_back(" = ");
output.push_back(itos(iconstant.value));
output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
@@ -1086,7 +1137,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
+ p_output.push_back(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
p_output.push_back(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.push_back(p_imethod.name);
p_output.push_back("\");\n");
@@ -1843,11 +1894,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
EnumInterface ienum(enum_proxy_cname);
const List<StringName> &constants = enum_map.get(*k);
for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- int *value = class_info->constant_map.getptr(E->get());
+ const StringName &constant_cname = E->get();
+ String constant_name = constant_cname.operator String();
+ int *value = class_info->constant_map.getptr(constant_cname);
ERR_FAIL_NULL(value);
- constant_list.erase(E->get().operator String());
+ constant_list.erase(constant_name);
- ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
iconstant.const_doc = NULL;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -1862,7 +1915,9 @@ void BindingsGenerator::_populate_object_type_interfaces() {
ienum.constants.push_back(iconstant);
}
- ienum.prefix = _determine_enum_prefix(ienum);
+ int prefix_length = _determine_enum_prefix(ienum);
+
+ _apply_prefix_to_enum_constants(ienum, prefix_length);
itype.enums.push_back(ienum);
@@ -1876,10 +1931,11 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
for (const List<String>::Element *E = constant_list.front(); E; E = E->next()) {
- int *value = class_info->constant_map.getptr(E->get());
+ const String &constant_name = E->get();
+ int *value = class_info->constant_map.getptr(StringName(E->get()));
ERR_FAIL_NULL(value);
- ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
iconstant.const_doc = NULL;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -1990,18 +2046,18 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
TypeInterface itype;
-#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
- { \
- itype = TypeInterface::create_value_type(String(#m_type)); \
- itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n"; \
- itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n" \
- "\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type_in = m_type_in; \
- itype.cs_in = "ref %s"; \
- itype.cs_out = "return (%1)%0;"; \
- itype.im_type_out = "object"; \
- builtin_types.insert(itype.cname, itype); \
+#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
+ { \
+ itype = TypeInterface::create_value_type(String(#m_type)); \
+ itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \
+ itype.c_out = "\treturn MARSHALLED_OUT(" #m_type ", %1);\n"; \
+ itype.c_arg_in = "&%s_in"; \
+ itype.c_type_in = "GDMonoMarshal::M_" #m_type "*"; \
+ itype.c_type_out = "GDMonoMarshal::M_" #m_type; \
+ itype.cs_in = "ref %s"; \
+ itype.cs_out = "return (%1)%0;"; \
+ itype.im_type_out = itype.cs_type; \
+ builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2, "real_t*")
@@ -2019,26 +2075,31 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// bool
itype = TypeInterface::create_value_type(String("bool"));
- itype.c_arg_in = "&%s_in";
- // /* MonoBoolean <---> bool
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "bool";
- // */
- itype.c_type_in = "MonoBoolean";
- itype.c_type_out = itype.c_type_in;
+
+ {
+ // MonoBoolean <---> bool
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "bool";
+ itype.c_type_in = "MonoBoolean";
+ itype.c_type_out = itype.c_type_in;
+ itype.c_arg_in = "&%s_in";
+ }
itype.im_type_in = itype.name;
itype.im_type_out = itype.name;
builtin_types.insert(itype.cname, itype);
// int
+ // C interface is the same as that of enums. Remember to apply any
+ // changes done here to TypeInterface::postsetup_enum_type as well
itype = TypeInterface::create_value_type(String("int"));
itype.c_arg_in = "&%s_in";
- // /* ptrcall only supports int64_t and uint64_t
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "int64_t";
- // */
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "int64_t";
+ }
itype.c_type_in = "int32_t";
itype.c_type_out = itype.c_type_in;
itype.im_type_in = itype.name;
@@ -2047,21 +2108,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// real_t
itype = TypeInterface();
+ itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE.
+ itype.cname = itype.name;
#ifdef REAL_T_IS_DOUBLE
- itype.name = "double";
+ itype.proxy_name = "double";
#else
- itype.name = "float";
+ itype.proxy_name = "float";
#endif
- itype.cname = itype.name;
- itype.proxy_name = itype.name;
- itype.c_arg_in = "&%s_in";
- //* ptrcall only supports double
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "double";
- //*/
- itype.c_type_in = "real_t";
- itype.c_type_out = "real_t";
+ {
+ // The expected type for parameters and return value in ptrcall is 'double'.
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "double";
+ itype.c_type_in = "real_t";
+ itype.c_type_out = "real_t";
+ itype.c_arg_in = "&%s_in";
+ }
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
@@ -2256,7 +2318,7 @@ void BindingsGenerator::_populate_global_constants() {
int constant_value = GlobalConstants::get_global_constant_value(i);
StringName enum_name = GlobalConstants::get_global_constant_enum(i);
- ConstantInterface iconstant(snake_to_pascal_case(constant_name, true), constant_value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), constant_value);
iconstant.const_doc = const_doc;
if (enum_name != StringName()) {
@@ -2284,16 +2346,18 @@ void BindingsGenerator::_populate_global_constants() {
TypeInterface::postsetup_enum_type(enum_itype);
enum_types.insert(enum_itype.cname, enum_itype);
- ienum.prefix = _determine_enum_prefix(ienum);
+ int prefix_length = _determine_enum_prefix(ienum);
- // HARDCODED
+ // HARDCODED: The Error enum have the prefix 'ERR_' for everything except 'OK' and 'FAILED'.
if (ienum.cname == name_cache.enum_Error) {
- if (!ienum.prefix.empty()) { // Just in case it ever changes
+ if (prefix_length > 0) { // Just in case it ever changes
ERR_PRINTS("Prefix for enum 'Error' is not empty");
}
- ienum.prefix = "Err";
+ prefix_length = 1; // 'ERR_'
}
+
+ _apply_prefix_to_enum_constants(ienum, prefix_length);
}
}
@@ -2335,12 +2399,11 @@ void BindingsGenerator::initialize() {
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
- const int NUM_OPTIONS = 3;
+ const int NUM_OPTIONS = 2;
int options_left = NUM_OPTIONS;
String mono_glue_option = "--generate-mono-glue";
- String cs_core_api_option = "--generate-cs-core-api";
- String cs_editor_api_option = "--generate-cs-editor-api";
+ String cs_api_option = "--generate-cs-api";
verbose_output = true;
@@ -2354,42 +2417,24 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
if (path_elem) {
if (get_singleton()->generate_glue(path_elem->get()) != OK)
- ERR_PRINT("Mono glue generation failed");
+ ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
elem = elem->next();
} else {
- ERR_PRINTS("--generate-mono-glue: No output directory specified");
+ ERR_PRINTS(mono_glue_option + ": No output directory specified");
}
--options_left;
- } else if (elem->get() == cs_core_api_option) {
+ } else if (elem->get() == cs_api_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- if (get_singleton()->generate_cs_core_project(path_elem->get()) != OK)
- ERR_PRINT("Generation of solution and C# project for the Core API failed");
+ if (get_singleton()->generate_cs_api(path_elem->get()) != OK)
+ ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
elem = elem->next();
} else {
- ERR_PRINTS(cs_core_api_option + ": No output directory specified");
- }
-
- --options_left;
-
- } else if (elem->get() == cs_editor_api_option) {
-
- const List<String>::Element *path_elem = elem->next();
-
- if (path_elem) {
- if (path_elem->next()) {
- if (get_singleton()->generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
- ERR_PRINT("Generation of solution and C# project for the Editor API failed");
- elem = path_elem->next();
- } else {
- ERR_PRINTS(cs_editor_api_option + ": No hint path for the Core API dll specified");
- }
- } else {
- ERR_PRINTS(cs_editor_api_option + ": No output directory specified");
+ ERR_PRINTS(cs_api_option + ": No output directory specified");
}
--options_left;
@@ -2401,7 +2446,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
verbose_output = false;
if (options_left != NUM_OPTIONS)
- exit(0);
+ ::exit(0);
}
#endif
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index ad89255ba5..91c474c4f0 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -32,6 +32,7 @@
#define BINDINGS_GENERATOR_H
#include "core/class_db.h"
+#include "dotnet_solution.h"
#include "editor/doc/doc_data.h"
#include "editor/editor_help.h"
@@ -43,20 +44,21 @@ class BindingsGenerator {
struct ConstantInterface {
String name;
+ String proxy_name;
int value;
const DocData::ConstantDoc *const_doc;
ConstantInterface() {}
- ConstantInterface(const String &p_name, int p_value) {
+ ConstantInterface(const String &p_name, const String &p_proxy_name, int p_value) {
name = p_name;
+ proxy_name = p_proxy_name;
value = p_value;
}
};
struct EnumInterface {
StringName cname;
- String prefix;
List<ConstantInterface> constants;
_FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const {
@@ -223,7 +225,7 @@ class BindingsGenerator {
String c_in;
/**
- * Determines the name of the variable that will be passed as argument to a ptrcall.
+ * Determines the expression that will be passed as argument to ptrcall.
* By default the value equals the name of the parameter,
* this varies for types that require special manipulation via [c_in].
* Formatting elements:
@@ -333,8 +335,6 @@ class BindingsGenerator {
itype.proxy_name = itype.name;
itype.c_type = itype.name;
- itype.c_type_in = "void*";
- itype.c_type_out = "MonoObject*";
itype.cs_type = itype.proxy_name;
itype.im_type_in = "ref " + itype.proxy_name;
itype.im_type_out = itype.proxy_name;
@@ -385,10 +385,19 @@ class BindingsGenerator {
}
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
- r_enum_itype.c_arg_in = "&%s";
- r_enum_itype.c_type = "int";
- r_enum_itype.c_type_in = "int";
- r_enum_itype.c_type_out = "int";
+ // C interface is the same as that of 'int'. Remember to apply any
+ // changes done here to the 'int' type interface as well
+
+ r_enum_itype.c_arg_in = "&%s_in";
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ r_enum_itype.c_out = "\treturn (%0)%1;\n";
+ r_enum_itype.c_type = "int64_t";
+ }
+ r_enum_itype.c_type_in = "int32_t";
+ r_enum_itype.c_type_out = r_enum_itype.c_type_in;
+
r_enum_itype.cs_type = r_enum_itype.proxy_name;
r_enum_itype.cs_in = "(int)%s";
r_enum_itype.cs_out = "return (%1)%0;";
@@ -513,7 +522,8 @@ class BindingsGenerator {
return p_type.name;
}
- String _determine_enum_prefix(const EnumInterface &p_ienum);
+ int _determine_enum_prefix(const EnumInterface &p_ienum);
+ void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
void _generate_method_icalls(const TypeInterface &p_itype);
@@ -547,8 +557,9 @@ class BindingsGenerator {
static BindingsGenerator *singleton;
public:
- Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true);
- Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
+ Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
+ Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
+ Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true);
Error generate_glue(const String &p_output_dir);
static uint32_t get_version();
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 6f223b75a3..416108603b 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -30,11 +30,17 @@
#include "csharp_project.h"
+#include "core/io/json.h"
+#include "core/os/dir_access.h"
+#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/project_settings.h"
+#include "../csharp_script.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
+#include "../utils/string_utils.h"
+#include "script_class_parser.h"
namespace CSharpProject {
@@ -58,16 +64,16 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi
return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
}
-String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) {
+String generate_editor_api_project(const String &p_dir, const String &p_core_proj_path, const Vector<String> &p_files) {
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
Variant dir = p_dir;
- Variant core_dll_path = p_core_dll_path;
+ Variant core_proj_path = p_core_proj_path;
Variant compile_items = p_files;
- const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
+ const Variant *args[3] = { &dir, &core_proj_path, &compile_items };
MonoException *exc = NULL;
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
@@ -102,6 +108,9 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
+ if (!GLOBAL_DEF("mono/project/auto_update_project", true))
+ return;
+
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
@@ -118,4 +127,118 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
ERR_FAIL();
}
}
+
+Error generate_scripts_metadata(const String &p_project_path, const String &p_output_path) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ if (FileAccess::exists(p_output_path)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Error rm_err = da->remove(p_output_path);
+
+ ERR_EXPLAIN("Failed to remove old scripts metadata file");
+ ERR_FAIL_COND_V(rm_err != OK, rm_err);
+ }
+
+ GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
+
+ void *args[2] = {
+ GDMonoMarshal::mono_string_from_godot(p_project_path),
+ GDMonoMarshal::mono_string_from_godot("Compile")
+ };
+
+ MonoException *exc = NULL;
+ MonoArray *ret = (MonoArray *)project_utils->get_method("GetIncludeFiles", 2)->invoke_raw(NULL, args, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ ERR_FAIL_V(FAILED);
+ }
+
+ PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret);
+ PoolStringArray::Read r = project_files.read();
+
+ Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata();
+ Dictionary new_dict;
+
+ for (int i = 0; i < project_files.size(); i++) {
+ const String &project_file = ("res://" + r[i]).simplify_path();
+
+ uint64_t modified_time = FileAccess::get_modified_time(project_file);
+
+ const Variant *old_file_var = old_dict.getptr(project_file);
+ if (old_file_var) {
+ Dictionary old_file_dict = old_file_var->operator Dictionary();
+
+ if (old_file_dict["modified_time"].operator uint64_t() == modified_time) {
+ // No changes so no need to parse again
+ new_dict[project_file] = old_file_dict;
+ continue;
+ }
+ }
+
+ ScriptClassParser scp;
+ Error err = scp.parse_file(project_file);
+ if (err != OK) {
+ ERR_PRINTS("Parse error: " + scp.get_error());
+ ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file);
+ ERR_FAIL_V(err);
+ }
+
+ Vector<ScriptClassParser::ClassDecl> classes = scp.get_classes();
+
+ bool found = false;
+ Dictionary class_dict;
+
+ String search_name = project_file.get_file().get_basename();
+
+ for (int j = 0; j < classes.size(); j++) {
+ const ScriptClassParser::ClassDecl &class_decl = classes[j];
+
+ if (class_decl.base.size() == 0)
+ continue; // Does not inherit nor implement anything, so it can't be a script class
+
+ String class_cmp;
+
+ if (class_decl.nested) {
+ class_cmp = class_decl.name.get_slice(".", class_decl.name.get_slice_count(".") - 1);
+ } else {
+ class_cmp = class_decl.name;
+ }
+
+ if (class_cmp != search_name)
+ continue;
+
+ class_dict["namespace"] = class_decl.namespace_;
+ class_dict["class_name"] = class_decl.name;
+ class_dict["nested"] = class_decl.nested;
+
+ found = true;
+ break;
+ }
+
+ if (found) {
+ Dictionary file_dict;
+ file_dict["modified_time"] = modified_time;
+ file_dict["class"] = class_dict;
+ new_dict[project_file] = file_dict;
+ }
+ }
+
+ if (new_dict.size()) {
+ String json = JSON::print(new_dict, "", false);
+
+ Error ferr;
+ FileAccess *f = FileAccess::open(p_output_path, FileAccess::WRITE, &ferr);
+ ERR_EXPLAIN("Cannot open file for writing: " + p_output_path);
+ ERR_FAIL_COND_V(ferr != OK, ferr);
+ f->store_string(json);
+ f->flush();
+ f->close();
+ memdelete(f);
+ }
+
+ return OK;
+}
+
} // namespace CSharpProject
diff --git a/modules/mono/editor/csharp_project.h b/modules/mono/editor/csharp_project.h
index d852139de0..aeeeff50f0 100644
--- a/modules/mono/editor/csharp_project.h
+++ b/modules/mono/editor/csharp_project.h
@@ -40,6 +40,9 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll
String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files = Vector<String>());
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include);
+
+Error generate_scripts_metadata(const String &p_project_path, const String &p_output_path);
+
} // namespace CSharpProject
#endif // CSHARP_PROJECT_H
diff --git a/modules/mono/editor/net_solution.cpp b/modules/mono/editor/dotnet_solution.cpp
index 8bbd376c9a..ab92e2e378 100644
--- a/modules/mono/editor/net_solution.cpp
+++ b/modules/mono/editor/dotnet_solution.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* net_solution.cpp */
+/* dotnet_solution.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "net_solution.h"
+#include "dotnet_solution.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
@@ -52,33 +52,32 @@
#define PROJECT_DECLARATION "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"%0\", \"%1\", \"{%2}\"\nEndProject"
-#define SOLUTION_PLATFORMS_CONFIG "\t\%0|Any CPU = %0|Any CPU"
+#define SOLUTION_PLATFORMS_CONFIG "\t%0|Any CPU = %0|Any CPU"
#define PROJECT_PLATFORMS_CONFIG \
"\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
"\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU"
-void NETSolution::add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs) {
- if (projects.has(p_name))
- WARN_PRINT("Overriding existing project.");
-
- ProjectInfo procinfo;
- procinfo.guid = p_guid;
+void DotNetSolution::add_new_project(const String &p_name, const ProjectInfo &p_project_info) {
+ projects[p_name] = p_project_info;
+}
- procinfo.configs.push_back("Debug");
- procinfo.configs.push_back("Release");
+bool DotNetSolution::has_project(const String &p_name) const {
+ return projects.find(p_name) != NULL;
+}
- for (int i = 0; i < p_extra_configs.size(); i++) {
- procinfo.configs.push_back(p_extra_configs[i]);
- }
+const DotNetSolution::ProjectInfo &DotNetSolution::get_project_info(const String &p_name) const {
+ return projects[p_name];
+}
- projects[p_name] = procinfo;
+bool DotNetSolution::remove_project(const String &p_name) {
+ return projects.erase(p_name);
}
-Error NETSolution::save() {
+Error DotNetSolution::save() {
bool dir_exists = DirAccess::exists(path);
ERR_EXPLAIN("The directory does not exist.");
- ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
+ ERR_FAIL_COND_V(!dir_exists, ERR_FILE_NOT_FOUND);
String projs_decl;
String sln_platform_cfg;
@@ -86,34 +85,40 @@ Error NETSolution::save() {
for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
const String &name = E->key();
- const ProjectInfo &procinfo = E->value();
+ const ProjectInfo &proj_info = E->value();
- projs_decl += sformat(PROJECT_DECLARATION, name, name + ".csproj", procinfo.guid);
+ bool is_front = E == projects.front();
- for (int i = 0; i < procinfo.configs.size(); i++) {
- const String &config = procinfo.configs[i];
+ if (!is_front)
+ projs_decl += "\n";
- if (i != 0) {
+ projs_decl += sformat(PROJECT_DECLARATION, name, proj_info.relpath.replace("/", "\\"), proj_info.guid);
+
+ for (int i = 0; i < proj_info.configs.size(); i++) {
+ const String &config = proj_info.configs[i];
+
+ if (i != 0 || !is_front) {
sln_platform_cfg += "\n";
proj_platform_cfg += "\n";
}
sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config);
- proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, procinfo.guid, config);
+ proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, proj_info.guid, config);
}
}
String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg);
- FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
- ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
+ FileAccess *file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
+ ERR_FAIL_NULL_V(file, ERR_FILE_CANT_WRITE);
file->store_string(content);
file->close();
+ memdelete(file);
return OK;
}
-bool NETSolution::set_path(const String &p_existing_path) {
+bool DotNetSolution::set_path(const String &p_existing_path) {
if (p_existing_path.is_abs_path()) {
path = p_existing_path;
} else {
@@ -126,6 +131,10 @@ bool NETSolution::set_path(const String &p_existing_path) {
return true;
}
-NETSolution::NETSolution(const String &p_name) {
+String DotNetSolution::get_path() {
+ return path;
+}
+
+DotNetSolution::DotNetSolution(const String &p_name) {
name = p_name;
}
diff --git a/modules/mono/editor/net_solution.h b/modules/mono/editor/dotnet_solution.h
index bdff24af0b..629605ad18 100644
--- a/modules/mono/editor/net_solution.h
+++ b/modules/mono/editor/dotnet_solution.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* net_solution.h */
+/* dotnet_solution.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -34,23 +34,28 @@
#include "core/map.h"
#include "core/ustring.h"
-struct NETSolution {
+struct DotNetSolution {
String name;
- void add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs = Vector<String>());
+ struct ProjectInfo {
+ String guid;
+ String relpath; // Must be relative to the solution directory
+ Vector<String> configs;
+ };
+
+ void add_new_project(const String &p_name, const ProjectInfo &p_project_info);
+ bool has_project(const String &p_name) const;
+ const ProjectInfo &get_project_info(const String &p_name) const;
+ bool remove_project(const String &p_name);
Error save();
bool set_path(const String &p_existing_path);
+ String get_path();
- NETSolution(const String &p_name);
+ DotNetSolution(const String &p_name);
private:
- struct ProjectInfo {
- String guid;
- Vector<String> configs;
- };
-
String path;
Map<String, ProjectInfo> projects;
};
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 8fe6e46b60..0f12fc5243 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -39,6 +39,7 @@
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
#include "bindings_generator.h"
+#include "csharp_project.h"
#include "godotsharp_editor.h"
#define PROP_NAME_MSBUILD_MONO "MSBuild (Mono)"
@@ -226,20 +227,24 @@ void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
MonoBottomPanel::get_singleton()->show_build_tab();
}
-bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config) {
+bool GodotSharpBuilds::build_api_sln(const String &p_api_sln_dir, const String &p_config) {
- String api_sln_file = p_api_sln_dir.plus_file(p_name + ".sln");
- String api_assembly_dir = p_api_sln_dir.plus_file("bin").plus_file(p_config);
- String api_assembly_file = api_assembly_dir.plus_file(p_name + ".dll");
+ String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
- if (!FileAccess::exists(api_assembly_file)) {
+ String core_api_assembly_dir = p_api_sln_dir.plus_file(CORE_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
+ String core_api_assembly_file = core_api_assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+
+ String editor_api_assembly_dir = p_api_sln_dir.plus_file(EDITOR_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
+ String editor_api_assembly_file = editor_api_assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+
+ if (!FileAccess::exists(core_api_assembly_file) || !FileAccess::exists(editor_api_assembly_file)) {
MonoBuildInfo api_build_info(api_sln_file, p_config);
// TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
// once we start to actively document manually maintained C# classes
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
- show_build_error_dialog("Failed to build " + p_name + " solution.");
+ show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution.");
return false;
}
}
@@ -268,7 +273,7 @@ bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &
if (!FileAccess::exists(assembly_dst) ||
FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) ||
GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = p_assembly_name + ".xml";
if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
@@ -280,8 +285,6 @@ bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &
Error err = da->copy(assembly_src, assembly_dst);
- memdelete(da);
-
if (err != OK) {
show_build_error_dialog("Failed to copy " + assembly_file);
return false;
@@ -303,61 +306,50 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
"_" + String::num_uint64(CS_GLUE_VERSION);
}
-bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
+bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
- String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
- String api_build_config = "Release";
+ String api_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
- EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3);
+ String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
- pr.step("Generating " + api_name + " solution", 0);
+ if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(api_name + ".dll"))) {
+ EditorProgress pr("mono_copy_prebuilt_api_assembly", "Copying prebuilt " + api_name + " assembly...", 1);
+ pr.step("Copying " + api_name + " assembly", 0);
+ return GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, api_name, p_api_type);
+ }
- String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
- .plus_file(_api_folder_name(APIAssembly::API_CORE))
- .plus_file(API_ASSEMBLY_NAME);
- String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
- .plus_file(_api_folder_name(APIAssembly::API_EDITOR))
- .plus_file(EDITOR_API_ASSEMBLY_NAME);
+ String api_build_config = "Release";
- String api_sln_dir = p_api_type == APIAssembly::API_CORE ? core_api_sln_dir : editor_api_sln_dir;
- String api_sln_file = api_sln_dir.plus_file(api_name + ".sln");
+ EditorProgress pr("mono_build_release_" API_SOLUTION_NAME, "Building " API_SOLUTION_NAME " solution...", 3);
- if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
- String core_api_assembly;
+ pr.step("Generating " API_SOLUTION_NAME " solution", 0);
- if (p_api_type == APIAssembly::API_EDITOR) {
- core_api_assembly = core_api_sln_dir.plus_file("bin")
- .plus_file(api_build_config)
- .plus_file(API_ASSEMBLY_NAME ".dll");
- }
+ String api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
+ .plus_file(_api_folder_name(APIAssembly::API_CORE));
-#ifndef DEBUG_METHODS_ENABLED
-#error "How am I supposed to generate the bindings?"
-#endif
+ String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
+ if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
BindingsGenerator *gen = BindingsGenerator::get_singleton();
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
- Error err = p_api_type == APIAssembly::API_CORE ?
- gen->generate_cs_core_project(api_sln_dir, gen_verbose) :
- gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
-
+ Error err = gen->generate_cs_api(api_sln_dir, gen_verbose);
if (err != OK) {
- show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err));
+ show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
return false;
}
}
- pr.step("Building " + api_name + " solution", 1);
+ pr.step("Building " API_SOLUTION_NAME " solution", 1);
- if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config))
+ if (!GodotSharpBuilds::build_api_sln(api_sln_dir, api_build_config))
return false;
pr.step("Copying " + api_name + " assembly", 2);
// Copy the built assembly to the assemblies directory
- String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+ String api_assembly_dir = api_sln_dir.plus_file(api_name).plus_file("bin").plus_file(api_build_config);
if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
return false;
@@ -369,36 +361,11 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
- String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
-
- if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(API_ASSEMBLY_NAME ".dll"))) {
- EditorProgress pr("mono_copy_prebuilt_api_assemblies",
- "Copying prebuilt " API_ASSEMBLY_NAME " assemblies...", 1);
- pr.step("Copying " API_ASSEMBLY_NAME " assembly", 0);
-
- if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
- API_ASSEMBLY_NAME, APIAssembly::API_CORE)) {
- return false;
- }
- } else {
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
- return false;
- }
-
- if (DirAccess::exists(editor_prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"))) {
- EditorProgress pr("mono_copy_prebuilt_api_assemblies",
- "Copying prebuilt " EDITOR_API_ASSEMBLY_NAME " assemblies...", 1);
- pr.step("Copying " EDITOR_API_ASSEMBLY_NAME " assembly", 0);
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
+ return false;
- if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
- EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
- return false;
- }
- } else {
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
- return false;
- }
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
+ return false;
EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
pr.step("Building project solution", 0);
@@ -414,6 +381,20 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
bool GodotSharpBuilds::editor_build_callback() {
+ String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
+ String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
+
+ Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
+ ERR_FAIL_COND_V(metadata_err != OK, false);
+
+ if (FileAccess::exists(scripts_metadata_path_editor)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
+
+ ERR_EXPLAIN("Failed to copy scripts metadata file");
+ ERR_FAIL_COND_V(copy_err != OK, false);
+ }
+
return build_project_blocking("Tools");
}
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
index c6dc6b6236..7f38b0aa49 100644
--- a/modules/mono/editor/godotsharp_builds.h
+++ b/modules/mono/editor/godotsharp_builds.h
@@ -84,10 +84,10 @@ public:
bool build(const MonoBuildInfo &p_build_info);
bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
- static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config);
+ static bool build_api_sln(const String &p_api_sln_dir, const String &p_config);
static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type);
- static bool make_api_sln(APIAssembly::Type p_api_type);
+ static bool make_api_assembly(APIAssembly::Type p_api_type);
static bool build_project_blocking(const String &p_config);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index fca88a7164..f27511ad5e 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -42,8 +42,8 @@
#include "../utils/path_utils.h"
#include "bindings_generator.h"
#include "csharp_project.h"
+#include "dotnet_solution.h"
#include "godotsharp_export.h"
-#include "net_solution.h"
#ifdef OSX_ENABLED
#include "../utils/osx_utils.h"
@@ -71,17 +71,21 @@ bool GodotSharpEditor::_create_project_solution() {
if (guid.length()) {
- NETSolution solution(name);
+ DotNetSolution solution(name);
if (!solution.set_path(path)) {
show_error_dialog(TTR("Failed to create solution."));
return false;
}
- Vector<String> extra_configs;
- extra_configs.push_back("Tools");
+ DotNetSolution::ProjectInfo proj_info;
+ proj_info.guid = guid;
+ proj_info.relpath = name + ".csproj";
+ proj_info.configs.push_back("Debug");
+ proj_info.configs.push_back("Release");
+ proj_info.configs.push_back("Tools");
- solution.add_new_project(name, guid, extra_configs);
+ solution.add_new_project(name, proj_info);
Error sln_error = solution.save();
@@ -90,10 +94,10 @@ bool GodotSharpEditor::_create_project_solution() {
return false;
}
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false;
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false;
pr.step(TTR("Done"));
@@ -108,6 +112,33 @@ bool GodotSharpEditor::_create_project_solution() {
return true;
}
+void GodotSharpEditor::_make_api_solutions_if_needed() {
+ // I'm sick entirely of ProgressDialog
+ static bool recursion_guard = false;
+ if (!recursion_guard) {
+ recursion_guard = true;
+ _make_api_solutions_if_needed_impl();
+ recursion_guard = false;
+ }
+}
+
+void GodotSharpEditor::_make_api_solutions_if_needed_impl() {
+ // If the project has a solution and C# project make sure the API assemblies are present and up to date
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+
+ if (!FileAccess::exists(res_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll")) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
+ return;
+ }
+
+ if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
+ if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
+ return; // Redundant? I don't think so
+ }
+}
+
void GodotSharpEditor::_remove_create_sln_menu_option() {
menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN));
@@ -169,6 +200,7 @@ void GodotSharpEditor::_notification(int p_notification) {
void GodotSharpEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
+ ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed);
ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
ClassDB::bind_method(D_METHOD("_toggle_about_dialog_on_start"), &GodotSharpEditor::_toggle_about_dialog_on_start);
ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
@@ -390,7 +422,10 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
String sln_path = GodotSharpDirs::get_project_sln_path();
String csproj_path = GodotSharpDirs::get_project_csproj_path();
- if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
+ if (FileAccess::exists(sln_path) && FileAccess::exists(csproj_path)) {
+ // We can't use EditorProgress here. It calls Main::iterarion() and the main loop is not initialized yet.
+ call_deferred("_make_api_solutions_if_needed");
+ } else {
bottom_panel_btn->hide();
menu_popup->add_item(TTR("Create C# solution"), MENU_CREATE_SLN);
}
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index 46b6bd5ebf..9fb0e40132 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -56,6 +56,8 @@ class GodotSharpEditor : public Node {
#endif
bool _create_project_solution();
+ void _make_api_solutions_if_needed();
+ void _make_api_solutions_if_needed_impl();
void _remove_create_sln_menu_option();
void _show_about_dialog();
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 933ede93dc..34c710320a 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -37,6 +37,7 @@
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
+#include "csharp_project.h"
#include "godotsharp_builds.h"
static MonoString *godot_icall_GodotSharpExport_GetTemplatesDir() {
@@ -86,6 +87,12 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
String build_config = p_debug ? "Debug" : "Release";
+ String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata." + String(p_debug ? "debug" : "release"));
+ Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
+ ERR_FAIL_COND(metadata_err != OK);
+
+ ERR_FAIL_COND(!_add_file(scripts_metadata_path, scripts_metadata_path));
+
ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config));
// Add dependency assemblies
@@ -110,7 +117,7 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
GDMonoAssembly *scripts_assembly = NULL;
bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
- project_dll_src_dir, &scripts_assembly, /* refonly: */ true);
+ project_dll_src_path, &scripts_assembly, /* refonly: */ true);
ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
ERR_FAIL_COND(!load_success);
@@ -124,7 +131,7 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) {
String depend_src_path = E->value();
String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file());
- ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path));
+ ERR_FAIL_COND(!_add_file(depend_src_path, depend_dst_path));
}
// Mono specific export template extras (data dir)
@@ -155,7 +162,7 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
}
}
-bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) {
+bool GodotSharpExport::_add_file(const String &p_src_path, const String &p_dst_path, bool p_remap) {
FileAccessRef f = FileAccess::open(p_src_path, FileAccess::READ);
ERR_FAIL_COND_V(!f, false);
@@ -164,7 +171,7 @@ bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_d
data.resize(f->get_len());
f->get_buffer(data.ptrw(), data.size());
- add_file(p_dst_path, data, false);
+ add_file(p_dst_path, data, p_remap);
return true;
}
@@ -191,21 +198,21 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, c
if (has_extension) {
path = search_dir.plus_file(ref_name);
if (FileAccess::exists(path)) {
- GDMono::get_singleton()->load_assembly_from(ref_name.get_basename(), search_dir, ref_aname, &ref_assembly, true);
+ GDMono::get_singleton()->load_assembly_from(ref_name.get_basename(), path, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
} else {
path = search_dir.plus_file(ref_name + ".dll");
if (FileAccess::exists(path)) {
- GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true);
+ GDMono::get_singleton()->load_assembly_from(ref_name, path, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
path = search_dir.plus_file(ref_name + ".exe");
if (FileAccess::exists(path)) {
- GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true);
+ GDMono::get_singleton()->load_assembly_from(ref_name, path, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index f007016578..10d4375567 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -41,7 +41,7 @@ class GodotSharpExport : public EditorExportPlugin {
MonoAssemblyName *aname_prealloc;
- bool _add_assembly(const String &p_src_path, const String &p_dst_path);
+ bool _add_file(const String &p_src_path, const String &p_dst_path, bool p_remap = false);
Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies);
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index 0ac59a1be8..d7bfa54aba 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -31,6 +31,8 @@
#include "mono_bottom_panel.h"
#include "../csharp_script.h"
+#include "../godotsharp_dirs.h"
+#include "csharp_project.h"
#include "godotsharp_editor.h"
MonoBottomPanel *MonoBottomPanel::singleton = NULL;
@@ -148,6 +150,10 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) {
void MonoBottomPanel::_build_project_pressed() {
+ String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
+ Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
+ ERR_FAIL_COND(metadata_err != OK);
+
GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");
MonoReloadNode::get_singleton()->restart_reload_timer();
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
new file mode 100644
index 0000000000..bc8eed81cf
--- /dev/null
+++ b/modules/mono/editor/script_class_parser.cpp
@@ -0,0 +1,542 @@
+#include "script_class_parser.h"
+
+#include "core/map.h"
+#include "core/os/os.h"
+
+#include "../utils/string_utils.h"
+
+const char *ScriptClassParser::token_names[ScriptClassParser::TK_MAX] = {
+ "[",
+ "]",
+ "{",
+ "}",
+ ".",
+ ":",
+ ",",
+ "Symbol",
+ "Identifier",
+ "String",
+ "Number",
+ "<",
+ ">",
+ "EOF",
+ "Error"
+};
+
+String ScriptClassParser::get_token_name(ScriptClassParser::Token p_token) {
+
+ ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>");
+ return token_names[p_token];
+}
+
+ScriptClassParser::Token ScriptClassParser::get_token() {
+
+ while (true) {
+ switch (code[idx]) {
+ case '\n': {
+ line++;
+ idx++;
+ break;
+ };
+ case 0: {
+ return TK_EOF;
+ } break;
+ case '{': {
+ idx++;
+ return TK_CURLY_BRACKET_OPEN;
+ };
+ case '}': {
+ idx++;
+ return TK_CURLY_BRACKET_CLOSE;
+ };
+ case '[': {
+ idx++;
+ return TK_BRACKET_OPEN;
+ };
+ case ']': {
+ idx++;
+ return TK_BRACKET_CLOSE;
+ };
+ case '<': {
+ idx++;
+ return TK_OP_LESS;
+ };
+ case '>': {
+ idx++;
+ return TK_OP_GREATER;
+ };
+ case ':': {
+ idx++;
+ return TK_COLON;
+ };
+ case ',': {
+ idx++;
+ return TK_COMMA;
+ };
+ case '.': {
+ idx++;
+ return TK_PERIOD;
+ };
+ case '#': {
+ //compiler directive
+ while (code[idx] != '\n' && code[idx] != 0) {
+ idx++;
+ }
+ continue;
+ } break;
+ case '/': {
+ switch (code[idx + 1]) {
+ case '*': { // block comment
+ idx += 2;
+ while (true) {
+ if (code[idx] == 0) {
+ error_str = "Unterminated comment";
+ error = true;
+ return TK_ERROR;
+ } else if (code[idx] == '*' && code[idx + 1] == '/') {
+ idx += 2;
+ break;
+ } else if (code[idx] == '\n') {
+ line++;
+ }
+
+ idx++;
+ }
+
+ } break;
+ case '/': { // line comment skip
+ while (code[idx] != '\n' && code[idx] != 0) {
+ idx++;
+ }
+
+ } break;
+ default: {
+ value = "/";
+ idx++;
+ return TK_SYMBOL;
+ }
+ }
+
+ continue; // a comment
+ } break;
+ case '\'':
+ case '"': {
+ bool verbatim = idx != 0 && code[idx - 1] == '@';
+
+ CharType begin_str = code[idx];
+ idx++;
+ String tk_string = String();
+ while (true) {
+ if (code[idx] == 0) {
+ error_str = "Unterminated String";
+ error = true;
+ return TK_ERROR;
+ } else if (code[idx] == begin_str) {
+ if (verbatim && code[idx + 1] == '"') { // `""` is verbatim string's `\"`
+ idx += 2; // skip next `"` as well
+ continue;
+ }
+
+ idx += 1;
+ break;
+ } else if (code[idx] == '\\' && !verbatim) {
+ //escaped characters...
+ idx++;
+ CharType next = code[idx];
+ if (next == 0) {
+ error_str = "Unterminated String";
+ error = true;
+ return TK_ERROR;
+ }
+ CharType res = 0;
+
+ switch (next) {
+ case 'b': res = 8; break;
+ case 't': res = 9; break;
+ case 'n': res = 10; break;
+ case 'f': res = 12; break;
+ case 'r':
+ res = 13;
+ break;
+ case '\"': res = '\"'; break;
+ case '\\':
+ res = '\\';
+ break;
+ default: {
+ res = next;
+ } break;
+ }
+
+ tk_string += res;
+
+ } else {
+ if (code[idx] == '\n')
+ line++;
+ tk_string += code[idx];
+ }
+ idx++;
+ }
+
+ value = tk_string;
+
+ return TK_STRING;
+ } break;
+ default: {
+ if (code[idx] <= 32) {
+ idx++;
+ break;
+ }
+
+ if ((code[idx] >= 33 && code[idx] <= 47) || (code[idx] >= 58 && code[idx] <= 63) || (code[idx] >= 91 && code[idx] <= 94) || code[idx] == 96 || (code[idx] >= 123 && code[idx] <= 127)) {
+ value = String::chr(code[idx]);
+ idx++;
+ return TK_SYMBOL;
+ }
+
+ if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
+ //a number
+ const CharType *rptr;
+ double number = String::to_double(&code[idx], &rptr);
+ idx += (rptr - &code[idx]);
+ value = number;
+ return TK_NUMBER;
+
+ } else if ((code[idx] == '@' && code[idx + 1] != '"') || code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
+ String id;
+
+ id += code[idx];
+ idx++;
+
+ while (code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || (code[idx] >= '0' && code[idx] <= '9') || code[idx] > 127) {
+ id += code[idx];
+ idx++;
+ }
+
+ value = id;
+ return TK_IDENTIFIER;
+ } else if (code[idx] == '@' && code[idx + 1] == '"') {
+ // begin of verbatim string
+ idx++;
+ } else {
+ error_str = "Unexpected character.";
+ error = true;
+ return TK_ERROR;
+ }
+ }
+ }
+ }
+}
+
+Error ScriptClassParser::_skip_generic_type_params() {
+
+ Token tk;
+
+ while (true) {
+ tk = get_token();
+
+ if (tk == TK_IDENTIFIER) {
+ tk = get_token();
+
+ if (tk == TK_PERIOD) {
+ while (true) {
+ tk = get_token();
+
+ if (tk != TK_IDENTIFIER) {
+ error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = get_token();
+
+ if (tk != TK_PERIOD)
+ break;
+ }
+ }
+
+ if (tk == TK_OP_LESS) {
+ Error err = _skip_generic_type_params();
+ if (err)
+ return err;
+ continue;
+ } else if (tk != TK_COMMA) {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ } else if (tk == TK_OP_LESS) {
+ error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS);
+ error = true;
+ return ERR_PARSE_ERROR;
+ } else if (tk == TK_OP_GREATER) {
+ return OK;
+ } else {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ }
+}
+
+Error ScriptClassParser::_parse_type_full_name(String &r_full_name) {
+
+ Token tk = get_token();
+
+ if (tk != TK_IDENTIFIER) {
+ error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ r_full_name += String(value);
+
+ if (code[idx] != '.') // We only want to take the next token if it's a period
+ return OK;
+
+ tk = get_token();
+
+ CRASH_COND(tk != TK_PERIOD); // Assertion
+
+ r_full_name += ".";
+
+ return _parse_type_full_name(r_full_name);
+}
+
+Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
+
+ String name;
+
+ Error err = _parse_type_full_name(name);
+ if (err)
+ return err;
+
+ Token tk = get_token();
+
+ if (tk == TK_OP_LESS) {
+ // We don't add it to the base list if it's generic
+ Error err = _skip_generic_type_params();
+ if (err)
+ return err;
+ } else if (tk == TK_COMMA) {
+ Error err = _parse_class_base(r_base);
+ if (err)
+ return err;
+ r_base.push_back(name);
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ r_base.push_back(name);
+ } else {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+}
+
+Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
+
+ Token tk = get_token();
+
+ if (tk == TK_IDENTIFIER) {
+ r_name += String(value);
+ } else {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = get_token();
+
+ if (tk == TK_PERIOD) {
+ r_name += ".";
+ return _parse_namespace_name(r_name, r_curly_stack);
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ r_curly_stack++;
+ return OK;
+ } else {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+}
+
+Error ScriptClassParser::parse(const String &p_code) {
+
+ code = p_code;
+ idx = 0;
+ line = 0;
+ error_str = String();
+ error = false;
+ value = Variant();
+ classes.clear();
+
+ Token tk = get_token();
+
+ Map<int, NameDecl> name_stack;
+ int curly_stack = 0;
+ int type_curly_stack = 0;
+
+ while (!error && tk != TK_EOF) {
+ if (tk == TK_IDENTIFIER && String(value) == "class") {
+ tk = get_token();
+
+ if (tk == TK_IDENTIFIER) {
+ String name = value;
+ int at_level = type_curly_stack;
+
+ ClassDecl class_decl;
+
+ for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) {
+ const NameDecl &name_decl = E->value();
+
+ if (name_decl.type == NameDecl::NAMESPACE_DECL) {
+ if (E != name_stack.front())
+ class_decl.namespace_ += ".";
+ class_decl.namespace_ += name_decl.name;
+ } else {
+ class_decl.name += name_decl.name + ".";
+ }
+ }
+
+ class_decl.name += name;
+ class_decl.nested = type_curly_stack > 0;
+
+ bool generic = false;
+
+ while (true) {
+ tk = get_token();
+
+ if (tk == TK_COLON) {
+ Error err = _parse_class_base(class_decl.base);
+ if (err)
+ return err;
+
+ curly_stack++;
+ type_curly_stack++;
+
+ break;
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ curly_stack++;
+ type_curly_stack++;
+ break;
+ } else if (tk == TK_OP_LESS && !generic) {
+ generic = true;
+
+ Error err = _skip_generic_type_params();
+ if (err)
+ return err;
+ } else {
+ error_str = "Unexpected token: " + get_token_name(tk);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ NameDecl name_decl;
+ name_decl.name = name;
+ name_decl.type = NameDecl::CLASS_DECL;
+ name_stack[at_level] = name_decl;
+
+ if (!generic) { // no generics, thanks
+ classes.push_back(class_decl);
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
+ String full_name = class_decl.namespace_;
+ if (full_name.length())
+ full_name += ".";
+ full_name += class_decl.name;
+ OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8());
+ }
+ }
+ } else if (tk == TK_IDENTIFIER && String(value) == "struct") {
+ String name;
+ int at_level = type_curly_stack;
+ while (true) {
+ tk = get_token();
+ if (tk == TK_IDENTIFIER && name.empty()) {
+ name = String(value);
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ if (name.empty()) {
+ error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ curly_stack++;
+ type_curly_stack++;
+ break;
+ } else if (tk == TK_EOF) {
+ error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF);
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ NameDecl name_decl;
+ name_decl.name = name;
+ name_decl.type = NameDecl::STRUCT_DECL;
+ name_stack[at_level] = name_decl;
+ } else if (tk == TK_IDENTIFIER && String(value) == "namespace") {
+ if (type_curly_stack > 0) {
+ error_str = "Found namespace nested inside type.";
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+
+ String name;
+ int at_level = curly_stack;
+
+ Error err = _parse_namespace_name(name, curly_stack);
+ if (err)
+ return err;
+
+ NameDecl name_decl;
+ name_decl.name = name;
+ name_decl.type = NameDecl::NAMESPACE_DECL;
+ name_stack[at_level] = name_decl;
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ curly_stack++;
+ } else if (tk == TK_CURLY_BRACKET_CLOSE) {
+ curly_stack--;
+ if (name_stack.has(curly_stack)) {
+ if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL)
+ type_curly_stack--;
+ name_stack.erase(curly_stack);
+ }
+ }
+
+ tk = get_token();
+ }
+
+ if (!error && tk == TK_EOF && curly_stack > 0) {
+ error_str = "Reached EOF with missing close curly brackets.";
+ error = true;
+ }
+
+ if (error)
+ return ERR_PARSE_ERROR;
+
+ return OK;
+}
+
+Error ScriptClassParser::parse_file(const String &p_filepath) {
+
+ String source;
+
+ Error ferr = read_all_file_utf8(p_filepath, source);
+ if (ferr != OK) {
+ if (ferr == ERR_INVALID_DATA) {
+ ERR_EXPLAIN("File '" + p_filepath + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
+ }
+ ERR_FAIL_V(ferr);
+ }
+
+ return parse(source);
+}
+
+String ScriptClassParser::get_error() {
+ return error_str;
+}
+
+Vector<ScriptClassParser::ClassDecl> ScriptClassParser::get_classes() {
+ return classes;
+}
diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h
new file mode 100644
index 0000000000..1e174c28a9
--- /dev/null
+++ b/modules/mono/editor/script_class_parser.h
@@ -0,0 +1,79 @@
+#ifndef SCRIPT_CLASS_PARSER_H
+#define SCRIPT_CLASS_PARSER_H
+
+#include "core/ustring.h"
+#include "core/variant.h"
+#include "core/vector.h"
+
+class ScriptClassParser {
+
+public:
+ struct NameDecl {
+ enum Type {
+ NAMESPACE_DECL,
+ CLASS_DECL,
+ STRUCT_DECL
+ };
+
+ String name;
+ Type type;
+ };
+
+ struct ClassDecl {
+ String name;
+ String namespace_;
+ Vector<String> base;
+ bool nested;
+ bool has_script_attr;
+ };
+
+private:
+ String code;
+ int idx;
+ int line;
+ String error_str;
+ bool error;
+ Variant value;
+
+ Vector<ClassDecl> classes;
+
+ enum Token {
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_PERIOD,
+ TK_COLON,
+ TK_COMMA,
+ TK_SYMBOL,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_NUMBER,
+ TK_OP_LESS,
+ TK_OP_GREATER,
+ TK_EOF,
+ TK_ERROR,
+ TK_MAX
+ };
+
+ static const char *token_names[TK_MAX];
+ static String get_token_name(Token p_token);
+
+ Token get_token();
+
+ Error _skip_generic_type_params();
+
+ Error _parse_type_full_name(String &r_full_name);
+ Error _parse_class_base(Vector<String> &r_base);
+ Error _parse_namespace_name(String &r_name, int &r_curly_stack);
+
+public:
+ Error parse(const String &p_code);
+ Error parse_file(const String &p_filepath);
+
+ String get_error();
+
+ Vector<ClassDecl> get_classes();
+};
+
+#endif // SCRIPT_CLASS_PARSER_H
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
index e4818e186c..75a35a9eea 100644
--- a/modules/mono/glue/Managed/Files/GD.cs
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -70,6 +70,16 @@ namespace Godot
return ResourceLoader.Load<T>(path);
}
+ public static void PushError(string message)
+ {
+ godot_icall_GD_pusherror(message);
+ }
+
+ public static void PushWarning(string message)
+ {
+ godot_icall_GD_pushwarning(message);
+ }
+
public static void Print(params object[] what)
{
godot_icall_GD_print(what);
@@ -238,5 +248,11 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pusherror(string type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pushwarning(string type);
}
}
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 051f42b966..9f5bcecdd9 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -157,6 +157,14 @@ bool godot_icall_GD_type_exists(MonoString *p_type) {
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
}
+void godot_icall_GD_pusherror(MonoString *p_str) {
+ ERR_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
+}
+
+void godot_icall_GD_pushwarning(MonoString *p_str) {
+ WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
+}
+
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) {
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
@@ -186,6 +194,8 @@ void godot_register_gd_icalls() {
mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index 39d608de9f..5a6a2d1742 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -36,7 +36,8 @@
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
#define BINDINGS_PTR_FIELD "ptr"
#define BINDINGS_NATIVE_NAME_FIELD "nativeName"
-#define API_ASSEMBLY_NAME "GodotSharp"
+#define API_SOLUTION_NAME "GodotSharp"
+#define CORE_API_ASSEMBLY_NAME "GodotSharp"
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
#define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools"
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 0c4433112d..a80155bd89 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -191,7 +191,6 @@ void GDMono::initialize() {
String hint_config_dir = path_join(locations[i], "etc");
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
- need_set_mono_dirs = false;
assembly_rootdir = hint_assembly_rootdir;
config_dir = hint_config_dir;
break;
@@ -378,34 +377,24 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
- return load_assembly_from(p_name, String(), r_assembly, p_refonly);
-}
-
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
-
- return load_assembly_from(p_name, String(), p_aname, r_assembly, p_refonly);
-}
-
-bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly) {
-
CRASH_COND(!r_assembly);
MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- bool result = load_assembly_from(p_name, p_basedir, aname, r_assembly, p_refonly);
+ bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
mono_assembly_name_free(aname);
mono_free(aname);
return result;
}
-bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
+bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
CRASH_COND(!r_assembly);
print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
MonoImageOpenStatus status = MONO_IMAGE_OK;
- MonoAssembly *assembly = mono_assembly_load_full(p_aname, p_basedir.length() ? p_basedir.utf8().get_data() : NULL, &status, p_refonly);
+ MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
if (!assembly)
return false;
@@ -426,6 +415,32 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, M
return true;
}
+bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly) {
+
+ CRASH_COND(!r_assembly);
+
+ print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
+
+ GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, p_refonly);
+
+ if (!assembly)
+ return false;
+
+#ifdef DEBUG_ENABLED
+ uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+ GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
+
+ ERR_FAIL_COND_V(stored_assembly == NULL, false);
+ ERR_FAIL_COND_V(*stored_assembly != assembly, false);
+#endif
+
+ *r_assembly = assembly;
+
+ print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
+
+ return true;
+}
+
APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, APIAssembly::Type p_api_type) {
APIAssembly::Version api_assembly_version;
@@ -481,7 +496,14 @@ bool GDMono::_load_core_api_assembly() {
}
#endif
- bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly);
+ String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+
+ if (!FileAccess::exists(assembly_path))
+ return false;
+
+ bool success = load_assembly_from(CORE_API_ASSEMBLY_NAME,
+ assembly_path,
+ &core_api_assembly);
if (success) {
#ifdef MONO_GLUE_ENABLED
@@ -511,7 +533,14 @@ bool GDMono::_load_editor_api_assembly() {
return false;
}
- bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
+ String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+
+ if (!FileAccess::exists(assembly_path))
+ return false;
+
+ bool success = load_assembly_from(EDITOR_API_ASSEMBLY_NAME,
+ assembly_path,
+ &editor_api_assembly);
if (success) {
#ifdef MONO_GLUE_ENABLED
@@ -552,6 +581,8 @@ bool GDMono::_load_project_assembly() {
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
+
+ CSharpLanguage::get_singleton()->project_assembly_loaded();
} else {
if (OS::get_singleton()->is_stdout_verbose())
print_error("Mono: Failed to load project assembly");
@@ -604,7 +635,7 @@ void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type,
String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
.plus_file(p_api_type == APIAssembly::API_CORE ?
- API_ASSEMBLY_NAME ".dll" :
+ CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll");
ERR_FAIL_COND(!FileAccess::exists(assembly_path));
@@ -635,7 +666,7 @@ bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type)
String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
.plus_file(p_api_type == APIAssembly::API_CORE ?
- API_ASSEMBLY_NAME ".dll" :
+ CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll");
if (!FileAccess::exists(assembly_path))
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 745dcc34eb..fd9551b6de 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -199,8 +199,7 @@ public:
bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly = false);
Error finalize_and_unload_domain(MonoDomain *p_domain);
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 1067c11e0e..72b0204672 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -457,6 +457,20 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
return match;
}
+GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
+
+ GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
+ if (loaded_asm)
+ return *loaded_asm;
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!FileAccess::exists(p_path));
+#endif
+ no_search = true;
+ GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly);
+ no_search = false;
+ return res;
+}
+
GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
loaded = false;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 4c9b1cb10d..2af40ec901 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -128,6 +128,8 @@ public:
static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String());
+ static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
+
GDMonoAssembly(const String &p_name, const String &p_path = String());
~GDMonoAssembly();
};
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index d3a673dc1b..5d9b9213e7 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -40,65 +40,71 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
}
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
-#define SET_FROM_STRUCT_AND_BREAK(m_type) \
- { \
- const m_type &val = p_value.operator ::m_type(); \
- MARSHALLED_OUT(m_type, val, raw); \
- mono_field_set_value(p_object, mono_field, raw); \
- break; \
+#define SET_FROM_STRUCT(m_type) \
+ { \
+ GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \
+ mono_field_set_value(p_object, mono_field, &from); \
}
-#define SET_FROM_PRIMITIVE(m_type) \
- { \
- m_type val = p_value.operator m_type(); \
- mono_field_set_value(p_object, mono_field, &val); \
- break; \
- }
-
-#define SET_FROM_ARRAY_AND_BREAK(m_type) \
- { \
- MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator m_type()); \
- mono_field_set_value(p_object, mono_field, &managed); \
- break; \
+#define SET_FROM_ARRAY(m_type) \
+ { \
+ MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
+ mono_field_set_value(p_object, mono_field, &managed); \
}
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
- SET_FROM_PRIMITIVE(bool);
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
+ } break;
+
+ case MONO_TYPE_CHAR: {
+ int16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I1: {
- SET_FROM_PRIMITIVE(signed char);
+ int8_t val = p_value.operator signed char();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I2: {
- SET_FROM_PRIMITIVE(signed short);
+ int16_t val = p_value.operator signed short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I4: {
- SET_FROM_PRIMITIVE(signed int);
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I8: {
- SET_FROM_PRIMITIVE(int64_t);
+ int64_t val = p_value.operator int64_t();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U1: {
- SET_FROM_PRIMITIVE(unsigned char);
+ uint8_t val = p_value.operator unsigned char();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U2: {
- SET_FROM_PRIMITIVE(unsigned short);
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U4: {
- SET_FROM_PRIMITIVE(unsigned int);
+ uint32_t val = p_value.operator unsigned int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U8: {
- SET_FROM_PRIMITIVE(uint64_t);
+ uint64_t val = p_value.operator uint64_t();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_R4: {
- SET_FROM_PRIMITIVE(float);
+ float val = p_value.operator float();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_R8: {
- SET_FROM_PRIMITIVE(double);
+ double val = p_value.operator double();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_STRING: {
@@ -109,38 +115,117 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
- SET_FROM_STRUCT_AND_BREAK(Vector2);
+ if (tclass == CACHED_CLASS(Vector2)) {
+ SET_FROM_STRUCT(Vector2);
+ break;
+ }
+
+ if (tclass == CACHED_CLASS(Rect2)) {
+ SET_FROM_STRUCT(Rect2);
+ break;
+ }
- if (tclass == CACHED_CLASS(Rect2))
- SET_FROM_STRUCT_AND_BREAK(Rect2);
+ if (tclass == CACHED_CLASS(Transform2D)) {
+ SET_FROM_STRUCT(Transform2D);
+ break;
+ }
- if (tclass == CACHED_CLASS(Transform2D))
- SET_FROM_STRUCT_AND_BREAK(Transform2D);
+ if (tclass == CACHED_CLASS(Vector3)) {
+ SET_FROM_STRUCT(Vector3);
+ break;
+ }
- if (tclass == CACHED_CLASS(Vector3))
- SET_FROM_STRUCT_AND_BREAK(Vector3);
+ if (tclass == CACHED_CLASS(Basis)) {
+ SET_FROM_STRUCT(Basis);
+ break;
+ }
- if (tclass == CACHED_CLASS(Basis))
- SET_FROM_STRUCT_AND_BREAK(Basis);
+ if (tclass == CACHED_CLASS(Quat)) {
+ SET_FROM_STRUCT(Quat);
+ break;
+ }
- if (tclass == CACHED_CLASS(Quat))
- SET_FROM_STRUCT_AND_BREAK(Quat);
+ if (tclass == CACHED_CLASS(Transform)) {
+ SET_FROM_STRUCT(Transform);
+ break;
+ }
- if (tclass == CACHED_CLASS(Transform))
- SET_FROM_STRUCT_AND_BREAK(Transform);
+ if (tclass == CACHED_CLASS(AABB)) {
+ SET_FROM_STRUCT(AABB);
+ break;
+ }
- if (tclass == CACHED_CLASS(AABB))
- SET_FROM_STRUCT_AND_BREAK(AABB);
+ if (tclass == CACHED_CLASS(Color)) {
+ SET_FROM_STRUCT(Color);
+ break;
+ }
- if (tclass == CACHED_CLASS(Color))
- SET_FROM_STRUCT_AND_BREAK(Color);
+ if (tclass == CACHED_CLASS(Plane)) {
+ SET_FROM_STRUCT(Plane);
+ break;
+ }
- if (tclass == CACHED_CLASS(Plane))
- SET_FROM_STRUCT_AND_BREAK(Plane);
+ if (mono_class_is_enum(tclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_value.operator signed char();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_value.operator signed short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_value.operator int64_t();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_value.operator unsigned char();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_value.operator unsigned int();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_value.operator uint64_t();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ default: {
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL();
+ }
+ }
- if (mono_class_is_enum(tclass->get_mono_ptr()))
- SET_FROM_PRIMITIVE(signed int);
+ break;
+ }
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
ERR_FAIL();
@@ -150,29 +235,45 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_SZARRAY: {
MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
- SET_FROM_ARRAY_AND_BREAK(Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+ SET_FROM_ARRAY(Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
- SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+ SET_FROM_ARRAY(PoolByteArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
- SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+ SET_FROM_ARRAY(PoolIntArray);
+ break;
+ }
- if (array_type->eklass == REAL_T_MONOCLASS)
- SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
+ if (array_type->eklass == REAL_T_MONOCLASS) {
+ SET_FROM_ARRAY(PoolRealArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(String))
- SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+ SET_FROM_ARRAY(PoolStringArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
- SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+ SET_FROM_ARRAY(PoolVector2Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
- SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+ SET_FROM_ARRAY(PoolVector3Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Color))
- SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+ SET_FROM_ARRAY(PoolColorArray);
+ break;
+ }
ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
ERR_FAIL();
@@ -220,32 +321,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
// Variant
switch (p_value.get_type()) {
case Variant::BOOL: {
- SET_FROM_PRIMITIVE(bool);
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case Variant::INT: {
- SET_FROM_PRIMITIVE(int);
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case Variant::REAL: {
#ifdef REAL_T_IS_DOUBLE
- SET_FROM_PRIMITIVE(double);
+ double val = p_value.operator double();
+ mono_field_set_value(p_object, mono_field, &val);
#else
- SET_FROM_PRIMITIVE(float);
+ float val = p_value.operator float();
+ mono_field_set_value(p_object, mono_field, &val);
#endif
} break;
case Variant::STRING: {
MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
mono_field_set_value(p_object, mono_field, mono_string);
} break;
- case Variant::VECTOR2: SET_FROM_STRUCT_AND_BREAK(Vector2);
- case Variant::RECT2: SET_FROM_STRUCT_AND_BREAK(Rect2);
- case Variant::VECTOR3: SET_FROM_STRUCT_AND_BREAK(Vector3);
- case Variant::TRANSFORM2D: SET_FROM_STRUCT_AND_BREAK(Transform2D);
- case Variant::PLANE: SET_FROM_STRUCT_AND_BREAK(Plane);
- case Variant::QUAT: SET_FROM_STRUCT_AND_BREAK(Quat);
- case Variant::AABB: SET_FROM_STRUCT_AND_BREAK(AABB);
- case Variant::BASIS: SET_FROM_STRUCT_AND_BREAK(Basis);
- case Variant::TRANSFORM: SET_FROM_STRUCT_AND_BREAK(Transform);
- case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
+ case Variant::VECTOR2: {
+ SET_FROM_STRUCT(Vector2);
+ } break;
+ case Variant::RECT2: {
+ SET_FROM_STRUCT(Rect2);
+ } break;
+ case Variant::VECTOR3: {
+ SET_FROM_STRUCT(Vector3);
+ } break;
+ case Variant::TRANSFORM2D: {
+ SET_FROM_STRUCT(Transform2D);
+ } break;
+ case Variant::PLANE: {
+ SET_FROM_STRUCT(Plane);
+ } break;
+ case Variant::QUAT: {
+ SET_FROM_STRUCT(Quat);
+ } break;
+ case Variant::AABB: {
+ SET_FROM_STRUCT(AABB);
+ } break;
+ case Variant::BASIS: {
+ SET_FROM_STRUCT(Basis);
+ } break;
+ case Variant::TRANSFORM: {
+ SET_FROM_STRUCT(Transform);
+ } break;
+ case Variant::COLOR: {
+ SET_FROM_STRUCT(Color);
+ } break;
case Variant::NODE_PATH: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
mono_field_set_value(p_object, mono_field, managed);
@@ -267,14 +392,27 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
mono_field_set_value(p_object, mono_field, managed);
} break;
- case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
- case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
- case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
- case Variant::POOL_STRING_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
- case Variant::POOL_VECTOR2_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
- case Variant::POOL_VECTOR3_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
- case Variant::POOL_COLOR_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
-#undef SET_FROM_ARRAY_AND_BREAK
+ case Variant::POOL_BYTE_ARRAY: {
+ SET_FROM_ARRAY(PoolByteArray);
+ } break;
+ case Variant::POOL_INT_ARRAY: {
+ SET_FROM_ARRAY(PoolIntArray);
+ } break;
+ case Variant::POOL_REAL_ARRAY: {
+ SET_FROM_ARRAY(PoolRealArray);
+ } break;
+ case Variant::POOL_STRING_ARRAY: {
+ SET_FROM_ARRAY(PoolStringArray);
+ } break;
+ case Variant::POOL_VECTOR2_ARRAY: {
+ SET_FROM_ARRAY(PoolVector2Array);
+ } break;
+ case Variant::POOL_VECTOR3_ARRAY: {
+ SET_FROM_ARRAY(PoolVector3Array);
+ } break;
+ case Variant::POOL_COLOR_ARRAY: {
+ SET_FROM_ARRAY(PoolColorArray);
+ } break;
default: break;
}
} break;
@@ -312,8 +450,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
} break;
}
+#undef SET_FROM_ARRAY_AND_BREAK
#undef SET_FROM_STRUCT_AND_BREAK
-#undef SET_FROM_PRIMITIVE
}
MonoObject *GDMonoField::get_value(MonoObject *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 4f2efc7b92..51d0c9b356 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -55,14 +55,4 @@ struct ManagedType {
}
};
-typedef union {
- uint32_t _uint32;
- float _float;
-} mono_float;
-
-typedef union {
- uint64_t _uint64;
- float _double;
-} mono_double;
-
#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index de91e71bab..2543f5dc47 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -35,20 +35,6 @@
namespace GDMonoMarshal {
-#define RETURN_BOXED_STRUCT(m_t, m_var_in) \
- { \
- const m_t &m_in = m_var_in->operator ::m_t(); \
- MARSHALLED_OUT(m_t, m_in, raw); \
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
- }
-
-#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
- { \
- float *raw = (float *)mono_object_unbox(m_var_in); \
- MARSHALLED_IN(m_t, raw, ret); \
- return ret; \
- }
-
Variant::Type managed_to_variant_type(const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
@@ -252,16 +238,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return BOX_BOOLEAN(val);
}
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_UINT16(val);
+ }
+
case MONO_TYPE_I1: {
- char val = p_var->operator signed char();
+ int8_t val = p_var->operator signed char();
return BOX_INT8(val);
}
case MONO_TYPE_I2: {
- short val = p_var->operator signed short();
+ int16_t val = p_var->operator signed short();
return BOX_INT16(val);
}
case MONO_TYPE_I4: {
- int val = p_var->operator signed int();
+ int32_t val = p_var->operator signed int();
return BOX_INT32(val);
}
case MONO_TYPE_I8: {
@@ -270,15 +261,15 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
case MONO_TYPE_U1: {
- char val = p_var->operator unsigned char();
+ uint8_t val = p_var->operator unsigned char();
return BOX_UINT8(val);
}
case MONO_TYPE_U2: {
- short val = p_var->operator unsigned short();
+ uint16_t val = p_var->operator unsigned short();
return BOX_UINT16(val);
}
case MONO_TYPE_U4: {
- int val = p_var->operator unsigned int();
+ uint32_t val = p_var->operator unsigned int();
return BOX_UINT32(val);
}
case MONO_TYPE_U8: {
@@ -302,39 +293,105 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
- RETURN_BOXED_STRUCT(Vector2, p_var);
+ if (tclass == CACHED_CLASS(Vector2)) {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
- if (tclass == CACHED_CLASS(Rect2))
- RETURN_BOXED_STRUCT(Rect2, p_var);
+ if (tclass == CACHED_CLASS(Rect2)) {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
- if (tclass == CACHED_CLASS(Transform2D))
- RETURN_BOXED_STRUCT(Transform2D, p_var);
+ if (tclass == CACHED_CLASS(Transform2D)) {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
- if (tclass == CACHED_CLASS(Vector3))
- RETURN_BOXED_STRUCT(Vector3, p_var);
+ if (tclass == CACHED_CLASS(Vector3)) {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
- if (tclass == CACHED_CLASS(Basis))
- RETURN_BOXED_STRUCT(Basis, p_var);
+ if (tclass == CACHED_CLASS(Basis)) {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
- if (tclass == CACHED_CLASS(Quat))
- RETURN_BOXED_STRUCT(Quat, p_var);
+ if (tclass == CACHED_CLASS(Quat)) {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
- if (tclass == CACHED_CLASS(Transform))
- RETURN_BOXED_STRUCT(Transform, p_var);
+ if (tclass == CACHED_CLASS(Transform)) {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
- if (tclass == CACHED_CLASS(AABB))
- RETURN_BOXED_STRUCT(AABB, p_var);
+ if (tclass == CACHED_CLASS(AABB)) {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
- if (tclass == CACHED_CLASS(Color))
- RETURN_BOXED_STRUCT(Color, p_var);
+ if (tclass == CACHED_CLASS(Color)) {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
- if (tclass == CACHED_CLASS(Plane))
- RETURN_BOXED_STRUCT(Plane, p_var);
+ if (tclass == CACHED_CLASS(Plane)) {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
if (mono_class_is_enum(tclass->get_mono_ptr())) {
- int val = p_var->operator signed int();
- return BOX_ENUM(tclass->get_mono_ptr(), val);
+ MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_var->operator bool();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_var->operator signed char();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_var->operator signed short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_var->operator signed int();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_var->operator int64_t();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_var->operator unsigned char();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_var->operator unsigned int();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_var->operator uint64_t();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ default: {
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL_V(NULL);
+ }
+ }
}
} break;
@@ -402,7 +459,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return BOX_BOOLEAN(val);
}
case Variant::INT: {
- int val = p_var->operator signed int();
+ int32_t val = p_var->operator signed int();
return BOX_INT32(val);
}
case Variant::REAL: {
@@ -416,33 +473,52 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
case Variant::STRING:
return (MonoObject *)mono_string_from_godot(p_var->operator String());
- case Variant::VECTOR2:
- RETURN_BOXED_STRUCT(Vector2, p_var);
- case Variant::RECT2:
- RETURN_BOXED_STRUCT(Rect2, p_var);
- case Variant::VECTOR3:
- RETURN_BOXED_STRUCT(Vector3, p_var);
- case Variant::TRANSFORM2D:
- RETURN_BOXED_STRUCT(Transform2D, p_var);
- case Variant::PLANE:
- RETURN_BOXED_STRUCT(Plane, p_var);
- case Variant::QUAT:
- RETURN_BOXED_STRUCT(Quat, p_var);
- case Variant::AABB:
- RETURN_BOXED_STRUCT(AABB, p_var);
- case Variant::BASIS:
- RETURN_BOXED_STRUCT(Basis, p_var);
- case Variant::TRANSFORM:
- RETURN_BOXED_STRUCT(Transform, p_var);
- case Variant::COLOR:
- RETURN_BOXED_STRUCT(Color, p_var);
+ case Variant::VECTOR2: {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
+ case Variant::RECT2: {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
+ case Variant::VECTOR3: {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
+ case Variant::TRANSFORM2D: {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
+ case Variant::PLANE: {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
+ case Variant::QUAT: {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
+ case Variant::AABB: {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
+ case Variant::BASIS: {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
+ case Variant::TRANSFORM: {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
+ case Variant::COLOR: {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
case Variant::NODE_PATH:
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
case Variant::_RID:
return GDMonoUtils::create_managed_from(p_var->operator RID());
- case Variant::OBJECT: {
+ case Variant::OBJECT:
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- }
case Variant::DICTIONARY:
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
case Variant::ARRAY:
@@ -512,6 +588,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
+ case MONO_TYPE_CHAR:
+ return unbox<uint16_t>(p_obj);
+
case MONO_TYPE_I1:
return unbox<int8_t>(p_obj);
case MONO_TYPE_I2:
@@ -545,34 +624,34 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
GDMonoClass *tclass = type.type_class;
if (tclass == CACHED_CLASS(Vector2))
- RETURN_UNBOXED_STRUCT(Vector2, p_obj);
+ return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Rect2))
- RETURN_UNBOXED_STRUCT(Rect2, p_obj);
+ return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Transform2D))
- RETURN_UNBOXED_STRUCT(Transform2D, p_obj);
+ return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Vector3))
- RETURN_UNBOXED_STRUCT(Vector3, p_obj);
+ return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Basis))
- RETURN_UNBOXED_STRUCT(Basis, p_obj);
+ return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Quat))
- RETURN_UNBOXED_STRUCT(Quat, p_obj);
+ return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Transform))
- RETURN_UNBOXED_STRUCT(Transform, p_obj);
+ return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(AABB))
- RETURN_UNBOXED_STRUCT(AABB, p_obj);
+ return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Color))
- RETURN_UNBOXED_STRUCT(Color, p_obj);
+ return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Plane))
- RETURN_UNBOXED_STRUCT(Plane, p_obj);
+ return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
if (mono_class_is_enum(tclass->get_mono_ptr()))
return unbox<int32_t>(p_obj);
@@ -708,13 +787,13 @@ Array mono_array_to_Array(MonoArray *p_array) {
return ret;
}
-// TODO Optimize reading/writing from/to PoolArrays
-
MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array) {
+ PoolIntArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, int32_t, i, p_array[i]);
+ mono_array_set(ret, int32_t, i, r[i]);
}
return ret;
@@ -726,19 +805,22 @@ PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolIntArray::Write w = ret.write();
+
for (int i = 0; i < length; i++) {
- int32_t elem = mono_array_get(p_array, int32_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, int32_t, i);
}
return ret;
}
MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array) {
+ PoolByteArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, uint8_t, i, p_array[i]);
+ mono_array_set(ret, uint8_t, i, r[i]);
}
return ret;
@@ -750,20 +832,22 @@ PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolByteArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- uint8_t elem = mono_array_get(p_array, uint8_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, uint8_t, i);
}
return ret;
}
MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array) {
+ PoolRealArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, real_t, i, p_array[i]);
+ mono_array_set(ret, real_t, i, r[i]);
}
return ret;
@@ -775,20 +859,22 @@ PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolRealArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t elem = mono_array_get(p_array, real_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, real_t, i);
}
return ret;
}
MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
+ PoolStringArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- MonoString *boxed = mono_string_from_godot(p_array[i]);
+ MonoString *boxed = mono_string_from_godot(r[i]);
mono_array_set(ret, MonoString *, i, boxed);
}
@@ -801,29 +887,24 @@ PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolStringArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
MonoString *elem = mono_array_get(p_array, MonoString *, i);
- ret.set(i, mono_string_to_godot(elem));
+ w[i] = mono_string_to_godot(elem);
}
return ret;
}
MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array) {
+ PoolColorArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Color, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 4, i);
- const Color &elem = p_array[i];
- raw[0] = elem.r;
- raw[1] = elem.g;
- raw[2] = elem.b;
- raw[3] = elem.a;
-#endif
+ M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
+ *raw = MARSHALLED_OUT(Color, r[i]);
}
return ret;
@@ -835,28 +916,23 @@ PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolColorArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 4, i);
- MARSHALLED_IN(Color, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
}
return ret;
}
MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array) {
+ PoolVector2Array::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Vector2, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 2, i);
- const Vector2 &elem = p_array[i];
- raw[0] = elem.x;
- raw[1] = elem.y;
-#endif
+ M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
+ *raw = MARSHALLED_OUT(Vector2, r[i]);
}
return ret;
@@ -868,29 +944,23 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolVector2Array::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 2, i);
- MARSHALLED_IN(Vector2, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
}
return ret;
}
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array) {
+ PoolVector3Array::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Vector3, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 3, i);
- const Vector3 &elem = p_array[i];
- raw[0] = elem.x;
- raw[1] = elem.y;
- raw[2] = elem.z;
-#endif
+ M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
+ *raw = MARSHALLED_OUT(Vector3, r[i]);
}
return ret;
@@ -902,11 +972,10 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolVector3Array::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 3, i);
- MARSHALLED_IN(Vector3, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
}
return ret;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index cc0ab5fa05..4002f2a225 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -147,78 +147,271 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
-#ifdef YOLO_COPY
-#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
-#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
+// Structures
+
+namespace InteropLayout {
+
+enum {
+ MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
+
+ MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
+
+#ifdef REAL_T_IS_DOUBLE
+ MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)),
#else
+ MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)),
+#endif
-// Expects m_in to be of type float*
+ MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) &&
+ offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
+ offsetof(Vector2, y) == (sizeof(real_t) * 1)),
-#define MARSHALLED_OUT(m_t, m_in, m_out) MARSHALLED_OUT_##m_t(m_in, m_out)
-#define MARSHALLED_IN(m_t, m_in, m_out) MARSHALLED_IN_##m_t(m_in, m_out)
+ MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
+ offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
+ offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
-// Vector2
+ MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
-#define MARSHALLED_OUT_Vector2(m_in, m_out) real_t m_out[2] = { m_in.x, m_in.y };
-#define MARSHALLED_IN_Vector2(m_in, m_out) Vector2 m_out(m_in[0], m_in[1]);
+ MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
+ offsetof(Vector3, x) == (sizeof(real_t) * 0) &&
+ offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
+ offsetof(Vector3, z) == (sizeof(real_t) * 2)),
-// Rect2
+ MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
-#define MARSHALLED_OUT_Rect2(m_in, m_out) real_t m_out[4] = { m_in.position.x, m_in.position.y, m_in.size.width, m_in.size.height };
-#define MARSHALLED_IN_Rect2(m_in, m_out) Rect2 m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) &&
+ offsetof(Quat, x) == (sizeof(real_t) * 0) &&
+ offsetof(Quat, y) == (sizeof(real_t) * 1) &&
+ offsetof(Quat, z) == (sizeof(real_t) * 2) &&
+ offsetof(Quat, w) == (sizeof(real_t) * 3)),
-// Transform2D
+ MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) &&
+ offsetof(Transform, basis) == 0 &&
+ offsetof(Transform, origin) == sizeof(Basis)),
-#define MARSHALLED_OUT_Transform2D(m_in, m_out) real_t m_out[6] = { m_in[0].x, m_in[0].y, m_in[1].x, m_in[1].y, m_in[2].x, m_in[2].y };
-#define MARSHALLED_IN_Transform2D(m_in, m_out) Transform2D m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5]);
+ MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
+ offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
+ offsetof(AABB, size) == (sizeof(Vector3) * 1)),
-// Vector3
+ MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) &&
+ offsetof(Color, r) == (sizeof(float) * 0) &&
+ offsetof(Color, g) == (sizeof(float) * 1) &&
+ offsetof(Color, b) == (sizeof(float) * 2) &&
+ offsetof(Color, a) == (sizeof(float) * 3)),
+
+ MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) &&
+ offsetof(Plane, normal) == 0 &&
+ offsetof(Plane, d) == sizeof(Vector3))
+};
+
+// In the future we may force this if we want to ref return these structs
+#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
+// Sometimes clang-format can be an ass
+GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 &&
+ MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane);
+#endif
-#define MARSHALLED_OUT_Vector3(m_in, m_out) real_t m_out[3] = { m_in.x, m_in.y, m_in.z };
-#define MARSHALLED_IN_Vector3(m_in, m_out) Vector3 m_out(m_in[0], m_in[1], m_in[2]);
+} // namespace InteropLayout
-// Basis
+#pragma pack(push, 1)
-#define MARSHALLED_OUT_Basis(m_in, m_out) real_t m_out[9] = { \
- m_in[0].x, m_in[0].y, m_in[0].z, \
- m_in[1].x, m_in[1].y, m_in[1].z, \
- m_in[2].x, m_in[2].y, m_in[2].z \
+struct M_Vector2 {
+ real_t x, y;
+
+ static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) {
+ return Vector2(p_from.x, p_from.y);
+ }
+
+ static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) {
+ M_Vector2 ret = { p_from.x, p_from.y };
+ return ret;
+ }
};
-#define MARSHALLED_IN_Basis(m_in, m_out) Basis m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]);
-// Quat
+struct M_Rect2 {
+ M_Vector2 position;
+ M_Vector2 size;
-#define MARSHALLED_OUT_Quat(m_in, m_out) real_t m_out[4] = { m_in.x, m_in.y, m_in.z, m_in.w };
-#define MARSHALLED_IN_Quat(m_in, m_out) Quat m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) {
+ return Rect2(M_Vector2::convert_to(p_from.position),
+ M_Vector2::convert_to(p_from.size));
+ }
-// Transform
+ static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) {
+ M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) };
+ return ret;
+ }
+};
-#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
- m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z, \
- m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z, \
- m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z, \
- m_in.origin.x, m_in.origin.y, m_in.origin.z \
+struct M_Transform2D {
+ M_Vector2 elements[3];
+
+ static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) {
+ return Transform2D(p_from.elements[0].x, p_from.elements[0].y,
+ p_from.elements[1].x, p_from.elements[1].y,
+ p_from.elements[2].x, p_from.elements[2].y);
+ }
+
+ static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
+ M_Transform2D ret = {
+ M_Vector2::convert_from(p_from.elements[0]),
+ M_Vector2::convert_from(p_from.elements[1]),
+ M_Vector2::convert_from(p_from.elements[2])
+ };
+ return ret;
+ }
};
-#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out( \
- Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
- Vector3(m_in[9], m_in[10], m_in[11]));
-// AABB
+struct M_Vector3 {
+ real_t x, y, z;
+
+ static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) {
+ return Vector3(p_from.x, p_from.y, p_from.z);
+ }
-#define MARSHALLED_OUT_AABB(m_in, m_out) real_t m_out[6] = { m_in.position.x, m_in.position.y, m_in.position.z, m_in.size.x, m_in.size.y, m_in.size.z };
-#define MARSHALLED_IN_AABB(m_in, m_out) AABB m_out(Vector3(m_in[0], m_in[1], m_in[2]), Vector3(m_in[3], m_in[4], m_in[5]));
+ static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) {
+ M_Vector3 ret = { p_from.x, p_from.y, p_from.z };
+ return ret;
+ }
+};
-// Color
+struct M_Basis {
+ M_Vector3 elements[3];
+
+ static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) {
+ return Basis(M_Vector3::convert_to(p_from.elements[0]),
+ M_Vector3::convert_to(p_from.elements[1]),
+ M_Vector3::convert_to(p_from.elements[2]));
+ }
+
+ static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
+ M_Basis ret = {
+ M_Vector3::convert_from(p_from.elements[0]),
+ M_Vector3::convert_from(p_from.elements[1]),
+ M_Vector3::convert_from(p_from.elements[2])
+ };
+ return ret;
+ }
+};
-#define MARSHALLED_OUT_Color(m_in, m_out) real_t m_out[4] = { m_in.r, m_in.g, m_in.b, m_in.a };
-#define MARSHALLED_IN_Color(m_in, m_out) Color m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+struct M_Quat {
+ real_t x, y, z, w;
-// Plane
+ static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) {
+ return Quat(p_from.x, p_from.y, p_from.z, p_from.w);
+ }
-#define MARSHALLED_OUT_Plane(m_in, m_out) real_t m_out[4] = { m_in.normal.x, m_in.normal.y, m_in.normal.z, m_in.d };
-#define MARSHALLED_IN_Plane(m_in, m_out) Plane m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) {
+ M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+ return ret;
+ }
+};
-#endif
+struct M_Transform {
+ M_Basis basis;
+ M_Vector3 origin;
+
+ static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) {
+ return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
+ }
+
+ static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) {
+ M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
+ return ret;
+ }
+};
+
+struct M_AABB {
+ M_Vector3 position;
+ M_Vector3 size;
+
+ static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) {
+ return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size));
+ }
+
+ static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) {
+ M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) };
+ return ret;
+ }
+};
+
+struct M_Color {
+ float r, g, b, a;
+
+ static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) {
+ return Color(p_from.r, p_from.g, p_from.b, p_from.a);
+ }
+
+ static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) {
+ M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a };
+ return ret;
+ }
+};
+
+struct M_Plane {
+ M_Vector3 normal;
+ real_t d;
+
+ static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) {
+ return Plane(M_Vector3::convert_to(p_from.normal), p_from.d);
+ }
+
+ static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) {
+ M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d };
+ return ret;
+ }
+};
+
+#pragma pack(pop)
+
+#define DECL_TYPE_MARSHAL_TEMPLATES(m_type) \
+ template <int> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from); \
+ \
+ template <> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) { \
+ return M_##m_type::convert_to(*p_from); \
+ } \
+ \
+ template <> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) { \
+ return *reinterpret_cast<const m_type *>(p_from); \
+ } \
+ \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) { \
+ return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
+ } \
+ \
+ template <int> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from); \
+ \
+ template <> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \
+ return M_##m_type::convert_from(p_from); \
+ } \
+ \
+ template <> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \
+ return *reinterpret_cast<const M_##m_type *>(&p_from); \
+ } \
+ \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) { \
+ return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
+ }
+
+DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
+DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
+DECL_TYPE_MARSHAL_TEMPLATES(Basis)
+DECL_TYPE_MARSHAL_TEMPLATES(Quat)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform)
+DECL_TYPE_MARSHAL_TEMPLATES(AABB)
+DECL_TYPE_MARSHAL_TEMPLATES(Color)
+DECL_TYPE_MARSHAL_TEMPLATES(Plane)
+
+#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
+#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index b97a24b09c..fe2c09799c 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -631,36 +631,36 @@ void set_pending_exception(MonoException *p_exc) {
_THREAD_LOCAL_(int)
current_invoke_count = 0;
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc) {
+MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)p_exc);
+ MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **p_exc) {
+MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)p_exc);
+ MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
-MonoString *object_to_string(MonoObject *p_obj, MonoException **p_exc) {
+MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)p_exc);
+ MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc) {
+void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)p_exc);
+ mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE;
}
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc) {
+MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)p_exc);
+ MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index ec3a57eb46..f00680ff03 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -233,13 +233,13 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
return current_invoke_count;
}
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc);
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **p_exc);
+MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
+MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
-MonoString *object_to_string(MonoObject *p_obj, MonoException **p_exc);
+MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc);
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc);
+void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
+MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index b4c78df538..fa1fbebb16 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -141,7 +141,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
if (exc) {
GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL_V();
+ ERR_FAIL();
}
}
}
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index 337a86870e..40b47e8648 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -33,6 +33,15 @@
// noreturn
+#if __cpp_static_assert
+#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
+#else
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_B(m_ignore, m_name) m_name
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_B(hello there, m_a##m_b)
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b)
+#define GD_STATIC_ASSERT(m_cond) typedef int GD_STATIC_ASSERT_VARNAME_CONCAT(godot_static_assert_, __COUNTER__)[((m_cond) ? 1 : -1)]
+#endif
+
#undef _NO_RETURN_
#ifdef __GNUC__
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index ea942a9a8e..e663ee3c4a 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -88,7 +88,7 @@ void fix_path(const String &p_path, String &r_out) {
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
#ifdef WINDOWS_ENABLED
CharType ret[_MAX_PATH];
- if (_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
+ if (::_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
String abspath = String(ret).replace("\\", "/");
int pos = abspath.find(":/");
if (pos != -1) {
@@ -99,10 +99,12 @@ bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
return true;
}
#else
- char ret[PATH_MAX];
- if (realpath(p_existing_path.utf8().get_data(), ret)) {
+ char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL);
+ if (resolved_path) {
String retstr;
- if (!retstr.parse_utf8(ret)) {
+ bool success = !retstr.parse_utf8(resolved_path);
+ ::free(resolved_path);
+ if (success) {
r_abs_path = retstr;
return true;
}
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 8691932f9a..6900866725 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -30,6 +30,8 @@
#include "string_utils.h"
+#include "core/os/file_access.h"
+
namespace {
int sfind(const String &p_text, int p_from) {
@@ -128,6 +130,7 @@ String sformat(const String &p_text, const Variant &p1, const Variant &p2, const
return new_string;
}
+#ifdef TOOLS_ENABLED
bool is_csharp_keyword(const String &p_name) {
// Reserved keywords
@@ -156,3 +159,28 @@ bool is_csharp_keyword(const String &p_name) {
String escape_csharp_keyword(const String &p_name) {
return is_csharp_keyword(p_name) ? "@" + p_name : p_name;
}
+#endif
+
+Error read_all_file_utf8(const String &p_path, String &r_content) {
+ PoolVector<uint8_t> sourcef;
+ Error err;
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ int len = f->get_len();
+ sourcef.resize(len + 1);
+ PoolVector<uint8_t>::Write w = sourcef.write();
+ int r = f->get_buffer(w.ptr(), len);
+ f->close();
+ memdelete(f);
+ ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
+ w[len] = 0;
+
+ String source;
+ if (source.parse_utf8((const char *)w.ptr())) {
+ ERR_FAIL_V(ERR_INVALID_DATA);
+ }
+
+ r_content = source;
+ return OK;
+}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index f2df2340ae..ee803bd720 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -42,4 +42,6 @@ bool is_csharp_keyword(const String &p_name);
String escape_csharp_keyword(const String &p_name);
#endif
+Error read_all_file_utf8(const String &p_path, String &r_content);
+
#endif // STRING_FORMAT_H
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index d88abb3180..ba54160a90 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -17,6 +17,9 @@
<member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap">
If true, the resulting texture contains a normal map created from the original noise interpreted as a bump map.
</member>
+ <member name="height" type="int" setter="set_height" getter="get_height">
+ Height of the generated texture.
+ </member>
<member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise">
The [OpenSimplexNoise] instance used to generate the noise.
</member>
@@ -26,9 +29,6 @@
<member name="width" type="int" setter="set_width" getter="get_width">
Width of the generated texture.
</member>
- <member name="height" type="int" setter="set_height" getter="get_height">
- Height of the generated texture.
- </member>
</members>
<constants>
</constants>
diff --git a/modules/recast/navigation_mesh_editor_plugin.cpp b/modules/recast/navigation_mesh_editor_plugin.cpp
index 98351fbaee..d121a82d9e 100644
--- a/modules/recast/navigation_mesh_editor_plugin.cpp
+++ b/modules/recast/navigation_mesh_editor_plugin.cpp
@@ -103,24 +103,25 @@ void NavigationMeshEditor::_bind_methods() {
NavigationMeshEditor::NavigationMeshEditor() {
bake_hbox = memnew(HBoxContainer);
+
button_bake = memnew(ToolButton);
- button_bake->set_text(TTR("Bake!"));
+ bake_hbox->add_child(button_bake);
button_bake->set_toggle_mode(true);
- button_reset = memnew(Button);
- button_bake->set_tooltip(TTR("Bake the navigation mesh.") + "\n");
+ button_bake->set_text(TTR("Bake NavMesh"));
+ button_bake->connect("pressed", this, "_bake_pressed");
- bake_info = memnew(Label);
- bake_hbox->add_child(button_bake);
+ button_reset = memnew(ToolButton);
bake_hbox->add_child(button_reset);
+ // No button text, we only use a revert icon which is set when entering the tree.
+ button_reset->set_tooltip(TTR("Clear the navigation mesh."));
+ button_reset->connect("pressed", this, "_clear_pressed");
+
+ bake_info = memnew(Label);
bake_hbox->add_child(bake_info);
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
node = NULL;
-
- button_bake->connect("pressed", this, "_bake_pressed");
- button_reset->connect("pressed", this, "_clear_pressed");
- button_reset->set_tooltip(TTR("Clear the navigation mesh."));
}
NavigationMeshEditor::~NavigationMeshEditor() {
diff --git a/modules/recast/navigation_mesh_editor_plugin.h b/modules/recast/navigation_mesh_editor_plugin.h
index 4f3e222002..914d9ab8b9 100644
--- a/modules/recast/navigation_mesh_editor_plugin.h
+++ b/modules/recast/navigation_mesh_editor_plugin.h
@@ -43,8 +43,8 @@ class NavigationMeshEditor : public Control {
AcceptDialog *err_dialog;
HBoxContainer *bake_hbox;
- Button *button_bake;
- Button *button_reset;
+ ToolButton *button_bake;
+ ToolButton *button_reset;
Label *bake_info;
NavigationMeshInstance *node;
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 28764aca40..70849c5a80 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -9,7 +9,7 @@
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/scripting/visual_script/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 52a30baaec..186e9e63b1 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2699,11 +2699,11 @@ VisualScriptLanguage::VisualScriptLanguage() {
_debug_parse_err_file = "";
_debug_call_stack_pos = 0;
int dmcs = GLOBAL_DEF("debug/settings/visual_script/max_call_stack", 1024);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/visual_script/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/visual_script/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
+
if (ScriptDebugger::get_singleton()) {
//debugging enabled!
_debug_max_call_stack = dmcs;
- if (_debug_max_call_stack < 1024)
- _debug_max_call_stack = 1024;
_call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
} else {
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 7fdd7fe446..c5f2070963 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -765,6 +765,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
void VisualScriptEditor::_update_members() {
+ ERR_FAIL_COND(!script.is_valid());
updating_members = true;
@@ -3018,11 +3019,15 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) {
void VisualScriptEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
+ if (p_what == NOTIFICATION_READY || (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())) {
+
node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
node_filter->set_clear_button_enabled(true);
- variable_editor->connect("changed", this, "_update_members");
- signal_editor->connect("changed", this, "_update_members");
+
+ if (p_what == NOTIFICATION_READY) {
+ variable_editor->connect("changed", this, "_update_members");
+ signal_editor->connect("changed", this, "_update_members");
+ }
Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
@@ -3056,8 +3061,12 @@ void VisualScriptEditor::_notification(int p_what) {
node_styles[E->get().first] = frame_style;
}
}
- }
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (is_visible_in_tree() && script.is_valid()) {
+ _update_members();
+ _update_graph();
+ }
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
left_vsplit->set_visible(is_visible_in_tree());
}
}
@@ -3644,7 +3653,7 @@ VisualScriptEditor::VisualScriptEditor() {
new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method");
- new_virtual_method_select->get_cancel()->connect("pressed", this, "_selected_new_virtual_method");
+ new_virtual_method_select->get_cancel();
member_popup = memnew(PopupMenu);
add_child(member_popup);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 97c75dae94..ce3245bc28 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -176,7 +176,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _cancel_connect_node();
void _create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point);
- void _selected_new_virtual_method(const String &p_text = String(""), const String &p_category = String(""), const bool p_connecting = true);
+ void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting);
int error_line;
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index ad4a758c0f..db02162699 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -71,6 +71,9 @@ int EMWSServer::get_peer_port(int p_peer_id) const {
void EMWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
}
+void EMWSServer::poll() {
+}
+
EMWSServer::EMWSServer() {
}
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
index b3e5f6ffab..07583bb85b 100644
--- a/modules/websocket/lws_client.cpp
+++ b/modules/websocket/lws_client.cpp
@@ -76,26 +76,11 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
ERR_FAIL_V(FAILED);
}
- char abuf[1024];
- char hbuf[1024];
- char pbuf[2048];
- String addr_str = (String)addr;
- strncpy(abuf, addr_str.ascii().get_data(), 1023);
- abuf[1023] = '\0';
- strncpy(hbuf, p_host.utf8().get_data(), 1023);
- hbuf[1023] = '\0';
- strncpy(pbuf, p_path.utf8().get_data(), 2047);
- pbuf[2047] = '\0';
-
i.context = context;
if (p_protocols.size() > 0)
i.protocol = _lws_ref->lws_names;
else
i.protocol = NULL;
- i.address = abuf;
- i.host = hbuf;
- i.path = pbuf;
- i.port = p_port;
if (p_ssl) {
i.ssl_connection = LCCSCF_USE_SSL;
@@ -105,7 +90,17 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
i.ssl_connection = 0;
}
+ // These CharStrings needs to survive till we call lws_client_connect_via_info
+ CharString addr_ch = ((String)addr).ascii();
+ CharString host_ch = p_host.utf8();
+ CharString path_ch = p_path.utf8();
+ i.address = addr_ch.get_data();
+ i.host = host_ch.get_data();
+ i.path = path_ch.get_data();
+ i.port = p_port;
+
lws_client_connect_via_info(&i);
+
return OK;
};
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index f9b94dc519..6c5018bb79 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -136,7 +136,7 @@ void WebSocketClient::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled);
ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled);
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
ADD_SIGNAL(MethodInfo("data_received"));
ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol")));
diff --git a/modules/websocket/websocket_multiplayer.cpp b/modules/websocket/websocket_multiplayer.cpp
index b948c439df..873658559a 100644
--- a/modules/websocket/websocket_multiplayer.cpp
+++ b/modules/websocket/websocket_multiplayer.cpp
@@ -313,7 +313,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
} else if (to < 0) {
// All but one, for us if not excluded
- if (_peer_id != -p_peer_id)
+ if (_peer_id != -(int32_t)p_peer_id)
_store_pkt(from, to, in_buffer, data_size);
} else {
diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template
index 1603ea70d9..18ffc74fc3 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/build.gradle.template
@@ -14,9 +14,9 @@ apply plugin: 'com.android.application'
allprojects {
repositories {
- jcenter()
mavenCentral()
google()
+ jcenter()
$$GRADLE_REPOSITORY_URLS$$
}
}
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 953a2fa6d2..e4cab2fb23 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -186,7 +186,7 @@ def configure(env):
env.PrependENVPath('PATH', tools_path)
ccache_path = os.environ.get("CCACHE")
- if ccache_path == None:
+ if ccache_path is None:
env['CC'] = compiler_path + '/clang'
env['CXX'] = compiler_path + '/clang++'
else:
@@ -293,7 +293,7 @@ def configure(env):
# Return NDK version string in source.properties (adapted from the Chromium project).
def get_ndk_version(path):
- if path == None:
+ if path is None:
return None
prop_file_path = os.path.join(path, "source.properties")
try:
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 3b503e2657..3766f732e4 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -395,7 +395,7 @@ class EditorExportAndroid : public EditorExportPlatform {
return aname;
}
- String get_package_name(const String &p_package) {
+ String get_package_name(const String &p_package) const {
String pname = p_package;
String basename = ProjectSettings::get_singleton()->get("application/config/name");
@@ -420,6 +420,70 @@ class EditorExportAndroid : public EditorExportPlatform {
return pname;
}
+ bool is_package_name_valid(const String &p_package, String *r_error = NULL) const {
+
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = "Package name is missing.";
+ }
+ return false;
+ }
+
+ int segments = 0;
+ bool first = true;
+ for (int i = 0; i < pname.length(); i++) {
+ CharType c = pname[i];
+ if (first && c == '.') {
+ if (r_error) {
+ *r_error = "Package segments must be of non-zero length.";
+ }
+ return false;
+ }
+ if (c == '.') {
+ segments++;
+ first = true;
+ continue;
+ }
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
+ if (r_error) {
+ *r_error = "The character '" + String::chr(c) + "' is not allowed in Android application package names.";
+ }
+ return false;
+ }
+ if (first && (c >= '0' && c <= '9')) {
+ if (r_error) {
+ *r_error = "A digit cannot be the first character in a package segment.";
+ }
+ return false;
+ }
+ if (first && c == '_') {
+ if (r_error) {
+ *r_error = "The character '" + String::chr(c) + "' cannot be the first character in a package segment.";
+ }
+ return false;
+ }
+ first = false;
+ }
+
+ if (segments == 0) {
+ if (r_error) {
+ *r_error = "The package must have at least one '.' separator.";
+ }
+ return false;
+ }
+
+ if (first) {
+ if (r_error) {
+ *r_error = "Package segments must be of non-zero length.";
+ }
+ return false;
+ }
+
+ return true;
+ }
+
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
/*
@@ -1382,12 +1446,23 @@ public:
}
}
+ String pn = p_preset->get("package/unique_name");
+ String pn_err;
+
+ if (!is_package_name_valid(get_package_name(pn), &pn_err)) {
+
+ valid = false;
+ err += "Invalid package name - " + pn_err + "\n";
+ }
+
r_error = err;
return valid;
}
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const {
- return "apk";
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("apk");
+ return list;
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index ab37f7a02c..88194f00d1 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -279,7 +279,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
// ...add to FrameLayout
layout.addView(edittext);
- mView = new GodotView(getApplication(), io, use_gl3, use_32_bits, use_debug_opengl,this);
+ mView = new GodotView(getApplication(), io, use_gl3, use_32_bits, use_debug_opengl, this);
layout.addView(mView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
edittext.setView(mView);
io.setEdit(edittext);
diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java
index 181ffc3b4b..4cb4db33de 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotView.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotView.java
@@ -86,7 +86,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
private Godot activity;
private InputManagerCompat mInputManager;
- public GodotView(Context context, GodotIO p_io, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl,Godot p_activity) {
+ public GodotView(Context context, GodotIO p_io, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl, Godot p_activity) {
super(context);
ctx = context;
io = p_io;
@@ -204,48 +204,65 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
return i;
}
}
- onInputDeviceAdded(device_id);
- return joy_devices.size() - 1;
+
+ return -1;
}
@Override
public void onInputDeviceAdded(int deviceId) {
- joystick joy = new joystick();
- joy.device_id = deviceId;
- final int id = joy_devices.size();
- InputDevice device = mInputManager.getInputDevice(deviceId);
- final String name = device.getName();
- joy.name = device.getName();
- joy.axes = new ArrayList<InputDevice.MotionRange>();
- joy.hats = new ArrayList<InputDevice.MotionRange>();
- List<InputDevice.MotionRange> ranges = device.getMotionRanges();
- Collections.sort(ranges, new RangeComparator());
- for (InputDevice.MotionRange range : ranges) {
- if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
- joy.hats.add(range);
- } else {
- joy.axes.add(range);
+ int id = find_joy_device(deviceId);
+
+ // Check if the device has not been already added
+ if (id < 0) {
+ InputDevice device = mInputManager.getInputDevice(deviceId);
+
+ id = joy_devices.size();
+
+ joystick joy = new joystick();
+ joy.device_id = deviceId;
+ joy.name = device.getName();
+ joy.axes = new ArrayList<InputDevice.MotionRange>();
+ joy.hats = new ArrayList<InputDevice.MotionRange>();
+
+ List<InputDevice.MotionRange> ranges = device.getMotionRanges();
+ Collections.sort(ranges, new RangeComparator());
+
+ for (InputDevice.MotionRange range : ranges) {
+ if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+ joy.hats.add(range);
+ } else {
+ joy.axes.add(range);
+ }
}
+
+ joy_devices.add(joy);
+
+ final int device_id = id;
+ final String name = joy.name;
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyconnectionchanged(device_id, true, name);
+ }
+ });
}
- joy_devices.add(joy);
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyconnectionchanged(id, true, name);
- }
- });
}
@Override
public void onInputDeviceRemoved(int deviceId) {
- final int id = find_joy_device(deviceId);
- joy_devices.remove(id);
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyconnectionchanged(id, false, "");
- }
- });
+ final int device_id = find_joy_device(deviceId);
+
+ // Check if the evice has not been already removed
+ if (device_id > -1) {
+ joy_devices.remove(device_id);
+
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyconnectionchanged(device_id, false, "");
+ }
+ });
+ }
}
@Override
@@ -266,15 +283,18 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
final int button = get_godot_button(keyCode);
- final int device = find_joy_device(event.getDeviceId());
+ final int device_id = find_joy_device(event.getDeviceId());
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joybutton(device, button, false);
- }
- });
- return true;
+ // Check if the device exists
+ if (device_id > -1) {
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joybutton(device_id, button, false);
+ }
+ });
+ return true;
+ }
} else {
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@@ -284,6 +304,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
}
});
};
+
return super.onKeyUp(keyCode, event);
};
@@ -308,18 +329,20 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
if (event.getRepeatCount() > 0) // ignore key echo
return true;
- final int button = get_godot_button(keyCode);
- final int device = find_joy_device(event.getDeviceId());
- //Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device));
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joybutton(device, button, true);
- }
- });
- return true;
+ final int button = get_godot_button(keyCode);
+ final int device_id = find_joy_device(event.getDeviceId());
+ // Check if the device exists
+ if (device_id > -1) {
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joybutton(device_id, button, true);
+ }
+ });
+ return true;
+ }
} else {
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@@ -329,6 +352,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
}
});
};
+
return super.onKeyDown(keyCode, event);
}
@@ -338,33 +362,35 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
final int device_id = find_joy_device(event.getDeviceId());
- joystick joy = joy_devices.get(device_id);
- for (int i = 0; i < joy.axes.size(); i++) {
- InputDevice.MotionRange range = joy.axes.get(i);
- final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
- //Log.e(TAG, String.format("axis event: %d, value %f", i, value));
- final int idx = i;
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyaxis(device_id, idx, value);
- }
- });
- }
+ // Check if the device exists
+ if (device_id > -1) {
+ joystick joy = joy_devices.get(device_id);
+
+ for (int i = 0; i < joy.axes.size(); i++) {
+ InputDevice.MotionRange range = joy.axes.get(i);
+ final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
+ final int idx = i;
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyaxis(device_id, idx, value);
+ }
+ });
+ }
- for (int i = 0; i < joy.hats.size(); i += 2) {
- final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
- final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis()));
- //Log.e(TAG, String.format("HAT EVENT %d, %d", hatX, hatY));
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyhat(device_id, hatX, hatY);
- }
- });
+ for (int i = 0; i < joy.hats.size(); i += 2) {
+ final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
+ final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis()));
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyhat(device_id, hatX, hatY);
+ }
+ });
+ }
+ return true;
}
- return true;
};
return super.onGenericMotionEvent(event);
@@ -408,9 +434,9 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
setRenderer(new Renderer());
}
- private static final int _EGL_CONTEXT_FLAGS_KHR = 0x30FC;
- private static final int _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR= 0x00000001;
-
+ private static final int _EGL_CONTEXT_FLAGS_KHR = 0x30FC;
+ private static final int _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x00000001;
+
private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
@@ -422,9 +448,9 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
checkEglError("Before eglCreateContext", egl);
EGLContext context;
if (use_debug_opengl) {
- int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2,_EGL_CONTEXT_FLAGS_KHR,_EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
- int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3,_EGL_CONTEXT_FLAGS_KHR,_EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
- context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3 ? attrib_list3 : attrib_list2);
+ int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
+ int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
+ context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3 ? attrib_list3 : attrib_list2);
} else {
int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE };
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 30bc413459..96ff226402 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -39,7 +39,7 @@
#include "file_access_android.h"
#include "main/main.h"
#include "servers/visual/visual_server_raster.h"
-//#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/visual/visual_server_wrap_mt.h"
#ifdef ANDROID_NATIVE_ACTIVITY
#include "dir_access_android.h"
@@ -183,13 +183,11 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
video_driver_index = p_video_driver;
visual_server = memnew(VisualServerRaster);
- /* if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
-
+ if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
visual_server = memnew(VisualServerWrapMT(visual_server, false));
- };*/
+ }
visual_server->init();
- // visual_server->cursor_set_visible(false, 0);
AudioDriverManager::initialize(p_audio_driver);
@@ -586,7 +584,7 @@ Error OS_Android::shell_open(String p_uri) {
String OS_Android::get_resource_dir() const {
- return "/"; //android has it's own filesystem for resources inside the APK
+ return "/"; //android has its own filesystem for resources inside the APK
}
String OS_Android::get_locale() const {
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index c80365f1f3..f9f12af817 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -117,16 +117,13 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p
#endif
- visual_server = memnew(VisualServerRaster());
-
- ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
-
- // TODO: enable multithreaded VS
- /*
+ visual_server = memnew(VisualServerRaster);
+ // FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+ visual_server = memnew(VisualServerWrapMT(visual_server, false));
}
- */
+
+ ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
video_driver_index = p_video_driver;
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index b13a1e9643..417571f6f3 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -87,7 +87,7 @@ def configure(env):
s_compiler_path = '$IPHONEPATH/Developer/usr/bin/'
ccache_path = os.environ.get("CCACHE")
- if ccache_path == None:
+ if ccache_path is None:
env['CC'] = compiler_path + 'clang'
env['CXX'] = compiler_path + 'clang++'
env['S_compiler'] = s_compiler_path + 'gcc'
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 63bc4a519b..1fc497456c 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -108,7 +108,11 @@ public:
virtual String get_os_name() const { return "iOS"; }
virtual Ref<Texture> get_logo() const { return logo; }
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const { return "ipa"; }
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("ipa");
+ return list;
+ }
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index addef61ec7..e996a5905b 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -34,7 +34,7 @@
#include "drivers/gles3/rasterizer_gles3.h"
#include "servers/visual/visual_server_raster.h"
-//#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/visual/visual_server_wrap_mt.h"
#include "main/main.h"
@@ -107,13 +107,11 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
- visual_server = memnew(VisualServerRaster());
- /*
- FIXME: Reimplement threaded rendering? Or remove?
+ visual_server = memnew(VisualServerRaster);
+ // FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
visual_server = memnew(VisualServerWrapMT(visual_server, false));
- };
- */
+ }
visual_server->init();
//visual_server->cursor_set_visible(false, 0);
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 17b31f8d73..cf85c3df7f 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -128,6 +128,10 @@ def configure(env):
# us since we don't know requirements at compile-time.
env.Append(LINKFLAGS=['-s', 'ALLOW_MEMORY_GROWTH=1'])
+ # Since we use both memory growth and MEMFS preloading,
+ # this avoids unecessary copying on start-up.
+ env.Append(LINKFLAGS=['--no-heap-copy'])
+
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js
index c3ef5bbbb5..91458eb4c3 100644
--- a/platform/javascript/engine.js
+++ b/platform/javascript/engine.js
@@ -1,3 +1,6 @@
+ // The following is concatenated with generated code, and acts as the end
+ // of a wrapper for said code. See pre.js for the other part of the
+ // wrapper.
exposedLibs['PATH'] = PATH;
exposedLibs['FS'] = FS;
return Module;
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 1e47d8db95..7a325e81dd 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -58,7 +58,7 @@ public:
virtual Ref<Texture> get_logo() const;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual bool poll_devices();
@@ -174,9 +174,11 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
return valid;
}
-String EditorExportPlatformJavaScript::get_binary_extension(const Ref<EditorExportPreset> &p_preset) const {
+List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
- return "html";
+ List<String> list;
+ list.push_back("html");
+ return list;
}
Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 7c7aeac980..9250ca4903 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -862,6 +862,24 @@ void OS_JavaScript::finalize() {
// Miscellaneous
+Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+
+ ERR_EXPLAIN("OS::execute() is not available on the HTML5 platform");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error OS_JavaScript::kill(const ProcessID &p_pid) {
+
+ ERR_EXPLAIN("OS::kill() is not available on the HTML5 platform");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+int OS_JavaScript::get_process_id() const {
+
+ ERR_EXPLAIN("OS::get_process_id() is not available on the HTML5 platform");
+ ERR_FAIL_V(0);
+}
+
extern "C" EMSCRIPTEN_KEEPALIVE void send_notification(int p_notification) {
if (p_notification == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || p_notification == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) {
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 84075898ac..79dac5940f 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -133,6 +133,10 @@ public:
void run_async();
bool main_loop_iterate();
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false);
+ virtual Error kill(const ProcessID &p_pid);
+ virtual int get_process_id() const;
+
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual void set_window_title(const String &p_title);
virtual void set_icon(const Ref<Image> &p_icon);
diff --git a/platform/javascript/pre.js b/platform/javascript/pre.js
index 02194bc75e..a870e676ea 100644
--- a/platform/javascript/pre.js
+++ b/platform/javascript/pre.js
@@ -1,2 +1,5 @@
var Engine = {
RuntimeEnvironment: function(Module, exposedLibs) {
+ // The above is concatenated with generated code, and acts as the start of
+ // a wrapper for said code. See engine.js for the other part of the
+ // wrapper.
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 8a0883eca3..c5bd64b15c 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -89,7 +89,7 @@ def configure(env):
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
ccache_path = os.environ.get("CCACHE")
- if ccache_path == None:
+ if ccache_path is None:
env['CC'] = basecmd + "cc"
env['CXX'] = basecmd + "c++"
else:
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 27b4fdc228..f27c042637 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -74,7 +74,14 @@ public:
virtual String get_os_name() const { return "OSX"; }
virtual Ref<Texture> get_logo() const { return logo; }
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const { return use_dmg() ? "dmg" : "zip"; }
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ if (use_dmg()) {
+ list.push_back("dmg");
+ }
+ list.push_back("zip");
+ return list;
+ }
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
@@ -334,7 +341,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
io2.opaque = &dst_f;
zipFile dst_pkg_zip = NULL;
- if (use_dmg()) {
+ String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
+ if (export_format == "dmg") {
// We're on OSX so we can export to DMG, but first we create our application bundle
tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
print_line("Exporting to " + tmp_app_path_name);
@@ -429,7 +437,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
print_line("ADDING: " + file + " size: " + itos(data.size()));
total_size += data.size();
- if (use_dmg()) {
+ if (export_format == "dmg") {
// write it into our application bundle
file = tmp_app_path_name + "/" + file;
@@ -491,7 +499,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (err == OK) {
ep.step("Making PKG", 1);
- if (use_dmg()) {
+ if (export_format == "dmg") {
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
Vector<SharedObject> shared_objects;
err = save_pack(p_preset, pack_path, &shared_objects);
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 6fd52f09d1..546c88e74a 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -74,8 +74,12 @@ public:
IP_Unix *ip_unix;
+#ifdef COREAUDIO_ENABLED
AudioDriverCoreAudio audio_driver;
+#endif
+#ifdef COREMIDI_ENABLED
MIDIDriverCoreMidi midi_driver;
+#endif
InputDefault *input;
JoypadOSX *joypad_osx;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 6ab433203f..81dc861f3f 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -100,12 +100,13 @@ static int prev_mouse_y = 0;
static int button_mask = 0;
static bool mouse_down_control = false;
-static Vector2 get_mouse_pos(NSEvent *event) {
+static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFactor) {
const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSPoint p = [event locationInWindow];
- mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
- mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
+ const NSPoint p = locationInWindow;
+ const float s = OS_OSX::singleton->_mouse_scale(backingScaleFactor);
+ mouse_x = p.x * s;
+ mouse_y = (contentRect.size.height - p.y) * s;
return Vector2(mouse_x, mouse_y);
}
@@ -325,8 +326,15 @@ static Vector2 get_mouse_pos(NSEvent *event) {
- (void)windowDidBecomeKey:(NSNotification *)notification {
//_GodotInputWindowFocus(window, GL_TRUE);
//_GodotPlatformSetCursorMode(window, window->cursorMode);
- if (OS_OSX::singleton->get_main_loop())
+
+ if (OS_OSX::singleton->get_main_loop()) {
+ get_mouse_pos(
+ [OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream],
+ [OS_OSX::singleton->window_view backingScaleFactor]);
+ OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y));
+
OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ }
}
- (void)windowDidResignKey:(NSNotification *)notification {
@@ -356,6 +364,8 @@ static Vector2 get_mouse_pos(NSEvent *event) {
bool imeMode;
}
- (void)cancelComposition;
+- (BOOL)wantsUpdateLayer;
+- (void)updateLayer;
@end
@implementation GodotContentView
@@ -366,6 +376,14 @@ static Vector2 get_mouse_pos(NSEvent *event) {
}
}
+- (BOOL)wantsUpdateLayer {
+ return YES;
+}
+
+- (void)updateLayer {
+ [OS_OSX::singleton->context update];
+}
+
- (id)init {
self = [super init];
trackingArea = nil;
@@ -593,12 +611,13 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
mm->set_button_mask(button_mask);
prev_mouse_x = mouse_x;
prev_mouse_y = mouse_y;
- const Vector2 pos = get_mouse_pos(event);
+ const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
+ const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
mm->set_position(pos);
mm->set_global_position(pos);
Vector2 relativeMotion = Vector2();
- relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]);
- relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]);
+ relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
+ relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
mm->set_relative(relativeMotion);
get_key_modifier_state([event modifierFlags], mm);
@@ -681,7 +700,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
Ref<InputEventMagnifyGesture> ev;
ev.instance();
get_key_modifier_state([event modifierFlags], ev);
- ev->set_position(get_mouse_pos(event));
+ ev->set_position(get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]));
ev->set_factor([event magnification] + 1.0);
OS_OSX::singleton->push_input(ev);
}
@@ -924,7 +943,7 @@ static int remapKey(unsigned int key) {
CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
if (!layoutData)
- return 0;
+ return translateKey(key);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
@@ -1073,6 +1092,8 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) {
- (void)scrollWheel:(NSEvent *)event {
double deltaX, deltaY;
+ get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]);
+
deltaX = [event scrollingDeltaX];
deltaY = [event scrollingDeltaY];
@@ -1216,6 +1237,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
ERR_FAIL_COND_V(window_object == nil, ERR_UNAVAILABLE);
window_view = [[GodotContentView alloc] init];
+ [window_view setWantsLayer:TRUE];
float displayScale = 1.0;
if (is_hidpi_allowed()) {
@@ -1373,7 +1395,6 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
visual_server = memnew(VisualServerRaster);
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
-
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
@@ -1397,7 +1418,9 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
void OS_OSX::finalize() {
+#ifdef COREMIDI_ENABLED
midi_driver.close();
+#endif
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
@@ -2714,7 +2737,9 @@ OS_OSX::OS_OSX() {
[NSApp sendEvent:event];
}
+#ifdef COREAUDIO_ENABLED
AudioDriverManager::add_driver(&audio_driver);
+#endif
}
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
diff --git a/platform/server/SCsub b/platform/server/SCsub
index c9082f9b3a..51fd05a87e 100644
--- a/platform/server/SCsub
+++ b/platform/server/SCsub
@@ -1,10 +1,21 @@
#!/usr/bin/env python
+import os
+import platform
+import sys
+
Import('env')
common_server = [\
"os_server.cpp",\
- "#platform/x11/crash_handler_x11.cpp",
- "#platform/x11/power_x11.cpp",
]
+
+if sys.platform == "darwin":
+ common_server.append("#platform/osx/crash_handler_osx.mm")
+ common_server.append("#platform/osx/power_osx.cpp")
+ common_server.append("#platform/osx/sem_osx.cpp")
+else:
+ common_server.append("#platform/x11/crash_handler_x11.cpp")
+ common_server.append("#platform/x11/power_x11.cpp")
+
prog = env.add_program('#bin/godot_server', ['godot_server.cpp'] + common_server)
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 597a2ff6a0..0b23e9c649 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -11,9 +11,15 @@ def get_name():
return "Server"
+def get_program_suffix():
+ if (sys.platform == "darwin"):
+ return "osx"
+ return "x11"
+
+
def can_build():
- if (os.name != "posix" or sys.platform == "darwin"):
+ if (os.name != "posix"):
return False
return True
@@ -147,6 +153,10 @@ def configure(env):
env.Append(CPPPATH=['#platform/server'])
env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED'])
+
+ if (platform.system() == "Darwin"):
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-lz', '-framework', 'IOKit'])
+
env.Append(LIBS=['pthread'])
if (platform.system() == "Linux"):
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 6a7038e946..60f20d6009 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -68,6 +68,10 @@ void OS_Server::initialize_core() {
crash_handler.initialize();
OS_Unix::initialize_core();
+
+#ifdef __APPLE__
+ SemaphoreOSX::make_default();
+#endif
}
Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
@@ -87,7 +91,11 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int
input = memnew(InputDefault);
+#ifdef __APPLE__
+ power_manager = memnew(power_osx);
+#else
power_manager = memnew(PowerX11);
+#endif
_ensure_user_data_dir();
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 07d70e5236..0367ec3db9 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -34,8 +34,14 @@
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/unix/os_unix.h"
#include "main/input_default.h"
+#ifdef __APPLE__
+#include "platform/osx/crash_handler_osx.h"
+#include "platform/osx/power_osx.h"
+#include "platform/osx/sem_osx.h"
+#else
#include "platform/x11/crash_handler_x11.h"
#include "platform/x11/power_x11.h"
+#endif
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
@@ -61,7 +67,11 @@ class OS_Server : public OS_Unix {
InputDefault *input;
+#ifdef __APPLE__
+ power_osx *power_manager;
+#else
PowerX11 *power_manager;
+#endif
CrashHandler crash_handler;
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
index 2fa8eda337..26ba8f26c6 100644
--- a/platform/server/platform_config.h
+++ b/platform/server/platform_config.h
@@ -28,10 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef __linux__
+#if defined(__linux__) || defined(__APPLE__)
#include <alloca.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <stdlib.h>
#define PTHREAD_BSD_SET_NAME
#endif
+#ifdef __APPLE__
+#define PTHREAD_RENAME_SELF
+#endif
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 559f23ca5b..f25b9ba9cd 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -17,7 +17,7 @@ def can_build():
# building natively on windows!
if (os.getenv("VSINSTALLDIR")):
- if (os.getenv("ANGLE_SRC_PATH") == None):
+ if (os.getenv("ANGLE_SRC_PATH") is None):
return False
return True
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 6a7284f770..41e59a5352 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -1021,8 +1021,10 @@ public:
return "UWP";
}
- virtual String get_binary_extension(const Ref<EditorExportPreset> &p_preset) const {
- return "appx";
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("appx");
+ return list;
}
virtual Ref<Texture> get_logo() const {
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 6410378593..1f81d476ea 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -47,6 +47,7 @@
#include "platform/windows/windows_terminal_logger.h"
#include "servers/audio_server.h"
#include "servers/visual/visual_server_raster.h"
+#include "servers/visual/visual_server_wrap_mt.h"
#include "thread_uwp.h"
#include <ppltasks.h>
@@ -295,13 +296,10 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
set_video_mode(vm);
visual_server = memnew(VisualServerRaster);
- // FIXME: Reimplement threaded rendering? Or remove?
- /*
+ // FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
-
- visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+ visual_server = memnew(VisualServerWrapMT(visual_server, false));
}
- */
visual_server->init();
input = memnew(InputDefault);
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 794f6df31f..2d70b00dda 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -91,18 +91,18 @@ Error ContextGL_Win::initialize() {
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER,
- PFD_TYPE_RGBA,
- OS::get_singleton()->is_layered_allowed() ? 32 : 24,
- 0, 0, 0, 0, 0, 0, // Color Bits Ignored
- OS::get_singleton()->is_layered_allowed() ? 8 : 0, // Alpha Buffer
- 0, // Shift Bit Ignored
- 0, // No Accumulation Buffer
- 0, 0, 0, 0, // Accumulation Bits Ignored
- 24, // 24Bit Z-Buffer (Depth Buffer)
- 0, // No Stencil Buffer
- 0, // No Auxiliary Buffer
- PFD_MAIN_PLANE, // Main Drawing Layer
- 0, // Reserved
+ (BYTE)PFD_TYPE_RGBA,
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
+ (BYTE)0, // Shift Bit Ignored
+ (BYTE)0, // No Accumulation Buffer
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
+ (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
+ (BYTE)0, // No Stencil Buffer
+ (BYTE)0, // No Auxiliary Buffer
+ (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
+ (BYTE)0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
diff --git a/platform/windows/joypad.cpp b/platform/windows/joypad.cpp
index b56fb6509e..7201714fb8 100644
--- a/platform/windows/joypad.cpp
+++ b/platform/windows/joypad.cpp
@@ -163,7 +163,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
const GUID &guid = instance->guidProduct;
char uid[128];
- sprintf(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+ sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
__builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
@@ -172,7 +172,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
joy->di_joy->SetDataFormat(&c_dfDIJoystick2);
joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND);
- joy->di_joy->EnumObjects(objectsCallback, this, NULL);
+ joy->di_joy->EnumObjects(objectsCallback, this, 0);
joy->joy_axis.sort();
joy->guid = instance->guidInstance;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 739fcbacda..bdf459fd83 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -58,11 +58,8 @@
static const WORD MAX_CONSOLE_LINES = 1500;
extern "C" {
-#ifdef _MSC_VER
-_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
-#else
-__attribute__((visibility("default"))) DWORD NvOptimusEnablement = 0x00000001;
-#endif
+__declspec(dllexport) DWORD NvOptimusEnablement = 1;
+__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
// Workaround mingw-w64 < 4.0 bug
@@ -303,19 +300,17 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
case WM_SETFOCUS: {
window_has_focus = true;
- // Re-capture cursor if we're in one of the capture modes
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
- SetCapture(hWnd);
- }
+
+ // Restore mouse mode
+ _set_mouse_mode_impl(mouse_mode);
+
break;
}
case WM_KILLFOCUS: {
window_has_focus = false;
- // Release capture if we're in one of the capture modes
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
- ReleaseCapture();
- }
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode
+ ReleaseCapture();
// Release every touch to avoid sticky points
for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
@@ -337,15 +332,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
alt_mem = false;
control_mem = false;
shift_mem = false;
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
- RECT clipRect;
- GetClientRect(hWnd, &clipRect);
- ClientToScreen(hWnd, (POINT *)&clipRect.left);
- ClientToScreen(hWnd, (POINT *)&clipRect.right);
- ClipCursor(&clipRect);
- SetCapture(hWnd);
- }
- } else {
+ } else { // WM_INACTIVE
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
alt_mem = false;
};
@@ -705,12 +692,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) {
if (mb->is_pressed()) {
- if (++pressrc > 0)
+ if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED)
SetCapture(hWnd);
} else {
if (--pressrc <= 0) {
- ReleaseCapture();
+ if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ ReleaseCapture();
+ }
pressrc = 0;
}
}
@@ -763,7 +752,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
RECT r;
GetWindowRect(hWnd, &r);
- dib_size = Size2(r.right - r.left, r.bottom - r.top);
+ dib_size = Size2i(r.right - r.left, r.bottom - r.top);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
@@ -773,7 +762,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = dib_size.x, dib_size.y * 4;
+ bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
SelectObject(hDC_dib, hBitmap);
@@ -1050,7 +1039,6 @@ static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Defau
UINT x = 0, y = 0;
HRESULT hr = E_FAIL;
- bool bSet = false;
if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) {
hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y);
if (SUCCEEDED(hr) && (x > 0) && (y > 0)) {
@@ -1204,7 +1192,14 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
- char *windowid = getenv("GODOT_WINDOWID");
+ char *windowid;
+#ifdef MINGW_ENABLED
+ windowid = getenv("GODOT_WINDOWID");
+#else
+ size_t len;
+ _dupenv_s(&windowid, &len, "GODOT_WINDOWID");
+#endif
+
if (windowid) {
// strtoull on mingw
@@ -1213,6 +1208,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
#else
hWnd = (HWND)_strtoui64(windowid, NULL, 0);
#endif
+ free(windowid);
SetLastError(0);
user_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)(WNDPROC)::WndProc);
@@ -1221,7 +1217,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
printf("Error setting WNDPROC: %li\n", le);
};
- LONG_PTR proc = GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+ GetWindowLongPtr(hWnd, GWLP_WNDPROC);
RECT rect;
if (!GetClientRect(hWnd, &rect)) {
@@ -1327,24 +1323,9 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
visual_server = memnew(VisualServerRaster);
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
-
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
- /*
- DEVMODE dmScreenSettings; // Device Mode
- memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
- dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
- dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
- dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
- dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
- dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
- if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
-
-
-
-
- */
visual_server->init();
input = memnew(InputDefault);
@@ -1527,18 +1508,27 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) {
if (mouse_mode == p_mode)
return;
+
+ _set_mouse_mode_impl(p_mode);
+
mouse_mode = p_mode;
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
+}
+
+void OS_Windows::_set_mouse_mode_impl(MouseMode p_mode) {
+
+ if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED) {
RECT clipRect;
GetClientRect(hWnd, &clipRect);
ClientToScreen(hWnd, (POINT *)&clipRect.left);
ClientToScreen(hWnd, (POINT *)&clipRect.right);
ClipCursor(&clipRect);
- center = Point2i(video_mode.width / 2, video_mode.height / 2);
- POINT pos = { (int)center.x, (int)center.y };
- ClientToScreen(hWnd, &pos);
- if (mouse_mode == MOUSE_MODE_CAPTURED)
+ if (p_mode == MOUSE_MODE_CAPTURED) {
+ center = Point2i(video_mode.width / 2, video_mode.height / 2);
+ POINT pos = { (int)center.x, (int)center.y };
+ ClientToScreen(hWnd, &pos);
SetCursorPos(pos.x, pos.y);
+ SetCapture(hWnd);
+ }
} else {
ReleaseCapture();
ClipCursor(NULL);
@@ -1552,7 +1542,6 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) {
set_cursor_shape(c);
}
}
-
OS_Windows::MouseMode OS_Windows::get_mouse_mode() const {
return mouse_mode;
@@ -1720,14 +1709,18 @@ void OS_Windows::set_window_position(const Point2 &p_position) {
Size2 OS_Windows::get_window_size() const {
RECT r;
- GetClientRect(hWnd, &r);
- return Vector2(r.right - r.left, r.bottom - r.top);
+ if (GetClientRect(hWnd, &r)) { // Only area inside of window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
}
Size2 OS_Windows::get_real_window_size() const {
RECT r;
- GetWindowRect(hWnd, &r);
- return Vector2(r.right - r.left, r.bottom - r.top);
+ if (GetWindowRect(hWnd, &r)) { // Includes area of the window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
}
void OS_Windows::set_window_size(const Size2 p_size) {
@@ -2266,7 +2259,6 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap
ERR_FAIL_COND(!image.is_valid());
UINT image_size = texture_size.width * texture_size.height;
- UINT size = sizeof(UINT) * image_size;
// Create the BITMAP with alpha channel
COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
@@ -2546,7 +2538,16 @@ void OS_Windows::set_icon(const Ref<Image> &p_icon) {
bool OS_Windows::has_environment(const String &p_var) const {
+#ifdef MINGW_ENABLED
return _wgetenv(p_var.c_str()) != NULL;
+#else
+ wchar_t *env;
+ size_t len;
+ _wdupenv_s(&env, &len, p_var.c_str());
+ const bool has_env = env != NULL;
+ free(env);
+ return has_env;
+#endif
};
String OS_Windows::get_environment(const String &p_var) const {
@@ -2729,11 +2730,6 @@ void OS_Windows::run() {
main_loop->init();
- uint64_t last_ticks = get_ticks_usec();
-
- int frames = 0;
- uint64_t frame = 0;
-
while (!force_quit) {
process_events(); // get rid of pending events
@@ -2926,7 +2922,7 @@ bool OS_Windows::is_disable_crash_handler() const {
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
WCHAR *from = new WCHAR[p_path.length() + 2];
- wcscpy(from, p_path.c_str());
+ wcscpy_s(from, p_path.length() + 1, p_path.c_str());
from[p_path.length() + 1] = 0;
sf.hwnd = hWnd;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 01e1c51ca5..6aadd6994c 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -157,6 +157,8 @@ class OS_Windows : public OS {
void _update_window_style(bool repaint = true);
+ void _set_mouse_mode_impl(MouseMode p_mode);
+
// functions used by main to initialize/deinitialize the OS
protected:
virtual int get_current_video_driver() const;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index ee59e9b5a1..e257a20bdd 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -149,6 +149,18 @@ def configure(env):
env.Append(CCFLAGS=['-pipe'])
env.Append(LINKFLAGS=['-pipe'])
+ # Check for gcc version > 5 before adding -no-pie
+ import re
+ import subprocess
+ proc = subprocess.Popen([env['CXX'], '--version'], stdout=subprocess.PIPE)
+ (stdout, _) = proc.communicate()
+ match = re.search('[0-9][0-9.]*', stdout)
+ if match is not None:
+ version = match.group().split('.')
+ if (version[0] > '5'):
+ env.Append(CCFLAGS=['-fpie'])
+ env.Append(LINKFLAGS=['-no-pie'])
+
## Dependencies
env.ParseConfig('pkg-config x11 --cflags --libs')
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 7c4c8f0eff..2ab7b835b6 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -267,6 +267,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
// maybe contextgl wants to be in charge of creating the window
#if defined(OPENGL_ENABLED)
+ // Set DRI_PRIME if not set. This means that Godot should default to a higher-power GPU if it exists.
+ // Note: Due to the final '0' parameter to setenv any existing DRI_PRIME environment variables will not
+ // be overwritten.
+ setenv("DRI_PRIME", "1", 0);
ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_3_0_COMPATIBLE;
@@ -342,12 +346,12 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
context_gl->set_use_vsync(current_videomode.use_vsync);
#endif
- visual_server = memnew(VisualServerRaster);
+ visual_server = memnew(VisualServerRaster);
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
-
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
+
if (current_videomode.maximized) {
current_videomode.maximized = false;
set_window_maximized(true);
@@ -2095,7 +2099,7 @@ void OS_X11::process_xevents() {
last_timestamp = event.xkey.time;
// key event is a little complex, so
- // it will be handled in it's own function.
+ // it will be handled in its own function.
handle_key_event((XKeyEvent *)&event);
} break;
case SelectionRequest: {
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 8a5910c10e..b31bb39c0d 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -312,12 +312,12 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
- ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
- ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
}
SpriteFrames::SpriteFrames() {
@@ -693,15 +693,15 @@ void AnimatedSprite::_bind_methods() {
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("animation_finished"));
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
}
AnimatedSprite::AnimatedSprite() {
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index c375374dce..48537f3cfc 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -664,19 +664,19 @@ void Area2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
ADD_GROUP("Collision", "collision_");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 788a39d05d..cc297d742d 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -710,7 +710,7 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin_drawing_enabled", "margin_drawing_enabled"), &Camera2D::set_margin_drawing_enabled);
ClassDB::bind_method(D_METHOD("is_margin_drawing_enabled"), &Camera2D::is_margin_drawing_enabled);
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current");
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index fab0b7d433..7c734d6af5 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -44,12 +44,19 @@
Mutex *CanvasItemMaterial::material_mutex = NULL;
SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials;
Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
+CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = NULL;
void CanvasItemMaterial::init_shaders() {
#ifndef NO_THREADS
material_mutex = Mutex::create();
#endif
+
+ shader_names = memnew(ShaderNames);
+
+ shader_names->particles_anim_h_frames = "particles_anim_h_frames";
+ shader_names->particles_anim_v_frames = "particles_anim_v_frames";
+ shader_names->particles_anim_loop = "particles_anim_loop";
}
void CanvasItemMaterial::finish_shaders() {
@@ -102,7 +109,37 @@ void CanvasItemMaterial::_update_shader() {
case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
}
- code += ";\n"; //that's it.
+
+ code += ";\n";
+
+ if (particles_animation) {
+
+ code += "uniform int particles_anim_h_frames;\n";
+ code += "uniform int particles_anim_v_frames;\n";
+ code += "uniform bool particles_anim_loop;\n";
+
+ code += "void vertex() {\n";
+
+ code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
+ code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
+
+ code += "\tVERTEX.xy /= TEXTURE_PIXEL_SIZE * vec2(h_frames, v_frames);\n";
+
+ code += "\tint total_frames = particles_anim_h_frames * particles_anim_v_frames;\n";
+ code += "\tint frame = int(float(total_frames) * INSTANCE_CUSTOM.z);\n";
+ code += "\tif (particles_anim_loop) {\n";
+ code += "\t\tframe = abs(frame) % total_frames;\n";
+ code += "\t} else {\n";
+ code += "\t\tframe = clamp(frame, 0, total_frames - 1);\n";
+ code += "\t}\n";
+
+ code += "\tfloat frame_w = 1.0 / h_frames;\n";
+ code += "\tfloat frame_h = 1.0 / v_frames;\n";
+ code += "\tUV.x = UV.x * frame_w + frame_w * float(frame % particles_anim_h_frames);\n";
+ code += "\tUV.y = UV.y * frame_h + frame_h * float(frame / particles_anim_v_frames);\n";
+
+ code += "}\n";
+ }
ShaderData shader_data;
shader_data.shader = VS::get_singleton()->shader_create();
@@ -177,7 +214,52 @@ CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
return light_mode;
}
+void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
+ particles_animation = p_particles_anim;
+ _queue_shader_change();
+ _change_notify();
+}
+
+bool CanvasItemMaterial::get_particles_animation() const {
+ return particles_animation;
+}
+
+void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
+
+ particles_anim_h_frames = p_frames;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_h_frames() const {
+
+ return particles_anim_h_frames;
+}
+void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
+
+ particles_anim_v_frames = p_frames;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_v_frames() const {
+
+ return particles_anim_v_frames;
+}
+
+void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
+
+ particles_anim_loop = p_loop;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
+}
+
+bool CanvasItemMaterial::get_particles_anim_loop() const {
+
+ return particles_anim_loop;
+}
+
void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
+ if (property.name.begins_with("particles_anim_") && !particles_animation) {
+ property.usage = 0;
+ }
}
RID CanvasItemMaterial::get_shader_rid() const {
@@ -199,8 +281,25 @@ void CanvasItemMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
+ ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
+ ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
@@ -218,6 +317,11 @@ CanvasItemMaterial::CanvasItemMaterial() :
blend_mode = BLEND_MODE_MIX;
light_mode = LIGHT_MODE_NORMAL;
+ particles_animation = false;
+
+ set_particles_anim_h_frames(1);
+ set_particles_anim_v_frames(1);
+ set_particles_anim_loop(false);
current_key.key = 0;
current_key.invalid_key = 1;
@@ -861,6 +965,15 @@ RID CanvasItem::get_canvas() const {
return get_viewport()->find_world_2d()->get_canvas();
}
+ObjectID CanvasItem::get_canvas_layer_instance_id() const {
+
+ if (canvas_layer) {
+ return canvas_layer->get_instance_id();
+ } else {
+ return 0;
+ }
+}
+
CanvasItem *CanvasItem::get_toplevel() const {
CanvasItem *ci = const_cast<CanvasItem *>(this);
@@ -1080,16 +1193,16 @@ void CanvasItem::_bind_methods() {
BIND_VMETHOD(MethodInfo("_draw"));
ADD_GROUP("Visibility", "");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
- ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
- ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Material", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
//exporting these things doesn't really make much sense i think
// ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
// ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 36a0e4039a..9fe7cb1e00 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -70,6 +70,7 @@ private:
struct {
uint32_t blend_mode : 4;
uint32_t light_mode : 4;
+ uint32_t particles_animation : 1;
uint32_t invalid_key : 1;
};
@@ -80,6 +81,14 @@ private:
}
};
+ struct ShaderNames {
+ StringName particles_anim_h_frames;
+ StringName particles_anim_v_frames;
+ StringName particles_anim_loop;
+ };
+
+ static ShaderNames *shader_names;
+
struct ShaderData {
RID shader;
int users;
@@ -95,6 +104,7 @@ private:
mk.key = 0;
mk.blend_mode = blend_mode;
mk.light_mode = light_mode;
+ mk.particles_animation = particles_animation;
return mk;
}
@@ -108,6 +118,11 @@ private:
BlendMode blend_mode;
LightMode light_mode;
+ bool particles_animation;
+
+ int particles_anim_h_frames;
+ int particles_anim_v_frames;
+ bool particles_anim_loop;
protected:
static void _bind_methods();
@@ -120,6 +135,17 @@ public:
void set_light_mode(LightMode p_light_mode);
LightMode get_light_mode() const;
+ void set_particles_animation(bool p_particles_anim);
+ bool get_particles_animation() const;
+
+ void set_particles_anim_h_frames(int p_frames);
+ int get_particles_anim_h_frames() const;
+ void set_particles_anim_v_frames(int p_frames);
+ int get_particles_anim_v_frames() const;
+
+ void set_particles_anim_loop(bool p_frames);
+ bool get_particles_anim_loop() const;
+
static void init_shaders();
static void finish_shaders();
static void flush_changes();
@@ -326,6 +352,7 @@ public:
Rect2 get_viewport_rect() const;
RID get_viewport_rid() const;
RID get_canvas() const;
+ ObjectID get_canvas_layer_instance_id() const;
Ref<World2D> get_world_2d() const;
virtual void set_material(const Ref<Material> &p_material);
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 7ade74e8a6..738f7ddf59 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -58,6 +58,14 @@ void CollisionObject2D::_notification(int p_what) {
//get space
}
+ case NOTIFICATION_ENTER_CANVAS: {
+
+ if (area)
+ Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+ else
+ Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+ }
+
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
@@ -86,6 +94,14 @@ void CollisionObject2D::_notification(int p_what) {
Physics2DServer::get_singleton()->body_set_space(rid, RID());
} break;
+
+ case NOTIFICATION_EXIT_CANVAS: {
+
+ if (area)
+ Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0);
+ else
+ Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0);
+ }
}
}
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 410b27c691..07bbbd9321 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -325,8 +325,8 @@ void CollisionPolygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
BIND_ENUM_CONSTANT(BUILD_SOLIDS);
BIND_ENUM_CONSTANT(BUILD_SEGMENTS);
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index cb9c8ecf95..d3e25d541a 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -229,9 +229,9 @@ void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape2D::_shape_changed);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
}
CollisionShape2D::CollisionShape2D() {
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index e6dcd643be..bc2bd9a1c5 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -29,8 +29,9 @@
/*************************************************************************/
#include "cpu_particles_2d.h"
-
-//#include "scene/resources/particles_material.h"
+#include "particles_2d.h"
+#include "scene/2d/canvas_item.h"
+#include "scene/resources/particles_material.h"
#include "servers/visual_server.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
@@ -152,19 +153,13 @@ CPUParticles2D::DrawOrder CPUParticles2D::get_draw_order() const {
return draw_order;
}
-void CPUParticles2D::_update_mesh_texture() {
+void CPUParticles2D::_generate_mesh_texture() {
- Size2 tex_size;
- if (texture.is_valid()) {
- tex_size = texture->get_size();
- } else {
- tex_size = Size2(1, 1);
- }
PoolVector<Vector2> vertices;
- vertices.push_back(-tex_size * 0.5);
- vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0));
- vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y));
- vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y));
+ vertices.push_back(Vector2(-0.5, -0.5));
+ vertices.push_back(Vector2(0.5, -0.5));
+ vertices.push_back(Vector2(0.5, 0.5));
+ vertices.push_back(Vector2(-0.5, 0.5));
PoolVector<Vector2> uvs;
uvs.push_back(Vector2(0, 0));
uvs.push_back(Vector2(1, 0));
@@ -198,7 +193,6 @@ void CPUParticles2D::set_texture(const Ref<Texture> &p_texture) {
texture = p_texture;
update();
- _update_mesh_texture();
}
Ref<Texture> CPUParticles2D::get_texture() const {
@@ -237,6 +231,14 @@ String CPUParticles2D::get_configuration_warning() const {
String warnings;
+ CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
+
+ if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
+ if (warnings != String())
+ warnings += "\n";
+ warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+ }
+
return warnings;
}
@@ -396,6 +398,7 @@ bool CPUParticles2D::get_particle_flag(Flags p_flag) const {
void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
emission_shape = p_shape;
+ _change_notify();
}
void CPUParticles2D::set_emission_sphere_radius(float p_radius) {
@@ -479,6 +482,15 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = 0;
}
+
+ if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+
/*
if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
property.usage = 0;
@@ -531,7 +543,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
if (!local_coords) {
emission_xform = get_global_transform();
velocity_xform = emission_xform;
- emission_xform[2] = Vector2();
+ velocity_xform[2] = Vector2();
}
for (int i = 0; i < pcount; i++) {
@@ -618,9 +630,12 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
- p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[1] = 0.0; //phase
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.rotation = Math::deg2rad(base_angle);
+
+ p.custom[0] = 0.0; // unused
+ p.custom[1] = 0.0; // phase [0..1]
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
+ p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
p.base_color = Color(1, 1, 1, 1);
@@ -767,14 +782,9 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
- p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
- if (flags[FLAG_ANIM_LOOP]) {
- p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
-
- } else {
- p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
- }
+ p.rotation = Math::deg2rad(base_angle); //angle
+ float animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
+ p.custom[2] = animation_phase;
}
//apply color
//apply hue rotation
@@ -825,8 +835,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
} else {
- p.transform.elements[0] = Vector2(Math::cos(p.custom[0]), -Math::sin(p.custom[0]));
- p.transform.elements[1] = Vector2(Math::sin(p.custom[0]), Math::cos(p.custom[0]));
+ p.transform.elements[0] = Vector2(Math::cos(p.rotation), -Math::sin(p.rotation));
+ p.transform.elements[1] = Vector2(Math::sin(p.rotation), Math::cos(p.rotation));
}
//scale by scale
@@ -1058,8 +1068,7 @@ void CPUParticles2D::_notification(int p_what) {
}
void CPUParticles2D::convert_from_particles(Node *p_particles) {
-#if 0
- Particles *particles = Object::cast_to<Particles>(p_particles);
+ Particles2D *particles = Object::cast_to<Particles2D>(p_particles);
ERR_FAIL_COND(!particles);
set_emitting(particles->is_emitting());
@@ -1074,7 +1083,12 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_fractional_delta(particles->get_fractional_delta());
set_speed_scale(particles->get_speed_scale());
set_draw_order(DrawOrder(particles->get_draw_order()));
- set_mesh(particles->get_draw_pass_mesh(0));
+ set_texture(particles->get_texture());
+
+ Ref<Material> mat = particles->get_material();
+ if (mat.is_valid()) {
+ set_material(mat);
+ }
Ref<ParticlesMaterial> material = particles->get_process_material();
if (material.is_null())
@@ -1091,15 +1105,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
}
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
- set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
- set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
- set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
- set_emission_rect_extents(material->get_emission_rect_extents());
+ Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
+ set_emission_rect_extents(rect_extents);
- set_gravity(material->get_gravity());
+ Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
+ set_gravity(gravity);
#define CONVERT_PARAM(m_param) \
set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
@@ -1123,7 +1136,6 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
CONVERT_PARAM(PARAM_ANIM_OFFSET);
#undef CONVERT_PARAM
-#endif
}
void CPUParticles2D::_bind_methods() {
@@ -1253,7 +1265,7 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
/*
@@ -1301,7 +1313,6 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
@@ -1385,7 +1396,7 @@ CPUParticles2D::CPUParticles2D() {
update_mutex = Mutex::create();
#endif
- _update_mesh_texture();
+ _generate_mesh_texture();
}
CPUParticles2D::~CPUParticles2D() {
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 4f51eb1062..15b7642b5e 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -68,7 +68,6 @@ public:
enum Flags {
FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ANIM_LOOP,
FLAG_MAX
};
@@ -87,6 +86,7 @@ private:
Transform2D transform;
Color color;
float custom[4];
+ float rotation;
Vector2 velocity;
bool active;
float angle_rand;
@@ -168,7 +168,6 @@ private:
PoolVector<Color> emission_colors;
int emission_point_count;
- bool anim_loop;
Vector2 gravity;
void _particles_process(float p_delta);
@@ -178,7 +177,7 @@ private:
void _update_render_thread();
- void _update_mesh_texture();
+ void _generate_mesh_texture();
protected:
static void _bind_methods();
@@ -223,6 +222,15 @@ public:
void set_texture(const Ref<Texture> &p_texture);
Ref<Texture> get_texture() const;
+ void set_h_frames(int p_frames);
+ int get_h_frames();
+
+ void set_v_frames(int p_frames);
+ int get_v_frames();
+
+ void set_loop_animation(bool p_loop);
+ bool get_loop_animation() const;
+
void set_normalmap(const Ref<Texture> &p_normalmap);
Ref<Texture> get_normalmap() const;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index e164f0ca75..6faf8c2855 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -347,13 +347,13 @@ void Line2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color");
ADD_GROUP("Fill", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile,Stretch"), "set_texture_mode", "get_texture_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile,Stretch"), "set_texture_mode", "get_texture_mode");
ADD_GROUP("Capping", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode");
ADD_GROUP("Border", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "sharp_limit"), "set_sharp_limit", "get_sharp_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision");
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index a3f1b25e05..d5e8a33805 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -294,7 +294,6 @@ void LineBuilder::build() {
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx1 = current_distance1 / (width * tile_aspect);
} else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
- uvx0 = current_distance0 / total_distance;
uvx1 = current_distance1 / total_distance;
}
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index 9f21fe1a1f..46777665d8 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -51,8 +51,8 @@ void MeshInstance2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_normal_map"), &MeshInstance2D::get_normal_map);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
}
void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) {
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 29065a89b3..2d9bbfe657 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -204,12 +204,6 @@ Size2 Node2D::get_scale() const {
return _scale;
}
-void Node2D::_notification(int p_what) {
-
- switch (p_what) {
- }
-}
-
Transform2D Node2D::get_transform() const {
return _mat;
@@ -441,10 +435,10 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
- ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
@@ -454,8 +448,8 @@ void Node2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_GROUP("Z Index", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
}
Node2D::Node2D() {
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 725686cdf8..924a84fb88 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -52,8 +52,6 @@ class Node2D : public CanvasItem {
void _update_xform_values();
protected:
- void _notification(int p_what);
-
static void _bind_methods();
public:
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 7e824cdf75..9c01d81c11 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -257,30 +257,6 @@ Ref<Texture> Particles2D::get_normal_map() const {
void Particles2D::_validate_property(PropertyInfo &property) const {
}
-void Particles2D::set_v_frames(int p_count) {
-
- ERR_FAIL_COND(p_count < 1);
- v_frames = p_count;
- update();
-}
-
-int Particles2D::get_v_frames() const {
-
- return v_frames;
-}
-
-void Particles2D::set_h_frames(int p_count) {
-
- ERR_FAIL_COND(p_count < 1);
- h_frames = p_count;
- update();
-}
-
-int Particles2D::get_h_frames() const {
-
- return h_frames;
-}
-
void Particles2D::restart() {
VS::get_singleton()->particles_restart(particles);
}
@@ -296,7 +272,7 @@ void Particles2D::_notification(int p_what) {
if (normal_map.is_valid())
normal_rid = normal_map->get_rid();
- VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames);
+ VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
@@ -361,12 +337,6 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
- ClassDB::bind_method(D_METHOD("set_v_frames", "frames"), &Particles2D::set_v_frames);
- ClassDB::bind_method(D_METHOD("get_v_frames"), &Particles2D::get_v_frames);
-
- ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
- ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
-
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
@@ -389,8 +359,6 @@ void Particles2D::_bind_methods() {
ADD_GROUP("Textures", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "h_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_h_frames", "get_h_frames");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "v_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_v_frames", "get_v_frames");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
@@ -413,8 +381,6 @@ Particles2D::Particles2D() {
set_use_local_coordinates(true);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
- h_frames = 1;
- v_frames = 1;
}
Particles2D::~Particles2D() {
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index af673841b1..6d52f8b28e 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -59,8 +59,6 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
- int v_frames;
- int h_frames;
Ref<Material> process_material;
@@ -118,12 +116,6 @@ public:
virtual String get_configuration_warning() const;
- void set_v_frames(int p_count);
- int get_v_frames() const;
-
- void set_h_frames(int p_count);
- int get_h_frames() const;
-
void restart();
Rect2 capture_rect() const;
Particles2D();
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index cdb208e6cd..4276918f53 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -63,6 +63,10 @@ bool Path2D::_edit_use_rect() const {
bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ if (curve.is_null()) {
+ return false;
+ }
+
for (int i = 0; i < curve->get_point_count(); i++) {
Vector2 s[2];
s[0] = curve->get_point_position(i);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 75221cf2af..4a01644c5b 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -32,8 +32,11 @@
#include "core/core_string_names.h"
#include "core/engine.h"
+#include "core/list.h"
#include "core/math/math_funcs.h"
#include "core/method_bind_ext.gen.inc"
+#include "core/object.h"
+#include "core/rid.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_notification(int p_what) {
@@ -65,6 +68,8 @@ void PhysicsBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody2D::_set_layers);
ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_layers);
+
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", 0), "_set_layers", "_get_layers"); //for backwards compat
@@ -134,6 +139,20 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) :
set_pickable(false);
}
+Array PhysicsBody2D::get_collision_exceptions() {
+ List<RID> exceptions;
+ Physics2DServer::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
+ Array ret;
+ for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
+ RID body = E->get();
+ ObjectID instance_id = Physics2DServer::get_singleton()->body_get_object_instance_id(body);
+ Object *obj = ObjectDB::get_instance(instance_id);
+ PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(obj);
+ ret.append(physics_body);
+ }
+ return ret;
+}
+
void PhysicsBody2D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
@@ -280,10 +299,10 @@ void StaticBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
#endif // DISABLE_DEPRECATED
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
}
StaticBody2D::StaticBody2D() :
@@ -1042,10 +1061,10 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "inertia", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", 0), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
#endif // DISABLE_DEPRECATED
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode");
@@ -1060,8 +1079,8 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "-1,128,0.01"), "set_angular_damp", "get_angular_damp");
ADD_GROUP("Applied Forces", "applied_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "applied_torque"), "set_applied_torque", "get_applied_torque");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "applied_torque"), "set_applied_torque", "get_applied_torque");
ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 02d56d8474..c7b42add84 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -67,6 +67,7 @@ public:
void set_collision_layer_bit(int p_bit, bool p_value);
bool get_collision_layer_bit(int p_bit) const;
+ Array get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index 04e199a21b..f4e6e2bdbb 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -435,22 +435,22 @@ void Sprite::_bind_methods() {
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("texture_changed"));
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
ADD_GROUP("Offset", "");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
ADD_GROUP("Animation", "");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
ADD_GROUP("Region", "region_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
- ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled");
}
Sprite::Sprite() {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index a60ce47f5c..8fe65f53a9 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -593,7 +593,7 @@ void TileMap::update_dirty_quadrants() {
if (quadrant_order_dirty) {
- int index = -0x80000000; //always must be drawn below children
+ int index = -(int64_t)0x80000000; //always must be drawn below children
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
@@ -1114,6 +1114,8 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) {
*/
set_cell(x, y, v, flip_h, flip_v, transpose, Vector2(coord_x, coord_y));
}
+
+ format = FORMAT_2;
}
PoolVector<int> TileMap::_get_tile_data() const {
@@ -1403,7 +1405,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "format") {
- r_ret = FORMAT_2;
+ r_ret = format;
return true;
} else if (p_name == "tile_data") {
r_ret = _get_tile_data();
@@ -1445,6 +1447,11 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
default: {}
}
+ // Account for precision errors on the border (GH-23250).
+ // 0.00005 is 5*CMP_EPSILON, results would start being unpredictible if
+ // cell size is > 15,000, but we can hardly have more precision anyway with
+ // floating point.
+ ret += Vector2(0.00005, 0.00005);
return ret.floor();
}
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 4bff26a200..2dc500f7ab 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -38,14 +38,14 @@
void ARVRCamera::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- // need to find our ARVROrigin parent and let it know we're it's camera!
+ // need to find our ARVROrigin parent and let it know we're its camera!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin != NULL) {
origin->set_tracked_camera(this);
}
}; break;
case NOTIFICATION_EXIT_TREE: {
- // need to find our ARVROrigin parent and let it know we're no longer it's camera!
+ // need to find our ARVROrigin parent and let it know we're no longer its camera!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin != NULL) {
origin->clear_tracked_camera_if(this);
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 67fb658562..d6690676cc 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -62,7 +62,7 @@ public:
};
/*
- ARVRController is a helper node that automatically updates it's position based on tracker data.
+ ARVRController is a helper node that automatically updates its position based on tracker data.
It must be a child node of our ARVROrigin node
*/
@@ -102,7 +102,7 @@ public:
};
/*
- ARVRAnchor is a helper node that automatically updates it's position based on anchor data, it represents a real world location.
+ ARVRAnchor is a helper node that automatically updates its position based on anchor data, it represents a real world location.
It must be a child node of our ARVROrigin node
*/
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 7ad43b722d..3046cad624 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -448,7 +448,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
//float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
- float center_val[3] = { 0.5, 0.25, 0.16666 };
+ float center_val[3] = { 0.5f, 0.25f, 0.16666f };
AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]);
if (attenuation < 1.0) {
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 35a2049bda..5b3229e931 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -781,12 +781,6 @@ void CPUParticles::_particles_process(float p_delta) {
base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
- if (flags[FLAG_ANIM_LOOP]) {
- p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
-
- } else {
- p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
- }
}
//apply color
//apply hue rotation
@@ -1151,7 +1145,6 @@ void CPUParticles::convert_from_particles(Node *p_particles) {
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
- set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
@@ -1309,7 +1302,7 @@ void CPUParticles::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
/*
@@ -1357,7 +1350,6 @@ void CPUParticles::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 77a144b70b..2e83924dfc 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -70,7 +70,6 @@ public:
FLAG_ALIGN_Y_TO_VELOCITY,
FLAG_ROTATE_Y,
FLAG_DISABLE_Z,
- FLAG_ANIM_LOOP,
FLAG_MAX
};
@@ -170,7 +169,6 @@ private:
PoolVector<Color> emission_colors;
int emission_point_count;
- bool anim_loop;
Vector3 gravity;
void _particles_process(float p_delta);
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 7e1d60ab8e..11d61315ba 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -163,11 +163,6 @@ void Light::_update_visibility() {
if (!is_inside_tree())
return;
- // FIXME: Since the call to VS::instance_light_set_enabled was disabled below,
- // the whole logic became pointless so editor_ok triggers unused variable warnings.
- // Commenting out for now but this should be fixed/reimplemented so that editor_only
- // works as expected (GH-17989).
- /*
bool editor_ok = true;
#ifdef TOOLS_ENABLED
@@ -184,8 +179,8 @@ void Light::_update_visibility() {
}
#endif
- //VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible_in_tree() && editor_ok);
- */
+ VS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree() && editor_ok);
+
_change_notify("geometry/visible");
}
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 4cbf6f2de3..cf0317cd58 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -253,6 +253,11 @@ void MeshInstance::_notification(int p_what) {
}
}
+int MeshInstance::get_surface_material_count() const {
+
+ return materials.size();
+}
+
void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_material) {
ERR_FAIL_INDEX(p_surface, materials.size());
@@ -359,6 +364,7 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance::get_surface_material);
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 0dfec538f9..0b5b4b9e7b 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -76,6 +76,7 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
+ int get_surface_material_count() const;
void set_surface_material(int p_surface, const Ref<Material> &p_material);
Ref<Material> get_surface_material(int p_surface) const;
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index e37efa0e8a..339a434a6e 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -43,6 +43,16 @@ void Path::_curve_changed() {
if (is_inside_tree()) {
emit_signal("curve_changed");
}
+
+ // update the configuration warnings of all children of type OrientedPathFollows
+ if (is_inside_tree()) {
+ for (int i = 0; i < get_child_count(); i++) {
+ OrientedPathFollow *child = Object::cast_to<OrientedPathFollow>(get_child(i));
+ if (child) {
+ child->update_configuration_warning();
+ }
+ }
+ }
}
void Path::set_curve(const Ref<Curve3D> &p_curve) {
@@ -207,6 +217,18 @@ void PathFollow::_validate_property(PropertyInfo &property) const {
}
}
+String PathFollow::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!Object::cast_to<Path>(get_parent())) {
+ return TTR("PathFollow only works when set as a child of a Path node.");
+ }
+
+ return String();
+}
+
void PathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow::set_offset);
@@ -444,6 +466,23 @@ void OrientedPathFollow::_validate_property(PropertyInfo &property) const {
}
}
+String OrientedPathFollow::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!Object::cast_to<Path>(get_parent())) {
+ return TTR("OrientedPathFollow only works when set as a child of a Path node.");
+ } else {
+ Path *path = Object::cast_to<Path>(get_parent());
+ if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled()) {
+ return TTR("OrientedPathFollow requires up vectors enabled in its parent Path.");
+ }
+ }
+
+ return String();
+}
+
void OrientedPathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &OrientedPathFollow::set_offset);
diff --git a/scene/3d/path.h b/scene/3d/path.h
index f73bf17dfe..beb37d9714 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -106,6 +106,8 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
+ String get_configuration_warning() const;
+
PathFollow();
};
@@ -151,6 +153,8 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
+ String get_configuration_warning() const;
+
OrientedPathFollow();
};
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 879e019503..d18986739e 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -32,7 +32,10 @@
#include "core/core_string_names.h"
#include "core/engine.h"
+#include "core/list.h"
#include "core/method_bind_ext.gen.inc"
+#include "core/object.h"
+#include "core/rid.h"
#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
@@ -108,6 +111,20 @@ bool PhysicsBody::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
+Array PhysicsBody::get_collision_exceptions() {
+ List<RID> exceptions;
+ PhysicsServer::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
+ Array ret;
+ for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
+ RID body = E->get();
+ ObjectID instance_id = PhysicsServer::get_singleton()->body_get_object_instance_id(body);
+ Object *obj = ObjectDB::get_instance(instance_id);
+ PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(obj);
+ ret.append(physics_body);
+ }
+ return ret;
+}
+
void PhysicsBody::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
@@ -289,14 +306,15 @@ void StaticBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics);
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
#endif // DISABLE_DEPRECATED
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
}
@@ -1006,10 +1024,10 @@ void RigidBody::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
#endif // DISABLE_DEPRECATED
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
@@ -2326,7 +2344,8 @@ void PhysicalBone::set_joint_type(JointType p_joint_type) {
if (p_joint_type == get_joint_type())
return;
- memdelete(joint_data);
+ if (joint_data)
+ memdelete(joint_data);
joint_data = NULL;
switch (p_joint_type) {
case JOINT_TYPE_PIN:
@@ -2526,7 +2545,8 @@ PhysicalBone::PhysicalBone() :
}
PhysicalBone::~PhysicalBone() {
- memdelete(joint_data);
+ if (joint_data)
+ memdelete(joint_data);
}
void PhysicalBone::update_bone_id() {
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 080ad61e00..20d948b6eb 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -69,6 +69,7 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+ Array get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index 4ebc941ebc..1e730d0b3d 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -29,8 +29,12 @@
/*************************************************************************/
#include "soft_body.h"
+#include "core/list.h"
+#include "core/object.h"
#include "core/os/os.h"
+#include "core/rid.h"
#include "scene/3d/collision_object.h"
+#include "scene/3d/physics_body.h"
#include "scene/3d/skeleton.h"
#include "servers/physics_server.h"
@@ -335,6 +339,7 @@ void SoftBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with);
@@ -547,6 +552,20 @@ PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() {
return pinned_points;
}
+Array SoftBody::get_collision_exceptions() {
+ List<RID> exceptions;
+ PhysicsServer::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
+ Array ret;
+ for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
+ RID body = E->get();
+ ObjectID instance_id = PhysicsServer::get_singleton()->body_get_object_instance_id(body);
+ Object *obj = ObjectDB::get_instance(instance_id);
+ PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(obj);
+ ret.append(physics_body);
+ }
+ return ret;
+}
+
void SoftBody::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
index ee3d8d87cf..b1e699e839 100644
--- a/scene/3d/soft_body.h
+++ b/scene/3d/soft_body.h
@@ -166,6 +166,7 @@ public:
void set_drag_coefficient(real_t p_drag_coefficient);
real_t get_drag_coefficient();
+ Array get_collision_exceptions();
void add_collision_exception_with(Node *p_node);
void remove_collision_exception_with(Node *p_node);
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index fcc908cdc6..dc09392713 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -800,15 +800,15 @@ void Spatial::_bind_methods() {
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
ADD_GROUP("Transform", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_GROUP("Matrix", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_GROUP("Visibility", "");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
ADD_SIGNAL(MethodInfo("visibility_changed"));
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 774ee49af2..c6717b36ec 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -1078,10 +1078,10 @@ void AnimatedSprite3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("frame_changed"));
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
}
AnimatedSprite3D::AnimatedSprite3D() {
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index f9bd905181..0eccbbc8f9 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -261,7 +261,7 @@ static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3
void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
if (p_level == cell_subdiv - 1) {
- //plot the face by guessing it's albedo and emission value
+ //plot the face by guessing its albedo and emission value
//find best axis to map to, for scanning values
int closest_axis = 0;
@@ -1619,7 +1619,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3(-0.700629, -0.509037, 0.5),
Vector3(0.267617, -0.823639, 0.5)
};
- static const float weights[6] = { 0.25, 0.15, 0.15, 0.15, 0.15, 0.15 };
+ static const float weights[6] = { 0.25f, 0.15f, 0.15f, 0.15f, 0.15f, 0.15f };
//
cone_dirs = dirs;
cone_dir_count = 6;
@@ -1641,7 +1641,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3(0.19124006749743122, 0.39355745585016605, 0.8991883926788214),
Vector3(0.19124006749743122, -0.39355745585016605, 0.8991883926788214),
};
- static const float weights[10] = { 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.133333, 0.133333, 0.13333 };
+ static const float weights[10] = { 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.133333f, 0.133333f, 0.13333f };
cone_dirs = dirs;
cone_dir_count = 10;
cone_aperture = 0.404; // tan(angle) 45 degrees
@@ -1875,7 +1875,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
if (bake_mode == BAKE_MODE_RAY_TRACE) {
//blur
//gauss kernel, 7 step sigma 2
- static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 };
+ static const float gauss_kernel[4] = { 0.214607f, 0.189879f, 0.131514f, 0.071303f };
//horizontal pass
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index b85d4e541e..a08639089e 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -40,12 +40,11 @@ StringName AnimationNodeAnimation::get_animation() const {
return animation;
}
-float AnimationNodeAnimation::get_playback_time() const {
- return time;
-}
-
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
+void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
+}
void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
if (property.name == "animation" && get_editable_animation_list) {
@@ -70,6 +69,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
+ float time = get_parameter(this->time);
+
if (!ap->has_animation(animation)) {
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
@@ -86,6 +87,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
Ref<Animation> anim = ap->get_animation(animation);
+ float step;
+
if (p_seek) {
time = p_time;
step = 0;
@@ -109,6 +112,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
blend_animation(animation, time, step, p_seek, 1.0);
+ set_parameter(this->time, time);
+
return anim_size - time;
}
@@ -120,16 +125,13 @@ void AnimationNodeAnimation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation);
ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation);
- ClassDB::bind_method(D_METHOD("get_playback_time"), &AnimationNodeAnimation::get_playback_time);
-
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
}
AnimationNodeAnimation::AnimationNodeAnimation() {
last_version = 0;
skip = false;
- time = 0;
- step = 0;
+ time = "time";
}
////////////////////////////////////////////////////////
@@ -266,7 +268,6 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (do_start) {
remaining = os_rem;
- do_start = false;
}
if (!p_seek) {
@@ -770,8 +771,6 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
rem = blend_input(current, p_time, p_seek, 1.0 - blend, FILTER_IGNORE, false);
}
- switched = false;
-
if (p_seek) { // don't seek prev animation
blend_input(prev, 0, false, blend, FILTER_IGNORE, false);
time = p_time;
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 4ca11e464b..5adb7fd71a 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -38,10 +38,9 @@ class AnimationNodeAnimation : public AnimationRootNode {
GDCLASS(AnimationNodeAnimation, AnimationRootNode);
StringName animation;
+ StringName time;
uint64_t last_version;
- float time;
- float step;
bool skip;
protected:
@@ -50,6 +49,8 @@ protected:
static void _bind_methods();
public:
+ void get_parameter_list(List<PropertyInfo> *r_list) const;
+
static Vector<String> (*get_editable_animation_list)();
virtual String get_caption() const;
@@ -58,8 +59,6 @@ public:
void set_animation(const StringName &p_name);
StringName get_animation() const;
- float get_playback_time() const;
-
AnimationNodeAnimation();
};
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 5923ad7657..a7af3f687b 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -345,7 +345,6 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm,
len_current = sm->blend_node(current, sm->states[current].node, 0, true, 1.0, AnimationNode::FILTER_IGNORE, false);
pos_current = 0;
loops_current = 0;
- play_start = false;
}
if (!sm->states.has(current)) {
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
index 64af7efb16..1d9d048fe1 100644
--- a/scene/audio/audio_player.cpp
+++ b/scene/audio/audio_player.cpp
@@ -219,6 +219,7 @@ void AudioStreamPlayer::seek(float p_seconds) {
void AudioStreamPlayer::stop() {
if (stream_playback.is_valid()) {
+ stream_playback->stop();
active = false;
set_process_internal(false);
}
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 6dfaacc776..d37eb22c4d 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -533,11 +533,11 @@ void BaseButton::_bind_methods() {
ADD_SIGNAL(MethodInfo("button_up"));
ADD_SIGNAL(MethodInfo("button_down"));
ADD_SIGNAL(MethodInfo("toggled", PropertyInfo(Variant::BOOL, "button_pressed")));
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 2d17fb1391..621153b6de 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -274,10 +274,10 @@ void Button::_bind_methods() {
BIND_ENUM_CONSTANT(ALIGN_CENTER);
BIND_ENUM_CONSTANT(ALIGN_RIGHT);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_button_icon", "get_button_icon");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_button_icon", "get_button_icon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align");
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index e155d0ef86..bf1f2dd2e0 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2844,36 +2844,36 @@ void Control::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_BOTTOM);
ADD_GROUP("Margin", "margin_");
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "margin_top", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "margin_right", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_RIGHT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "margin_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_top", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_right", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_BOTTOM);
ADD_GROUP("Grow Direction", "grow_");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_h_grow_direction", "get_h_grow_direction");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_v_grow_direction", "get_v_grow_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_h_grow_direction", "get_h_grow_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_v_grow_direction", "get_v_grow_direction");
ADD_GROUP("Rect", "rect_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_size", "get_size");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees");
- ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
- ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
ADD_GROUP("Hint", "hint_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
ADD_GROUP("Focus", "focus_");
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
- ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next");
- ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
ADD_GROUP("Mouse", "mouse_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_filter", PROPERTY_HINT_ENUM, "Stop,Pass,Ignore"), "set_mouse_filter", "get_mouse_filter");
@@ -2882,9 +2882,9 @@ void Control::_bind_methods() {
ADD_GROUP("Size Flags", "size_flags_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_h_size_flags", "get_h_size_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_vertical", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_v_size_flags", "get_v_size_flags");
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_stretch_ratio", "get_stretch_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_stretch_ratio", "get_stretch_ratio");
ADD_GROUP("Theme", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
ADD_GROUP("", "");
BIND_ENUM_CONSTANT(FOCUS_NONE);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index e3a21eb10d..50511f6bbd 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -535,7 +535,7 @@ void AcceptDialog::_bind_methods() {
ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING, "action")));
ADD_GROUP("Dialog", "dialog");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok");
}
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 934b84ec0c..c13964d196 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -236,8 +236,8 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
//Snap to nearest point if holding shift
if (mm->get_shift()) {
- float snap_treshhold = 0.03;
- float smallest_ofs = snap_treshhold;
+ float snap_threshold = 0.03;
+ float smallest_ofs = snap_threshold;
bool found = false;
int nearest_point = 0;
for (int i = 0; i < points.size(); ++i) {
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index b4fd7484e9..b3bebc88ec 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -406,7 +406,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(to)->get_connection_input_color(E->get().to_port);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
emit_signal("disconnection_request", E->get().from, E->get().from_port, E->get().to, E->get().to_port);
to = get_node(String(connecting_from)); //maybe it was erased
@@ -427,7 +427,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconected = false;
+ just_disconnected = false;
return;
}
}
@@ -453,7 +453,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(fr)->get_connection_output_color(E->get().from_port);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
emit_signal("disconnection_request", E->get().from, E->get().from_port, E->get().to, E->get().to_port);
fr = get_node(String(connecting_from)); //maybe it was erased
@@ -474,7 +474,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
return;
}
@@ -544,7 +544,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
emit_signal("connection_request", from, from_slot, to, to_slot);
- } else if (!just_disconected) {
+ } else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);
@@ -1368,6 +1368,6 @@ GraphEdit::GraphEdit() {
zoom_hb->add_child(snap_amount);
setting_scroll_ofs = false;
- just_disconected = false;
+ just_disconnected = false;
set_clip_contents(true);
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 31a449eb59..71165e3dc9 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -94,7 +94,7 @@ private:
Vector2 connecting_to;
String connecting_target_to;
int connecting_target_index;
- bool just_disconected;
+ bool just_disconnected;
bool dragging;
bool just_selected;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 0d5fbee9ee..1669d62082 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -36,6 +36,7 @@ void ItemList::add_item(const String &p_item, const Ref<Texture> &p_texture, boo
Item item;
item.icon = p_texture;
+ item.icon_transposed = false;
item.icon_region = Rect2i();
item.icon_modulate = Color(1, 1, 1, 1);
item.text = p_item;
@@ -54,6 +55,7 @@ void ItemList::add_icon_item(const Ref<Texture> &p_item, bool p_selectable) {
Item item;
item.icon = p_item;
+ item.icon_transposed = false;
item.icon_region = Rect2i();
item.icon_modulate = Color(1, 1, 1, 1);
//item.text=p_item;
@@ -124,6 +126,22 @@ Ref<Texture> ItemList::get_item_icon(int p_idx) const {
return items[p_idx].icon;
}
+void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) {
+
+ ERR_FAIL_INDEX(p_idx, items.size());
+
+ items.write[p_idx].icon_transposed = p_transposed;
+ update();
+ shape_changed = true;
+}
+
+bool ItemList::is_item_icon_transposed(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx, items.size(), false);
+
+ return items[p_idx].icon_transposed;
+}
+
void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
ERR_FAIL_INDEX(p_idx, items.size());
@@ -416,6 +434,7 @@ void ItemList::set_icon_mode(IconMode p_mode) {
update();
shape_changed = true;
}
+
ItemList::IconMode ItemList::get_icon_mode() const {
return icon_mode;
@@ -435,10 +454,18 @@ Size2 ItemList::Item::get_icon_size() const {
if (icon.is_null())
return Size2();
- if (icon_region.has_no_area())
- return icon->get_size();
- return icon_region.size;
+ Size2 size_result = Size2(icon_region.size).abs();
+ if (icon_region.size.x == 0 || icon_region.size.y == 0)
+ size_result = icon->get_size();
+
+ if (icon_transposed) {
+ Size2 size_tmp = size_result;
+ size_result.x = size_tmp.y;
+ size_result.y = size_tmp.x;
+ }
+
+ return size_result;
}
void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
@@ -1067,10 +1094,15 @@ void ItemList::_notification(int p_what) {
if (items[i].disabled)
modulate.a *= 0.5;
- if (items[i].icon_region.has_no_area())
- draw_texture_rect(items[i].icon, draw_rect, false, modulate);
- else
- draw_texture_rect_region(items[i].icon, draw_rect, items[i].icon_region, modulate);
+ // If the icon is transposed, we have to swith the size so that it is drawn correctly
+ if (items[i].icon_transposed) {
+ Size2 size_tmp = draw_rect.size;
+ draw_rect.size.x = size_tmp.y;
+ draw_rect.size.y = size_tmp.x;
+ }
+
+ Rect2 region = (items[i].icon_region.size.x == 0 || items[i].icon_region.size.y == 0) ? Rect2(Vector2(), items[i].icon->get_size()) : Rect2(items[i].icon_region);
+ draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed);
}
if (items[i].tag_icon.is_valid()) {
@@ -1405,6 +1437,9 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &ItemList::set_item_icon);
ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &ItemList::get_item_icon);
+ ClassDB::bind_method(D_METHOD("set_item_icon_transposed", "idx", "rect"), &ItemList::set_item_icon_transposed);
+ ClassDB::bind_method(D_METHOD("is_item_icon_transposed", "idx"), &ItemList::is_item_icon_transposed);
+
ClassDB::bind_method(D_METHOD("set_item_icon_region", "idx", "rect"), &ItemList::set_item_icon_region);
ClassDB::bind_method(D_METHOD("get_item_icon_region", "idx"), &ItemList::get_item_icon_region);
@@ -1498,17 +1533,17 @@ void ItemList::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
ADD_GROUP("Columns", "");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_columns"), "set_max_columns", "get_max_columns");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fixed_column_width"), "set_fixed_column_width", "get_fixed_column_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_columns"), "set_max_columns", "get_max_columns");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_column_width"), "set_fixed_column_width", "get_fixed_column_width");
ADD_GROUP("Icon", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
- ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "fixed_icon_size"), "set_fixed_icon_size", "get_fixed_icon_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fixed_icon_size"), "set_fixed_icon_size", "get_fixed_icon_size");
BIND_ENUM_CONSTANT(ICON_MODE_TOP);
BIND_ENUM_CONSTANT(ICON_MODE_LEFT);
@@ -1524,6 +1559,7 @@ void ItemList::_bind_methods() {
ADD_SIGNAL(MethodInfo("nothing_selected"));
GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers
}
ItemList::ItemList() {
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 58771c1777..acd17986eb 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -53,6 +53,7 @@ private:
struct Item {
Ref<Texture> icon;
+ bool icon_transposed;
Rect2i icon_region;
Color icon_modulate;
Ref<Texture> tag_icon;
@@ -133,6 +134,9 @@ public:
void set_item_icon(int p_idx, const Ref<Texture> &p_icon);
Ref<Texture> get_item_icon(int p_idx) const;
+ void set_item_icon_transposed(int p_idx, const bool transposed);
+ bool is_item_icon_transposed(int p_idx) const;
+
void set_item_icon_region(int p_idx, const Rect2 &p_region);
Rect2 get_item_icon_region(int p_idx) const;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 6ff2d232f0..8009a96a4f 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -665,12 +665,12 @@ void Label::_bind_methods() {
BIND_ENUM_CONSTANT(VALIGN_BOTTOM);
BIND_ENUM_CONSTANT(VALIGN_FILL);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "valign", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_valign", "get_valign");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "autowrap"), "set_autowrap", "has_autowrap");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "valign", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_valign", "get_valign");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autowrap"), "set_autowrap", "has_autowrap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 6f344f1028..299c304c5f 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1573,22 +1573,22 @@ void LineEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_REDO);
BIND_ENUM_CONSTANT(MENU_MAX);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "max_length"), "set_max_length", "get_max_length");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_length"), "set_max_length", "get_max_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");
ADD_GROUP("Placeholder", "placeholder_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position");
}
@@ -1608,6 +1608,8 @@ LineEdit::LineEdit() {
text_changed_dirty = false;
placeholder_alpha = 0.6;
clear_button_enabled = false;
+ clear_button_status.press_attempt = false;
+ clear_button_status.pressing_inside = false;
deselect();
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index d38a067fef..a603487cf1 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -75,6 +75,7 @@ void LinkButton::_notification(int p_what) {
color = get_color("font_color");
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
} break;
+ case DRAW_HOVER_PRESSED:
case DRAW_PRESSED: {
if (has_color("font_color_pressed"))
@@ -91,7 +92,6 @@ void LinkButton::_notification(int p_what) {
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
- case DRAW_HOVER_PRESSED: break; // Not used in this class
case DRAW_DISABLED: {
color = get_color("font_color_disabled");
@@ -134,8 +134,8 @@ void LinkButton::_bind_methods() {
BIND_ENUM_CONSTANT(UNDERLINE_MODE_ON_HOVER);
BIND_ENUM_CONSTANT(UNDERLINE_MODE_NEVER);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
}
LinkButton::LinkButton() {
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index c6a34921c7..802dc0db4f 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -70,18 +70,18 @@ void NinePatchRect::_bind_methods() {
ADD_SIGNAL(MethodInfo("texture_changed"));
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_GROUP("Patch Margin", "patch_margin_");
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "patch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_LEFT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "patch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "patch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_RIGHT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "patch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_STRETCH);
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE);
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 3239641c2f..f621522102 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -557,6 +557,21 @@ void PopupMenu::_notification(int p_what) {
mouse_over = -1;
update();
}
+
+ for (int i = 0; i < items.size(); i++) {
+ if (items[i].submenu == "")
+ continue;
+
+ Node *n = get_node(items[i].submenu);
+ if (!n)
+ continue;
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ if (!pm || !pm->is_visible())
+ continue;
+
+ pm->hide();
+ }
} break;
}
}
@@ -1012,8 +1027,7 @@ bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_fo
code |= KEY_MASK_SHIFT;
}
- int il = items.size();
- for (int i = 0; i < il; i++) {
+ for (int i = 0; i < items.size(); i++) {
if (is_item_disabled(i) || items[i].shortcut_is_disabled)
continue;
@@ -1381,9 +1395,9 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay");
ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID")));
@@ -1411,6 +1425,7 @@ PopupMenu::PopupMenu() {
set_hide_on_item_selection(true);
set_hide_on_checkable_item_selection(true);
set_hide_on_multistate_item_selection(false);
+ set_hide_on_window_lose_focus(true);
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index bb36852cf9..9f1687262f 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -220,13 +220,14 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
case ALIGN_LEFT: l.offset_caches.push_back(0); break; \
case ALIGN_CENTER: l.offset_caches.push_back(((p_width - margin) - used) / 2); break; \
case ALIGN_RIGHT: l.offset_caches.push_back(((p_width - margin) - used)); break; \
- case ALIGN_FILL: l.offset_caches.push_back((p_width - margin) - used /*+spaces_size*/); break; \
+ case ALIGN_FILL: l.offset_caches.push_back(line_wrapped ? ((p_width - margin) - used) : 0); break; \
} \
l.height_caches.push_back(line_height); \
l.ascent_caches.push_back(line_ascent); \
l.descent_caches.push_back(line_descent); \
l.space_caches.push_back(spaces); \
} \
+ line_wrapped = false; \
y += line_height + get_constant(SceneStringNames::get_singleton()->line_separation); \
line_height = 0; \
line_ascent = 0; \
@@ -254,6 +255,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
l.minimum_width = MAX(l.minimum_width, m_width); \
} \
if (wofs + m_width > p_width) { \
+ line_wrapped = true; \
if (p_mode == PROCESS_CACHE) { \
if (spaces > 0) \
spaces -= 1; \
@@ -298,6 +300,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int rchar = 0;
int lh = 0;
bool line_is_blank = true;
+ bool line_wrapped = false;
int fh = 0;
while (it) {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index f766c0722d..ace22dddff 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -276,7 +276,7 @@ void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("_line_edit_input"), &SpinBox::_line_edit_input);
ClassDB::bind_method(D_METHOD("_range_click_timeout"), &SpinBox::_range_click_timeout);
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index c56b7d0f26..cf3113ca8c 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -106,41 +106,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- // test hovering to display right or close button
- int hover_now = -1;
- int hover_buttons = -1;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
-
- Rect2 rect = get_tab_rect(i);
- if (rect.has_point(pos)) {
- hover_now = i;
- }
- if (tabs[i].rb_rect.has_point(pos)) {
- rb_hover = i;
- cb_hover = -1;
- hover_buttons = i;
- break;
- } else if (!tabs[i].disabled && tabs[i].cb_rect.has_point(pos)) {
- cb_hover = i;
- rb_hover = -1;
- hover_buttons = i;
- break;
- }
- }
- if (hover != hover_now) {
- hover = hover_now;
- emit_signal("tab_hover", hover);
- }
-
- if (hover_buttons == -1) { // no hover
- rb_hover = hover_buttons;
- cb_hover = hover_buttons;
- }
+ _update_hover();
update();
-
return;
}
@@ -522,6 +489,48 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const {
return tabs[p_tab].right_button;
}
+void Tabs::_update_hover() {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ const Point2 &pos = get_local_mouse_position();
+ // test hovering to display right or close button
+ int hover_now = -1;
+ int hover_buttons = -1;
+ for (int i = 0; i < tabs.size(); i++) {
+
+ if (i < offset)
+ continue;
+
+ Rect2 rect = get_tab_rect(i);
+ if (rect.has_point(pos)) {
+ hover_now = i;
+ }
+ if (tabs[i].rb_rect.has_point(pos)) {
+ rb_hover = i;
+ cb_hover = -1;
+ hover_buttons = i;
+ break;
+ } else if (!tabs[i].disabled && tabs[i].cb_rect.has_point(pos)) {
+ cb_hover = i;
+ rb_hover = -1;
+ hover_buttons = i;
+ break;
+ }
+ }
+ if (hover != hover_now) {
+ hover = hover_now;
+ emit_signal("tab_hover", hover);
+ }
+
+ if (hover_buttons == -1) { // no hover
+ rb_hover = hover_buttons;
+ cb_hover = hover_buttons;
+ }
+}
+
void Tabs::_update_cache() {
Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
@@ -597,6 +606,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) {
tabs.push_back(t);
_update_cache();
+ call_deferred("_update_hover");
update();
minimum_size_changed();
}
@@ -604,6 +614,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) {
void Tabs::clear_tabs() {
tabs.clear();
current = 0;
+ call_deferred("_update_hover");
update();
}
@@ -614,6 +625,7 @@ void Tabs::remove_tab(int p_idx) {
if (current >= p_idx)
current--;
_update_cache();
+ call_deferred("_update_hover");
update();
minimum_size_changed();
@@ -931,6 +943,7 @@ bool Tabs::get_select_with_rmb() const {
void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
+ ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover);
ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab);
ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab);
@@ -970,7 +983,7 @@ void Tabs::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index e204f4364b..a98744b804 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -97,6 +97,8 @@ private:
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
+
+ void _update_hover();
void _update_cache();
protected:
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index f8a5c4cea3..7bfcd0843c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1429,9 +1429,6 @@ void TextEdit::_notification(int p_what) {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->show_virtual_keyboard(get_text(), get_global_rect());
- if (raised_from_completion) {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
- }
} break;
case NOTIFICATION_FOCUS_EXIT: {
@@ -1443,9 +1440,6 @@ void TextEdit::_notification(int p_what) {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->hide_virtual_keyboard();
- if (raised_from_completion) {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
- }
} break;
}
}
@@ -5666,16 +5660,12 @@ void TextEdit::_confirm_completion() {
void TextEdit::_cancel_code_hint() {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
- raised_from_completion = false;
completion_hint = "";
update();
}
void TextEdit::_cancel_completion() {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
- raised_from_completion = false;
if (!completion_active)
return;
@@ -5833,8 +5823,6 @@ void TextEdit::query_code_comple() {
void TextEdit::set_code_hint(const String &p_hint) {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
- raised_from_completion = true;
completion_hint = p_hint;
completion_hint_offset = -0xFFFF;
update();
@@ -5842,8 +5830,6 @@ void TextEdit::set_code_hint(const String &p_hint) {
void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) {
- VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
- raised_from_completion = true;
completion_strings = p_strings;
completion_active = true;
completion_forced = p_forced;
@@ -6214,7 +6200,7 @@ void TextEdit::_bind_methods() {
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret");
ADD_SIGNAL(MethodInfo("cursor_changed"));
@@ -6232,6 +6218,7 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_MAX);
GLOBAL_DEF("gui/timers/text_edit_idle_detect_sec", 3);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers
}
TextEdit::TextEdit() {
@@ -6345,8 +6332,6 @@ TextEdit::TextEdit() {
target_v_scroll = 0;
v_scroll_speed = 80;
- raised_from_completion = false;
-
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index f0c18ad047..8a508a8738 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -306,8 +306,6 @@ private:
float target_v_scroll;
float v_scroll_speed;
- bool raised_from_completion;
-
String highlighted_word;
uint64_t last_dblclk;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 413f9dbbe6..4a8d87902b 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -128,6 +128,7 @@ void TextureButton::_notification(int p_what) {
if (normal.is_valid())
texdraw = normal;
} break;
+ case DRAW_HOVER_PRESSED:
case DRAW_PRESSED: {
if (pressed.is_null()) {
@@ -150,7 +151,6 @@ void TextureButton::_notification(int p_what) {
} else
texdraw = hover;
} break;
- case DRAW_HOVER_PRESSED: break; // Not used in this class
case DRAW_DISABLED: {
if (disabled.is_null()) {
@@ -247,14 +247,14 @@ void TextureButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureButton::get_stretch_mode);
ADD_GROUP("Textures", "texture_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_texture", "get_normal_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_pressed_texture", "get_pressed_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_hover_texture", "get_hover_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_disabled_texture", "get_disabled_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_focused_texture", "get_focused_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_texture", "get_normal_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_pressed_texture", "get_pressed_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_hover_texture", "get_hover_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_disabled_texture", "get_disabled_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_focused_texture", "get_focused_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
BIND_ENUM_CONSTANT(STRETCH_SCALE);
BIND_ENUM_CONSTANT(STRETCH_TILE);
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index 75f88dc4e6..a37659e521 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -486,21 +486,21 @@ void TextureProgress::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_under_texture", "get_under_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_over_texture", "get_over_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_progress_texture", "get_progress_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
ADD_GROUP("Tint", "tint_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over"), "set_tint_over", "get_tint_over");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_progress"), "set_tint_progress", "get_tint_progress");
ADD_GROUP("Radial Fill", "radial_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_radial_initial_angle", "get_radial_initial_angle");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_fill_degrees", "get_fill_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_radial_initial_angle", "get_radial_initial_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_fill_degrees", "get_fill_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "radial_center_offset"), "set_radial_center_offset", "get_radial_center_offset");
ADD_GROUP("Stretch", "stretch_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "nine_patch_stretch"), "set_nine_patch_stretch", "get_nine_patch_stretch");
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_LEFT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_RIGHT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_BOTTOM);
BIND_ENUM_CONSTANT(FILL_LEFT_TO_RIGHT);
BIND_ENUM_CONSTANT(FILL_RIGHT_TO_LEFT);
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index f4285525f6..4371baf08c 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -109,9 +109,9 @@ void TextureRect::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode);
ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureRect::get_stretch_mode);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
BIND_ENUM_CONSTANT(STRETCH_SCALE_ON_EXPAND);
BIND_ENUM_CONSTANT(STRETCH_SCALE);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 0c11181f98..31f7a21114 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2519,7 +2519,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
pressing_for_editor = false;
}
- if (cache.click_type == Cache::CLICK_BUTTON) {
+ if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != NULL) {
// make sure in case of wrong reference after reconstructing whole TreeItems
cache.click_item = get_item_at_position(cache.click_pos);
emit_signal("button_pressed", cache.click_item, cache.click_column, cache.click_id);
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 39e7c73390..812ca0042b 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -90,53 +90,32 @@ void VideoPlayer::_mix_audio() {
AudioFrame vol = AudioFrame(volume, volume);
- // Copy to server's audio buffer
- switch (AudioServer::get_singleton()->get_speaker_mode()) {
+ int cc = AudioServer::get_singleton()->get_channel_count();
- case AudioServer::SPEAKER_MODE_STEREO: {
- AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
+ if (cc == 1) {
+ AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
+ ERR_FAIL_COND(!target);
- for (int j = 0; j < buffer_size; j++) {
+ for (int j = 0; j < buffer_size; j++) {
- target[j] += buffer[j] * vol;
- }
-
- } break;
- case AudioServer::SPEAKER_SURROUND_31: {
-
- // FIXME: Implement
- } break;
- case AudioServer::SPEAKER_SURROUND_51: {
-
- AudioFrame *targets[2] = {
- AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
- AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
- };
-
- for (int j = 0; j < buffer_size; j++) {
+ target[j] += buffer[j] * vol;
+ }
- AudioFrame frame = buffer[j] * vol;
- targets[0][j] = frame;
- targets[1][j] = frame;
- }
- } break;
- case AudioServer::SPEAKER_SURROUND_71: {
+ } else {
+ AudioFrame *targets[4];
- AudioFrame *targets[3] = {
- AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
- AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
- AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 3)
- };
+ for (int k = 0; k < cc; k++) {
+ targets[k] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, k);
+ ERR_FAIL_COND(!targets[k]);
+ }
- for (int j = 0; j < buffer_size; j++) {
+ for (int j = 0; j < buffer_size; j++) {
- AudioFrame frame = buffer[j] * vol;
- targets[0][j] += frame;
- targets[1][j] += frame;
- targets[2][j] += frame;
+ AudioFrame frame = buffer[j] * vol;
+ for (int k = 0; k < cc; k++) {
+ targets[k][j] += frame;
}
-
- } break;
+ }
}
}
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index a2e890e7a7..93f51a44f4 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -35,7 +35,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
+ VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
}
int CanvasLayer::get_layer() const {
@@ -146,19 +146,26 @@ void CanvasLayer::_notification(int p_what) {
vp = Node::get_viewport();
}
ERR_FAIL_COND(!vp);
+
+ vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
+ VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
} break;
case NOTIFICATION_EXIT_TREE: {
+ vp->_canvas_layer_remove(this);
VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
} break;
+ case NOTIFICATION_MOVED_IN_PARENT: {
+
+ VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
+ } break;
}
}
@@ -179,6 +186,7 @@ RID CanvasLayer::get_viewport() const {
void CanvasLayer::set_custom_viewport(Node *p_viewport) {
ERR_FAIL_NULL(p_viewport);
if (is_inside_tree()) {
+ vp->_canvas_layer_remove(this);
VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
}
@@ -198,10 +206,11 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
else
vp = Node::get_viewport();
+ vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
+ VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 8fd7dc1d7b..ec99c51212 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1835,7 +1835,7 @@ void Node::set_editable_instance(Node *p_node, bool p_editable) {
}
}
-bool Node::is_editable_instance(Node *p_node) const {
+bool Node::is_editable_instance(const Node *p_node) const {
if (!p_node)
return false; //easier, null is never editable :)
@@ -2192,7 +2192,7 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
if (p_copy->has_node(ptarget))
copytarget = p_copy->get_node(ptarget);
- if (copy && copytarget) {
+ if (copy && copytarget && !copy->is_connected(E->get().signal, copytarget, E->get().method)) {
copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, E->get().flags);
}
}
@@ -2724,7 +2724,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path);
ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path);
- ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
{
MethodInfo mi;
@@ -2782,18 +2782,18 @@ void Node::_bind_methods() {
ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
- //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),"set_process","is_processing") ;
- //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/physics_process" ), "set_physics_process","is_physics_processing") ;
- //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/input" ), "set_process_input","is_processing_input" ) ;
- //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
+ //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/process" ),"set_process","is_processing") ;
+ //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/physics_process" ), "set_physics_process","is_physics_processing") ;
+ //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/input" ), "set_process_input","is_processing_input" ) ;
+ //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
ADD_GROUP("Pause", "pause_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::REAL, "delta")));
BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::REAL, "delta")));
diff --git a/scene/main/node.h b/scene/main/node.h
index a7baebc9c2..78db12dda9 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -303,7 +303,7 @@ public:
String get_filename() const;
void set_editable_instance(Node *p_node, bool p_editable);
- bool is_editable_instance(Node *p_node) const;
+ bool is_editable_instance(const Node *p_node) const;
void set_editable_instances(const HashMap<NodePath, int> &p_editable_instances);
HashMap<NodePath, int> get_editable_instances() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index fdbe3b57f0..f7dec77ce4 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1944,6 +1944,7 @@ SceneTree::SceneTree() {
debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
tree_version = 1;
physics_process_time = 1;
@@ -1977,7 +1978,9 @@ SceneTree::SceneTree() {
current_scene = NULL;
int ref_atlas_size = GLOBAL_DEF("rendering/quality/reflections/atlas_size", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_size", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_size", PROPERTY_HINT_RANGE, "0,8192,or_greater")); //next_power_of_2 will return a 0 as min value
int ref_atlas_subdiv = GLOBAL_DEF("rendering/quality/reflections/atlas_subdiv", 8);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_subdiv", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_subdiv", PROPERTY_HINT_RANGE, "0,32,or_greater")); //next_power_of_2 will return a 0 as min value
int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"));
root->set_msaa(Viewport::MSAA(msaa_mode));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index bb379ff4af..f8cc1bdd77 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -45,6 +45,7 @@
#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/popup_menu.h"
+#include "scene/main/canvas_layer.h"
#include "scene/main/timer.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
@@ -443,24 +444,39 @@ void Viewport::_notification(int p_what) {
uint64_t frame = get_tree()->get_frame();
- Vector2 point = get_canvas_transform().affine_inverse().xform(pos);
Physics2DDirectSpaceState::ShapeResult res[64];
- int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
- for (int i = 0; i < rc; i++) {
-
- if (res[i].collider_id && res[i].collider) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
- if (co) {
-
- Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id);
- if (!E) {
- E = physics_2d_mouseover.insert(res[i].collider_id, frame);
- co->_mouse_enter();
- } else {
- E->get() = frame;
- }
+ for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
+ Transform2D canvas_transform;
+ ObjectID canvas_layer_id;
+ if (E->get()) {
+ // A descendant CanvasLayer
+ canvas_transform = E->get()->get_transform();
+ canvas_layer_id = E->get()->get_instance_id();
+ } else {
+ // This Viewport's builtin canvas
+ canvas_transform = get_canvas_transform();
+ canvas_layer_id = 0;
+ }
- co->_input_event(this, ev, res[i].shape);
+ Vector2 point = canvas_transform.affine_inverse().xform(pos);
+
+ int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
+ for (int i = 0; i < rc; i++) {
+
+ if (res[i].collider_id && res[i].collider) {
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
+ if (co) {
+
+ Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id);
+ if (!E) {
+ E = physics_2d_mouseover.insert(res[i].collider_id, frame);
+ co->_mouse_enter();
+ } else {
+ E->get() = frame;
+ }
+
+ co->_input_event(this, ev, res[i].shape);
+ }
}
}
}
@@ -629,10 +645,8 @@ Rect2 Viewport::get_visible_rect() const {
Rect2 r;
if (size == Size2()) {
-
- r = Rect2(Point2(), Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height));
+ r = Rect2(Point2(), OS::get_singleton()->get_window_size());
} else {
-
r = Rect2(Point2(), size);
}
@@ -856,6 +870,16 @@ void Viewport::_camera_make_next_current(Camera *p_exclude) {
}
#endif
+void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
+
+ canvas_layers.insert(p_canvas_layer);
+}
+
+void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
+
+ canvas_layers.erase(p_canvas_layer);
+}
+
void Viewport::set_transparent_background(bool p_enable) {
transparent_bg = p_enable;
@@ -1841,8 +1865,16 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
MenuButton *popup_menu_parent = NULL;
MenuButton *menu_button = Object::cast_to<MenuButton>(over);
- if (popup_menu)
+ if (popup_menu) {
popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
+ if (!popup_menu_parent) {
+ // Go through the parents to see if there's a MenuButton at the end.
+ while (Object::cast_to<PopupMenu>(popup_menu->get_parent())) {
+ popup_menu = Object::cast_to<PopupMenu>(popup_menu->get_parent());
+ }
+ popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
+ }
+ }
// If the mouse is over a menu button, this menu will open automatically
// if there is already a pop-up menu open at the same hierarchical level.
@@ -2905,6 +2937,7 @@ Viewport::Viewport() {
parent = NULL;
listener = NULL;
camera = NULL;
+ canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
arvr = false;
size_override = false;
size_override_stretch = false;
@@ -2945,6 +2978,7 @@ Viewport::Viewport() {
//gui.tooltip_timer->force_parent_owned();
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.7);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
gui.tooltip = NULL;
gui.tooltip_label = NULL;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index c1a4c0e3eb..08c1ac1d12 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -45,6 +45,7 @@ class Camera2D;
class Listener;
class Control;
class CanvasItem;
+class CanvasLayer;
class Panel;
class Label;
class Timer;
@@ -163,6 +164,7 @@ private:
Camera *camera;
Set<Camera *> cameras;
+ Set<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
@@ -354,6 +356,10 @@ private:
void _camera_remove(Camera *p_camera);
void _camera_make_next_current(Camera *p_exclude);
+ friend class CanvasLayer;
+ void _canvas_layer_add(CanvasLayer *p_canvas_layer);
+ void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 5c01cadcd5..803c85ef34 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1469,7 +1469,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const {
middle = (low + high) / 2;
- if (p_time == keys[middle].time) { //match
+ if (Math::abs(p_time - keys[middle].time) < CMP_EPSILON) { //match
return middle;
} else if (p_time < keys[middle].time)
high = middle - 1; //search low end of array
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 9d47bca5ed..39488760cd 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -38,10 +38,9 @@ Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() {
if (points.size() > 3) {
- QuickHull qh;
Vector<Vector3> varr = Variant(points);
Geometry::MeshData md;
- Error err = qh.build(varr, md);
+ Error err = QuickHull::build(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 6790c35c4b..d6b40766a2 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -201,10 +201,10 @@ Error DynamicFontAtSize::_load() {
if (FT_HAS_COLOR(face)) {
int best_match = 0;
- int diff = ABS(id.size - face->available_sizes[0].width);
+ int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width));
scale_color_font = float(id.size) / face->available_sizes[0].width;
for (int i = 1; i < face->num_fixed_sizes; i++) {
- int ndiff = ABS(id.size - face->available_sizes[i].width);
+ int ndiff = ABS(id.size - ((int64_t)face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
@@ -1014,10 +1014,10 @@ void DynamicFont::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "get_use_mipmaps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_filter"), "set_use_filter", "get_use_filter");
ADD_GROUP("Extra Spacing", "extra_spacing");
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "extra_spacing_top"), "set_spacing", "get_spacing", SPACING_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "extra_spacing_bottom"), "set_spacing", "get_spacing", SPACING_BOTTOM);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "extra_spacing_char"), "set_spacing", "get_spacing", SPACING_CHAR);
- ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_top"), "set_spacing", "get_spacing", SPACING_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_bottom"), "set_spacing", "get_spacing", SPACING_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_char"), "set_spacing", "get_spacing", SPACING_CHAR);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE);
ADD_GROUP("Font", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font_data", PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"), "set_font_data", "get_font_data");
@@ -1029,7 +1029,7 @@ void DynamicFont::_bind_methods() {
Mutex *DynamicFont::dynamic_font_mutex = NULL;
-SelfList<DynamicFont>::List DynamicFont::dynamic_fonts;
+SelfList<DynamicFont>::List *DynamicFont::dynamic_fonts = NULL;
DynamicFont::DynamicFont() :
font_list(this) {
@@ -1041,29 +1041,31 @@ DynamicFont::DynamicFont() :
spacing_char = 0;
spacing_space = 0;
outline_color = Color(1, 1, 1);
- if (dynamic_font_mutex)
+ if (dynamic_font_mutex) {
dynamic_font_mutex->lock();
- dynamic_fonts.add(&font_list);
- if (dynamic_font_mutex)
+ dynamic_fonts->add(&font_list);
dynamic_font_mutex->unlock();
+ }
}
DynamicFont::~DynamicFont() {
-
- if (dynamic_font_mutex)
+ if (dynamic_font_mutex) {
dynamic_font_mutex->lock();
- dynamic_fonts.remove(&font_list);
- if (dynamic_font_mutex)
+ dynamic_fonts->remove(&font_list);
dynamic_font_mutex->unlock();
+ }
}
void DynamicFont::initialize_dynamic_fonts() {
+ dynamic_fonts = memnew(SelfList<DynamicFont>::List());
dynamic_font_mutex = Mutex::create();
}
void DynamicFont::finish_dynamic_fonts() {
memdelete(dynamic_font_mutex);
dynamic_font_mutex = NULL;
+ memdelete(dynamic_fonts);
+ dynamic_fonts = NULL;
}
void DynamicFont::update_oversampling() {
@@ -1073,7 +1075,7 @@ void DynamicFont::update_oversampling() {
if (dynamic_font_mutex)
dynamic_font_mutex->lock();
- SelfList<DynamicFont> *E = dynamic_fonts.first();
+ SelfList<DynamicFont> *E = dynamic_fonts->first();
while (E) {
if (E->self()->data_at_size.is_valid()) {
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index afda48a566..bd3f84d62c 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -285,7 +285,7 @@ public:
SelfList<DynamicFont> font_list;
static Mutex *dynamic_font_mutex;
- static SelfList<DynamicFont>::List dynamic_fonts;
+ static SelfList<DynamicFont>::List *dynamic_fonts;
static void initialize_dynamic_fonts();
static void finish_dynamic_fonts();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 274c74a9a2..a9d7b2adf7 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -612,9 +612,9 @@ void SpatialMaterial::_update_shader() {
//handle animation
code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
- code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n";
+ code += "\tif (!particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n";
code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n";
- code += "\tUV += vec2(mod(particle_frame,float(particles_anim_h_frames)) / float(particles_anim_h_frames),particle_frame / float(particles_anim_h_frames) / float(particles_anim_v_frames));\n";
+ code += "\tUV += vec2(mod(particle_frame,float(particles_anim_h_frames)) / float(particles_anim_h_frames), floor(particle_frame / float(particles_anim_h_frames)) / float(particles_anim_v_frames));\n";
} break;
}
@@ -1541,13 +1541,13 @@ int SpatialMaterial::get_particles_anim_v_frames() const {
return particles_anim_v_frames;
}
-void SpatialMaterial::set_particles_anim_loop(int p_frames) {
+void SpatialMaterial::set_particles_anim_loop(bool p_loop) {
- particles_anim_loop = p_frames;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, p_frames);
+ particles_anim_loop = p_loop;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
}
-int SpatialMaterial::get_particles_anim_loop() const {
+bool SpatialMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
@@ -1898,7 +1898,7 @@ void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &SpatialMaterial::set_particles_anim_v_frames);
ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &SpatialMaterial::get_particles_anim_v_frames);
- ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "frames"), &SpatialMaterial::set_particles_anim_loop);
+ ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &SpatialMaterial::set_particles_anim_loop);
ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &SpatialMaterial::get_particles_anim_loop);
ClassDB::bind_method(D_METHOD("set_depth_deep_parallax", "enable"), &SpatialMaterial::set_depth_deep_parallax);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index cf4d19b5a7..49b4a79d92 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -574,8 +574,8 @@ public:
void set_particles_anim_v_frames(int p_frames);
int get_particles_anim_v_frames() const;
- void set_particles_anim_loop(int p_frames);
- int get_particles_anim_loop() const;
+ void set_particles_anim_loop(bool p_loop);
+ bool get_particles_anim_loop() const;
void set_grow_enabled(bool p_enable);
bool is_grow_enabled() const;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 6cd701eb9a..838d73edb3 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -482,7 +482,7 @@ void Mesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint);
ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint);
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count);
ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays);
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index a5449e1fe8..7af9086ab7 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -42,8 +42,6 @@ void MeshDataTool::clear() {
Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surface) {
ERR_FAIL_COND_V(p_mesh.is_null(), ERR_INVALID_PARAMETER);
-
- ERR_FAIL_COND_V(p_mesh.is_null(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_mesh->surface_get_primitive_type(p_surface) != Mesh::PRIMITIVE_TRIANGLES, ERR_INVALID_PARAMETER);
Array arrays = p_mesh->surface_get_arrays(p_surface);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 086fb83af9..87483a7da4 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -264,7 +264,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
if (n.instance >= 0 || n.type != TYPE_INSTANCED || i == 0) {
- //if node was not part of instance, must set it's name, parenthood and ownership
+ //if node was not part of instance, must set its name, parenthood and ownership
if (i > 0) {
if (parent) {
parent->_add_child_nocheck(node, snames[n.name]);
@@ -472,6 +472,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
List<PropertyInfo> plist;
p_node->get_property_list(&plist);
+ StringName type = p_node->get_class();
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
@@ -482,12 +483,23 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
String name = E->get().name;
Variant value = p_node->get(E->get().name);
- bool isdefault = ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one());
+ bool isdefault = false;
+ Variant default_value = ClassDB::class_get_default_property_value(type, name);
- if (E->get().usage & PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE) {
- isdefault = true; //is script default value
+ if (default_value.get_type() != Variant::NIL) {
+ isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
}
+ Ref<Script> script = p_node->get_script();
+ if (!isdefault && script.is_valid() && script->get_property_default_value(name, default_value)) {
+ isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
+ }
+ // the version above makes more sense, because it does not rely on placeholder or usage flag
+ // in the script, just the default value function.
+ // if (E->get().usage & PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE) {
+ // isdefault = true; //is script default value
+ // }
+
if (pack_state_stack.size()) {
// we are on part of an instanced subscene
// or part of instanced scene.
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index ba48982fda..d500609c43 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -463,12 +463,6 @@ void ParticlesMaterial::_update_shader() {
code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
- if (flags[FLAG_ANIM_LOOP]) {
- code += " CUSTOM.z = mod(CUSTOM.z, 1.0);\n"; // loop
-
- } else {
- code += " CUSTOM.z = clamp(CUSTOM.z, 0.0, 1.0);\n"; // 0 to 1 only
- }
code += " }\n";
// apply color
// apply hue rotation
@@ -1129,7 +1123,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
@@ -1175,7 +1169,6 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 91fdcc0346..06ebb3c4dc 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -60,7 +60,6 @@ public:
FLAG_ALIGN_Y_TO_VELOCITY,
FLAG_ROTATE_Y,
FLAG_DISABLE_Z,
- FLAG_ANIM_LOOP,
FLAG_MAX
};
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 63aa44e1d8..4906ceb2eb 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -102,6 +102,9 @@ void PrimitiveMesh::_request_update() {
}
int PrimitiveMesh::get_surface_count() const {
+ if (pending_request) {
+ _update();
+ }
return 1;
}
@@ -1282,7 +1285,7 @@ void PrismMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
index 597ffe49ae..5ae843f2bd 100644
--- a/scene/resources/scene_format_text.cpp
+++ b/scene/resources/scene_format_text.cpp
@@ -626,14 +626,14 @@ Error ResourceInteractiveLoaderText::poll() {
if (!packed_scene.is_valid())
return error;
- error = OK;
+ error = ERR_FILE_EOF;
//get it here
resource = packed_scene;
if (!ResourceCache::has(res_path)) {
packed_scene->set_path(res_path);
}
- return ERR_FILE_EOF;
+ return error;
} else {
error_text += "Unknown tag in file: " + next_tag.name;
@@ -1600,9 +1600,11 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
String name = PE->get().name;
Variant value = res->get(name);
+ Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name);
- if ((PE->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) || (PE->get().usage & PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()))
+ if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
continue;
+ }
if (PE->get().type == Variant::OBJECT && value.is_zero() && !(PE->get().usage & PROPERTY_USAGE_STORE_IF_NULL))
continue;
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 869f4a3a9b..214e2e8edc 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -101,7 +101,7 @@ void Shape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &Shape::get_margin);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.04,10,0.001"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
Shape::Shape() :
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 69d85eeef3..087990c308 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -310,7 +310,7 @@ void StyleBoxTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
- ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_GROUP("Margin", "margin_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_RIGHT);
@@ -322,8 +322,8 @@ void StyleBoxTexture::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
ADD_GROUP("Modulate", "modulate_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
@@ -565,8 +565,6 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
vert_offset = 0;
}
int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
- int rings = (border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0) ? 1 : 2;
- rings = 2;
int ring_corner_radius[4];
set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);
@@ -592,7 +590,7 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
//calculate the vert array
for (int corner_index = 0; corner_index < 4; corner_index++) {
for (int detail = 0; detail <= adapted_corner_detail; detail++) {
- for (int inner_outer = (2 - rings); inner_outer < 2; inner_outer++) {
+ for (int inner_outer = 0; inner_outer < 2; inner_outer++) {
float radius;
Color color;
Point2 corner_point;
@@ -613,19 +611,17 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
}
}
- if (rings == 2) {
- int vert_count = (adapted_corner_detail + 1) * 4 * rings;
- //fill the indices and the colors for the border
- for (int i = 0; i < vert_count; i++) {
- //poly 1
- indices.push_back(vert_offset + ((i + 0) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- //poly 2
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 3) % vert_count));
- }
+ int vert_count = (adapted_corner_detail + 1) * 4 * 2;
+ //fill the indices and the colors for the border
+ for (int i = 0; i < vert_count; i++) {
+ //poly 1
+ indices.push_back(vert_offset + ((i + 0) % vert_count));
+ indices.push_back(vert_offset + ((i + 2) % vert_count));
+ indices.push_back(vert_offset + ((i + 1) % vert_count));
+ //poly 2
+ indices.push_back(vert_offset + ((i + 1) % vert_count));
+ indices.push_back(vert_offset + ((i + 2) % vert_count));
+ indices.push_back(vert_offset + ((i + 3) % vert_count));
}
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 96b9cfa137..3d247ab7ad 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -106,7 +106,7 @@ void VisualShaderNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualShaderNode::_get_default_input_values);
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
- ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
}
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 7de0695e8c..02a0bed964 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -136,16 +136,20 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
+ int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
+ int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
+#ifdef DEBUG_ENABLED
+ unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
+#endif
- // p_frames is multiplied by two since an AudioFrame is stereo
- if ((p_frames + MICROPHONE_PLAYBACK_DELAY * 2) > input_size) {
+ if (playback_delay > input_size) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0.0f, 0.0f);
}
input_ofs = 0;
} else {
for (int i = 0; i < p_frames; i++) {
- if (input_size >= input_ofs) {
+ if (input_size > input_ofs) {
float l = (buf[input_ofs++] >> 16) / 32768.f;
if (input_ofs >= buf.size()) {
input_ofs = 0;
@@ -162,6 +166,12 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
}
}
+#ifdef DEBUG_ENABLED
+ if (input_ofs > input_position && (input_ofs - input_position) < (p_frames * 2)) {
+ print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size));
+ }
+#endif
+
AudioDriver::get_singleton()->unlock();
}
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 2740f86d55..f6ed45cc9c 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -122,8 +122,6 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled {
GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback)
friend class AudioStreamMicrophone;
- static const int MICROPHONE_PLAYBACK_DELAY = 256;
-
bool active;
unsigned int input_ofs;
diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp
index ef23e4aaf3..b032c91da2 100644
--- a/servers/audio/effects/reverb.cpp
+++ b/servers/audio/effects/reverb.cpp
@@ -36,22 +36,22 @@
const float Reverb::comb_tunings[MAX_COMBS] = {
//freeverb comb tunings
- 0.025306122448979593,
- 0.026938775510204082,
- 0.028956916099773241,
- 0.03074829931972789,
- 0.032244897959183672,
- 0.03380952380952381,
- 0.035306122448979592,
- 0.036666666666666667
+ 0.025306122448979593f,
+ 0.026938775510204082f,
+ 0.028956916099773241f,
+ 0.03074829931972789f,
+ 0.032244897959183672f,
+ 0.03380952380952381f,
+ 0.035306122448979592f,
+ 0.036666666666666667f
};
const float Reverb::allpass_tunings[MAX_ALLPASS] = {
//freeverb allpass tunings
- 0.0051020408163265302,
- 0.007732426303854875,
- 0.01,
- 0.012607709750566893
+ 0.0051020408163265302f,
+ 0.007732426303854875f,
+ 0.01f,
+ 0.012607709750566893f
};
void Reverb::process(float *p_src, float *p_dst, int p_frames) {
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index d36057b465..33d1e72669 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -80,6 +80,14 @@ double AudioDriver::get_mix_time() const {
return total;
}
+void AudioDriver::input_buffer_init(int driver_buffer_frames) {
+
+ const int input_buffer_channels = 2;
+ input_buffer.resize(driver_buffer_frames * input_buffer_channels * 4);
+ input_position = 0;
+ input_size = 0;
+}
+
void AudioDriver::input_buffer_write(int32_t sample) {
input_buffer.write[input_position++] = sample;
@@ -926,6 +934,7 @@ void AudioServer::init() {
channel_disable_threshold_db = GLOBAL_DEF_RST("audio/channel_disable_threshold_db", -60.0);
channel_disable_frames = float(GLOBAL_DEF_RST("audio/channel_disable_time", 2.0)) * get_mix_rate();
+ ProjectSettings::get_singleton()->set_custom_property_info("audio/channel_disable_time", PropertyInfo(Variant::REAL, "audio/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
buffer_size = 1024; //hardcoded for now
init_channels_and_buffers();
@@ -1008,7 +1017,7 @@ void AudioServer::update() {
void AudioServer::load_default_bus_layout() {
- if (FileAccess::exists("res://default_bus_layout.tres")) {
+ if (ResourceLoader::exists("res://default_bus_layout.tres")) {
Ref<AudioBusLayout> default_layout = ResourceLoader::load("res://default_bus_layout.tres");
if (default_layout.is_valid()) {
set_bus_layout(default_layout);
diff --git a/servers/audio_server.h b/servers/audio_server.h
index ba6569eb38..b12ca6e589 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -59,6 +59,7 @@ protected:
void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true);
void update_mix_time(int p_frames);
+ void input_buffer_init(int driver_buffer_frames);
void input_buffer_write(int32_t sample);
#ifdef DEBUG_ENABLED
diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp
index d2fef0ab77..5e295edcd1 100644
--- a/servers/physics/area_pair_sw.cpp
+++ b/servers/physics/area_pair_sw.cpp
@@ -147,10 +147,10 @@ Area2PairSW::~Area2PairSW() {
if (colliding) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ if (area_b->has_area_monitor_callback())
area_b->remove_area_from_query(area_a, shape_a, shape_b);
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ if (area_a->has_area_monitor_callback())
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index 087ae570fb..f17f6f7014 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -98,7 +98,6 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 c = rel_A.cross(rel_B).cross(rel_B);
- //if ( Math::abs(rel_A.dot(c) )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) {
// should handle somehow..
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index 731749b8ce..3b5344f020 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -544,14 +544,24 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo
AABB body_aabb;
+ bool shapes_found = false;
+
for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (i == 0)
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
body_aabb = p_body->get_shape_aabb(i);
- else
+ shapes_found = true;
+ } else {
body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
}
+ if (!shapes_found) {
+ return 0;
+ }
// Undo the currently transform the physics server is aware of and apply the provided one
body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin);
@@ -691,13 +701,23 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
r_result->collider_shape = 0;
}
AABB body_aabb;
+ bool shapes_found = false;
for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (i == 0)
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
body_aabb = p_body->get_shape_aabb(i);
- else
+ shapes_found = true;
+ } else {
body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ return false;
}
// Undo the currently transform the physics server is aware of and apply the provided one
@@ -1183,6 +1203,7 @@ SpaceSW::SpaceSW() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);
body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
body_angular_velocity_damp_ratio = 10;
broadphase = BroadPhaseSW::create_func();
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 9d515d2183..cdd35cf657 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -147,10 +147,10 @@ Area2Pair2DSW::~Area2Pair2DSW() {
if (colliding) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ if (area_b->has_area_monitor_callback())
area_b->remove_area_from_query(area_a, shape_a, shape_b);
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ if (area_a->has_area_monitor_callback())
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index aa063d6c1e..52362386d2 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -511,8 +511,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
if (continuous_cd_mode != Physics2DServer::CCD_MODE_DISABLED) {
- motion = new_transform.get_origin() - get_transform().get_origin();
- //linear_velocity*p_step;
+ motion = linear_velocity * p_step;
do_motion = true;
}
}
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 950f0f9d24..95195c8fff 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -635,11 +635,15 @@ BroadPhase2DSW *BroadPhase2DHashGrid::_create() {
BroadPhase2DHashGrid::BroadPhase2DHashGrid() {
hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
hash_table_size = Math::larger_prime(hash_table_size);
hash_table = memnew_arr(PosBin *, hash_table_size);
cell_size = GLOBAL_DEF("physics/2d/cell_size", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater"));
+
large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"));
for (uint32_t i = 0; i < hash_table_size; i++)
hash_table[i] = NULL;
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 4dd5b2040f..2f5b484040 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -244,6 +244,7 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) {
type = p_type;
space = NULL;
instance_id = 0;
+ canvas_instance_id = 0;
collision_mask = 1;
collision_layer = 1;
pickable = true;
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index f2b2363499..f256910f52 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -49,6 +49,7 @@ private:
Type type;
RID self;
ObjectID instance_id;
+ ObjectID canvas_instance_id;
bool pickable;
struct Shape {
@@ -102,6 +103,9 @@ public:
_FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
_FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
+ _FORCE_INLINE_ void set_canvas_instance_id(const ObjectID &p_canvas_instance_id) { canvas_instance_id = p_canvas_instance_id; }
+ _FORCE_INLINE_ ObjectID get_canvas_instance_id() const { return canvas_instance_id; }
+
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index 000e38c4a2..2df09057c4 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -169,7 +169,9 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &
cbk->invalid_by_dir++;
return;
}
- if (cbk->valid_dir.dot((p_point_A - p_point_B).normalized()) < 0.7071) {
+ Vector2 rel_dir = (p_point_A - p_point_B).normalized();
+
+ if (cbk->valid_dir.dot(rel_dir) < 0.7071) { //sqrt(2)/2.0 - 45 degrees
cbk->invalid_by_dir++;
/*
@@ -469,6 +471,27 @@ ObjectID Physics2DServerSW::area_get_object_instance_id(RID p_area) const {
return area->get_instance_id();
}
+void Physics2DServerSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.get(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_canvas_instance_id(p_ID);
+}
+ObjectID Physics2DServerSW::area_get_canvas_instance_id(RID p_area) const {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.get(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+ return area->get_canvas_instance_id();
+}
+
void Physics2DServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
if (space_owner.owns(p_area)) {
@@ -744,6 +767,22 @@ uint32_t Physics2DServerSW::body_get_object_instance_id(RID p_body) const {
return body->get_instance_id();
};
+void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_canvas_instance_id(p_ID);
+};
+
+uint32_t Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const {
+
+ Body2DSW *body = body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_canvas_instance_id();
+};
+
void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
Body2DSW *body = body_owner.get(p_body);
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index d4fc44b1d7..f41c599579 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -144,6 +144,9 @@ public:
virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID);
virtual ObjectID area_get_object_instance_id(RID p_area) const;
+ virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID);
+ virtual ObjectID area_get_canvas_instance_id(RID p_area) const;
+
virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
virtual void area_set_transform(RID p_area, const Transform2D &p_transform);
@@ -188,6 +191,9 @@ public:
virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID);
virtual uint32_t body_get_object_instance_id(RID p_body) const;
+ virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID);
+ virtual uint32_t body_get_canvas_instance_id(RID p_body) const;
+
virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index 5f5fd3866f..58517bf1a7 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -154,6 +154,9 @@ public:
FUNC2(area_attach_object_instance_id, RID, ObjectID);
FUNC1RC(ObjectID, area_get_object_instance_id, RID);
+ FUNC2(area_attach_canvas_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, area_get_canvas_instance_id, RID);
+
FUNC3(area_set_param, RID, AreaParameter, const Variant &);
FUNC2(area_set_transform, RID, const Transform2D &);
@@ -199,6 +202,9 @@ public:
FUNC2(body_attach_object_instance_id, RID, uint32_t);
FUNC1RC(uint32_t, body_get_object_instance_id, RID);
+ FUNC2(body_attach_canvas_instance_id, RID, uint32_t);
+ FUNC1RC(uint32_t, body_get_canvas_instance_id, RID);
+
FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID);
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index f36328c985..23c3c739c2 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -31,9 +31,9 @@
#include "space_2d_sw.h"
#include "collision_solver_2d_sw.h"
+#include "core/os/os.h"
#include "core/pair.h"
#include "physics_2d_server_sw.h"
-
_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (!(p_object->get_collision_layer() & p_collision_mask)) {
@@ -49,7 +49,7 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint
return true;
}
-int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
if (p_result_max <= 0)
return 0;
@@ -75,6 +75,9 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe
if (p_pick_point && !col_obj->is_pickable())
continue;
+ if (p_filter_by_canvas && col_obj->get_canvas_instance_id() != p_canvas_instance_id)
+ continue;
+
int shape_idx = space->intersection_query_subindex_results[i];
Shape2DSW *shape = col_obj->get_shape(shape_idx);
@@ -100,6 +103,16 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe
return cc;
}
+int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+
+ return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point);
+}
+
+int Physics2DDirectSpaceStateSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+
+ return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point, true, p_canvas_instance_id);
+}
+
bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
ERR_FAIL_COND_V(space->locked, false);
@@ -487,12 +500,23 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
Rect2 body_aabb;
+ bool shapes_found = false;
+
for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (i == 0)
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
body_aabb = p_body->get_shape_aabb(i);
- else
+ shapes_found = true;
+ } else {
body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ return 0;
}
// Undo the currently transform the physics server is aware of and apply the provided one
@@ -555,9 +579,11 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
}
}
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
+ cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
cbk.valid_depth = p_margin; //only valid depth is the collision margin
cbk.invalid_by_dir = 0;
@@ -568,7 +594,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
}
Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) {
if (cbk.amount > 0) {
collided = true;
}
@@ -647,12 +673,23 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
Rect2 body_aabb;
+ bool shapes_found = false;
+
for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (i == 0)
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
body_aabb = p_body->get_shape_aabb(i);
- else
+ shapes_found = true;
+ } else {
body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ return false;
}
// Undo the currently transform the physics server is aware of and apply the provided one
@@ -710,24 +747,42 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
}
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
+ cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
+
cbk.valid_depth = p_margin; //only valid depth is the collision margin
cbk.invalid_by_dir = 0;
+ if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
+ const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
+ if (b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC || b->get_mode() == Physics2DServer::BODY_MODE_RIGID) {
+ //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
+ Vector2 lv = b->get_linear_velocity();
+ //compute displacement from linear velocity
+ Vector2 motion = lv * Physics2DDirectBodyStateSW::singleton->step;
+ float motion_len = motion.length();
+ motion.normalize();
+ cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0);
+ }
+ }
} else {
cbk.valid_dir = Vector2();
cbk.valid_depth = 0;
cbk.invalid_by_dir = 0;
}
+ int current_collisions = cbk.amount;
+ bool did_collide = false;
+
Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) {
- collided = cbk.amount > 0;
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) {
+ did_collide = cbk.amount > current_collisions;
}
- if (!collided && cbk.invalid_by_dir > 0) {
+ if (!did_collide && cbk.invalid_by_dir > 0) {
//this shape must be excluded
if (excluded_shape_pair_count < max_excluded_shape_pairs) {
ExcludedShapeSW esp;
@@ -737,6 +792,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
excluded_shape_pairs[excluded_shape_pair_count++] = esp;
}
}
+
+ if (did_collide) {
+ collided = true;
+ }
}
}
@@ -824,14 +883,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue;
}
- Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
//test initial overlap, does it collide if going all the way?
- if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) {
+ if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
continue;
}
//test initial overlap
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
continue;
@@ -851,7 +910,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
real_t ofs = (low + hi) * 0.5;
Vector2 sep = mnormal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_xform, Vector2(), NULL, NULL, &sep, 0);
+ bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, &sep, 0);
if (collided) {
@@ -869,12 +928,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.max = 1;
cbk.amount = 0;
cbk.ptr = cd;
- cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
+ cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
cbk.valid_depth = 10e20;
Vector2 sep = mnormal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
+ bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) {
continue;
}
@@ -959,9 +1018,11 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (excluded)
continue;
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- rcd.valid_dir = body_shape_xform.get_axis(1).normalized();
+ rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
rcd.valid_depth = 10e20;
} else {
rcd.valid_dir = Vector2();
@@ -970,7 +1031,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.object = col_obj;
rcd.shape = shape_idx;
- bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
+ bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
if (!sc)
continue;
}
@@ -1233,6 +1294,7 @@ Space2DSW::Space2DSW() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0);
body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
broadphase = BroadPhase2DSW::create_func();
broadphase->set_pair_callback(_broadphase_pair, this);
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index c894eb9c40..bf4ea12eb5 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -45,10 +45,13 @@ class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState {
GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState);
+ int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
+
public:
Space2DSW *space;
virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false);
+ virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false);
virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 3ca6e29f0b..2ed8a4c478 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -328,7 +328,7 @@ Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParam
return ret;
}
-Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+Array Physics2DDirectSpaceState::_intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
Set<RID> exclude;
for (int i = 0; i < p_exclude.size(); i++)
@@ -337,7 +337,12 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_
Vector<ShapeResult> ret;
ret.resize(p_max_results);
- int rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+ int rc;
+ if (p_filter_by_canvas)
+ rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+ else
+ rc = intersect_point_on_canvas(p_point, p_canvas_instance_id, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+
if (rc == 0)
return Array();
@@ -356,6 +361,16 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_
return r;
}
+Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+}
+
+Array Physics2DDirectSpaceState::_intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas, true, p_canvas_intance_id);
+}
+
Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) {
ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
@@ -400,6 +415,7 @@ Physics2DDirectSpaceState::Physics2DDirectSpaceState() {
void Physics2DDirectSpaceState::_bind_methods() {
ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32));
ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &Physics2DDirectSpaceState::_cast_motion);
@@ -575,6 +591,9 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &Physics2DServer::area_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &Physics2DServer::area_get_object_instance_id);
+ ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &Physics2DServer::area_attach_canvas_instance_id);
+ ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &Physics2DServer::area_get_canvas_instance_id);
+
ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_monitor_callback);
ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_area_monitor_callback);
ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &Physics2DServer::area_set_monitorable);
@@ -606,6 +625,9 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &Physics2DServer::body_get_object_instance_id);
+ ClassDB::bind_method(D_METHOD("body_attach_canvas_instance_id", "body", "id"), &Physics2DServer::body_attach_canvas_instance_id);
+ ClassDB::bind_method(D_METHOD("body_get_canvas_instance_id", "body"), &Physics2DServer::body_get_canvas_instance_id);
+
ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode);
ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode);
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 7c23fcdaea..2e91d89c53 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -147,8 +147,9 @@ class Physics2DDirectSpaceState : public Object {
GDCLASS(Physics2DDirectSpaceState, Object);
Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
-
Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
@@ -181,6 +182,7 @@ public:
};
virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+ virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
@@ -348,6 +350,9 @@ public:
virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID) = 0;
virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
+ virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) = 0;
+ virtual ObjectID area_get_canvas_instance_id(RID p_area) const = 0;
+
virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0;
@@ -401,6 +406,9 @@ public:
virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID) = 0;
virtual uint32_t body_get_object_instance_id(RID p_body) const = 0;
+ virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) = 0;
+ virtual uint32_t body_get_canvas_instance_id(RID p_body) const = 0;
+
enum CCDMode {
CCD_MODE_DISABLED,
CCD_MODE_CAST_RAY,
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 8c3736a1bf..f87f838fd6 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -800,8 +800,6 @@ public:
RID particles;
RID texture;
RID normal_map;
- int h_frames;
- int v_frames;
CommandParticles() { type = TYPE_PARTICLES; }
};
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 67a810bf1c..3fe661090c 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -691,6 +691,30 @@ String ShaderLanguage::token_debug(const String &p_code) {
return output;
}
+bool ShaderLanguage::is_token_variable_datatype(TokenType p_type) {
+ return (
+ p_type == TK_TYPE_VOID ||
+ p_type == TK_TYPE_BOOL ||
+ p_type == TK_TYPE_BVEC2 ||
+ p_type == TK_TYPE_BVEC3 ||
+ p_type == TK_TYPE_BVEC4 ||
+ p_type == TK_TYPE_INT ||
+ p_type == TK_TYPE_IVEC2 ||
+ p_type == TK_TYPE_IVEC3 ||
+ p_type == TK_TYPE_IVEC4 ||
+ p_type == TK_TYPE_UINT ||
+ p_type == TK_TYPE_UVEC2 ||
+ p_type == TK_TYPE_UVEC3 ||
+ p_type == TK_TYPE_UVEC4 ||
+ p_type == TK_TYPE_FLOAT ||
+ p_type == TK_TYPE_VEC2 ||
+ p_type == TK_TYPE_VEC3 ||
+ p_type == TK_TYPE_VEC4 ||
+ p_type == TK_TYPE_MAT2 ||
+ p_type == TK_TYPE_MAT3 ||
+ p_type == TK_TYPE_MAT4);
+}
+
bool ShaderLanguage::is_token_datatype(TokenType p_type) {
return (
@@ -2498,7 +2522,7 @@ bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionT
identifier = StringName();
- TkPos pos;
+ TkPos pos = { 0, 0 };
Token tk = _get_token();
@@ -3506,6 +3530,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
nv.sint = -cn->values[i].sint;
} break;
case TYPE_UINT: {
+ // FIXME: This can't work on uint
nv.uint = -cn->values[i].uint;
} break;
case TYPE_FLOAT: {
@@ -3562,6 +3587,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
}
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for variable (samplers not allowed)");
+ return ERR_PARSE_ERROR;
+ }
+
DataType type = get_token_datatype(tk.type);
tk = _get_token();
@@ -4217,6 +4247,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for function return (samplers not allowed)");
+ return ERR_PARSE_ERROR;
+ }
+
type = get_token_datatype(tk.type);
_get_completable_identifier(NULL, COMPLETION_MAIN_FUNCTION, name);
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index 08c4d06992..f07b1fade5 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -534,6 +534,7 @@ public:
static String get_token_text(Token p_token);
static bool is_token_datatype(TokenType p_type);
+ static bool is_token_variable_datatype(TokenType p_type);
static DataType get_token_datatype(TokenType p_type);
static bool is_token_interpolation(TokenType p_type);
static DataInterpolation get_token_interpolation(TokenType p_type);
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index 69acf52e17..baafe2f8d0 100644
--- a/servers/visual/shader_types.cpp
+++ b/servers/visual/shader_types.cpp
@@ -199,6 +199,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index 16cda0326d..84b7504ad4 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -689,7 +689,7 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2
if (indices.empty()) {
ERR_EXPLAIN("Bad Polygon!");
- ERR_FAIL_V();
+ ERR_FAIL();
}
Item::CommandPolygon *polygon = memnew(Item::CommandPolygon);
@@ -776,7 +776,7 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID
canvas_item->commands.push_back(m);
}
-void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames) {
+void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -786,8 +786,6 @@ void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles,
part->particles = p_particles;
part->texture = p_texture;
part->normal_map = p_normal;
- part->h_frames = p_h_frames;
- part->v_frames = p_v_frames;
//take the chance and request processing for them, at least once until they become visible again
VSG::storage->particles_request_process(p_particles);
diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h
index 966b51d341..d12bd520bf 100644
--- a/servers/visual/visual_server_canvas.h
+++ b/servers/visual/visual_server_canvas.h
@@ -186,7 +186,7 @@ public:
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, RID p_normal_map = RID());
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
- void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames);
+ void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal);
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 62ba2eab69..b33ef21e78 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -474,7 +474,7 @@ public:
BIND2(viewport_set_transparent_background, RID, bool)
BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &)
- BIND3(viewport_set_canvas_layer, RID, RID, int)
+ BIND4(viewport_set_canvas_stacking, RID, RID, int, int)
BIND2(viewport_set_shadow_atlas_size, RID, int)
BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
BIND2(viewport_set_msaa, RID, ViewportMSAA)
@@ -599,7 +599,7 @@ public:
BIND10(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, RID)
BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID)
BIND4(canvas_item_add_multimesh, RID, RID, RID, RID)
- BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
+ BIND4(canvas_item_add_particles, RID, RID, RID, RID)
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
BIND2(canvas_item_add_clip_ignore, RID, bool)
BIND2(canvas_item_set_sort_children_by_y, RID, bool)
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 654994b83f..33fa8d365f 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -601,8 +601,9 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf
Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);
- if (instance->update_item.in_list()) {
- _update_dirty_instance(instance);
+ if (instance->base_type == VS::INSTANCE_MESH) {
+ //may not have been updated yet
+ instance->materials.resize(VSG::storage->mesh_get_surface_count(instance->base));
}
ERR_FAIL_INDEX(p_surface, instance->materials.size());
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
index b286533590..571b71db85 100644
--- a/servers/visual/visual_server_viewport.cpp
+++ b/servers/visual/visual_server_viewport.cpp
@@ -137,7 +137,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
}
- canvas_map[Viewport::CanvasKey(E->key(), E->get().layer)] = &E->get();
+ canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get();
}
if (lights_with_shadow) {
@@ -176,7 +176,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
VSG::rasterizer->restore_render_target();
- if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().layer > scenario_canvas_max_layer) {
+ if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
if (!can_draw_3d) {
@@ -209,7 +209,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect);
i++;
- if (scenario_draw_canvas_bg && E->key().layer >= scenario_canvas_max_layer) {
+ if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
if (!can_draw_3d) {
@@ -496,6 +496,7 @@ void VisualServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas)
canvas->viewports.insert(p_viewport);
viewport->canvas_map[p_canvas] = Viewport::CanvasData();
viewport->canvas_map[p_canvas].layer = 0;
+ viewport->canvas_map[p_canvas].sublayer = 0;
viewport->canvas_map[p_canvas].canvas = canvas;
}
@@ -534,13 +535,14 @@ void VisualServerViewport::viewport_set_global_canvas_transform(RID p_viewport,
viewport->global_transform = p_transform;
}
-void VisualServerViewport::viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer) {
+void VisualServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
viewport->canvas_map[p_canvas].layer = p_layer;
+ viewport->canvas_map[p_canvas].sublayer = p_sublayer;
}
void VisualServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) {
diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h
index cb7912d6f4..66baa48458 100644
--- a/servers/visual/visual_server_viewport.h
+++ b/servers/visual/visual_server_viewport.h
@@ -78,17 +78,21 @@ public:
struct CanvasKey {
- int layer;
+ int64_t stacking;
RID canvas;
bool operator<(const CanvasKey &p_canvas) const {
- if (layer == p_canvas.layer) return canvas < p_canvas.canvas;
- return layer < p_canvas.layer;
+ if (stacking == p_canvas.stacking)
+ return canvas < p_canvas.canvas;
+ return stacking < p_canvas.stacking;
+ }
+ CanvasKey() {
+ stacking = 0;
}
- CanvasKey() { layer = 0; }
- CanvasKey(const RID &p_canvas, int p_layer) {
+ CanvasKey(const RID &p_canvas, int p_layer, int p_sublayer) {
canvas = p_canvas;
- layer = p_layer;
+ stacking = ((int64_t)p_layer << 32) + p_sublayer;
}
+ int get_layer() const { return stacking >> 32; }
};
struct CanvasData {
@@ -96,6 +100,7 @@ public:
CanvasBase *canvas;
Transform2D transform;
int layer;
+ int sublayer;
};
Transform2D global_transform;
@@ -176,7 +181,7 @@ public:
void viewport_set_transparent_background(RID p_viewport, bool p_enabled);
void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform);
- void viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer);
+ void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer);
void viewport_set_shadow_atlas_size(RID p_viewport, int p_size);
void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv);
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index e4d69121f0..137fcb55f4 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -400,7 +400,7 @@ public:
FUNC2(viewport_set_transparent_background, RID, bool)
FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &)
- FUNC3(viewport_set_canvas_layer, RID, RID, int)
+ FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
FUNC2(viewport_set_shadow_atlas_size, RID, int)
FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
FUNC2(viewport_set_msaa, RID, ViewportMSAA)
@@ -516,7 +516,7 @@ public:
FUNC10(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, RID)
FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID)
FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID)
- FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
+ FUNC4(canvas_item_add_particles, RID, RID, RID, RID)
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
FUNC2(canvas_item_add_clip_ignore, RID, bool)
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 9d684d33d6..4b0e5cd28d 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -1890,7 +1890,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_canvas_transform", "viewport", "canvas", "offset"), &VisualServer::viewport_set_canvas_transform);
ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &VisualServer::viewport_set_transparent_background);
ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &VisualServer::viewport_set_global_canvas_transform);
- ClassDB::bind_method(D_METHOD("viewport_set_canvas_layer", "viewport", "canvas", "layer"), &VisualServer::viewport_set_canvas_layer);
+ ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &VisualServer::viewport_set_canvas_stacking);
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &VisualServer::viewport_set_shadow_atlas_size);
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &VisualServer::viewport_set_shadow_atlas_quadrant_subdivision);
ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &VisualServer::viewport_set_msaa);
@@ -1978,7 +1978,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_mesh, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_multimesh, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map", "h_frames", "v_frames"), &VisualServer::canvas_item_add_particles);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &VisualServer::canvas_item_add_particles);
ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &VisualServer::canvas_item_add_set_transform);
ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &VisualServer::canvas_item_add_clip_ignore);
ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &VisualServer::canvas_item_set_sort_children_by_y);
@@ -2370,6 +2370,7 @@ VisualServer::VisualServer() {
GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096);
GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096);
GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384"));
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 9d98fca21b..5af10ded28 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -644,7 +644,7 @@ public:
virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0;
virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0;
- virtual void viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer) = 0;
+ virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0;
virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0;
virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0;
@@ -895,7 +895,7 @@ public:
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, RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
- virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0;
+ virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0;
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0;
virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 7fdd9e20b0..1e1fea85e5 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -264,9 +264,7 @@ File extracted from upstream source:
- From `roles/ws` exclude `ext` folder.
- From `tls` exclude `openssl` folder.
- Also copy `win32helpers/` from `win32port/` inside `thirdparty/libwebsockets`
-- A small fix has been added in `libwebsockets/libwebsockets.h` to `#include <sys/socket.h>` for the BSD family.
- This change has been PRed upstream, and should be merged before the next update. Remember to check and remove this line.
-- Another fix has been added to allow building for 32-bits UWP, replacing `GetFileSize[Ex]` and `CreateFileW` with supported functions.
+- A fix has been added to allow building for 32-bits UWP, replacing `GetFileSize[Ex]` and `CreateFileW` with supported functions.
There is a diff for this change in `thirdparty/libwebsockets/uwp_fixes.diff`
Important: `lws_config.h` and `lws_config_private.h` contains custom
diff --git a/thirdparty/libwebsockets/core/context.c b/thirdparty/libwebsockets/core/context.c
index db9151b95f..7be004df33 100644
--- a/thirdparty/libwebsockets/core/context.c
+++ b/thirdparty/libwebsockets/core/context.c
@@ -134,7 +134,7 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost,
{
int n = 0;
- if (!vhost || !vhost->protocol_vh_privs)
+ if (!vhost || !vhost->protocol_vh_privs || !prot)
return NULL;
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
@@ -808,7 +808,7 @@ lws_create_vhost(struct lws_context *context,
#ifdef LWS_WITH_ACCESS_LOG
if (info->log_filepath) {
- vh->log_fd = open(info->log_filepath,
+ vh->log_fd = lws_open(info->log_filepath,
O_CREAT | O_APPEND | O_RDWR, 0600);
if (vh->log_fd == (int)LWS_INVALID_FILE) {
lwsl_err("unable to open log filepath %s\n",
@@ -936,24 +936,29 @@ lws_create_event_pipes(struct lws_context *context)
wsi->tsi = n;
wsi->vhost = NULL;
wsi->event_pipe = 1;
+ wsi->desc.sockfd = LWS_SOCK_INVALID;
+ context->pt[n].pipe_wsi = wsi;
+ context->count_wsi_allocated++;
- if (lws_plat_pipe_create(wsi)) {
- lws_free(wsi);
+ if (lws_plat_pipe_create(wsi))
+ /*
+ * platform code returns 0 if it actually created pipes
+ * and initialized pt->dummy_pipe_fds[]. If it used
+ * some other mechanism outside of signaling in the
+ * normal event loop, we skip treating the pipe as
+ * related to dummy_pipe_fds[], adding it to the fds,
+ * etc.
+ */
continue;
- }
+
wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
- context->pt[n].pipe_wsi = wsi;
-
if (context->event_loop_ops->accept)
context->event_loop_ops->accept(wsi);
if (__insert_wsi_socket_into_fds(context, wsi))
return 1;
-
- //lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
- context->count_wsi_allocated++;
}
return 0;
diff --git a/thirdparty/libwebsockets/core/libwebsockets.c b/thirdparty/libwebsockets/core/libwebsockets.c
index 0da02b17e4..58f00226f6 100644
--- a/thirdparty/libwebsockets/core/libwebsockets.c
+++ b/thirdparty/libwebsockets/core/libwebsockets.c
@@ -28,7 +28,7 @@
#ifdef LWS_WITH_IPV6
#if defined(WIN32) || defined(_WIN32)
#include <wincrypt.h>
-#include <Iphlpapi.h>
+#include <iphlpapi.h>
#else
#include <net/if.h>
#endif
@@ -58,6 +58,28 @@ static const char * const log_level_names[] = {
};
#endif
+int lws_open(const char *__file, int __oflag, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, __oflag);
+ if (((__oflag & O_CREAT) == O_CREAT)
+#if defined(O_TMPFILE)
+ || ((__oflag & O_TMPFILE) == O_TMPFILE)
+#endif
+ )
+ /* last arg is really a mode_t. But windows... */
+ n = open(__file, __oflag, va_arg(ap, uint32_t));
+ else
+ n = open(__file, __oflag);
+ va_end(ap);
+
+ lws_plat_apply_FD_CLOEXEC(n);
+
+ return n;
+}
+
#if defined (_DEBUG)
void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
{
@@ -826,7 +848,15 @@ just_kill_connection:
if (!wsi->protocol)
pro = &wsi->vhost->protocols[0];
- pro->callback(wsi,
+ if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi))
+ /*
+ * The network wsi for a client h2 connection shouldn't
+ * call back for its role: the child stream connections
+ * own the role. Otherwise h2 will call back closed
+ * one too many times as the children do it and then
+ * the closing network stream.
+ */
+ pro->callback(wsi,
wsi->role_ops->close_cb[lwsi_role_server(wsi)],
wsi->user_space, NULL, 0);
wsi->told_user_closed = 1;
@@ -1453,7 +1483,7 @@ lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
pf = fops->next;
while (pf) {
n = 0;
- while (n < (int)ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
+ while (n < (int)LWS_ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
if (p >= vfs_path + pf->fi[n].len)
if (!strncmp(p - (pf->fi[n].len - 1),
pf->fi[n].sig,
@@ -1935,9 +1965,9 @@ static const char * const colours[] = {
"[32;1m", /* LLL_INFO */
"[34;1m", /* LLL_DEBUG */
"[33;1m", /* LLL_PARSER */
- "[33;1m", /* LLL_HEADER */
- "[33;1m", /* LLL_EXT */
- "[33;1m", /* LLL_CLIENT */
+ "[33m", /* LLL_HEADER */
+ "[33m", /* LLL_EXT */
+ "[33m", /* LLL_CLIENT */
"[33;1m", /* LLL_LATENCY */
"[30;1m", /* LLL_USER */
};
@@ -1946,14 +1976,14 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
{
char buf[50];
static char tty = 3;
- int n, m = ARRAY_SIZE(colours) - 1;
+ int n, m = LWS_ARRAY_SIZE(colours) - 1;
if (!tty)
tty = isatty(2) | 2;
lwsl_timestamp(level, buf, sizeof(buf));
if (tty == 3) {
- n = 1 << (ARRAY_SIZE(colours) - 1);
+ n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
while (n) {
if (level & n)
break;
@@ -2060,7 +2090,9 @@ lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
LWS_VISIBLE void
lwsl_hexdump(const void *vbuf, size_t len)
{
+#if defined(_DEBUG)
lwsl_hexdump_level(LLL_DEBUG, vbuf, len);
+#endif
}
LWS_VISIBLE int
@@ -2091,6 +2123,8 @@ lws_partial_buffered(struct lws *wsi)
LWS_VISIBLE lws_fileofs_t
lws_get_peer_write_allowance(struct lws *wsi)
{
+ if (!wsi->role_ops->tx_credit)
+ return -1;
return wsi->role_ops->tx_credit(wsi);
}
@@ -3364,7 +3398,7 @@ lws_stats_log_dump(struct lws_context *context)
wl = pt->http.ah_wait_list;
while (wl) {
m++;
- wl = wl->ah_wait_list;
+ wl = wl->http.ah_wait_list;
}
lwsl_notice(" AH wait list count / actual: %d / %d\n",
@@ -3401,7 +3435,8 @@ lws_stats_log_dump(struct lws_context *context)
strcpy(buf, "unknown");
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n",
- buf, df->count_wsi, df->count_ah);
+ buf, df->count_wsi,
+ df->http.count_ah);
#else
lwsl_notice(" peer %s: count wsi: %d\n",
buf, df->count_wsi);
diff --git a/thirdparty/libwebsockets/core/output.c b/thirdparty/libwebsockets/core/output.c
index e2ff18ef27..11965a06b9 100644
--- a/thirdparty/libwebsockets/core/output.c
+++ b/thirdparty/libwebsockets/core/output.c
@@ -126,6 +126,18 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
lwsl_info("** %p signalling to close now\n", wsi);
return -1; /* retry closing now */
}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+#if !defined(LWS_WITHOUT_SERVER)
+ if (wsi->http.deferred_transaction_completed) {
+ lwsl_notice("%s: partial completed, doing "
+ "deferred transaction completed\n",
+ __func__);
+ wsi->http.deferred_transaction_completed = 0;
+ return lws_http_transaction_completed(wsi);
+ }
+#endif
+#endif
}
/* always callback on writeable */
lws_callback_on_writable(wsi);
diff --git a/thirdparty/libwebsockets/core/private.h b/thirdparty/libwebsockets/core/private.h
index d6b494ac8c..73748b0498 100644
--- a/thirdparty/libwebsockets/core/private.h
+++ b/thirdparty/libwebsockets/core/private.h
@@ -232,7 +232,7 @@
#endif
#else /* not windows */
- static inline int compatible_close(int fd) { return close(fd); }
+ static LWS_INLINE int compatible_close(int fd) { return close(fd); }
#include <sys/stat.h>
#include <sys/time.h>
@@ -351,7 +351,15 @@ extern "C" {
#define LWS_H2_RX_SCRATCH_SIZE 512
-
+#if defined(WIN32) || defined(_WIN32)
+ // Visual studio older than 2015 and WIN_CE has only _stricmp
+ #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
+ #define strcasecmp _stricmp
+ #elif !defined(__MINGW32__)
+ #define strcasecmp stricmp
+ #endif
+ #define getdtablesize() 30000
+#endif
/*
* All lws_tls...() functions must return this type, converting the
@@ -863,6 +871,7 @@ struct lws_context {
unsigned int timeout_secs;
unsigned int pt_serv_buf_size;
int max_http_header_data;
+ int max_http_header_pool;
int simultaneous_ssl_restriction;
int simultaneous_ssl;
#if defined(LWS_WITH_PEER_LIMITS)
@@ -889,7 +898,6 @@ struct lws_context {
volatile int service_tid;
int service_tid_detected;
- short max_http_header_pool;
short count_threads;
short plugin_protocol_count;
short plugin_extension_count;
@@ -1216,7 +1224,7 @@ LWS_EXTERN int
lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
#ifndef LWS_LATENCY
-static inline void
+static LWS_INLINE void
lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
int ret, int completion) {
do {
@@ -1224,7 +1232,7 @@ lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
(void)completion;
} while (0);
}
-static inline void
+static LWS_INLINE void
lws_latency_pre(struct lws_context *context, struct lws *wsi) {
do { (void)context; (void)wsi; } while (0);
}
@@ -1597,6 +1605,9 @@ void lws_free(void *p);
#define lws_free_set_NULL(P) do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0)
#endif
+char *
+lws_strdup(const char *s);
+
int
lws_plat_pipe_create(struct lws *wsi);
int
@@ -1606,6 +1617,9 @@ lws_plat_pipe_close(struct lws *wsi);
int
lws_create_event_pipes(struct lws_context *context);
+int lws_open(const char *__file, int __oflag, ...);
+void lws_plat_apply_FD_CLOEXEC(int n);
+
const struct lws_plat_file_ops *
lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
const char **vpath);
@@ -1673,10 +1687,10 @@ lws_broadcast(struct lws_context *context, int reason, void *in, size_t len);
lws_stats_atomic_max(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t val);
#else
- static inline uint64_t lws_stats_atomic_bump(struct lws_context * context,
+ static LWS_INLINE uint64_t lws_stats_atomic_bump(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t bump) {
(void)context; (void)pt; (void)index; (void)bump; return 0; }
- static inline uint64_t lws_stats_atomic_max(struct lws_context * context,
+ static LWS_INLINE uint64_t lws_stats_atomic_max(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t val) {
(void)context; (void)pt; (void)index; (void)val; return 0; }
#endif
@@ -1703,6 +1717,11 @@ void
lws_peer_dump_from_wsi(struct lws *wsi);
#endif
+#ifdef LWS_WITH_HTTP_PROXY
+hubbub_error
+html_parser_cb(const hubbub_token *token, void *pw);
+#endif
+
void
__lws_remove_from_timeout_list(struct lws *wsi);
diff --git a/thirdparty/libwebsockets/libwebsockets.h b/thirdparty/libwebsockets/libwebsockets.h
index 7ae563d582..2c01696404 100644
--- a/thirdparty/libwebsockets/libwebsockets.h
+++ b/thirdparty/libwebsockets/libwebsockets.h
@@ -66,14 +66,6 @@ typedef unsigned long long lws_intptr_t;
#define O_RDONLY _O_RDONLY
#endif
-// Visual studio older than 2015 and WIN_CE has only _stricmp
-#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
-#define strcasecmp _stricmp
-#elif !defined(__MINGW32__)
-#define strcasecmp stricmp
-#endif
-#define getdtablesize() 30000
-
#define LWS_INLINE __inline
#define LWS_VISIBLE
#define LWS_WARN_UNUSED_RESULT
@@ -150,6 +142,7 @@ typedef unsigned long long lws_intptr_t;
#endif
#if defined(__ANDROID__)
+#include <netinet/in.h>
#include <unistd.h>
#define getdtablesize() sysconf(_SC_OPEN_MAX)
#endif
@@ -164,6 +157,9 @@ typedef unsigned long long lws_intptr_t;
#ifdef LWS_HAVE_UV_VERSION_H
#include <uv-version.h>
#endif
+#ifdef LWS_HAVE_NEW_UV_VERSION_H
+#include <uv/version.h>
+#endif
#endif /* LWS_WITH_LIBUV */
#if defined(LWS_WITH_LIBEVENT)
#include <event2/event.h>
@@ -456,9 +452,6 @@ lwsl_visible(int level);
#endif
struct lws;
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#endif
typedef int64_t lws_usec_t;
@@ -540,7 +533,7 @@ struct timer_mapping {
#define lws_uv_getloop(a, b) (NULL)
-static inline void uv_timer_init(void *l, uv_timer_t *t)
+static LWS_INLINE void uv_timer_init(void *l, uv_timer_t *t)
{
(void)l;
*t = NULL;
@@ -548,7 +541,7 @@ static inline void uv_timer_init(void *l, uv_timer_t *t)
extern void esp32_uvtimer_cb(TimerHandle_t t);
-static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
+static LWS_INLINE void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
{
struct timer_mapping *tm = (struct timer_mapping *)malloc(sizeof(*tm));
@@ -563,12 +556,12 @@ static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep
xTimerStart(*t, 0);
}
-static inline void uv_timer_stop(uv_timer_t *t)
+static LWS_INLINE void uv_timer_stop(uv_timer_t *t)
{
xTimerStop(*t, 0);
}
-static inline void uv_close(uv_handle_t *h, void *v)
+static LWS_INLINE void uv_close(uv_handle_t *h, void *v)
{
free(pvTimerGetTimerID((uv_timer_t)h));
xTimerDelete(*(uv_timer_t *)h, 0);
@@ -1757,7 +1750,7 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result);
* If the return is nonzero, it failed and there is nothing needing to be
* destroyed.
*/
-int
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
const uint8_t *key, size_t key_len);
@@ -1771,7 +1764,7 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
*
* If the return is nonzero, it failed and needs destroying.
*/
-int
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len);
/** lws_genhmac_destroy() - copy out the result digest and destroy the ctx
@@ -1785,7 +1778,7 @@ lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len);
* NULL result is supported so that you can destroy the ctx cleanly on error
* conditions, where there is no valid result.
*/
-int
+LWS_VISIBLE LWS_EXTERN int
lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result);
///@}
@@ -2812,7 +2805,7 @@ struct lws_context_creation_info {
/**< VHOST: pointer to optional linked list of per-vhost
* options made accessible to protocols */
int keepalive_timeout;
- /**< VHOST: (default = 0 = 60s) seconds to allow remote
+ /**< VHOST: (default = 0 = 5s) seconds to allow remote
* client to hold on to an idle HTTP/1.1 connection */
const char *log_filepath;
/**< VHOST: filepath to append logs to... this is opened before
@@ -4943,7 +4936,7 @@ lws_write(struct lws *wsi, unsigned char *buf, size_t len,
lws_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP)
/* helper for multi-frame ws message flags */
-static inline int
+static LWS_INLINE int
lws_write_ws_flags(int initial, int is_start, int is_end)
{
int r;
@@ -5621,13 +5614,13 @@ struct lws_dll_lws { /* typed as struct lws * */
#define lws_dll_is_null(___dll) (!(___dll)->prev && !(___dll)->next)
-static inline void
+static LWS_INLINE void
lws_dll_lws_add_front(struct lws_dll_lws *_a, struct lws_dll_lws *_head)
{
lws_dll_add_front((struct lws_dll *)_a, (struct lws_dll *)_head);
}
-static inline void
+static LWS_INLINE void
lws_dll_lws_remove(struct lws_dll_lws *_a)
{
lws_dll_remove((struct lws_dll *)_a);
@@ -7064,9 +7057,6 @@ lws_email_destroy(struct lws_email *email);
//@{
struct lejp_ctx;
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
-#endif
#define LWS_ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
#define LEJP_FLAG_WS_KEEP 64
#define LEJP_FLAG_WS_COMMENTLINE 32
@@ -7219,7 +7209,7 @@ typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
#endif
#ifndef LEJP_STRING_CHUNK
/* must be >= 30 to assemble floats */
-#define LEJP_STRING_CHUNK 255
+#define LEJP_STRING_CHUNK 254
#endif
enum num_flags {
@@ -7253,7 +7243,7 @@ struct lejp_ctx {
uint16_t i[LEJP_MAX_INDEX_DEPTH]; /* index array */
uint16_t wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
char path[LEJP_MAX_PATH];
- char buf[LEJP_STRING_CHUNK];
+ char buf[LEJP_STRING_CHUNK + 1];
/* int */
diff --git a/thirdparty/libwebsockets/lws_config.h b/thirdparty/libwebsockets/lws_config.h
index e5e15cc2fd..86ce9ac38a 100644
--- a/thirdparty/libwebsockets/lws_config.h
+++ b/thirdparty/libwebsockets/lws_config.h
@@ -174,7 +174,7 @@
#define LWS_HAVE_MALLOC_H
#endif
-#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED) && !defined(__HAIKU__)
+#if !defined(__APPLE__) && !defined(__HAIKU__)
#define LWS_HAVE_PIPE2
#endif
diff --git a/thirdparty/libwebsockets/lws_config_private.h b/thirdparty/libwebsockets/lws_config_private.h
index b26d225afa..e531777624 100644
--- a/thirdparty/libwebsockets/lws_config_private.h
+++ b/thirdparty/libwebsockets/lws_config_private.h
@@ -81,7 +81,7 @@
/* Define to 1 if you have the <sys/prctl.h> header file. */
#define LWS_HAVE_SYS_PRCTL_H
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
#undef LWS_HAVE_SYS_PRCTL_H
#endif
diff --git a/thirdparty/libwebsockets/misc/lejp.c b/thirdparty/libwebsockets/misc/lejp.c
index 00d350f81e..99142b9553 100644
--- a/thirdparty/libwebsockets/misc/lejp.c
+++ b/thirdparty/libwebsockets/misc/lejp.c
@@ -20,6 +20,7 @@
*/
#include <libwebsockets.h>
+#include "core/private.h"
#include <string.h>
#include <stdio.h>
@@ -30,7 +31,7 @@
* \param callback: your user callback which will received parsed tokens
* \param user: optional user data pointer untouched by lejp
* \param paths: your array of name elements you are interested in
- * \param count_paths: ARRAY_SIZE() of @paths
+ * \param count_paths: LWS_ARRAY_SIZE() of @paths
*
* Prepares your context struct for use with lejp
*/
@@ -250,7 +251,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
case LEJP_MP_STRING:
if (c == '\"') {
- if (!ctx->sp) {
+ if (!ctx->sp) { /* JSON can't end on quote */
ret = LEJP_REJECT_MP_STRING_UNDERRUN;
goto reject;
}
@@ -417,7 +418,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
goto reject;
}
ctx->i[ctx->ipos++] = 0;
- if (ctx->ipos > ARRAY_SIZE(ctx->i)) {
+ if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
ret = LEJP_REJECT_MP_DELIM_ISTACK;
goto reject;
}
@@ -425,17 +426,23 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
case ']':
/* pop */
+ if (!ctx->sp) { /* JSON can't end on ] */
+ ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
+ goto reject;
+ }
ctx->sp--;
if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
goto reject;
}
/* drop the path [n] bit */
- ctx->ppos = ctx->st[ctx->sp - 1].p;
- ctx->ipos = ctx->st[ctx->sp - 1].i;
+ if (ctx->sp) {
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->ipos = ctx->st[ctx->sp - 1].i;
+ }
ctx->path[ctx->ppos] = '\0';
if (ctx->path_match &&
- ctx->ppos <= ctx->path_match_len)
+ ctx->ppos <= ctx->path_match_len)
/*
* we shrank the path to be
* smaller than the matching point
@@ -603,7 +610,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
break;
}
if (c == ']') {
- if (!ctx->sp) {
+ if (!ctx->sp) { /* JSON can't end on ] */
ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
goto reject;
}
@@ -631,7 +638,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
goto redo_character;
}
if (c == '}') {
- if (ctx->sp == 0) {
+ if (!ctx->sp) {
lejp_check_path_match(ctx);
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
ret = LEJP_REJECT_CALLBACK;
@@ -716,7 +723,7 @@ add_stack_level:
ctx->st[ctx->sp].p = ctx->ppos;
ctx->st[ctx->sp].i = ctx->ipos;
- if (++ctx->sp == ARRAY_SIZE(ctx->st)) {
+ if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
ret = LEJP_REJECT_STACK_OVERFLOW;
goto reject;
}
diff --git a/thirdparty/libwebsockets/plat/lws-plat-unix.c b/thirdparty/libwebsockets/plat/lws-plat-unix.c
index bacc6af647..7dba3bd82f 100644
--- a/thirdparty/libwebsockets/plat/lws-plat-unix.c
+++ b/thirdparty/libwebsockets/plat/lws-plat-unix.c
@@ -30,6 +30,12 @@
#endif
#include <dirent.h>
+void lws_plat_apply_FD_CLOEXEC(int n)
+{
+ if (n != -1)
+ fcntl(n, F_SETFD, FD_CLOEXEC );
+}
+
int
lws_plat_socket_offset(void)
{
@@ -330,6 +336,8 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
struct protoent *tcp_proto;
#endif
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
if (vhost->ka_time) {
/* enable keepalive on this socket */
optval = 1;
@@ -952,7 +960,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
LWS_VISIBLE int
lws_plat_read_file(const char *filename, void *buf, int len)
{
- int n, fd = open(filename, O_RDONLY);
+ int n, fd = lws_open(filename, O_RDONLY);
if (fd == -1)
return -1;
diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
index 8a43081ef1..1850b64250 100644
--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
+++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
@@ -3,6 +3,10 @@
#endif
#include "core/private.h"
+void lws_plat_apply_FD_CLOEXEC(int n)
+{
+}
+
int
lws_plat_socket_offset(void)
{
@@ -54,7 +58,7 @@ time_in_microseconds()
memcpy(&datetime, &filetime, sizeof(datetime));
/* Windows file times are in 100s of nanoseconds. */
- return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;
+ return (datetime.QuadPart / 10) - DELTA_EPOCH_IN_MICROSECS;
}
#ifdef _WIN32_WCE
@@ -229,23 +233,21 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
continue;
wsi = wsi_from_fd(context, pfd->fd);
- if (wsi->listener)
+ if (!wsi || wsi->listener)
continue;
- if (!wsi || wsi->sock_send_blocking)
+ if (wsi->sock_send_blocking)
continue;
pfd->revents = LWS_POLLOUT;
n = lws_service_fd(context, pfd);
if (n < 0)
return -1;
+
+ /* Force WSAWaitForMultipleEvents() to check events and then return immediately. */
+ timeout_ms = 0;
+
/* if something closed, retry this slot */
if (n)
i--;
-
- /*
- * any wsi has truncated, force him signalled
- */
- if (wsi->trunc_len)
- WSASetEvent(pt->events[0]);
}
/*
@@ -261,9 +263,11 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
}
if (timeout_ms) {
+ lws_usec_t t;
+
lws_pt_lock(pt, __func__);
/* don't stay in poll wait longer than next hr timeout */
- lws_usec_t t = __lws_hrtimer_service(pt);
+ t = __lws_hrtimer_service(pt);
if ((lws_usec_t)timeout_ms * 1000 > t)
timeout_ms = (int)(t / 1000);
@@ -310,8 +314,10 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (pfd->revents & LWS_POLLHUP)
--eIdx;
- if (pfd->revents)
+ if (pfd->revents) {
+ recv(pfd->fd, NULL, 0, 0);
lws_service_fd_tsi(context, pfd, tsi);
+ }
}
}
@@ -637,7 +643,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
lws_fop_fd_t fop_fd;
FILE_STANDARD_INFO fInfo = {0};
- MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
@@ -810,7 +816,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
{
int m, fd;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
return -1;
@@ -824,7 +830,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
LWS_VISIBLE int
lws_plat_read_file(const char *filename, void *buf, int len)
{
- int n, fd = open(filename, O_RDONLY);
+ int n, fd = lws_open(filename, O_RDONLY);
if (fd == -1)
return -1;
diff --git a/thirdparty/libwebsockets/roles/h1/ops-h1.c b/thirdparty/libwebsockets/roles/h1/ops-h1.c
index d3b16f4d1f..9001c864ea 100644
--- a/thirdparty/libwebsockets/roles/h1/ops-h1.c
+++ b/thirdparty/libwebsockets/roles/h1/ops-h1.c
@@ -195,6 +195,7 @@ postbody_completion:
}
break;
+ case LRS_RETURNED_CLOSE:
case LRS_AWAITING_CLOSE_ACK:
case LRS_WAITING_TO_SEND_CLOSE:
case LRS_SHUTDOWN:
@@ -444,6 +445,16 @@ try_pollout:
if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
+ if (wsi->trunc_len) {
+ //lwsl_notice("%s: completing partial\n", __func__);
+ if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset,
+ wsi->trunc_len) < 0) {
+ lwsl_info("%s signalling to close\n", __func__);
+ goto fail;
+ }
+ return LWS_HPI_RET_HANDLED;
+ }
+
lws_stats_atomic_bump(wsi->context, pt,
LWSSTATS_C_WRITEABLE_CB, 1);
#if defined(LWS_WITH_STATS)
@@ -655,6 +666,9 @@ rops_destroy_role_h1(struct lws *wsi)
ah = ah->next;
}
+#ifdef LWS_ROLE_WS
+ lws_free_set_NULL(wsi->ws);
+#endif
return 0;
}
diff --git a/thirdparty/libwebsockets/roles/http/client/client-handshake.c b/thirdparty/libwebsockets/roles/http/client/client-handshake.c
index 4830fc9eca..0095c79a69 100644
--- a/thirdparty/libwebsockets/roles/http/client/client-handshake.c
+++ b/thirdparty/libwebsockets/roles/http/client/client-handshake.c
@@ -162,7 +162,7 @@ create_new_conn:
if (!wsi->client_hostname_copy)
wsi->client_hostname_copy =
- strdup(lws_hdr_simple_ptr(wsi,
+ lws_strdup(lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS));
/*
@@ -654,13 +654,13 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
lws_ssl_close(wsi);
#endif
+ __remove_wsi_socket_from_fds(wsi);
+
if (wsi->context->event_loop_ops->close_handle_manually)
wsi->context->event_loop_ops->close_handle_manually(wsi);
else
compatible_close(wsi->desc.sockfd);
- __remove_wsi_socket_from_fds(wsi);
-
#if defined(LWS_WITH_TLS)
wsi->tls.use_ssl = ssl;
#else
@@ -717,7 +717,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
}
#ifdef LWS_WITH_HTTP_PROXY
-static hubbub_error
+hubbub_error
html_parser_cb(const hubbub_token *token, void *pw)
{
struct lws_rewrite *r = (struct lws_rewrite *)pw;
@@ -846,7 +846,7 @@ html_parser_cb(const hubbub_token *token, void *pw)
#endif
-static char *
+char *
lws_strdup(const char *s)
{
char *d = lws_malloc(strlen(s) + 1, "strdup");
diff --git a/thirdparty/libwebsockets/roles/http/client/client.c b/thirdparty/libwebsockets/roles/http/client/client.c
index ce42dc6cd3..5645fa2b7a 100644
--- a/thirdparty/libwebsockets/roles/http/client/client.c
+++ b/thirdparty/libwebsockets/roles/http/client/client.c
@@ -93,7 +93,7 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
char *sb = p;
int n = 0;
#if defined(LWS_WITH_SOCKS5)
- char conn_mode = 0, pending_timeout = 0;
+ int conn_mode = 0, pending_timeout = 0;
#endif
if ((pollfd->revents & LWS_POLLOUT) &&
@@ -252,6 +252,8 @@ socks_reply_fail:
/* clear his proxy connection timeout */
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
goto start_ws_handshake;
+ default:
+ break;
}
break;
#endif
@@ -578,6 +580,8 @@ lws_http_transaction_completed_client(struct lws *wsi)
"queued client done");
}
+ _lws_header_table_reset(wsi->http.ah);
+
/* after the first one, they can only be coming from the queue */
wsi->transaction_from_pipeline_queue = 1;
@@ -629,12 +633,20 @@ lws_http_transaction_completed_client(struct lws *wsi)
}
LWS_VISIBLE LWS_EXTERN unsigned int
-lws_http_client_http_response(struct lws *wsi)
+lws_http_client_http_response(struct lws *_wsi)
{
- if (!wsi->http.ah)
- return 0;
+ struct lws *wsi;
+ unsigned int resp;
+
+ if (_wsi->http.ah && _wsi->http.ah->http_response)
+ return _wsi->http.ah->http_response;
- return wsi->http.ah->http_response;
+ lws_vhost_lock(_wsi->vhost);
+ wsi = _lws_client_wsi_master(_wsi);
+ resp = wsi->http.ah->http_response;
+ lws_vhost_unlock(_wsi->vhost);
+
+ return resp;
}
#endif
#if defined(LWS_PLAT_OPTEE)
@@ -781,7 +793,7 @@ lws_client_interpret_server_handshake(struct lws *wsi)
q = strrchr(new_path, '/');
if (q)
lws_strncpy(q + 1, p, sizeof(new_path) -
- (q - new_path));
+ (q - new_path) - 1);
else
path = p;
}
@@ -910,9 +922,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
* we seem to be good to go, give client last chance to check
* headers and OK it
*/
- if (wsi->protocol->callback(wsi,
+ if (w->protocol->callback(w,
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
- wsi->user_space, NULL, 0)) {
+ w->user_space, NULL, 0)) {
cce = "HS: disallowed by client filter";
goto bail2;
@@ -924,9 +936,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
/* call him back to inform him he is up */
- if (wsi->protocol->callback(wsi,
+ if (w->protocol->callback(w,
LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
- wsi->user_space, NULL, 0)) {
+ w->user_space, NULL, 0)) {
cce = "HS: disallowed at ESTABLISHED";
goto bail3;
}
@@ -964,9 +976,9 @@ bail2:
n = 0;
if (cce)
n = (int)strlen(cce);
- wsi->protocol->callback(wsi,
+ w->protocol->callback(w,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
- wsi->user_space, (void *)cce,
+ w->user_space, (void *)cce,
(unsigned int)n);
}
wsi->already_did_cce = 1;
@@ -1228,4 +1240,4 @@ completed:
return 0;
}
-#endif \ No newline at end of file
+#endif
diff --git a/thirdparty/libwebsockets/roles/http/header.c b/thirdparty/libwebsockets/roles/http/header.c
index 99e56f7564..dbcf27cbd1 100644
--- a/thirdparty/libwebsockets/roles/http/header.c
+++ b/thirdparty/libwebsockets/roles/http/header.c
@@ -26,7 +26,7 @@
const unsigned char *
lws_token_to_string(enum lws_token_indexes token)
{
- if ((unsigned int)token >= ARRAY_SIZE(set))
+ if ((unsigned int)token >= LWS_ARRAY_SIZE(set))
return NULL;
return (unsigned char *)set[token];
@@ -149,9 +149,17 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
(int)strlen(content_type), p, end))
return 1;
- if (content_len != LWS_ILLEGAL_HTTP_CONTENT_LEN &&
- lws_add_http_header_content_length(wsi, content_len, p, end))
- return 1;
+ if (content_len != LWS_ILLEGAL_HTTP_CONTENT_LEN) {
+ if (lws_add_http_header_content_length(wsi, content_len, p, end))
+ return 1;
+ } else {
+ if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
+ (unsigned char *)"close", 5,
+ p, end))
+ return 1;
+
+ wsi->http.connection_type = HTTP_CONNECTION_CLOSE;
+ }
return 0;
}
@@ -204,34 +212,40 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
#endif
#ifdef LWS_WITH_HTTP2
- if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
- return lws_add_http2_header_status(wsi, code, p, end);
+ if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi)) {
+ n = lws_add_http2_header_status(wsi, code, p, end);
+ if (n)
+ return n;
+ } else
#endif
- if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
- description = err400[code - 400];
- if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
- description = err500[code - 500];
-
- if (code == 100)
- description = "Continue";
- if (code == 200)
- description = "OK";
- if (code == 304)
- description = "Not Modified";
- else
- if (code >= 300 && code < 400)
- description = "Redirect";
-
- if (wsi->http.request_version < ARRAY_SIZE(hver))
- p1 = hver[wsi->http.request_version];
- else
- p1 = hver[0];
-
- n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description);
-
- if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end))
- return 1;
-
+ {
+ if (code >= 400 && code < (400 + LWS_ARRAY_SIZE(err400)))
+ description = err400[code - 400];
+ if (code >= 500 && code < (500 + LWS_ARRAY_SIZE(err500)))
+ description = err500[code - 500];
+
+ if (code == 100)
+ description = "Continue";
+ if (code == 200)
+ description = "OK";
+ if (code == 304)
+ description = "Not Modified";
+ else
+ if (code >= 300 && code < 400)
+ description = "Redirect";
+
+ if (wsi->http.request_version < LWS_ARRAY_SIZE(hver))
+ p1 = hver[wsi->http.request_version];
+ else
+ p1 = hver[0];
+
+ n = sprintf((char *)code_and_desc, "%s %u %s", p1, code,
+ description);
+
+ if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p,
+ end))
+ return 1;
+ }
headers = wsi->vhost->headers;
while (headers) {
if (lws_add_http_header_by_name(wsi,
diff --git a/thirdparty/libwebsockets/roles/http/private.h b/thirdparty/libwebsockets/roles/http/private.h
index 2aa7a92f75..5699914742 100644
--- a/thirdparty/libwebsockets/roles/http/private.h
+++ b/thirdparty/libwebsockets/roles/http/private.h
@@ -227,6 +227,7 @@ struct _lws_http_mode_related {
#if defined(LWS_WITH_HTTP_PROXY)
unsigned int perform_rewrite:1;
#endif
+ unsigned int deferred_transaction_completed:1;
};
diff --git a/thirdparty/libwebsockets/roles/http/server/lejp-conf.c b/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
index e9ce854cfc..fbf10c288e 100644
--- a/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
+++ b/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
@@ -205,6 +205,7 @@ struct jpargs {
unsigned int enable_client_ssl:1;
unsigned int fresh_mount:1;
unsigned int any_vhosts:1;
+ unsigned int chunk:1;
};
static void *
@@ -213,6 +214,8 @@ lwsws_align(struct jpargs *a)
if ((lws_intptr_t)(a->p) & 15)
a->p += 16 - ((lws_intptr_t)(a->p) & 15);
+ a->chunk = 0;
+
return a->p;
}
@@ -225,7 +228,7 @@ arg_to_bool(const char *s)
if (n)
return 1;
- for (n = 0; n < (int)ARRAY_SIZE(on); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(on); n++)
if (!strcasecmp(s, on[n]))
return 1;
@@ -413,25 +416,30 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
}
/* this catches, eg, vhosts[].headers[].xxx */
- if (reason == LEJPCB_VAL_STR_END &&
+ if ((reason == LEJPCB_VAL_STR_END || reason == LEJPCB_VAL_STR_CHUNK) &&
ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
- headers = lwsws_align(a);
- a->p += sizeof(*headers);
-
- n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
- /* ie, enable this protocol, no options yet */
- headers->next = a->info->headers;
- a->info->headers = headers;
- headers->name = a->p;
- // lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
- a->p += n - 1;
- *(a->p++) = ':';
- if (a->p < a->end)
- *(a->p++) = '\0';
- else
- *(a->p - 1) = '\0';
- headers->value = a->p;
- headers->options = NULL;
+ if (!a->chunk) {
+ headers = lwsws_align(a);
+ a->p += sizeof(*headers);
+
+ n = lejp_get_wildcard(ctx, 0, a->p,
+ lws_ptr_diff(a->end, a->p));
+ /* ie, add this header */
+ headers->next = a->info->headers;
+ a->info->headers = headers;
+ headers->name = a->p;
+
+ lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
+ a->p += n - 1;
+ *(a->p++) = ':';
+ if (a->p < a->end)
+ *(a->p++) = '\0';
+ else
+ *(a->p - 1) = '\0';
+ headers->value = a->p;
+ headers->options = NULL;
+ }
+ a->chunk = reason == LEJPCB_VAL_STR_CHUNK;
goto dostring;
}
@@ -502,7 +510,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
if (a->last)
a->last->mount_next = m;
- for (n = 0; n < (int)ARRAY_SIZE(mount_protocols); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(mount_protocols); n++)
if (!strncmp(a->m.origin, mount_protocols[n],
strlen(mount_protocols[n]))) {
lwsl_info("----%s\n", a->m.origin);
@@ -512,7 +520,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
break;
}
- if (n == (int)ARRAY_SIZE(mount_protocols)) {
+ if (n == (int)LWS_ARRAY_SIZE(mount_protocols)) {
lwsl_err("unsupported protocol:// %s\n", a->m.origin);
return 1;
}
@@ -750,6 +758,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
dostring:
p = ctx->buf;
+ p[LEJP_STRING_CHUNK] = '\0';
p1 = strstr(p, ESC_INSTALL_DATADIR);
if (p1) {
n = p1 - p;
@@ -762,7 +771,8 @@ dostring:
}
a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
- *(a->p)++ = '\0';
+ if (reason == LEJPCB_VAL_STR_END)
+ *(a->p)++ = '\0';
return 0;
}
@@ -779,7 +789,7 @@ lwsws_get_config(void *user, const char *f, const char * const *paths,
struct lejp_ctx ctx;
int n, m, fd;
- fd = open(f, O_RDONLY);
+ fd = lws_open(f, O_RDONLY);
if (fd < 0) {
lwsl_err("Cannot open %s\n", f);
return 2;
@@ -927,11 +937,11 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_global,
- ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
+ LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_global,
- ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
+ LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
a.plugin_dirs[a.count_plugin_dirs] = NULL;
@@ -962,11 +972,11 @@ lwsws_get_config_vhosts(struct lws_context *context,
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_vhosts,
- ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
+ LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_vhosts,
- ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
+ LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
*cs = a.p;
diff --git a/thirdparty/libwebsockets/roles/http/server/parsers.c b/thirdparty/libwebsockets/roles/http/server/parsers.c
index cb022e362b..482bdc676a 100644
--- a/thirdparty/libwebsockets/roles/http/server/parsers.c
+++ b/thirdparty/libwebsockets/roles/http/server/parsers.c
@@ -563,7 +563,7 @@ int LWS_WARN_UNUSED_RESULT
lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
{
wsi->http.ah->nfrag++;
- if (wsi->http.ah->nfrag == ARRAY_SIZE(wsi->http.ah->frags)) {
+ if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) {
lwsl_warn("More hdr frags than we can deal with, dropping\n");
return -1;
}
@@ -677,18 +677,16 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
return -1;
/* genuine delimiter */
if ((c == '&' || c == ';') && !enc) {
- if (issue_char(wsi, c) < 0)
+ if (issue_char(wsi, '\0') < 0)
return -1;
- /* swallow the terminator */
- ah->frags[ah->nfrag].len--;
/* link to next fragment */
ah->frags[ah->nfrag].nfrag = ah->nfrag + 1;
ah->nfrag++;
- if (ah->nfrag >= ARRAY_SIZE(ah->frags))
+ if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
goto excessive;
/* start next fragment after the & */
ah->post_literal_equal = 0;
- ah->frags[ah->nfrag].offset = ah->pos;
+ ah->frags[ah->nfrag].offset = ++ah->pos;
ah->frags[ah->nfrag].len = 0;
ah->frags[ah->nfrag].nfrag = 0;
goto swallow;
@@ -787,9 +785,9 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
/* move to using WSI_TOKEN_HTTP_URI_ARGS */
ah->nfrag++;
- if (ah->nfrag >= ARRAY_SIZE(ah->frags))
+ if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
goto excessive;
- ah->frags[ah->nfrag].offset = ah->pos;
+ ah->frags[ah->nfrag].offset = ++ah->pos;
ah->frags[ah->nfrag].len = 0;
ah->frags[ah->nfrag].nfrag = 0;
@@ -852,10 +850,10 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
c == ' ')
break;
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (ah->parser_state == methods[m])
break;
- if (m == ARRAY_SIZE(methods))
+ if (m == LWS_ARRAY_SIZE(methods))
/* it was not any of the methods */
goto check_eol;
@@ -983,7 +981,7 @@ nope:
if (ah->lextable_pos < 0 && lwsi_role_h1(wsi) &&
lwsi_role_server(wsi)) {
/* this is not a header we know about */
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (ah->frag_index[methods[m]]) {
/*
* already had the method, no idea what
@@ -996,7 +994,7 @@ nope:
* hm it's an unknown http method from a client in fact,
* it cannot be valid http
*/
- if (m == ARRAY_SIZE(methods)) {
+ if (m == LWS_ARRAY_SIZE(methods)) {
/*
* are we set up to accept raw in these cases?
*/
@@ -1025,7 +1023,7 @@ nope:
lextable[ah->lextable_pos + 1];
lwsl_parser("known hdr %d\n", n);
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (n == methods[m] &&
ah->frag_index[methods[m]]) {
lwsl_warn("Duplicated method\n");
@@ -1061,7 +1059,7 @@ nope:
start_fragment:
ah->nfrag++;
excessive:
- if (ah->nfrag == ARRAY_SIZE(ah->frags)) {
+ if (ah->nfrag == LWS_ARRAY_SIZE(ah->frags)) {
lwsl_warn("More hdr frags than we can deal with\n");
return -1;
}
diff --git a/thirdparty/libwebsockets/roles/http/server/server.c b/thirdparty/libwebsockets/roles/http/server/server.c
index 350af3cd7e..abd86dc9b5 100644
--- a/thirdparty/libwebsockets/roles/http/server/server.c
+++ b/thirdparty/libwebsockets/roles/http/server/server.c
@@ -131,6 +131,17 @@ done_list:
(void)n;
#if defined(__linux__)
+#ifdef LWS_WITH_UNIX_SOCK
+ /*
+ * A Unix domain sockets cannot be bound for several times, even if we set
+ * the SO_REUSE* options on.
+ * However, fortunately, each thread is able to independently listen when
+ * running on a reasonably new Linux kernel. So we can safely assume
+ * creating just one listening socket for a multi-threaded environment won't
+ * fail in most cases.
+ */
+ if (!LWS_UNIX_SOCK_ENABLED(vhost))
+#endif
limit = vhost->context->count_threads;
#endif
@@ -694,7 +705,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
char buf[128];
int fd, match = 0, pos = 0, n = 0, hit = 0;
- fd = open(filename, O_RDONLY);
+ fd = lws_open(filename, O_RDONLY);
if (fd < 0) {
lwsl_err("can't open auth file: %s\n", filename);
return 0;
@@ -812,7 +823,7 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
{
int n, count = 0;
- for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n]))
count++;
if (!count) {
@@ -827,7 +838,7 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
return -1;
}
- for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n])) {
*puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
*puri_len = lws_hdr_total_length(wsi, methods[n]);
@@ -857,7 +868,7 @@ lws_http_action(struct lws *wsi)
};
meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
- if (meth < 0 || meth >= (int)ARRAY_SIZE(method_names))
+ if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names))
goto bail_nuke_ah;
/* we insist on absolute paths */
@@ -1128,7 +1139,7 @@ lws_http_action(struct lws *wsi)
}
if (pcolon > pslash)
pcolon = NULL;
-
+
if (pcolon)
n = pcolon - hit->origin;
else
@@ -1142,13 +1153,13 @@ lws_http_action(struct lws *wsi)
i.address = ads;
i.port = 80;
- if (hit->origin_protocol == LWSMPRO_HTTPS) {
+ if (hit->origin_protocol == LWSMPRO_HTTPS) {
i.port = 443;
i.ssl_connection = 1;
}
if (pcolon)
i.port = atoi(pcolon + 1);
-
+
lws_snprintf(rpath, sizeof(rpath) - 1, "/%s/%s", pslash + 1,
uri_ptr + hit->mountpoint_len);
lws_clean_url(rpath);
@@ -1164,7 +1175,7 @@ lws_http_action(struct lws *wsi)
p++;
}
}
-
+
i.path = rpath;
i.host = i.address;
@@ -1178,7 +1189,7 @@ lws_http_action(struct lws *wsi)
"from %s, to %s\n",
i.address, i.port, i.path, i.ssl_connection,
i.uri_replace_from, i.uri_replace_to);
-
+
if (!lws_client_connect_via_info(&i)) {
lwsl_err("proxy connect fail\n");
return 1;
@@ -1714,12 +1725,31 @@ lws_http_transaction_completed(struct lws *wsi)
{
int n = NO_PENDING_TIMEOUT;
+ if (wsi->trunc_len) {
+ /*
+ * ...so he tried to send something large as the http reply,
+ * it went as a partial, but he immediately said the
+ * transaction was completed.
+ *
+ * Defer the transaction completed until the last part of the
+ * partial is sent.
+ */
+ lwsl_notice("%s: deferring due to partial\n", __func__);
+ wsi->http.deferred_transaction_completed = 1;
+
+ return 0;
+ }
+
lwsl_info("%s: wsi %p\n", __func__, wsi);
lws_access_log(wsi);
if (!wsi->hdr_parsing_completed) {
- lwsl_notice("%s: ignoring, ah parsing incomplete\n", __func__);
+ char peer[64];
+ lws_get_peer_simple(wsi, peer, sizeof(peer) - 1);
+ peer[sizeof(peer) - 1] = '\0';
+ lwsl_notice("%s: (from %s) ignoring, ah parsing incomplete\n",
+ __func__, peer);
return 0;
}
diff --git a/thirdparty/libwebsockets/roles/ws/client-parser-ws.c b/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
index aa561ce034..7287fb1590 100644
--- a/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
+++ b/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
@@ -450,7 +450,7 @@ ping_drop:
break;
case LWSWSOPC_PONG:
- lwsl_info("client receied pong\n");
+ lwsl_info("client received pong\n");
lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
wsi->ws->rx_ubuf_head);
@@ -488,9 +488,6 @@ ping_drop:
ebuf.token = &wsi->ws->rx_ubuf[LWS_PRE];
ebuf.len = wsi->ws->rx_ubuf_head;
- if (wsi->ws->opcode == LWSWSOPC_PONG && !ebuf.len)
- goto already_done;
-
#if !defined(LWS_WITHOUT_EXTENSIONS)
drain_extension:
lwsl_ext("%s: passing %d to ext\n", __func__, ebuf.len);
@@ -504,14 +501,12 @@ drain_extension:
#endif
lwsl_debug("post inflate ebuf len %d\n", ebuf.len);
- if (
#if !defined(LWS_WITHOUT_EXTENSIONS)
- rx_draining_ext &&
-#endif
- !ebuf.len) {
+ if (rx_draining_ext && !ebuf.len) {
lwsl_debug(" --- ending drain on 0 read result\n");
goto already_done;
}
+#endif
if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
if (lws_check_utf8(&wsi->ws->utf8,
diff --git a/thirdparty/libwebsockets/roles/ws/ops-ws.c b/thirdparty/libwebsockets/roles/ws/ops-ws.c
index 5ddaba9e18..665b2c9b74 100644
--- a/thirdparty/libwebsockets/roles/ws/ops-ws.c
+++ b/thirdparty/libwebsockets/roles/ws/ops-ws.c
@@ -1246,8 +1246,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
return LWS_HP_RET_BAIL_OK;
}
- if (lwsi_role_client(wsi) && !wsi->socket_is_permanently_unusable &&
- wsi->ws->send_check_ping) {
+ if (!wsi->socket_is_permanently_unusable && wsi->ws->send_check_ping) {
lwsl_info("issuing ping on wsi %p\n", wsi);
wsi->ws->send_check_ping = 0;
@@ -1282,7 +1281,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
* payload ordering, but since they are always complete
* fragments control packets can interleave OK.
*/
- if (lwsi_role_client(wsi) && wsi->ws->tx_draining_ext) {
+ if (wsi->ws->tx_draining_ext) {
lwsl_ext("SERVICING TX EXT DRAINING\n");
if (lws_write(wsi, NULL, 0, LWS_WRITE_CONTINUATION) < 0)
return LWS_HP_RET_BAIL_DIE;
@@ -1292,8 +1291,10 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
/* Priority 6: extensions
*/
- if (!wsi->ws->extension_data_pending)
+ if (!wsi->ws->extension_data_pending && !wsi->ws->tx_draining_ext) {
+ lwsl_ext("%s: !wsi->ws->extension_data_pending\n", __func__);
return LWS_HP_RET_USER_SERVICE;
+ }
/*
* check in on the active extensions, see if they
@@ -1412,15 +1413,13 @@ rops_periodic_checks_ws(struct lws_context *context, int tsi, time_t now)
wsi->ws->time_next_ping_check) >
context->ws_ping_pong_interval) {
- lwsl_info("req pp on wsi %p\n",
- wsi);
+ lwsl_info("req pp on wsi %p\n", wsi);
wsi->ws->send_check_ping = 1;
lws_set_timeout(wsi,
PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING,
context->timeout_secs);
lws_callback_on_writable(wsi);
- wsi->ws->time_next_ping_check =
- now;
+ wsi->ws->time_next_ping_check = now;
}
wsi = wsi->same_vh_protocol_next;
}
@@ -1466,6 +1465,9 @@ rops_service_flag_pending_ws(struct lws_context *context, int tsi)
static int
rops_close_via_role_protocol_ws(struct lws *wsi, enum lws_close_status reason)
{
+ if (!wsi->ws)
+ return 0;
+
if (!wsi->ws->close_in_ping_buffer_len && /* already a reason */
(reason == LWS_CLOSE_STATUS_NOSTATUS ||
reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY))
@@ -1512,7 +1514,7 @@ rops_close_role_ws(struct lws_context_per_thread *pt, struct lws *wsi)
if (wsi->ws->tx_draining_ext) {
struct lws **w = &pt->ws.tx_draining_ext_list;
- lwsl_notice("%s: CLEARING tx_draining_ext\n", __func__);
+ lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
wsi->ws->tx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
@@ -1563,7 +1565,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
/* remove us from the list */
struct lws **w = &pt->ws.tx_draining_ext_list;
- lwsl_notice("%s: CLEARING tx_draining_ext\n", __func__);
+ lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
wsi->ws->tx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
@@ -1588,7 +1590,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
if (!(wpt & LWS_WRITE_NO_FIN) && len)
*wp &= ~LWS_WRITE_NO_FIN;
- lwsl_notice("FORCED draining wp to 0x%02X (stashed 0x%02X, incoming 0x%02X)\n", *wp,
+ lwsl_ext("FORCED draining wp to 0x%02X (stashed 0x%02X, incoming 0x%02X)\n", *wp,
wsi->ws->tx_draining_stashed_wp, wpt);
// assert(0);
}
@@ -1644,7 +1646,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
// lwsl_notice("ext processed %d plaintext into %d compressed (wp 0x%x)\n", m, (int)ebuf.len, *wp);
if (n && ebuf.len) {
- lwsl_notice("write drain len %d (wp 0x%x) SETTING tx_draining_ext\n", (int)ebuf.len, *wp);
+ lwsl_ext("write drain len %d (wp 0x%x) SETTING tx_draining_ext\n", (int)ebuf.len, *wp);
/* extension requires further draining */
wsi->ws->tx_draining_ext = 1;
wsi->ws->tx_draining_ext_list = pt->ws.tx_draining_ext_list;
diff --git a/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
index 2de6d422e3..f17c7e5494 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
+++ b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
@@ -631,7 +631,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
- for (n = 0; n < (int)ARRAY_SIZE(x5); n++) {
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(x5); n++) {
if (p != subject)
*p++ = ',';
if (elements[n])
diff --git a/thirdparty/libwebsockets/tls/mbedtls/ssl.c b/thirdparty/libwebsockets/tls/mbedtls/ssl.c
index 6ae9d2556b..f311ef50e3 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/ssl.c
+++ b/thirdparty/libwebsockets/tls/mbedtls/ssl.c
@@ -121,8 +121,6 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
if (wsi->vhost)
wsi->vhost->conn_stats.rx += n;
- lws_restart_ws_ping_pong_timer(wsi);
-
/*
* if it was our buffer that limited what we read,
* check if SSL has additional data pending inside SSL buffers.
diff --git a/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h b/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
index ba19663d9e..68ac748a28 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
+++ b/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
@@ -37,7 +37,11 @@ typedef void RSA;
typedef void STACK;
typedef void BIO;
+#if defined(WIN32) || defined(_WIN32)
+#define ossl_inline __inline
+#else
#define ossl_inline inline
+#endif
#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__)
#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__)
diff --git a/thirdparty/libwebsockets/uwp_fixes.diff b/thirdparty/libwebsockets/uwp_fixes.diff
index 5b9d8724ed..21c3275bba 100644
--- a/thirdparty/libwebsockets/uwp_fixes.diff
+++ b/thirdparty/libwebsockets/uwp_fixes.diff
@@ -1,15 +1,15 @@
diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
-index 948db6289..511e29739 100644
+index bd513b494..1850b6425 100644
--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
+++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
-@@ -635,9 +635,20 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+@@ -641,9 +641,20 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
HANDLE ret;
WCHAR buf[MAX_PATH];
lws_fop_fd_t fop_fd;
- LARGE_INTEGER llFileSize = {0};
+ FILE_STANDARD_INFO fInfo = {0};
- MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
+ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
@@ -24,7 +24,7 @@ index 948db6289..511e29739 100644
if (((*flags) & 7) == _O_RDONLY) {
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-@@ -645,6 +656,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+@@ -651,6 +662,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
@@ -32,7 +32,7 @@ index 948db6289..511e29739 100644
if (ret == LWS_INVALID_FILE)
goto bail;
-@@ -657,9 +669,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+@@ -663,9 +675,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
fop_fd->fd = ret;
fop_fd->filesystem_priv = NULL; /* we don't use it */
fop_fd->flags = *flags;
diff --git a/thirdparty/libwebsockets/win32helpers/getopt.c b/thirdparty/libwebsockets/win32helpers/getopt.c
index 2181f1cb12..3bb21f6f28 100644
--- a/thirdparty/libwebsockets/win32helpers/getopt.c
+++ b/thirdparty/libwebsockets/win32helpers/getopt.c
@@ -1,153 +1,153 @@
-/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
-
-/*
- * Copyright (c) 1987, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if 0
-static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-#ifdef __weak_alias
-__weak_alias(getopt,_getopt);
-#endif
-
-
-int opterr = 1, /* if error message should be printed */
- optind = 1, /* index into parent argv vector */
- optopt, /* character checked for validity */
- optreset; /* reset getopt */
-char *optarg; /* argument associated with option */
-
-static char * _progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-_progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt(nargc, nargv, ostr)
- int nargc;
- char * const nargv[];
- const char *ostr;
-{
- static char *__progname = 0;
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
- __progname = __progname?__progname:_progname(*nargv);
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-' /* found "--" */
- && place[1] == '\0') {
- ++optind;
- place = EMSG;
- return (-1);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname, optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- }
- else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if (*ostr == ':')
- return (BADARG);
- if (opterr)
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname, optopt);
- return (BADCH);
- }
- else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
+/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt);
+#endif
+
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+static char * _progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+_progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *__progname = 0;
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ __progname = __progname?__progname:_progname(*nargv);
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-' /* found "--" */
+ && place[1] == '\0') {
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
diff --git a/thirdparty/libwebsockets/win32helpers/getopt_long.c b/thirdparty/libwebsockets/win32helpers/getopt_long.c
index 22e5fa8945..6dfccf367d 100644
--- a/thirdparty/libwebsockets/win32helpers/getopt_long.c
+++ b/thirdparty/libwebsockets/win32helpers/getopt_long.c
@@ -1,240 +1,240 @@
-
-/*
- * Copyright (c) 1987, 1993, 1994, 1996
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "getopt.h"
-
-#define lws_ptr_diff(head, tail) \
- ((int)((char *)(head) - (char *)(tail)))
-
-extern int opterr; /* if error message should be printed */
-extern int optind; /* index into parent argv vector */
-extern int optopt; /* character checked for validity */
-extern int optreset; /* reset getopt */
-extern char *optarg; /* argument associated with option */
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-static char * __progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-__progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt_internal(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-') { /* found "--" */
- /* ++optind; */
- place = EMSG;
- return (-2);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- } else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if ((opterr) && (*ostr != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname(nargv[0]), optopt);
- return (BADARG);
- } else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
-#if 0
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt2(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- int retval;
-
- if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
- retval = -1;
- ++optind;
- }
- return(retval);
-}
-#endif
-
-/*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long(nargc, nargv, options, long_options, index)
- int nargc;
- char ** nargv;
- char * options;
- struct option * long_options;
- int * index;
-{
- int retval;
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(options != NULL);
- _DIAGASSERT(long_options != NULL);
- /* index may be NULL */
-
- if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
- char *current_argv = nargv[optind++] + 2, *has_equal;
- int i, current_argv_len, match = -1;
-
- if (*current_argv == '\0') {
- return(-1);
- }
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- current_argv_len = lws_ptr_diff(has_equal, current_argv);
- has_equal++;
- } else
- current_argv_len = (int)strlen(current_argv);
-
- for (i = 0; long_options[i].name; i++) {
- if (strncmp(current_argv, long_options[i].name, current_argv_len))
- continue;
-
- if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
- match = i;
- break;
- }
- if (match == -1)
- match = i;
- }
- if (match != -1) {
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else
- optarg = nargv[optind++];
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument, leading :
- * indicates no error should be generated
- */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %s\n",
- __progname(nargv[0]), current_argv);
- return (BADARG);
- }
- } else { /* No matching argument */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
- return (BADCH);
- }
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- retval = 0;
- } else
- retval = long_options[match].val;
- if (index)
- *index = match;
- }
- return(retval);
-}
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+#define lws_ptr_diff(head, tail) \
+ ((int)((char *)(head) - (char *)(tail)))
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+static char * __progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+__progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ /* ++optind; */
+ place = EMSG;
+ return (-2);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ } else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if ((opterr) && (*ostr != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname(nargv[0]), optopt);
+ return (BADARG);
+ } else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
+#if 0
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt2(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ int retval;
+
+ if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+ retval = -1;
+ ++optind;
+ }
+ return(retval);
+}
+#endif
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+ int nargc;
+ char ** nargv;
+ char * options;
+ struct option * long_options;
+ int * index;
+{
+ int retval;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+ _DIAGASSERT(long_options != NULL);
+ /* index may be NULL */
+
+ if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+ char *current_argv = nargv[optind++] + 2, *has_equal;
+ int i, current_argv_len, match = -1;
+
+ if (*current_argv == '\0') {
+ return(-1);
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ current_argv_len = lws_ptr_diff(has_equal, current_argv);
+ has_equal++;
+ } else
+ current_argv_len = (int)strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ if (strncmp(current_argv, long_options[i].name, current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
+ match = i;
+ break;
+ }
+ if (match == -1)
+ match = i;
+ }
+ if (match != -1) {
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else
+ optarg = nargv[optind++];
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument, leading :
+ * indicates no error should be generated
+ */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ __progname(nargv[0]), current_argv);
+ return (BADARG);
+ }
+ } else { /* No matching argument */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+ return (BADCH);
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (index)
+ *index = match;
+ }
+ return(retval);
+}
diff --git a/thirdparty/libwebsockets/win32helpers/gettimeofday.c b/thirdparty/libwebsockets/win32helpers/gettimeofday.c
index 08385c2320..35dd73531d 100644
--- a/thirdparty/libwebsockets/win32helpers/gettimeofday.c
+++ b/thirdparty/libwebsockets/win32helpers/gettimeofday.c
@@ -1,36 +1,36 @@
-#include <time.h>
-#include <windows.h> //I've omitted context line
-
-#include "gettimeofday.h"
-
-int gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- FILETIME ft;
- unsigned __int64 tmpres = 0;
- static int tzflag;
-
- if (NULL != tv) {
- GetSystemTimeAsFileTime(&ft);
-
- tmpres |= ft.dwHighDateTime;
- tmpres <<= 32;
- tmpres |= ft.dwLowDateTime;
-
- /*converting file time to unix epoch*/
- tmpres /= 10; /*convert into microseconds*/
+#include <time.h>
+#include <windows.h> //I've omitted context line
+
+#include "gettimeofday.h"
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ unsigned __int64 tmpres = 0;
+ static int tzflag;
+
+ if (NULL != tv) {
+ GetSystemTimeAsFileTime(&ft);
+
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+
+ /*converting file time to unix epoch*/
+ tmpres /= 10; /*convert into microseconds*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
- tv->tv_sec = (long)(tmpres / 1000000UL);
- tv->tv_usec = (long)(tmpres % 1000000UL);
- }
-
- if (NULL != tz) {
- if (!tzflag) {
- _tzset();
- tzflag++;
- }
- tz->tz_minuteswest = _timezone / 60;
- tz->tz_dsttime = _daylight;
- }
-
- return 0;
-}
+ tv->tv_sec = (long)(tmpres / 1000000UL);
+ tv->tv_usec = (long)(tmpres % 1000000UL);
+ }
+
+ if (NULL != tz) {
+ if (!tzflag) {
+ _tzset();
+ tzflag++;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ return 0;
+}