summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/config/engine.cpp4
-rw-r--r--core/config/engine.h2
-rw-r--r--core/core_bind.cpp12
-rw-r--r--core/core_bind.h1
-rw-r--r--core/io/remote_filesystem_client.h4
-rw-r--r--doc/classes/Callable.xml2
-rw-r--r--doc/classes/Geometry3D.xml7
-rw-r--r--doc/classes/Node.xml8
-rw-r--r--doc/classes/ProjectSettings.xml2
-rw-r--r--doc/classes/int.xml2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp58
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h1
-rw-r--r--drivers/vulkan/vulkan_context.cpp4
-rw-r--r--editor/icons/CurveTexture.svg2
-rw-r--r--editor/icons/CurveXYZTexture.svg1
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp6
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp7
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h2
-rw-r--r--main/main.cpp3
-rw-r--r--methods.py3
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp3
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h1
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/gdscript_rpc_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_rpc_callable.h1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.gd21
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.out5
-rw-r--r--modules/glslang/register_types.cpp30
-rw-r--r--modules/mono/godotsharp_dirs.cpp4
-rw-r--r--platform/android/export/export_plugin.cpp13
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h8
-rw-r--r--scene/2d/camera_2d.cpp77
-rw-r--r--scene/2d/camera_2d.h1
-rw-r--r--scene/2d/canvas_modulate.cpp67
-rw-r--r--scene/2d/canvas_modulate.h8
-rw-r--r--scene/gui/dialogs.cpp3
-rw-r--r--scene/gui/popup.cpp3
-rw-r--r--scene/main/viewport.cpp4
-rw-r--r--scene/main/viewport.h5
-rw-r--r--scene/main/window.cpp38
-rw-r--r--scene/main/window.h4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp14
-rw-r--r--servers/rendering/rendering_device.h1
-rw-r--r--tests/scene/test_window.h96
-rw-r--r--tests/servers/test_navigation_server_3d.h2
-rw-r--r--tests/test_main.cpp1
48 files changed, 442 insertions, 112 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 7fdea7d1aa..6727c58fd1 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -239,6 +239,10 @@ bool Engine::is_validation_layers_enabled() const {
return use_validation_layers;
}
+bool Engine::is_generate_spirv_debug_info_enabled() const {
+ return generate_spirv_debug_info;
+}
+
void Engine::set_print_error_messages(bool p_enabled) {
CoreGlobals::print_error_enabled = p_enabled;
}
diff --git a/core/config/engine.h b/core/config/engine.h
index 5ea653ba6c..73d40d50ae 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -67,6 +67,7 @@ private:
double _physics_interpolation_fraction = 0.0f;
bool abort_on_gpu_errors = false;
bool use_validation_layers = false;
+ bool generate_spirv_debug_info = false;
int32_t gpu_idx = -1;
uint64_t _process_frames = 0;
@@ -156,6 +157,7 @@ public:
bool is_abort_on_gpu_errors_enabled() const;
bool is_validation_layers_enabled() const;
+ bool is_generate_spirv_debug_info_enabled() const;
int32_t get_gpu_index() const;
Engine();
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 4e220d0839..05fe393a2f 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -929,6 +929,17 @@ Geometry3D *Geometry3D::get_singleton() {
return singleton;
}
+Vector<Vector3> Geometry3D::compute_convex_mesh_points(const TypedArray<Plane> &p_planes) {
+ Vector<Plane> planes_vec;
+ int size = p_planes.size();
+ planes_vec.resize(size);
+ for (int i = 0; i < size; ++i) {
+ planes_vec.set(i, p_planes[i]);
+ }
+ Variant ret = ::Geometry3D::compute_convex_mesh_points(planes_vec.ptr(), size);
+ return ret;
+}
+
TypedArray<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
Variant ret = ::Geometry3D::build_box_planes(p_extents);
return ret;
@@ -1029,6 +1040,7 @@ Vector<Vector3> Geometry3D::clip_polygon(const Vector<Vector3> &p_points, const
}
void Geometry3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("compute_convex_mesh_points", "planes"), &Geometry3D::compute_convex_mesh_points);
ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &Geometry3D::build_box_planes);
ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &Geometry3D::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z));
ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &Geometry3D::build_capsule_planes, DEFVAL(Vector3::AXIS_Z));
diff --git a/core/core_bind.h b/core/core_bind.h
index 1cbbcdd251..5f51b64eb7 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -320,6 +320,7 @@ protected:
public:
static Geometry3D *get_singleton();
+ Vector<Vector3> compute_convex_mesh_points(const TypedArray<Plane> &p_planes);
TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
diff --git a/core/io/remote_filesystem_client.h b/core/io/remote_filesystem_client.h
index 42eba98eb1..fcb5c1cfc3 100644
--- a/core/io/remote_filesystem_client.h
+++ b/core/io/remote_filesystem_client.h
@@ -44,8 +44,8 @@ protected:
String _get_cache_path() { return cache_path; }
struct FileCache {
String path; // Local path (as in "folder/to/file.png")
- uint64_t server_modified_time; // MD5 checksum.
- uint64_t modified_time;
+ uint64_t server_modified_time = 0; // MD5 checksum.
+ uint64_t modified_time = 0;
};
virtual bool _is_configured() { return !cache_path.is_empty(); }
// Can be re-implemented per platform. If so, feel free to ignore get_cache_path()
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index c7b2d6df94..b903e98319 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -138,7 +138,7 @@
<method name="get_method" qualifiers="const">
<return type="StringName" />
<description>
- Returns the name of the method represented by this [Callable]. If the callable is a lambda function, returns the function's name.
+ Returns the name of the method represented by this [Callable]. If the callable is a GDScript lambda function, returns the function's name or [code]"&lt;anonymous lambda&gt;"[/code].
</description>
</method>
<method name="get_object" qualifiers="const">
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index 85b8965faf..a85d17d925 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -45,6 +45,13 @@
Clips the polygon defined by the points in [param points] against the [param plane] and returns the points of the clipped polygon.
</description>
</method>
+ <method name="compute_convex_mesh_points">
+ <return type="PackedVector3Array" />
+ <param index="0" name="planes" type="Plane[]" />
+ <description>
+ Calculates and returns all the vertex points of a convex shape defined by an array of [param planes].
+ </description>
+ </method>
<method name="get_closest_point_to_segment">
<return type="Vector3" />
<param index="0" name="point" type="Vector3" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 49ab3918bb..7510d6bb64 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -1022,12 +1022,12 @@
Notification received right after the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects.
</constant>
<constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002">
- Notification received from the OS when the mouse enters the game window.
- Implemented on desktop and web platforms.
+ Notification received when the mouse enters the window.
+ Implemented for embedded windows and on desktop and web platforms.
</constant>
<constant name="NOTIFICATION_WM_MOUSE_EXIT" value="1003">
- Notification received from the OS when the mouse leaves the game window.
- Implemented on desktop and web platforms.
+ Notification received when the mouse leaves the window.
+ Implemented for embedded windows and on desktop and web platforms.
</constant>
<constant name="NOTIFICATION_WM_WINDOW_FOCUS_IN" value="1004">
Notification received when the node's parent [Window] is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also emitted).
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 3eb1959a44..1be69052e4 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -298,7 +298,7 @@
[b]Note:[/b] Changing this value can help on platforms or with third-party tools where hidden directory patterns are disallowed. Only modify this setting if you know that your environment requires it, as changing the default can impact compatibility with some external tools or plugins which expect the default [code].godot[/code] folder.
</member>
<member name="application/config/version" type="String" setter="" getter="" default="&quot;&quot;">
- The project's human-readable version identifier. This should always be set to a non-empty string, as some exporters rely on this value being defined.
+ The project's human-readable version identifier. This is used by exporters if the version identifier isn't overridden there. If [member application/config/version] is an empty string and the version identifier isn't overridden in an exporter, the exporter will use [code]1.0.0[/code] as a version identifier.
</member>
<member name="application/config/windows_native_icon" type="String" setter="" getter="" default="&quot;&quot;">
Icon set in [code].ico[/code] format used on Windows to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon].
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index bc0da03e98..914cf75929 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -390,7 +390,7 @@
<operator name="operator ~">
<return type="int" />
<description>
- Performs the bitwise [code]NOT[/code] operation on the [int]. Due to [url=https://en.wikipedia.org/wiki/Two%27s_complement/]2's complement[/url], it's effectively equal to [code]-(int + 1)[/code].
+ Performs the bitwise [code]NOT[/code] operation on the [int]. Due to [url=https://en.wikipedia.org/wiki/Two%27s_complement]2's complement[/url], it's effectively equal to [code]-(int + 1)[/code].
[codeblock]
print(~4) # Prints -5
print(~(-7)) # Prints 6
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 1ed6839dd7..a55abe6a82 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -5905,6 +5905,64 @@ void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_
us->invalidated_callback_userdata = p_userdata;
}
+Error RenderingDeviceVulkan::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
+ "Copying buffers is forbidden during creation of a draw list");
+ ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
+ "Copying buffers is forbidden during creation of a compute list");
+
+ // This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed
+ // for the source or destination buffers before performing the copy. These masks are effectively ignored.
+ VkPipelineShaderStageCreateFlags src_stage_mask = 0;
+ VkAccessFlags src_access_mask = 0;
+ Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_NO_BARRIER);
+ if (!src_buffer) {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");
+ }
+
+ VkPipelineStageFlags dst_stage_mask = 0;
+ VkAccessFlags dst_access = 0;
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ // If the post barrier mask defines it, we indicate the destination buffer will require a barrier with these flags set
+ // after the copy command is queued.
+ dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
+ }
+
+ Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stage_mask, dst_access, p_post_barrier);
+ if (!dst_buffer) {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");
+ }
+
+ // Validate the copy's dimensions for both buffers.
+ ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer.");
+ ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer.");
+
+ // Perform the copy.
+ VkBufferCopy region;
+ region.srcOffset = p_src_offset;
+ region.dstOffset = p_dst_offset;
+ region.size = p_size;
+ vkCmdCopyBuffer(frames[frame].draw_command_buffer, src_buffer->buffer, dst_buffer->buffer, 1, &region);
+
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
+#else
+ if (dst_stage_mask == 0) {
+ dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ }
+
+ // As indicated by the post barrier mask, push a new barrier.
+ if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
+ _buffer_memory_barrier(dst_buffer->buffer, p_dst_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
+ }
+#endif
+
+ return OK;
+}
+
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index fd832312ac..edff19a70c 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -1152,6 +1152,7 @@ public:
virtual bool uniform_set_is_valid(RID p_uniform_set);
virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
+ virtual Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer.
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index c167caeb7c..4b18a500e1 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -504,6 +504,10 @@ Error VulkanContext::_initialize_device_extensions() {
register_requested_device_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false);
+ if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
+ register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true);
+ }
+
// TODO consider the following extensions:
// - VK_KHR_spirv_1_4
// - VK_KHR_swapchain_mutable_format
diff --git a/editor/icons/CurveTexture.svg b/editor/icons/CurveTexture.svg
index 50232fdc4a..a5524f145c 100644
--- a/editor/icons/CurveTexture.svg
+++ b/editor/icons/CurveTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v9.16A3 3 0 0 1 2 11c.331 0 .666-.008 1-.014V3h10v1.135a3 3 0 0 1 2-.006V2a1 1 0 0 0-1-1H2zm7 4v1H8v1H6v1H5v1H4v1h4.39c1.113-.567 1.968-1.454 2.61-3.473V6h-1V5H9zm4.967.988a1 1 0 0 0-.928.739c-.927 3.246-2.636 4.682-4.652 5.466C6.37 12.978 4 13 2 13a1 1 0 1 0 0 2c2 0 4.63.024 7.113-.941 2.484-.966 4.775-3.03 5.848-6.784a1 1 0 0 0-.994-1.287z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v9.16A3 3 0 0 1 2 11h1V3h10v1.135a3 3 0 0 1 2 0V2a1 1 0 0 0-1-1zm7 4v1H8v1H6v1H5v1H4v1h4.39c1.113-.567 1.968-1.454 2.61-3.473V6h-1V5H9zm4.039 1.727c-.927 3.246-2.636 4.682-4.652 5.466C6.37 12.978 4 13 2 13a1 1 0 1 0 0 2c2 0 4.63.024 7.113-.941 2.484-.966 4.775-3.03 5.848-6.784a1 1 0 0 0-1.922-.548z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/CurveXYZTexture.svg b/editor/icons/CurveXYZTexture.svg
new file mode 100644
index 0000000000..e376dd434b
--- /dev/null
+++ b/editor/icons/CurveXYZTexture.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v10a2 2 0 0 1 .75-.1Q3 11.9 3 10.62V3h10v6.5a2 2 0 0 1 2 0V2a1 1 0 0 0-1-1zm7 4v1H8v1H6v1H5v1H4v.5a2 2 0 0 1 2.7.5h1.2a2 2 0 0 1 3.2 0h.9V8h-1V6h-1V5z" fill="#e0e0e0"/><g stroke-width="1.6" stroke-linecap="round" fill="none"><path d="M2 14.2q2.5 0 3-3" stroke="#ff5f5f"/><path d="M6.5 14.2q2.5 0 3-3" stroke="#5fff97"/><path d="M11 14.2q2.5 0 3-3" stroke="#5fb2ff"/></g></svg>
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index c98d9086d1..b1111be006 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2655,6 +2655,12 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
memdelete(tile_proxy_object);
memdelete(atlas_source_proxy_object);
+
+ // Remove listener for old objects, so the TileSet doesn't
+ // try to call the destroyed TileSetAtlasSourceEditor.
+ if (tile_set.is_valid()) {
+ tile_set->disconnect_changed(callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
+ }
}
////// EditorPropertyTilePolygon //////
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 121b70a74f..e432704702 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -325,6 +325,7 @@ void TileMapEditorPlugin::_tile_map_changed() {
}
void TileMapEditorPlugin::_update_tile_map() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
Ref<TileSet> tile_set = tile_map->get_tileset();
if (tile_set.is_valid() && edited_tileset != tile_set->get_instance_id()) {
@@ -347,11 +348,17 @@ void TileMapEditorPlugin::_notification(int p_notification) {
}
void TileMapEditorPlugin::edit(Object *p_object) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
tile_map->disconnect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_changed));
}
tile_map = Object::cast_to<TileMap>(p_object);
+ if (tile_map) {
+ tile_map_id = tile_map->get_instance_id();
+ } else {
+ tile_map_id = ObjectID();
+ }
editor->edit(tile_map);
if (tile_map) {
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index f8e944af81..81cb48eb00 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -115,7 +115,7 @@ class TileMapEditorPlugin : public EditorPlugin {
TileMapEditor *editor = nullptr;
Button *button = nullptr;
- TileMap *tile_map = nullptr;
+ ObjectID tile_map_id;
bool tile_map_changed_needs_update = false;
ObjectID edited_tileset;
diff --git a/main/main.cpp b/main/main.cpp
index 220afda5de..f79a71474d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -458,6 +458,7 @@ void Main::print_help(const char *p_binary) {
#if DEBUG_ENABLED
OS::get_singleton()->print(" --gpu-abort Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes.\n");
#endif
+ OS::get_singleton()->print(" --generate-spirv-debug-info Generate SPIR-V debug information. This allows source-level shader debugging with RenderDoc.\n");
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
OS::get_singleton()->print(" --single-threaded-scene Scene tree runs in single-threaded mode. Sub-thread groups are disabled and run on the main thread.\n");
#if defined(DEBUG_ENABLED)
@@ -1019,6 +1020,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--gpu-abort") {
Engine::singleton->abort_on_gpu_errors = true;
#endif
+ } else if (I->get() == "--generate-spirv-debug-info") {
+ Engine::singleton->generate_spirv_debug_info = true;
} else if (I->get() == "--tablet-driver") {
if (I->next()) {
tablet_driver = I->next()->get();
diff --git a/methods.py b/methods.py
index 571a3f739e..7c1781d699 100644
--- a/methods.py
+++ b/methods.py
@@ -868,6 +868,9 @@ def generate_vs_project(env, num_jobs, project_name="godot"):
if env["custom_modules"]:
common_build_postfix.append("custom_modules=%s" % env["custom_modules"])
+ if env["windows_subsystem"] == "console":
+ common_build_postfix.append("windows_subsystem=console")
+
if env["precision"] == "double":
common_build_postfix.append("precision=double")
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 9a0f121e19..96d89ff486 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -16,7 +16,8 @@
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] resource to use as a CSG shape.
- [b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel.
+ [b]Note:[/b] When using an [ArrayMesh], all vertex attributes except [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL] and [constant Mesh.ARRAY_TEX_UV] are left unused. Only [constant Mesh.ARRAY_VERTEX] and [constant Mesh.ARRAY_TEX_UV] will be passed to the GPU.
+ [constant Mesh.ARRAY_NORMAL] is only used to determine which faces require the use of flat shading. By default, CSGMesh will ignore the mesh's vertex normals, recalculate them for each vertex and use a smooth shader. If a flat shader is required for a face, ensure that all vertex normals of the face are approximately equal.
</member>
</members>
</class>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index cb04913620..ad4528747b 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3469,6 +3469,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
for (GDScriptParser::ClassNode *script_class : script_classes) {
if (p_base == nullptr && script_class->identifier && script_class->identifier->name == name) {
reduce_identifier_from_base_set_class(p_identifier, script_class->get_datatype());
+ if (script_class->outer != nullptr) {
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CLASS;
+ }
return;
}
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index 9e14e43a58..3b89f077bd 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -67,6 +67,10 @@ ObjectID GDScriptLambdaCallable::get_object() const {
return script->get_instance_id();
}
+StringName GDScriptLambdaCallable::get_method() const {
+ return function->get_name();
+}
+
void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
int captures_amount = captures.size();
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index 33bdf6dfc1..1c7a18fb9d 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -56,6 +56,7 @@ public:
CompareEqualFunc get_compare_equal_func() const override;
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
+ StringName get_method() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index debc85ebbf..9e1e8f0c75 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -2446,7 +2446,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
complete_extents(operation);
if (operation->right_operand == nullptr) {
- push_error(vformat(R"(Expected expression after "%s" operator.")", op.get_name()));
+ push_error(vformat(R"(Expected expression after "%s" operator.)", op.get_name()));
}
// TODO: Also for unary, ternary, and assignment.
diff --git a/modules/gdscript/gdscript_rpc_callable.cpp b/modules/gdscript/gdscript_rpc_callable.cpp
index a4dd8a8d3c..265e624b6c 100644
--- a/modules/gdscript/gdscript_rpc_callable.cpp
+++ b/modules/gdscript/gdscript_rpc_callable.cpp
@@ -63,6 +63,10 @@ ObjectID GDScriptRPCCallable::get_object() const {
return object->get_instance_id();
}
+StringName GDScriptRPCCallable::get_method() const {
+ return method;
+}
+
void GDScriptRPCCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_return_value = object->callp(method, p_arguments, p_argcount, r_call_error);
}
diff --git a/modules/gdscript/gdscript_rpc_callable.h b/modules/gdscript/gdscript_rpc_callable.h
index c1007b18b0..66052157be 100644
--- a/modules/gdscript/gdscript_rpc_callable.h
+++ b/modules/gdscript/gdscript_rpc_callable.h
@@ -51,6 +51,7 @@ public:
CompareEqualFunc get_compare_equal_func() const override;
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
+ StringName get_method() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.gd b/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.gd
new file mode 100644
index 0000000000..51c589b8e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.gd
@@ -0,0 +1,21 @@
+# GH-80508
+
+class A:
+ func a():
+ return A.new()
+ func b():
+ return B.new()
+
+class B:
+ func a():
+ return A.new()
+ func b():
+ return B.new()
+
+func test():
+ var a := A.new()
+ var b := B.new()
+ print(a.a() is A)
+ print(a.b() is B)
+ print(b.a() is A)
+ print(b.b() is B)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.out b/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.out
new file mode 100644
index 0000000000..f9783e4362
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_access_from_inside.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+true
+true
+true
+true
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 622910761d..2b070c24b8 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -32,6 +32,7 @@
#include "glslang_resource_limits.h"
+#include "core/config/engine.h"
#include "servers/rendering/rendering_device.h"
#include <glslang/Include/Types.h>
@@ -56,7 +57,6 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2;
glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
- glslang::TShader::ForbidIncluder includer;
if (capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
if (capabilities->version_major == 1 && capabilities->version_minor == 0) {
@@ -127,23 +127,10 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
}
EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
- const int DefaultVersion = 100;
- std::string pre_processed_code;
-
- //preprocess
- if (!shader.preprocess(&DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) {
- if (r_error) {
- (*r_error) = "Failed pre-process:\n";
- (*r_error) += shader.getInfoLog();
- (*r_error) += "\n";
- (*r_error) += shader.getInfoDebugLog();
- }
-
- return ret;
+ if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
+ messages = (EShMessages)(messages | EShMsgDebugInfo);
}
- //set back..
- cs_strings = pre_processed_code.c_str();
- shader.setStrings(&cs_strings, 1);
+ const int DefaultVersion = 100;
//parse
if (!shader.parse(&DefaultTBuiltInResource, DefaultVersion, false, messages)) {
@@ -174,6 +161,13 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
std::vector<uint32_t> SpirV;
spv::SpvBuildLogger logger;
glslang::SpvOptions spvOptions;
+
+ if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
+ spvOptions.generateDebugInfo = true;
+ spvOptions.emitNonSemanticShaderDebugInfo = true;
+ spvOptions.emitNonSemanticShaderDebugSource = true;
+ }
+
glslang::GlslangToSpv(*program.getIntermediate(stages[p_stage]), SpirV, &logger, &spvOptions);
ret.resize(SpirV.size() * sizeof(uint32_t));
@@ -188,7 +182,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
static String _get_cache_key_function_glsl(const RenderingDevice *p_render_device) {
const RD::Capabilities *capabilities = p_render_device->get_device_capabilities();
String version;
- version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(capabilities->version_major) + ", minor=" + itos(capabilities->version_minor) + " , subgroup_size=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_SIZE)) + " , subgroup_ops=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS)) + " , subgroup_in_shaders=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS));
+ version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(capabilities->version_major) + ", minor=" + itos(capabilities->version_minor) + " , subgroup_size=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_SIZE)) + " , subgroup_ops=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS)) + " , subgroup_in_shaders=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS)) + " , debug=" + itos(Engine::get_singleton()->is_generate_spirv_debug_info_enabled());
return version;
}
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 00ef4ccdde..c84ecf4ceb 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -33,10 +33,6 @@
#include "mono_gd/gd_mono.h"
#include "utils/path_utils.h"
-#ifdef ANDROID_ENABLED
-#include "mono_gd/support/android_support.h"
-#endif
-
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 8744e545e4..20aaed1e3e 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2226,17 +2226,15 @@ String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_
}
bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
-#ifdef MODULE_MONO_ENABLED
- // Don't check for additional errors, as this particular error cannot be resolved.
- r_error += TTR("Exporting to Android is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target Android with C#/Mono instead.") + "\n";
- r_error += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
- return false;
-#else
-
String err;
bool valid = false;
const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
+#ifdef MODULE_MONO_ENABLED
+ // Android export is still a work in progress, keep a message as a warning.
+ err += TTR("Exporting to Android when using C#/.NET is experimental.") + "\n";
+#endif
+
// Look for export templates (first official, and if defined custom templates).
if (!gradle_build_enabled) {
@@ -2366,7 +2364,6 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
return valid;
-#endif // !MODULE_MONO_ENABLED
}
bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h
index 59e20fec45..d3a25506a8 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.h
+++ b/platform/linuxbsd/x11/gl_manager_x11.h
@@ -74,17 +74,17 @@ private:
};
struct GLDisplay {
- GLDisplay() { context = nullptr; }
+ GLDisplay() {}
~GLDisplay();
GLManager_X11_Private *context = nullptr;
- ::Display *x11_display;
- XVisualInfo x_vi;
+ ::Display *x11_display = nullptr;
+ XVisualInfo x_vi = {};
};
// just for convenience, window and display struct
struct XWinDisp {
::Window x11_window;
- ::Display *x11_display;
+ ::Display *x11_display = nullptr;
} _x_windisp;
LocalVector<GLWindow> _windows;
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index e7003ab98b..78987738a5 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -33,20 +33,21 @@
#include "core/config/project_settings.h"
#include "scene/main/window.h"
+bool Camera2D::_is_editing_in_editor() const {
+#ifdef TOOLS_ENABLED
+ return is_part_of_edited_scene();
+#else
+ return false;
+#endif // TOOLS_ENABLED
+}
+
void Camera2D::_update_scroll() {
- if (!is_inside_tree()) {
+ if (!is_inside_tree() || !viewport) {
return;
}
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (_is_editing_in_editor()) {
queue_redraw();
- // Only set viewport transform when not bound to the main viewport.
- if (get_tree()->get_edited_scene_root() && get_viewport() == get_tree()->get_edited_scene_root()->get_viewport()) {
- return;
- }
- }
-
- if (!viewport) {
return;
}
@@ -65,7 +66,7 @@ void Camera2D::_update_scroll() {
}
void Camera2D::_update_process_callback() {
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (_is_editing_in_editor()) {
set_process_internal(false);
set_physics_process_internal(false);
} else if (process_callback == CAMERA2D_PROCESS_IDLE) {
@@ -106,7 +107,7 @@ Transform2D Camera2D::get_camera_transform() {
if (!first) {
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
- if (drag_horizontal_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_horizontal_offset_changed) {
+ if (drag_horizontal_enabled && !_is_editing_in_editor() && !drag_horizontal_offset_changed) {
camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom_scale.x * drag_margin[SIDE_LEFT]));
camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom_scale.x * drag_margin[SIDE_RIGHT]));
} else {
@@ -119,7 +120,7 @@ Transform2D Camera2D::get_camera_transform() {
drag_horizontal_offset_changed = false;
}
- if (drag_vertical_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_vertical_offset_changed) {
+ if (drag_vertical_enabled && !_is_editing_in_editor() && !drag_vertical_offset_changed) {
camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom_scale.y * drag_margin[SIDE_TOP]));
camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom_scale.y * drag_margin[SIDE_BOTTOM]));
@@ -158,7 +159,7 @@ Transform2D Camera2D::get_camera_transform() {
}
}
- if (position_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
+ if (position_smoothing_enabled && !_is_editing_in_editor()) {
real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
@@ -175,7 +176,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom_scale) : Point2());
if (!ignore_rotation) {
- if (rotation_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
+ if (rotation_smoothing_enabled && !_is_editing_in_editor()) {
real_t step = rotation_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
camera_angle = Math::lerp_angle(camera_angle, get_global_rotation(), step);
} else {
@@ -250,7 +251,7 @@ void Camera2D::_notification(int p_what) {
add_to_group(group_name);
add_to_group(canvas_group_name);
- if (!Engine::get_singleton()->is_editor_hint() && enabled && !viewport->get_camera_2d()) {
+ if (!_is_editing_in_editor() && enabled && !viewport->get_camera_2d()) {
make_current();
}
@@ -272,7 +273,7 @@ void Camera2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_DRAW: {
- if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) {
+ if (!is_inside_tree() || !_is_editing_in_editor()) {
break;
}
@@ -398,7 +399,11 @@ void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
void Camera2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- if (enabled && is_inside_tree() && !viewport->get_camera_2d()) {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (enabled && !viewport->get_camera_2d()) {
make_current();
} else if (!enabled && is_current()) {
clear_current();
@@ -414,27 +419,27 @@ Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const {
}
void Camera2D::_make_current(Object *p_which) {
- if (!viewport || (custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ if (!is_inside_tree() || !viewport) {
return;
}
+ if (custom_viewport && !ObjectDB::get_instance(custom_viewport_id)) {
+ return;
+ }
+
+ queue_redraw();
+
if (p_which == this) {
- if (is_inside_tree()) {
- viewport->_camera_2d_set(this);
- queue_redraw();
- }
+ viewport->_camera_2d_set(this);
} else {
- if (is_inside_tree()) {
- if (viewport->get_camera_2d() == this) {
- viewport->_camera_2d_set(nullptr);
- }
- queue_redraw();
+ if (viewport->get_camera_2d() == this) {
+ viewport->_camera_2d_set(nullptr);
}
}
}
void Camera2D::_update_process_internal_for_smoothing() {
- bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
+ bool is_not_in_scene_or_editor = !(is_inside_tree() && _is_editing_in_editor());
bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
bool enable = is_any_smoothing_valid && is_not_in_scene_or_editor;
@@ -453,13 +458,22 @@ void Camera2D::make_current() {
void Camera2D::clear_current() {
ERR_FAIL_COND(!is_current());
- if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)) && viewport->is_inside_tree()) {
+
+ if (!viewport || !viewport->is_inside_tree()) {
+ return;
+ }
+
+ if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) {
viewport->assign_next_enabled_camera_2d(group_name);
}
}
bool Camera2D::is_current() const {
- if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ if (!viewport) {
+ return false;
+ }
+
+ if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) {
return viewport->get_camera_2d() == this;
}
return false;
@@ -567,8 +581,7 @@ Point2 Camera2D::get_camera_screen_center() const {
}
Size2 Camera2D::_get_camera_screen_size() const {
- // special case if the camera2D is in the root viewport
- if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
+ if (_is_editing_in_editor()) {
return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
return get_viewport_rect().size;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 808529b0fb..5693d05ee5 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -85,6 +85,7 @@ protected:
bool drag_vertical_offset_changed = false;
Point2 camera_screen_center;
+ bool _is_editing_in_editor() const;
void _update_process_callback();
void _update_scroll();
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 7dd2e75f09..2c5c6a1a16 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -30,32 +30,67 @@
#include "canvas_modulate.h"
+void CanvasModulate::_on_in_canvas_visibility_changed(bool p_new_visibility) {
+ RID canvas = get_canvas();
+ StringName group_name = "_canvas_modulate_" + itos(canvas.get_id());
+
+ ERR_FAIL_COND_MSG(p_new_visibility == is_in_group(group_name), vformat("CanvasModulate becoming %s in the canvas already %s in the modulate group. Buggy logic, please report.", p_new_visibility ? "visible" : "invisible", p_new_visibility ? "was" : "was not"));
+
+ if (p_new_visibility) {
+ bool has_active_canvas_modulate = get_tree()->has_group(group_name); // Group would be removed if empty; otherwise one CanvasModulate within must be active.
+ add_to_group(group_name);
+ if (!has_active_canvas_modulate) {
+ is_active = true;
+ RS::get_singleton()->canvas_set_modulate(canvas, color);
+ }
+ } else {
+ remove_from_group(group_name);
+ if (is_active) {
+ is_active = false;
+ CanvasModulate *new_active = Object::cast_to<CanvasModulate>(get_tree()->get_first_node_in_group(group_name));
+ if (new_active) {
+ new_active->is_active = true;
+ RS::get_singleton()->canvas_set_modulate(canvas, new_active->color);
+ } else {
+ RS::get_singleton()->canvas_set_modulate(canvas, Color(1, 1, 1, 1));
+ }
+ }
+ }
+
+ update_configuration_warnings();
+}
+
void CanvasModulate::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_CANVAS: {
- if (is_visible_in_tree()) {
- RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
- add_to_group("_canvas_modulate_" + itos(get_canvas().get_id()));
+ is_in_canvas = true;
+ bool visible_in_tree = is_visible_in_tree();
+ if (visible_in_tree) {
+ _on_in_canvas_visibility_changed(true);
}
+ was_visible_in_tree = visible_in_tree;
} break;
case NOTIFICATION_EXIT_CANVAS: {
- if (is_visible_in_tree()) {
- RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
- remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
+ is_in_canvas = false;
+ if (was_visible_in_tree) {
+ _on_in_canvas_visibility_changed(false);
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible_in_tree()) {
- RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
- add_to_group("_canvas_modulate_" + itos(get_canvas().get_id()));
- } else {
- RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
- remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
+ if (!is_in_canvas) {
+ return;
}
- update_configuration_warnings();
+ bool visible_in_tree = is_visible_in_tree();
+ if (visible_in_tree == was_visible_in_tree) {
+ return;
+ }
+
+ _on_in_canvas_visibility_changed(visible_in_tree);
+
+ was_visible_in_tree = visible_in_tree;
} break;
}
}
@@ -69,7 +104,7 @@ void CanvasModulate::_bind_methods() {
void CanvasModulate::set_color(const Color &p_color) {
color = p_color;
- if (is_visible_in_tree()) {
+ if (is_active) {
RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
}
}
@@ -81,12 +116,12 @@ Color CanvasModulate::get_color() const {
PackedStringArray CanvasModulate::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
- if (is_visible_in_tree() && is_inside_tree()) {
+ if (is_in_canvas && is_visible_in_tree()) {
List<Node *> nodes;
get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
if (nodes.size() > 1) {
- warnings.push_back(RTR("Only one visible CanvasModulate is allowed per scene (or set of instantiated scenes). The first created one will work, while the rest will be ignored."));
+ warnings.push_back(RTR("Only one visible CanvasModulate is allowed per canvas.\nWhen there are more than one, only one of them will be active. Which one is undefined."));
}
}
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
index 3b11cf71f1..08ded52e23 100644
--- a/scene/2d/canvas_modulate.h
+++ b/scene/2d/canvas_modulate.h
@@ -38,6 +38,14 @@ class CanvasModulate : public Node2D {
Color color = Color(1, 1, 1, 1);
+ // CanvasModulate is in canvas-specific modulate group when both in canvas and visible in tree.
+ // Exactly one CanvasModulate in each such non-empty group is active.
+ bool is_in_canvas = false;
+ bool was_visible_in_tree = false; // Relevant only when in canvas.
+ bool is_active = false;
+
+ void _on_in_canvas_visibility_changed(bool p_new_visibility);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 4f94f0d9f2..6e75be268d 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -38,8 +38,7 @@
// AcceptDialog
void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> key = p_event;
- if (close_on_escape && key.is_valid() && key->is_action_pressed(SNAME("ui_cancel"), false, true)) {
+ if (close_on_escape && p_event->is_action_pressed(SNAME("ui_cancel"), false, true)) {
_cancel_pressed();
}
}
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index c0a2dc81d0..6915f3d242 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -35,8 +35,7 @@
#include "scene/gui/panel.h"
void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> key = p_event;
- if (get_flag(FLAG_POPUP) && key.is_valid() && key->is_action_pressed(SNAME("ui_cancel"), false, true)) {
+ if (get_flag(FLAG_POPUP) && p_event->is_action_pressed(SNAME("ui_cancel"), false, true)) {
_close_pressed();
}
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 2d3aa66f2c..180efaaa60 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2955,7 +2955,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
void Viewport::_update_mouse_over() {
// Update gui.mouse_over and gui.subwindow_over in all Viewports.
- // Send necessary mouse_enter/mouse_exit signals and the NOTIFICATION_VP_MOUSE_ENTER/NOTIFICATION_VP_MOUSE_EXIT notifications for every Viewport in the SceneTree.
+ // Send necessary mouse_enter/mouse_exit signals and the MOUSE_ENTER/MOUSE_EXIT notifications for every Viewport in the SceneTree.
if (is_attached_in_viewport()) {
// Execute this function only, when it is processed by a native Window or a SubViewport, that has no SubViewportContainer as parent.
@@ -3009,7 +3009,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
}
gui.subwindow_over = sw;
if (!sw->is_input_disabled()) {
- sw->notification(NOTIFICATION_VP_MOUSE_ENTER);
+ sw->_propagate_window_notification(sw, NOTIFICATION_WM_MOUSE_ENTER);
}
}
if (!sw->is_input_disabled()) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 331ce98cdd..1e107ea99c 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -468,7 +468,8 @@ private:
SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
void _update_mouse_over();
- void _update_mouse_over(Vector2 p_pos);
+ virtual void _update_mouse_over(Vector2 p_pos);
+ virtual void _mouse_leave_viewport();
virtual bool _can_consume_input_events() const { return true; }
uint64_t event_count = 0;
@@ -482,8 +483,6 @@ protected:
Size2i _get_size_2d_override() const;
bool _is_size_allocated() const;
- void _mouse_leave_viewport();
-
void _notification(int p_what);
void _process_picking();
static void _bind_methods();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 0b95406b94..1af279d94c 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -679,7 +679,7 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
}
_propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
root->gui.windowmanager_window_over = this;
- notification(NOTIFICATION_VP_MOUSE_ENTER);
+ mouse_in_window = true;
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape
}
@@ -692,6 +692,7 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
#endif // DEV_ENABLED
return;
}
+ mouse_in_window = false;
root->gui.windowmanager_window_over->_mouse_leave_viewport();
root->gui.windowmanager_window_over = nullptr;
_propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT);
@@ -2552,6 +2553,41 @@ bool Window::is_attached_in_viewport() const {
return get_embedder();
}
+void Window::_update_mouse_over(Vector2 p_pos) {
+ if (!mouse_in_window) {
+ if (is_embedded()) {
+ mouse_in_window = true;
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
+ } else {
+ // Prevent update based on delayed InputEvents from DisplayServer.
+ return;
+ }
+ }
+
+ bool new_in = get_visible_rect().has_point(p_pos);
+ if (new_in == gui.mouse_in_viewport) {
+ if (new_in) {
+ Viewport::_update_mouse_over(p_pos);
+ }
+ return;
+ }
+
+ if (new_in) {
+ notification(NOTIFICATION_VP_MOUSE_ENTER);
+ Viewport::_update_mouse_over(p_pos);
+ } else {
+ Viewport::_mouse_leave_viewport();
+ }
+}
+
+void Window::_mouse_leave_viewport() {
+ Viewport::_mouse_leave_viewport();
+ if (is_embedded()) {
+ mouse_in_window = false;
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT);
+ }
+}
+
void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
diff --git a/scene/main/window.h b/scene/main/window.h
index d5b8cd4ead..c387ffa92a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -203,6 +203,10 @@ private:
void _event_callback(DisplayServer::WindowEvent p_event);
virtual bool _can_consume_input_events() const override;
+ bool mouse_in_window = false;
+ void _update_mouse_over(Vector2 p_pos) override;
+ void _mouse_leave_viewport() override;
+
Ref<Shortcut> debugger_stop_shortcut;
protected:
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 4bfec8ae8d..56f2ea0b0c 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -1309,16 +1309,13 @@ void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
RID new_buffer = RD::get_singleton()->storage_buffer_create(new_buffer_size);
if (multimesh->buffer_set && multimesh->data_cache.is_empty()) {
- // If the buffer was set but there's no data cached in the CPU, we must download it from the GPU and
- // upload it because RD does not provide a way to copy the buffer directly yet.
+ // If the buffer was set but there's no data cached in the CPU, we copy the buffer directly on the GPU.
RD::get_singleton()->barrier();
- Vector<uint8_t> buffer_data = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- ERR_FAIL_COND(buffer_data.size() != int(buffer_size));
- RD::get_singleton()->buffer_update(new_buffer, 0, buffer_size, buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
- RD::get_singleton()->buffer_update(new_buffer, buffer_size, buffer_size, buffer_data.ptr());
+ RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size, RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, buffer_size, buffer_size);
} else if (!multimesh->data_cache.is_empty()) {
// Simply upload the data cached in the CPU, which should already be doubled in size.
- ERR_FAIL_COND(multimesh->data_cache.size() != int(new_buffer_size));
+ ERR_FAIL_COND(multimesh->data_cache.size() * sizeof(float) != size_t(new_buffer_size));
RD::get_singleton()->buffer_update(new_buffer, 0, new_buffer_size, multimesh->data_cache.ptr());
}
@@ -1328,6 +1325,9 @@ void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
multimesh->buffer = new_buffer;
multimesh->uniform_set_3d = RID(); // Cleared by dependency.
+
+ // Invalidate any references to the buffer that was released and the uniform set that was pointing to it.
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 30d9b1c7b7..1ade1b25c4 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -840,6 +840,7 @@ public:
virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) = 0;
+ virtual Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
virtual Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0) = 0; // This causes stall, only use to retrieve large buffers for saving.
diff --git a/tests/scene/test_window.h b/tests/scene/test_window.h
new file mode 100644
index 0000000000..e0c55101de
--- /dev/null
+++ b/tests/scene/test_window.h
@@ -0,0 +1,96 @@
+/**************************************************************************/
+/* test_window.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_WINDOW_H
+#define TEST_WINDOW_H
+
+#include "scene/gui/control.h"
+#include "scene/main/window.h"
+
+#include "tests/test_macros.h"
+
+namespace TestWindow {
+
+class NotificationControl : public Control {
+ GDCLASS(NotificationControl, Control);
+
+protected:
+ void _notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_MOUSE_ENTER: {
+ mouse_over = true;
+ } break;
+
+ case NOTIFICATION_MOUSE_EXIT: {
+ mouse_over = false;
+ } break;
+ }
+ }
+
+public:
+ bool mouse_over = false;
+};
+
+TEST_CASE("[SceneTree][Window]") {
+ Window *root = SceneTree::get_singleton()->get_root();
+
+ SUBCASE("Control-mouse-over within Window-black bars should not happen") {
+ Window *w = memnew(Window);
+ root->add_child(w);
+ w->set_size(Size2i(400, 200));
+ w->set_position(Size2i(0, 0));
+ w->set_content_scale_size(Size2i(200, 200));
+ w->set_content_scale_mode(Window::CONTENT_SCALE_MODE_CANVAS_ITEMS);
+ w->set_content_scale_aspect(Window::CONTENT_SCALE_ASPECT_KEEP);
+ NotificationControl *c = memnew(NotificationControl);
+ w->add_child(c);
+ c->set_size(Size2i(100, 100));
+ c->set_position(Size2i(-50, -50));
+
+ CHECK_FALSE(c->mouse_over);
+ SEND_GUI_MOUSE_MOTION_EVENT(Point2i(110, 10), MouseButtonMask::NONE, Key::NONE);
+ CHECK(c->mouse_over);
+ SEND_GUI_MOUSE_MOTION_EVENT(Point2i(90, 10), MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(c->mouse_over); // GH-80011
+
+ /* TODO:
+ SEND_GUI_MOUSE_BUTTON_EVENT(Point2i(90, 10), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2i(90, 10), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(Control was not pressed);
+ */
+
+ memdelete(c);
+ memdelete(w);
+ }
+}
+
+} // namespace TestWindow
+
+#endif // TEST_WINDOW_H
diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h
index 8ea69ec67c..a116559cb2 100644
--- a/tests/servers/test_navigation_server_3d.h
+++ b/tests/servers/test_navigation_server_3d.h
@@ -423,6 +423,7 @@ TEST_SUITE("[Navigation]") {
navigation_server->free(map);
}
+#ifndef DISABLE_DEPRECATED
// This test case uses only public APIs on purpose - other test cases use simplified baking.
// FIXME: Remove once deprecated `region_bake_navigation_mesh()` is removed.
TEST_CASE("[NavigationServer3D][SceneTree][DEPRECATED] Server should be able to bake map correctly") {
@@ -470,6 +471,7 @@ TEST_SUITE("[Navigation]") {
memdelete(mesh_instance);
memdelete(node_3d);
}
+#endif // DISABLE_DEPRECATED
// This test case uses only public APIs on purpose - other test cases use simplified baking.
TEST_CASE("[NavigationServer3D][SceneTree] Server should be able to bake map correctly") {
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 5ca03a20af..f1e348345b 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -115,6 +115,7 @@
#include "tests/scene/test_theme.h"
#include "tests/scene/test_viewport.h"
#include "tests/scene/test_visual_shader.h"
+#include "tests/scene/test_window.h"
#include "tests/servers/rendering/test_shader_preprocessor.h"
#include "tests/servers/test_navigation_server_2d.h"
#include "tests/servers/test_navigation_server_3d.h"