From 532630e7cd41c4b4dc3b64a721a6a5447baf59c5 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Tue, 12 Dec 2023 18:23:15 -0500 Subject: [PATCH 01/34] Fix volumetric fog artifacts when inside the fog --- .../rendering/renderer_rd/environment/fog.cpp | 80 +++++++++++++------ 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 48537a97d9..94ffc6e841 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -622,6 +622,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); bool any_uses_time = false; + Vector3 cam_position = p_cam_transform.get_origin(); for (int i = 0; i < (int)p_fog_volumes.size(); i++) { FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]); @@ -652,41 +653,68 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P any_uses_time |= shader_data->uses_time; - Vector3i min; - Vector3i max; + Vector3i froxel_min; + Vector3i froxel_max; Vector3i kernel_size; - Vector3 position = fog_volume_instance->transform.get_origin(); + Vector3 fog_position = fog_volume_instance->transform.get_origin(); RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume); Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_size(fog_volume) / 2; if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { // Local fog volume. - Vector3i points[8]; Vector3 fog_size = Vector3(fog->width, fog->height, fog->depth); float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env); - points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); - - min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1); - max = Vector3i(1, 1, 1); - + Vector3 corners[8]{ + fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), + fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)) + }; + Vector3i froxels[8]; + Vector3 corner_min = corners[0]; + Vector3 corner_max = corners[0]; for (int j = 0; j < 8; j++) { - min = min.min(points[j]); - max = max.max(points[j]); + froxels[j] = _point_get_position_in_froxel_volume(corners[j], fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform); + corner_min = corner_min.min(corners[j]); + corner_max = corner_max.max(corners[j]); } - kernel_size = max - min; + froxel_min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1); + froxel_max = Vector3i(1, 1, 1); + + // Tracking just the corners of the fog volume can result in missing some fog: + // when the camera's near plane is inside the fog, we must always consider the entire screen + Vector3 near_plane_corner(frustum_near_size.x, frustum_near_size.y, z_near); + float expand = near_plane_corner.length(); + if (cam_position.x > (corner_min.x - expand) && cam_position.x < (corner_max.x + expand) && + cam_position.y > (corner_min.y - expand) && cam_position.y < (corner_max.y + expand) && + cam_position.z > (corner_min.z - expand) && cam_position.z < (corner_max.z + expand)) { + froxel_min.x = 0; + froxel_min.y = 0; + froxel_min.z = 0; + froxel_max.x = int32_t(fog->width); + froxel_max.y = int32_t(fog->height); + for (int j = 0; j < 8; j++) { + froxel_max.z = MAX(froxel_max.z, froxels[j].z); + } + } else { + // Camera is guaranteed to be outside the fog volume + for (int j = 0; j < 8; j++) { + froxel_min = froxel_min.min(froxels[j]); + froxel_max = froxel_max.max(froxels[j]); + } + } + + kernel_size = froxel_max - froxel_min; } else { // Volume type global runs on all cells extents = Vector3(fog->width, fog->height, fog->depth); - min = Vector3i(0, 0, 0); + froxel_min = Vector3i(0, 0, 0); kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->depth)); } @@ -695,15 +723,15 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P } VolumetricFogShader::FogPushConstant push_constant; - push_constant.position[0] = position.x; - push_constant.position[1] = position.y; - push_constant.position[2] = position.z; + push_constant.position[0] = fog_position.x; + push_constant.position[1] = fog_position.y; + push_constant.position[2] = fog_position.z; push_constant.size[0] = extents.x * 2; push_constant.size[1] = extents.y * 2; push_constant.size[2] = extents.z * 2; - push_constant.corner[0] = min.x; - push_constant.corner[1] = min.y; - push_constant.corner[2] = min.z; + push_constant.corner[0] = froxel_min.x; + push_constant.corner[1] = froxel_min.y; + push_constant.corner[2] = froxel_min.z; push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume)); RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform); From 3eb8b0ac8c6a44474618b584ab2cd1aaff92b7fc Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Wed, 7 Jun 2023 19:18:41 +0200 Subject: [PATCH 02/34] Add Markdown syntax highlighting to the script editor --- editor/plugins/script_editor_plugin.cpp | 50 +++++++++++++++++++++++++ editor/plugins/script_editor_plugin.h | 18 +++++++++ 2 files changed, 68 insertions(+) diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index a670c7937b..e1aac44348 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -259,6 +259,52 @@ Ref EditorJSONSyntaxHighlighter::_create() const { return syntax_highlighter; } +//// + +void EditorMarkdownSyntaxHighlighter::_update_cache() { + highlighter->set_text_edit(text_edit); + highlighter->clear_keyword_colors(); + highlighter->clear_member_keyword_colors(); + highlighter->clear_color_regions(); + + // Disable automatic symbolic highlights, as these don't make sense for prose. + highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/text_color")); + highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/text_color")); + highlighter->set_member_variable_color(EDITOR_GET("text_editor/theme/highlighting/text_color")); + highlighter->set_function_color(EDITOR_GET("text_editor/theme/highlighting/text_color")); + + // Headings (any level). + const Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color"); + highlighter->add_color_region("#", "", function_color); + + // Bold. + highlighter->add_color_region("**", "**", function_color); + // `__bold__` syntax is not supported as color regions must begin with a symbol, + // not a character that is valid in an identifier. + + // Code (both inline code and triple-backticks code blocks). + const Color code_color = EDITOR_GET("text_editor/theme/highlighting/engine_type_color"); + highlighter->add_color_region("`", "`", code_color); + + // Link (both references and inline links with URLs). The URL is not highlighted. + const Color link_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); + highlighter->add_color_region("[", "]", link_color); + + // Quote. + const Color quote_color = EDITOR_GET("text_editor/theme/highlighting/string_color"); + highlighter->add_color_region(">", "", quote_color, true); + + // HTML comment, which is also supported in Markdown. + const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); + highlighter->add_color_region("", comment_color); +} + +Ref EditorMarkdownSyntaxHighlighter::_create() const { + Ref syntax_highlighter; + syntax_highlighter.instantiate(); + return syntax_highlighter; +} + //////////////////////////////////////////////////////////////////////////////// /*** SCRIPT EDITOR ****/ @@ -4331,6 +4377,10 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { json_syntax_highlighter.instantiate(); register_syntax_highlighter(json_syntax_highlighter); + Ref markdown_syntax_highlighter; + markdown_syntax_highlighter.instantiate(); + register_syntax_highlighter(markdown_syntax_highlighter); + _update_online_doc(); } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9db1aff76a..2a84a790bb 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -120,6 +120,24 @@ public: EditorJSONSyntaxHighlighter() { highlighter.instantiate(); } }; +class EditorMarkdownSyntaxHighlighter : public EditorSyntaxHighlighter { + GDCLASS(EditorMarkdownSyntaxHighlighter, EditorSyntaxHighlighter) + +private: + Ref highlighter; + +public: + virtual void _update_cache() override; + virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override { return highlighter->get_line_syntax_highlighting(p_line); } + + virtual PackedStringArray _get_supported_languages() const override { return PackedStringArray{ "md", "markdown" }; } + virtual String _get_name() const override { return TTR("Markdown"); } + + virtual Ref _create() const override; + + EditorMarkdownSyntaxHighlighter() { highlighter.instantiate(); } +}; + /////////////////////////////////////////////////////////////////////////////// class ScriptEditorQuickOpen : public ConfirmationDialog { From a54b71bbdfda9bc36534d18bc873cb90016c0a13 Mon Sep 17 00:00:00 2001 From: Hannah Crawford Date: Mon, 12 Aug 2024 00:17:11 +0100 Subject: [PATCH 03/34] Add `shadow_caster_mask` to Light3D. --- doc/classes/Light3D.xml | 3 +++ doc/classes/RenderingServer.xml | 8 ++++++++ drivers/gles3/storage/light_storage.cpp | 17 +++++++++++++++++ drivers/gles3/storage/light_storage.h | 3 +++ scene/3d/light_3d.cpp | 15 ++++++++++++++- scene/3d/light_3d.h | 4 ++++ servers/rendering/dummy/storage/light_storage.h | 2 ++ .../renderer_rd/storage_rd/light_storage.cpp | 17 +++++++++++++++++ .../renderer_rd/storage_rd/light_storage.h | 3 +++ servers/rendering/renderer_scene_cull.cpp | 9 +++++---- servers/rendering/renderer_scene_cull.h | 1 + servers/rendering/rendering_server_default.h | 1 + servers/rendering/storage/light_storage.h | 2 ++ servers/rendering_server.cpp | 1 + servers/rendering_server.h | 1 + 15 files changed, 82 insertions(+), 5 deletions(-) diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index bda5fb69de..966d0fdcb4 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -115,6 +115,9 @@ Blurs the edges of the shadow. Can be used to hide pixel artifacts in low-resolution shadow maps. A high value can impact performance, make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible. + + The light will only cast shadows using objects in the selected layers. + If [code]true[/code], the light will cast real-time shadows. This has a significant performance cost. Only enable shadow rendering when it makes a noticeable difference in the scene's appearance, and consider using [member distance_fade_enabled] to hide the light when far away from the [Camera3D]. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 3c9f0fc7af..37c7519462 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -2111,6 +2111,14 @@ If [code]true[/code], light will cast shadows. Equivalent to [member Light3D.shadow_enabled]. + + + + + + Sets the shadow caster mask for this 3D light. Shadows will only be cast using objects in the selected layers. Equivalent to [member Light3D.shadow_caster_mask]. + + diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index f9547502f4..bbd48fe5cc 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -213,6 +213,23 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } +void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL(light); + + light->shadow_caster_mask = p_caster_mask; + + light->version++; + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); +} + +uint32_t LightStorage::light_get_shadow_caster_mask(RID p_light) const { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL_V(light, 0); + + return light->shadow_caster_mask; +} + void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) { Light *light = light_owner.get_or_null(p_light); ERR_FAIL_NULL(light); diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index b6e64c9492..a5758e0a4c 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -59,6 +59,7 @@ struct Light { RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC; uint32_t max_sdfgi_cascade = 2; uint32_t cull_mask = 0xFFFFFFFF; + uint32_t shadow_caster_mask = 0xFFFFFFFF; bool distance_fade = false; real_t distance_fade_begin = 40.0; real_t distance_fade_shadow = 50.0; @@ -326,6 +327,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override; + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override; virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override; virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {} diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 7b70986adc..2d18e62b10 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -146,6 +146,15 @@ bool Light3D::get_shadow_reverse_cull_face() const { return reverse_cull; } +void Light3D::set_shadow_caster_mask(uint32_t p_caster_mask) { + shadow_caster_mask = p_caster_mask; + RS::get_singleton()->light_set_shadow_caster_mask(light, shadow_caster_mask); +} + +uint32_t Light3D::get_shadow_caster_mask() const { + return shadow_caster_mask; +} + AABB Light3D::get_aabb() const { if (type == RenderingServer::LIGHT_DIRECTIONAL) { return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); @@ -300,7 +309,7 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &p_property) const { - if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) { + if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow" || p_property.name == "shadow_caster_mask")) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } @@ -354,6 +363,9 @@ void Light3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light3D::set_shadow_reverse_cull_face); ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light3D::get_shadow_reverse_cull_face); + ClassDB::bind_method(D_METHOD("set_shadow_caster_mask", "caster_mask"), &Light3D::set_shadow_caster_mask); + ClassDB::bind_method(D_METHOD("get_shadow_caster_mask"), &Light3D::get_shadow_caster_mask); + ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode); ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode); @@ -388,6 +400,7 @@ void Light3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_caster_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_shadow_caster_mask", "get_shadow_caster_mask"); ADD_GROUP("Distance Fade", "distance_fade_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled"); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index d6eca8d8b6..5f549469c6 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -75,6 +75,7 @@ private: bool negative = false; bool reverse_cull = false; uint32_t cull_mask = 0; + uint32_t shadow_caster_mask = 0xFFFFFFFF; bool distance_fade_enabled = false; real_t distance_fade_begin = 40.0; real_t distance_fade_shadow = 50.0; @@ -136,6 +137,9 @@ public: void set_shadow_reverse_cull_face(bool p_enable); bool get_shadow_reverse_cull_face() const; + void set_shadow_caster_mask(uint32_t p_caster_mask); + uint32_t get_shadow_caster_mask() const; + void set_bake_mode(BakeMode p_mode); BakeMode get_bake_mode() const; diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index c3b63cdbf6..d25523753c 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -78,6 +78,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override {} virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override {} virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {} + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override {} + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override { return 0xFFFFFFFF; } virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {} virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {} diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 3d294ca8cb..b4acdbec11 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -285,6 +285,23 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } +void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL(light); + + light->shadow_caster_mask = p_caster_mask; + + light->version++; + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); +} + +uint32_t LightStorage::light_get_shadow_caster_mask(RID p_light) const { + Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_NULL_V(light, 0); + + return light->shadow_caster_mask; +} + void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { Light *light = light_owner.get_or_null(p_light); ERR_FAIL_NULL(light); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index f152cc5dae..34d8f58e2a 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -72,6 +72,7 @@ private: RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC; uint32_t max_sdfgi_cascade = 2; uint32_t cull_mask = 0xFFFFFFFF; + uint32_t shadow_caster_mask = 0xFFFFFFFF; bool distance_fade = false; real_t distance_fade_begin = 40.0; real_t distance_fade_shadow = 50.0; @@ -474,6 +475,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override; + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override; virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override; virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index b02d3def88..74c79dbce4 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2139,6 +2139,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in cull.shadow_count = p_shadow_index + 1; cull.shadows[p_shadow_index].cascade_count = splits; cull.shadows[p_shadow_index].light_instance = light->instance; + cull.shadows[p_shadow_index].caster_mask = RSG::light_storage->light_get_shadow_caster_mask(p_instance->base); for (int i = 0; i < splits; i++) { RENDER_TIMESTAMP("Cull DirectionalLight3D, Split " + itos(i)); @@ -2369,7 +2370,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast(instance->base_data)->material_is_animated) { @@ -2451,7 +2452,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast(instance->base_data)->material_is_animated) { @@ -2518,7 +2519,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) { continue; } else { if (static_cast(instance->base_data)->material_is_animated) { @@ -2978,7 +2979,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) { uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && LAYER_CHECK) { + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && (LAYER_CHECK & cull_data.cull->shadows[j].caster_mask)) { cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); mesh_visible = true; } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 0039d14475..8f02860118 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1084,6 +1084,7 @@ public: struct Cull { struct Shadow { RID light_instance; + uint32_t caster_mask; struct Cascade { Frustum frustum; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 164ec3cc09..73c4706bee 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -377,6 +377,7 @@ public: FUNC2(light_set_cull_mask, RID, uint32_t) FUNC5(light_set_distance_fade, RID, bool, float, float, float) FUNC2(light_set_reverse_cull_face_mode, RID, bool) + FUNC2(light_set_shadow_caster_mask, RID, uint32_t) FUNC2(light_set_bake_mode, RID, LightBakeMode) FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t) diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 6a0adfa596..1e149e3a97 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -59,6 +59,8 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) = 0; + virtual uint32_t light_get_shadow_caster_mask(RID p_light) const = 0; virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 70b585d683..2549bfa7a3 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2467,6 +2467,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &RenderingServer::light_set_cull_mask); ClassDB::bind_method(D_METHOD("light_set_distance_fade", "decal", "enabled", "begin", "shadow", "length"), &RenderingServer::light_set_distance_fade); ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &RenderingServer::light_set_reverse_cull_face_mode); + ClassDB::bind_method(D_METHOD("light_set_shadow_caster_mask", "light", "mask"), &RenderingServer::light_set_shadow_caster_mask); ClassDB::bind_method(D_METHOD("light_set_bake_mode", "light", "bake_mode"), &RenderingServer::light_set_bake_mode); ClassDB::bind_method(D_METHOD("light_set_max_sdfgi_cascade", "light", "cascade"), &RenderingServer::light_set_max_sdfgi_cascade); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 693c822488..9e26710166 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -508,6 +508,7 @@ public: virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0; virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; + virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) = 0; enum LightBakeMode { LIGHT_BAKE_DISABLED, From e479c238a227520fb82eb001b5b26b4f8c2675dd Mon Sep 17 00:00:00 2001 From: stechyo Date: Sat, 23 Dec 2023 17:12:29 +0000 Subject: [PATCH 04/34] Expose some AudioStreamPlayback methods. Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> --- doc/classes/AudioStreamPlayback.xml | 41 +++++++++++++++++++++++++++++ servers/audio/audio_stream.cpp | 31 ++++++++++++++++++++++ servers/audio/audio_stream.h | 4 +++ 3 files changed, 76 insertions(+) diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml index 02f3407f79..d7f6ef2014 100644 --- a/doc/classes/AudioStreamPlayback.xml +++ b/doc/classes/AudioStreamPlayback.xml @@ -79,12 +79,40 @@ Overridable method. Called whenever the audio stream is mixed if the playback is active and [method AudioServer.set_enable_tagging_used_audio_streams] has been set to [code]true[/code]. Editor plugins may use this method to "tag" the current position along the audio stream and display it in a preview. + + + + Returns the number of times the stream has looped. + + + + + + Returns the current position in the stream, in seconds. + + Returns the [AudioSamplePlayback] associated with this [AudioStreamPlayback] for playing back the audio sample of this stream. + + + + Returns [code]true[/code] if the stream is playing. + + + + + + + + Mixes up to [param frames] of audio from the stream from the current position, at a rate of [param rate_scale], advancing the stream. + Returns a [PackedVector2Array] where each element holds the left and right channel volume levels of each frame. + [b]Note:[/b] Can return fewer frames than requested, make sure to use the size of the return value. + + @@ -92,5 +120,18 @@ Associates [AudioSamplePlayback] to this [AudioStreamPlayback] for playing back the audio sample of this stream. + + + + + Starts the stream from the given [param from_pos], in seconds. + + + + + + Stops the stream. + + diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 7ab150c141..4921299ef1 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -76,6 +76,31 @@ int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_fra return ret; } +PackedVector2Array AudioStreamPlayback::mix_audio(float p_rate_scale, int p_frames) { + Vector frames_in; + frames_in.resize(p_frames); + + int frames = mix(frames_in.ptrw(), p_rate_scale, p_frames); + + PackedVector2Array res; + res.resize(frames); + + Vector2 *res_ptrw = res.ptrw(); + for (int i = 0; i < frames; i++) { + res_ptrw[i] = Vector2(frames_in[i].left, frames_in[i].right); + } + + return res; +} + +void AudioStreamPlayback::start_playback(double p_from_pos) { + start(); +} + +void AudioStreamPlayback::stop_playback() { + stop(); +} + void AudioStreamPlayback::tag_used_streams() { GDVIRTUAL_CALL(_tag_used_streams); } @@ -108,6 +133,12 @@ void AudioStreamPlayback::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_playback", "playback_sample"), &AudioStreamPlayback::set_sample_playback); ClassDB::bind_method(D_METHOD("get_sample_playback"), &AudioStreamPlayback::get_sample_playback); + ClassDB::bind_method(D_METHOD("mix_audio", "rate_scale", "frames"), &AudioStreamPlayback::mix_audio); + ClassDB::bind_method(D_METHOD("start", "from_pos"), &AudioStreamPlayback::start_playback, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayback::stop_playback); + ClassDB::bind_method(D_METHOD("get_loop_count"), &AudioStreamPlayback::get_loop_count); + ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayback::get_playback_position); + ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayback::is_playing); } AudioStreamPlayback::AudioStreamPlayback() {} diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 0ca4777d5c..31fd94038e 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -116,6 +116,10 @@ public: AudioStreamPlayback(); ~AudioStreamPlayback(); + + PackedVector2Array mix_audio(float p_rate_scale, int p_frames); + void start_playback(double p_from_pos = 0.0); + void stop_playback(); }; class AudioStreamPlaybackResampled : public AudioStreamPlayback { From c32f72f7fa9aadd960d8d445535e8a7065539a79 Mon Sep 17 00:00:00 2001 From: stechyo Date: Mon, 26 Aug 2024 19:42:42 +0100 Subject: [PATCH 05/34] Post-code review changes. --- doc/classes/AudioStreamPlayback.xml | 7 +++++++ servers/audio/audio_stream.cpp | 32 ++++++++++++++++++++--------- servers/audio/audio_stream.h | 4 +++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml index d7f6ef2014..f01406d0f1 100644 --- a/doc/classes/AudioStreamPlayback.xml +++ b/doc/classes/AudioStreamPlayback.xml @@ -113,6 +113,13 @@ [b]Note:[/b] Can return fewer frames than requested, make sure to use the size of the return value. + + + + + Seeks the stream at the given [param time], in seconds. + + diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 4921299ef1..13ba139f31 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -76,31 +76,42 @@ int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_fra return ret; } -PackedVector2Array AudioStreamPlayback::mix_audio(float p_rate_scale, int p_frames) { - Vector frames_in; - frames_in.resize(p_frames); - - int frames = mix(frames_in.ptrw(), p_rate_scale, p_frames); +PackedVector2Array AudioStreamPlayback::_mix_audio_bind(float p_rate_scale, int p_frames) { + Vector frames = mix_audio(p_rate_scale, p_frames); PackedVector2Array res; - res.resize(frames); + res.resize(frames.size()); Vector2 *res_ptrw = res.ptrw(); - for (int i = 0; i < frames; i++) { - res_ptrw[i] = Vector2(frames_in[i].left, frames_in[i].right); + for (int i = 0; i < frames.size(); i++) { + res_ptrw[i] = Vector2(frames[i].left, frames[i].right); } return res; } +Vector AudioStreamPlayback::mix_audio(float p_rate_scale, int p_frames) { + Vector res; + res.resize(p_frames); + + int frames = mix(res.ptrw(), p_rate_scale, p_frames); + res.resize(frames); + + return res; +} + void AudioStreamPlayback::start_playback(double p_from_pos) { - start(); + start(p_from_pos); } void AudioStreamPlayback::stop_playback() { stop(); } +void AudioStreamPlayback::seek_playback(double p_time) { + seek(p_time); +} + void AudioStreamPlayback::tag_used_streams() { GDVIRTUAL_CALL(_tag_used_streams); } @@ -133,8 +144,9 @@ void AudioStreamPlayback::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_playback", "playback_sample"), &AudioStreamPlayback::set_sample_playback); ClassDB::bind_method(D_METHOD("get_sample_playback"), &AudioStreamPlayback::get_sample_playback); - ClassDB::bind_method(D_METHOD("mix_audio", "rate_scale", "frames"), &AudioStreamPlayback::mix_audio); + ClassDB::bind_method(D_METHOD("mix_audio", "rate_scale", "frames"), &AudioStreamPlayback::_mix_audio_bind); ClassDB::bind_method(D_METHOD("start", "from_pos"), &AudioStreamPlayback::start_playback, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("seek", "time"), &AudioStreamPlayback::seek_playback, DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayback::stop_playback); ClassDB::bind_method(D_METHOD("get_loop_count"), &AudioStreamPlayback::get_loop_count); ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayback::get_playback_position); diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 31fd94038e..f49eb8af01 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -81,6 +81,7 @@ class AudioStreamPlayback : public RefCounted { protected: static void _bind_methods(); + PackedVector2Array _mix_audio_bind(float p_rate_scale, int p_frames); GDVIRTUAL1(_start, double) GDVIRTUAL0(_stop) GDVIRTUAL0RC(bool, _is_playing) @@ -117,9 +118,10 @@ public: AudioStreamPlayback(); ~AudioStreamPlayback(); - PackedVector2Array mix_audio(float p_rate_scale, int p_frames); + Vector mix_audio(float p_rate_scale, int p_frames); void start_playback(double p_from_pos = 0.0); void stop_playback(); + void seek_playback(double p_time); }; class AudioStreamPlaybackResampled : public AudioStreamPlayback { From 4e916f1fd97d6b416c80ed6bdb685086c3f95dff Mon Sep 17 00:00:00 2001 From: shahriarlabib000 Date: Thu, 19 Sep 2024 20:39:32 +0600 Subject: [PATCH 06/34] fix popup scale --- editor/plugins/sprite_2d_editor_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index c7db243662..5333e10b56 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -593,12 +593,12 @@ Sprite2DEditor::Sprite2DEditor() { add_child(err_dialog); debug_uv_dialog = memnew(ConfirmationDialog); + debug_uv_dialog->set_size(Size2(960, 540) * EDSCALE); VBoxContainer *vb = memnew(VBoxContainer); debug_uv_dialog->add_child(vb); debug_uv = memnew(Panel); debug_uv->connect(SceneStringName(gui_input), callable_mp(this, &Sprite2DEditor::_debug_uv_input)); debug_uv->connect(SceneStringName(draw), callable_mp(this, &Sprite2DEditor::_debug_uv_draw)); - debug_uv->set_custom_minimum_size(Size2(800, 500) * EDSCALE); debug_uv->set_clip_contents(true); vb->add_margin_child(TTR("Preview:"), debug_uv, true); From d3ad99d3d1adbb08649b41fc1d07425a5f2fd79b Mon Sep 17 00:00:00 2001 From: rune-scape Date: Sat, 21 Sep 2024 21:56:11 -0700 Subject: [PATCH 07/34] GDScriptNativeClass: Allow getting static function as callable --- modules/gdscript/gdscript.cpp | 11 +++++++++-- .../features/native_static_method_as_callable.gd | 8 ++++++++ .../features/native_static_method_as_callable.out | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd create mode 100644 modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 7b9aa70686..6979373ad3 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -76,9 +76,16 @@ bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const { if (ok) { r_ret = v; return true; - } else { - return false; } + + MethodBind *method = ClassDB::get_method(name, p_name); + if (method && method->is_static()) { + // Native static method. + r_ret = Callable(this, p_name); + return true; + } + + return false; } void GDScriptNativeClass::_bind_methods() { diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd new file mode 100644 index 0000000000..63d5935d1e --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd @@ -0,0 +1,8 @@ +func get_parse_string(t: Variant): + return t.parse_string + +func test(): + var a: Callable = JSON.parse_string + var b: Callable = get_parse_string(JSON) + prints(a.call("{\"test\": \"a\"}"), a.is_valid()) + prints(b.call("{\"test\": \"b\"}"), b.is_valid()) diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out new file mode 100644 index 0000000000..a2cb4b9a07 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +{ "test": "a" } false +{ "test": "b" } false From 9c50312f0d6f27328fc19b603319e3b79cf30660 Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Fri, 27 Sep 2024 21:11:43 +0300 Subject: [PATCH 08/34] Extract common check functions in windows_detect.py file Signed-off-by: Yevhen Babiichuk (DustDFG) --- platform/windows/detect.py | 45 ++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 4043f3a8c2..d6cd2536e9 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -483,9 +483,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): else: print_warning("Missing environment variable: WindowsSdkDir") - if int(env["target_win_version"], 16) < 0x0601: - print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") - sys.exit(255) + validate_win_version(env) env.AppendUnique( CPPDEFINES=[ @@ -549,15 +547,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): LIBS += ["vulkan"] if env["d3d12"]: - # Check whether we have d3d12 dependencies installed. - if not os.path.exists(env["mesa_libs"]): - print_error( - "The Direct3D 12 rendering driver requires dependencies to be installed.\n" - "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" - "See the documentation for more information:\n\t" - "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" - ) - sys.exit(255) + check_d3d12_installed(env) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) LIBS += ["dxgi", "dxguid"] @@ -819,9 +809,7 @@ def configure_mingw(env: "SConsEnvironment"): ## Compile flags - if int(env["target_win_version"], 16) < 0x0601: - print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") - sys.exit(255) + validate_win_version(env) if not env["use_llvm"]: env.Append(CCFLAGS=["-mwindows"]) @@ -899,15 +887,7 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(LIBS=["vulkan"]) if env["d3d12"]: - # Check whether we have d3d12 dependencies installed. - if not os.path.exists(env["mesa_libs"]): - print_error( - "The Direct3D 12 rendering driver requires dependencies to be installed.\n" - "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" - "See the documentation for more information:\n\t" - "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" - ) - sys.exit(255) + check_d3d12_installed(env) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) env.Append(LIBS=["dxgi", "dxguid"]) @@ -983,3 +963,20 @@ def configure(env: "SConsEnvironment"): else: # MinGW configure_mingw(env) + + +def check_d3d12_installed(env): + if not os.path.exists(env["mesa_libs"]): + print_error( + "The Direct3D 12 rendering driver requires dependencies to be installed.\n" + "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" + "See the documentation for more information:\n\t" + "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" + ) + sys.exit(255) + + +def validate_win_version(env): + if int(env["target_win_version"], 16) < 0x0601: + print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) From 33d9b40386f11c18d14a72bfbf76cb50bd386ade Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Sun, 6 Oct 2024 11:38:05 +0800 Subject: [PATCH 09/34] Fix "No loader found" error after editing PO file PO files used to be loaded as simple `Translation` resources. We later added a dedicated `TranslationPO` resource for it. But the loader still thinks it can only handle `Translation` resources, so it refuses to load the updated `TranslationPO` resource. --- core/io/translation_loader_po.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 578cd91c52..812fbc774e 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -31,7 +31,6 @@ #include "translation_loader_po.h" #include "core/io/file_access.h" -#include "core/string/translation.h" #include "core/string/translation_po.h" Ref TranslationLoaderPO::load_translation(Ref f, Error *r_error) { @@ -361,7 +360,7 @@ void TranslationLoaderPO::get_recognized_extensions(List *p_extensions) } bool TranslationLoaderPO::handles_type(const String &p_type) const { - return (p_type == "Translation"); + return (p_type == "Translation") || (p_type == "TranslationPO"); } String TranslationLoaderPO::get_resource_type(const String &p_path) const { From 96ab05e89ff7d4f9f2865b04d3b7bf2b489b009f Mon Sep 17 00:00:00 2001 From: Travis Lange Date: Tue, 8 Oct 2024 14:06:45 -0400 Subject: [PATCH 10/34] clear addon_name_to_plugin ater unload_editor_addons because of memdelete --- editor/editor_node.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d88fb134f1..7b2e33376c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3378,6 +3378,8 @@ void EditorNode::unload_editor_addons() { remove_editor_plugin(E.value, false); memdelete(E.value); } + + addon_name_to_plugin.clear(); } void EditorNode::_discard_changes(const String &p_str) { From e999f11d53695a2158820871c5fadb23d0c93cef Mon Sep 17 00:00:00 2001 From: HolonProduction Date: Mon, 14 Oct 2024 14:57:16 +0200 Subject: [PATCH 11/34] GDScript: Don't highlight unexposed classes --- modules/gdscript/editor/gdscript_highlighter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index d765cfa1ea..0b12f2ff76 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -701,7 +701,9 @@ void GDScriptSyntaxHighlighter::_update_cache() { List types; ClassDB::get_class_list(&types); for (const StringName &E : types) { - class_names[E] = types_color; + if (ClassDB::is_class_exposed(E)) { + class_names[E] = types_color; + } } /* User types. */ From 74c000db17fe18229b5eff4f025fc07a250cc1b7 Mon Sep 17 00:00:00 2001 From: Yuri Rubinsky Date: Thu, 27 Jun 2024 10:18:44 +0300 Subject: [PATCH 12/34] Allow using stage functions inside custom shader functions --- servers/rendering/shader_language.cpp | 106 +++++++++++++++++--------- servers/rendering/shader_language.h | 1 + servers/rendering/shader_types.cpp | 2 + 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index b6770c773c..26df210e65 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3565,28 +3565,33 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI int argcount = args.size(); - if (p_function_info.stage_functions.has(name)) { - //stage based function - const StageFunctionInfo &sf = p_function_info.stage_functions[name]; - if (argcount != sf.arguments.size()) { - _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size())); - return false; - } - //validate arguments - for (int i = 0; i < argcount; i++) { - if (args[i] != sf.arguments[i].type) { - _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type))); - return false; + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue &E : *stages) { + if (E.value.stage_functions.has(name)) { + // Stage-based function. + const StageFunctionInfo &sf = E.value.stage_functions[name]; + if (argcount != sf.arguments.size()) { + _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size())); + return false; + } + // Validate arguments. + for (int i = 0; i < argcount; i++) { + if (args[i] != sf.arguments[i].type) { + _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type))); + return false; + } + } + + if (r_ret_type) { + *r_ret_type = sf.return_type; + } + if (r_ret_type_str) { + *r_ret_type_str = ""; + } + return true; } } - - if (r_ret_type) { - *r_ret_type = sf.return_type; - } - if (r_ret_type_str) { - *r_ret_type_str = ""; - } - return true; } bool failed_builtin = false; @@ -5937,22 +5942,35 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons calls_info[current_function].calls.push_back(&calls_info[name]); } - int idx = 0; bool is_builtin = false; - while (frag_only_func_defs[idx].name) { - if (frag_only_func_defs[idx].name == name) { - // If a built-in function not found for the current shader type, then it shouldn't be parsed further. - if (!is_supported_frag_only_funcs) { - _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier)); - return nullptr; + if (is_supported_frag_only_funcs && stages) { + for (const KeyValue &E : *stages) { + if (E.value.stage_functions.has(name)) { + // Register usage of the restricted stage function. + calls_info[current_function].uses_restricted_items.push_back(Pair(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); + is_builtin = true; + break; } - // Register usage of the restricted function. - calls_info[current_function].uses_restricted_items.push_back(Pair(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); - is_builtin = true; - break; } - idx++; + } + + if (!is_builtin) { + int idx = 0; + while (frag_only_func_defs[idx].name) { + if (frag_only_func_defs[idx].name == name) { + // If a built-in function not found for the current shader type, then it shouldn't be parsed further. + if (!is_supported_frag_only_funcs) { + _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier)); + return nullptr; + } + // Register usage of the restricted function. + calls_info[current_function].uses_restricted_items.push_back(Pair(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos()))); + is_builtin = true; + break; + } + idx++; + } } // Recursively checks for the restricted function call. @@ -11160,9 +11178,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ int idx = 0; bool low_end = RenderingServer::get_singleton()->is_low_end(); - if (stages && stages->has(skip_function)) { - for (const KeyValue &E : (*stages)[skip_function].stage_functions) { - matches.insert(String(E.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue &E : *stages) { + for (const KeyValue &F : E.value.stage_functions) { + if (F.value.skip_function == skip_function && stages->has(skip_function)) { + continue; + } + matches.insert(String(F.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + } } } @@ -11292,9 +11316,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ return OK; } - if (stages && stages->has(block_function)) { - for (const KeyValue &E : (*stages)[block_function].stage_functions) { - if (completion_function == E.key) { + if (stages) { + // Stage functions can be used in custom functions as well, that why need to check them all. + for (const KeyValue &S : *stages) { + for (const KeyValue &E : S.value.stage_functions) { + // No need to check for the skip function here. + if (completion_function != E.key) { + continue; + } + calltip += get_datatype_name(E.value.return_type); calltip += " "; calltip += E.key; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index fb0a526230..3bbddf7be5 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -859,6 +859,7 @@ public: Vector arguments; DataType return_type = TYPE_VOID; + String skip_function; }; struct ModeInfo { diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index f498c0bf93..9ccfe2f9d7 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -284,6 +284,7 @@ ShaderTypes::ShaderTypes() { { ShaderLanguage::StageFunctionInfo func; + func.skip_function = "vertex"; func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("sdf_pos", ShaderLanguage::TYPE_VEC2)); func.return_type = ShaderLanguage::TYPE_FLOAT; //whether it could emit shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf"] = func; @@ -297,6 +298,7 @@ ShaderTypes::ShaderTypes() { { ShaderLanguage::StageFunctionInfo func; + func.skip_function = "vertex"; func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("uv", ShaderLanguage::TYPE_VEC2)); func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["screen_uv_to_sdf"] = func; From ad7e7a51b21a0c1b5b7142fcace66a7c00407c6a Mon Sep 17 00:00:00 2001 From: Yuri Rubinsky Date: Tue, 25 Jun 2024 15:39:21 +0300 Subject: [PATCH 13/34] Allow usage of `discard` inside custom shader functions --- servers/rendering/shader_language.cpp | 23 ++++++++++++++++------- servers/rendering/shader_language.h | 3 ++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index b6770c773c..44d3cf4f6e 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -356,7 +356,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_CF_BREAK, "break", CF_BLOCK, {}, {} }, { TK_CF_CONTINUE, "continue", CF_BLOCK, {}, {} }, { TK_CF_RETURN, "return", CF_BLOCK, {}, {} }, - { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "fragment" } }, + { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "vertex" } }, // function specifier keywords @@ -8581,6 +8581,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun block = block->parent_block; } } else if (tk.type == TK_CF_DISCARD) { + if (!is_discard_supported) { + _set_error(vformat(RTR("Use of '%s' is not supported for the '%s' shader type."), "discard", shader_type_identifier)); + return ERR_PARSE_ERROR; + } + //check return type BlockNode *b = p_block; while (b && !b->parent_function) { @@ -8592,7 +8597,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (!b->parent_function->can_discard) { - _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard")); + _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), "discard", b->parent_function->name)); return ERR_PARSE_ERROR; } @@ -8601,6 +8606,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun pos = _get_tkpos(); tk = _get_token(); + + calls_info[b->parent_function->name].uses_restricted_items.push_back(Pair("discard", CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, pos))); + if (tk.type != TK_SEMICOLON) { _set_expected_after_error(";", "discard"); return ERR_PARSE_ERROR; @@ -8838,7 +8846,9 @@ Error ShaderLanguage::_parse_shader(const HashMap &p_f ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; stages = &p_functions; - is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky"; + + is_discard_supported = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial"; + is_supported_frag_only_funcs = is_discard_supported || shader_type_identifier == "sky"; const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo(); @@ -10332,6 +10342,8 @@ Error ShaderLanguage::_parse_shader(const HashMap &p_f if (p_functions.has(name)) { func_node->can_discard = p_functions[name].can_discard; + } else { + func_node->can_discard = is_discard_supported; // Allow use it for custom functions (in supported shader types). } if (!function_overload_count.has(name)) { @@ -10922,10 +10934,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ break; // Ignore hint keywords (parsed below). } if (keyword_list[i].flags & keyword_completion_context) { - if (keyword_list[i].excluded_shader_types.has(shader_type_identifier)) { - continue; - } - if (!keyword_list[i].functions.is_empty() && !keyword_list[i].functions.has(current_function)) { + if (keyword_list[i].excluded_shader_types.has(shader_type_identifier) || keyword_list[i].excluded_functions.has(current_function)) { continue; } ScriptLanguage::CodeCompletionOption option(keyword_list[i].text, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index fb0a526230..a1550bc2cd 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -934,7 +934,7 @@ private: const char *text; uint32_t flags; const Vector excluded_shader_types; - const Vector functions; + const Vector excluded_functions; }; static const KeyWord keyword_list[]; @@ -1150,6 +1150,7 @@ private: const HashMap *stages = nullptr; bool is_supported_frag_only_funcs = false; + bool is_discard_supported = false; bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); static const BuiltinFuncDef builtin_func_defs[]; From fc7dd35d78dff8c2cc11a197c2aa4d1766f15db2 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Sat, 19 Oct 2024 00:32:01 +0800 Subject: [PATCH 14/34] Clarify `LineEdit.shortcut_keys_enabled` only affects context menu items --- doc/classes/LineEdit.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 3e0c328dcb..91c9072f73 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -33,6 +33,7 @@ - [kbd]Cmd + E[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line - [kbd]Cmd + Left Arrow[/kbd]: Same as [kbd]Home[/kbd], move the caret to the beginning of the line - [kbd]Cmd + Right Arrow[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line + [b]Note:[/b] Caret movement shortcuts listed above are not affected by [member shortcut_keys_enabled]. @@ -334,7 +335,7 @@ If [code]false[/code], it's impossible to select the text using mouse nor keyboard. - If [code]false[/code], using shortcuts will be disabled. + If [code]true[/code], shortcut keys for context menu items are enabled, even if the context menu is disabled. Set BiDi algorithm override for the structured text. From 4dad9c6c05921cf98c9ee59a5f28358496912433 Mon Sep 17 00:00:00 2001 From: katsuhisa yuasa Date: Sat, 19 Oct 2024 12:37:56 +0900 Subject: [PATCH 15/34] optimize ImageLoaderSVG::create_image_from_utf8_buffer --- modules/svg/image_loader_svg.cpp | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index d903137195..b9d493b844 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -104,51 +104,33 @@ Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref p_image, const ui picture->size(width, height); std::unique_ptr sw_canvas = tvg::SwCanvas::gen(); - // Note: memalloc here, be sure to memfree before any return. - uint32_t *buffer = (uint32_t *)memalloc(sizeof(uint32_t) * width * height); + Vector buffer; + buffer.resize(sizeof(uint32_t) * width * height); - tvg::Result res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888S); + tvg::Result res = sw_canvas->target((uint32_t *)buffer.ptrw(), width, width, height, tvg::SwCanvas::ABGR8888S); if (res != tvg::Result::Success) { - memfree(buffer); ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't set target on ThorVG canvas."); } res = sw_canvas->push(std::move(picture)); if (res != tvg::Result::Success) { - memfree(buffer); ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't insert ThorVG picture on canvas."); } res = sw_canvas->draw(); if (res != tvg::Result::Success) { - memfree(buffer); ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't draw ThorVG pictures on canvas."); } res = sw_canvas->sync(); if (res != tvg::Result::Success) { - memfree(buffer); ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't sync ThorVG canvas."); } - Vector image; - image.resize(width * height * sizeof(uint32_t)); - - for (uint32_t y = 0; y < height; y++) { - for (uint32_t x = 0; x < width; x++) { - uint32_t n = buffer[y * width + x]; - const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x; - image.write[offset + 0] = (n >> 16) & 0xff; - image.write[offset + 1] = (n >> 8) & 0xff; - image.write[offset + 2] = n & 0xff; - image.write[offset + 3] = (n >> 24) & 0xff; - } - } + p_image->set_data(width, height, false, Image::FORMAT_RGBA8, buffer); res = sw_canvas->clear(true); - memfree(buffer); - p_image->set_data(width, height, false, Image::FORMAT_RGBA8, image); return OK; } From 549bffdcbc4cd43e03b1f6300f087e6d5816397c Mon Sep 17 00:00:00 2001 From: Giganzo <158825920+Giganzo@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:53:15 +0200 Subject: [PATCH 16/34] Fix PopupPanel menu style --- editor/plugins/control_editor_plugin.cpp | 1 - editor/themes/editor_theme_manager.cpp | 46 +++++++++--------------- editor/themes/editor_theme_manager.h | 1 + editor/window_wrapper.cpp | 7 +--- editor/window_wrapper.h | 1 - 5 files changed, 19 insertions(+), 37 deletions(-) diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index 5c5f236ff3..7fbdc73b6d 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -534,7 +534,6 @@ ControlEditorPopupButton::ControlEditorPopupButton() { set_focus_mode(FOCUS_NONE); popup_panel = memnew(PopupPanel); - popup_panel->set_theme_type_variation("ControlEditorPopupPanel"); add_child(popup_panel); popup_panel->connect("about_to_popup", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(true)); popup_panel->connect("popup_hide", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(false)); diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index f5a790353a..e5004a2715 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -633,6 +633,16 @@ void EditorThemeManager::_create_shared_styles(const Ref &p_theme, // in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled). p_config.popup_style->set_corner_radius_all(0); + p_config.popup_border_style = p_config.popup_style->duplicate(); + p_config.popup_border_style->set_content_margin_all(MAX(Math::round(EDSCALE), p_config.border_width) + 2 + (p_config.base_margin * 1.5) * EDSCALE); + // Always display a border for popups like PopupMenus so they can be distinguished from their background. + p_config.popup_border_style->set_border_width_all(MAX(Math::round(EDSCALE), p_config.border_width)); + if (p_config.draw_extra_borders) { + p_config.popup_border_style->set_border_color(p_config.extra_border_color_2); + } else { + p_config.popup_border_style->set_border_color(p_config.dark_color_2); + } + p_config.window_style = p_config.popup_style->duplicate(); p_config.window_style->set_border_color(p_config.base_color); p_config.window_style->set_border_width(SIDE_TOP, 24 * EDSCALE); @@ -707,7 +717,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the } // PopupPanel - p_theme->set_stylebox(SceneStringName(panel), "PopupPanel", p_config.popup_style); + p_theme->set_stylebox(SceneStringName(panel), "PopupPanel", p_config.popup_border_style); } // Buttons. @@ -1310,18 +1320,11 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the // PopupMenu. { - Ref style_popup_menu = p_config.popup_style->duplicate(); + Ref style_popup_menu = p_config.popup_border_style->duplicate(); // Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn // on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted, // and it looks weird. 1px solves this. - style_popup_menu->set_content_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); - // Always display a border for PopupMenus so they can be distinguished from their background. - style_popup_menu->set_border_width_all(EDSCALE); - if (p_config.draw_extra_borders) { - style_popup_menu->set_border_color(p_config.extra_border_color_2); - } else { - style_popup_menu->set_border_color(p_config.dark_color_2); - } + style_popup_menu->set_content_margin_individual(Math::round(EDSCALE), 2 * EDSCALE, Math::round(EDSCALE), 2 * EDSCALE); p_theme->set_stylebox(SceneStringName(panel), "PopupMenu", style_popup_menu); Ref style_menu_hover = p_config.button_style_hover->duplicate(); @@ -1331,17 +1334,17 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the Ref style_popup_separator(memnew(StyleBoxLine)); style_popup_separator->set_color(p_config.separator_color); - style_popup_separator->set_grow_begin(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width)); - style_popup_separator->set_grow_end(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width)); + style_popup_separator->set_grow_begin(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width)); + style_popup_separator->set_grow_end(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width)); style_popup_separator->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width)); Ref style_popup_labeled_separator_left(memnew(StyleBoxLine)); - style_popup_labeled_separator_left->set_grow_begin(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width)); + style_popup_labeled_separator_left->set_grow_begin(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width)); style_popup_labeled_separator_left->set_color(p_config.separator_color); style_popup_labeled_separator_left->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width)); Ref style_popup_labeled_separator_right(memnew(StyleBoxLine)); - style_popup_labeled_separator_right->set_grow_end(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width)); + style_popup_labeled_separator_right->set_grow_end(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width)); style_popup_labeled_separator_right->set_color(p_config.separator_color); style_popup_labeled_separator_right->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width)); @@ -2114,21 +2117,6 @@ void EditorThemeManager::_populate_editor_styles(const Ref &p_theme // EditorValidationPanel. p_theme->set_stylebox(SceneStringName(panel), "EditorValidationPanel", p_config.tree_panel_style); - - // ControlEditor. - { - p_theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel"); - - Ref control_editor_popup_style = p_config.popup_style->duplicate(); - control_editor_popup_style->set_shadow_size(0); - control_editor_popup_style->set_content_margin(SIDE_LEFT, p_config.base_margin * EDSCALE); - control_editor_popup_style->set_content_margin(SIDE_TOP, p_config.base_margin * EDSCALE); - control_editor_popup_style->set_content_margin(SIDE_RIGHT, p_config.base_margin * EDSCALE); - control_editor_popup_style->set_content_margin(SIDE_BOTTOM, p_config.base_margin * EDSCALE); - control_editor_popup_style->set_border_width_all(0); - - p_theme->set_stylebox(SceneStringName(panel), "ControlEditorPopupPanel", control_editor_popup_style); - } } // Editor inspector. diff --git a/editor/themes/editor_theme_manager.h b/editor/themes/editor_theme_manager.h index 5e7bd00083..ca5e1a4e2d 100644 --- a/editor/themes/editor_theme_manager.h +++ b/editor/themes/editor_theme_manager.h @@ -135,6 +135,7 @@ class EditorThemeManager { Ref button_style_hover; Ref popup_style; + Ref popup_border_style; Ref window_style; Ref dialog_style; Ref panel_container_style; diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp index 9496ba016c..7f61623980 100644 --- a/editor/window_wrapper.cpp +++ b/editor/window_wrapper.cpp @@ -391,7 +391,6 @@ void ScreenSelect::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { set_icon(get_editor_theme_icon("MakeFloating")); - popup_background->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles))); const real_t popup_height = real_t(get_theme_font_size(SceneStringName(font_size))) * 2.0; popup->set_min_size(Size2(0, popup_height * 3)); @@ -454,14 +453,10 @@ ScreenSelect::ScreenSelect() { // Create the popup. const Size2 borders = Size2(4, 4) * EDSCALE; - popup = memnew(Popup); + popup = memnew(PopupPanel); popup->connect("popup_hide", callable_mp(static_cast(this), &ScreenSelect::set_pressed).bind(false)); add_child(popup); - popup_background = memnew(Panel); - popup_background->set_anchors_and_offsets_preset(PRESET_FULL_RECT); - popup->add_child(popup_background); - MarginContainer *popup_root = memnew(MarginContainer); popup_root->add_theme_constant_override("margin_right", borders.width); popup_root->add_theme_constant_override("margin_top", borders.height); diff --git a/editor/window_wrapper.h b/editor/window_wrapper.h index a07e95f09e..3597276de9 100644 --- a/editor/window_wrapper.h +++ b/editor/window_wrapper.h @@ -88,7 +88,6 @@ class ScreenSelect : public Button { GDCLASS(ScreenSelect, Button); Popup *popup = nullptr; - Panel *popup_background = nullptr; HBoxContainer *screen_list = nullptr; void _build_advanced_menu(); From c1fd4df3e41bfb6564c33203f506ba9ff6ec8cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 21 Oct 2024 13:33:42 +0200 Subject: [PATCH 17/34] Android & iOS: Enable strict aliasing --- platform/android/detect.py | 4 +--- platform/ios/detect.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/android/detect.py b/platform/android/detect.py index 0a10754e24..233e74364f 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -171,9 +171,7 @@ def configure(env: "SConsEnvironment"): env["AS"] = compiler_path + "/clang" env.Append( - CCFLAGS=( - "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() - ) + CCFLAGS=("-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden".split()) ) if get_min_sdk_version(env["ndk_platform"]) >= 24: diff --git a/platform/ios/detect.py b/platform/ios/detect.py index 20a3a996bc..317dbd3f4a 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -134,7 +134,7 @@ def configure(env: "SConsEnvironment"): elif env["arch"] == "arm64": env.Append( CCFLAGS=( - "-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" + "-fobjc-arc -arch arm64 -fmessage-length=0" " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" " -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies" " -isysroot $IOS_SDK_PATH".split() From d5d509bbd68f829f5cb9dbf3e0ee5c1a349f9a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 21 Oct 2024 20:56:42 +0200 Subject: [PATCH 18/34] Implement thread ownership change for RenderingDevice --- servers/rendering/rendering_device.cpp | 4 ++++ servers/rendering/rendering_device.h | 2 ++ servers/rendering/rendering_server_default.cpp | 2 ++ 3 files changed, 8 insertions(+) diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 942d5631e4..6eb1386749 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -7260,6 +7260,10 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DEBUG_PASS); } +void RenderingDevice::make_current() { + render_thread_id = Thread::get_caller_id(); +} + RenderingDevice::~RenderingDevice() { finalize(); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 71ffbfbd88..c440e11cd4 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1496,6 +1496,8 @@ public: static RenderingDevice *get_singleton(); + void make_current(); + RenderingDevice(); ~RenderingDevice(); diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 20f1f9ad6f..2ec693cbbf 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -370,6 +370,8 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const { void RenderingServerDefault::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) { server_thread = Thread::get_caller_id(); server_task_id = p_pump_task_id; + // This is needed because the main RD is created on the main thread. + RenderingDevice::get_singleton()->make_current(); } void RenderingServerDefault::_thread_exit() { From 3e36f52524b9ce65a50962aa62b52f4b8add64b3 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Mon, 14 Oct 2024 15:29:40 +1100 Subject: [PATCH 19/34] OpenXR: change bindings to 'flatten' source paths --- .../openxr/action_map/openxr_action_map.cpp | 21 +-- .../action_map/openxr_interaction_profile.cpp | 137 +++++++++++++----- .../action_map/openxr_interaction_profile.h | 32 ++-- .../openxr/doc_classes/OpenXRIPBinding.xml | 18 ++- .../openxr_interaction_profile_editor.cpp | 41 +++--- modules/openxr/openxr_interface.cpp | 5 +- 6 files changed, 154 insertions(+), 100 deletions(-) diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 5430a41d6d..f924386ecf 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -576,20 +576,15 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref p const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path()); if (profile != nullptr) { - for (int j = 0; j < ip->get_binding_count(); j++) { - Ref binding = ip->get_binding(j); - if (binding->get_action() == p_action) { - PackedStringArray paths = binding->get_paths(); + Vector> bindings = ip->get_bindings_for_action(p_action); + for (const Ref &binding : bindings) { + String binding_path = binding->get_binding_path(); + const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(binding_path); + if (io_path != nullptr) { + String top_path = io_path->top_level_path; - for (int k = 0; k < paths.size(); k++) { - const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(paths[k]); - if (io_path != nullptr) { - String top_path = io_path->top_level_path; - - if (!arr.has(top_path)) { - arr.push_back(top_path); - } - } + if (!arr.has(top_path)) { + arr.push_back(top_path); } } } diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 1266457113..2aab55f6ec 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -35,23 +35,30 @@ void OpenXRIPBinding::_bind_methods() { ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action"); - ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); + ClassDB::bind_method(D_METHOD("set_binding_path", "binding_path"), &OpenXRIPBinding::set_binding_path); + ClassDB::bind_method(D_METHOD("get_binding_path"), &OpenXRIPBinding::get_binding_path); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "binding_path"), "set_binding_path", "get_binding_path"); + + // Deprecated +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paths", "get_paths"); + ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path); ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path); ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path); +#endif // DISABLE_DEPRECATED } -Ref OpenXRIPBinding::new_binding(const Ref p_action, const char *p_paths) { +Ref OpenXRIPBinding::new_binding(const Ref p_action, const String &p_binding_path) { // This is a helper function to help build our default action sets Ref binding; binding.instantiate(); binding->set_action(p_action); - binding->parse_paths(String(p_paths)); + binding->set_binding_path(p_binding_path); return binding; } @@ -65,41 +72,67 @@ Ref OpenXRIPBinding::get_action() const { return action; } -int OpenXRIPBinding::get_path_count() const { - return paths.size(); -} - -void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { - paths = p_paths; +void OpenXRIPBinding::set_binding_path(const String &path) { + binding_path = path; emit_changed(); } -PackedStringArray OpenXRIPBinding::get_paths() const { +String OpenXRIPBinding::get_binding_path() const { + return binding_path; +} + +#ifndef DISABLE_DEPRECATED + +void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps. + // Fallback logic, this should ONLY be called when loading older action maps. + // We'll parse this momentarily and extract individual bindings. + binding_path = ""; + for (const String &path : p_paths) { + if (!binding_path.is_empty()) { + binding_path += ","; + } + binding_path += path; + } +} + +PackedStringArray OpenXRIPBinding::get_paths() const { // Deprecated, but needed for converting old action maps. + // Fallback logic, return an array. + // If we just loaded an old action map from disc, this will be a comma separated list of actions. + // Once parsed there should be only one path in our array. + PackedStringArray paths = binding_path.split(",", false); + return paths; } -void OpenXRIPBinding::parse_paths(const String p_paths) { - paths = p_paths.split(",", false); +int OpenXRIPBinding::get_path_count() const { // Deprecated. + // Fallback logic, we only have one entry. + return binding_path.is_empty() ? 0 : 1; +} + +bool OpenXRIPBinding::has_path(const String p_path) const { // Deprecated. + // Fallback logic, return true if this is our path. + return binding_path == p_path; +} + +void OpenXRIPBinding::add_path(const String p_path) { // Deprecated. + // Fallback logic, only assign first time this is called. + if (binding_path != p_path) { + ERR_FAIL_COND_MSG(!binding_path.is_empty(), "Method add_path has been deprecated. A binding path was already set, create separate binding resources for each path and use set_binding_path instead."); + + binding_path = p_path; + emit_changed(); + } +} + +void OpenXRIPBinding::remove_path(const String p_path) { // Deprecated. + ERR_FAIL_COND_MSG(binding_path != p_path, "Method remove_path has been deprecated. Attempt at removing a different binding path, remove the correct binding record from the interaction profile instead."); + + // Fallback logic, clear if this is our path. + binding_path = p_path; emit_changed(); } -bool OpenXRIPBinding::has_path(const String p_path) const { - return paths.has(p_path); -} - -void OpenXRIPBinding::add_path(const String p_path) { - if (!paths.has(p_path)) { - paths.push_back(p_path); - emit_changed(); - } -} - -void OpenXRIPBinding::remove_path(const String p_path) { - if (paths.has(p_path)) { - paths.erase(p_path); - emit_changed(); - } -} +#endif // DISABLE_DEPRECATED OpenXRIPBinding::~OpenXRIPBinding() { action.unref(); @@ -151,9 +184,18 @@ Ref OpenXRInteractionProfile::get_binding(int p_index) const { } void OpenXRInteractionProfile::set_bindings(Array p_bindings) { - // TODO add check here that our bindings don't contain duplicate actions + bindings.clear(); + + for (Ref binding : p_bindings) { + String binding_path = binding->get_binding_path(); + if (binding_path.find_char(',') >= 0) { + // Convert old binding approach to new... + add_new_binding(binding->get_action(), binding_path); + } else { + add_binding(binding); + } + } - bindings = p_bindings; emit_changed(); } @@ -161,10 +203,9 @@ Array OpenXRInteractionProfile::get_bindings() const { return bindings; } -Ref OpenXRInteractionProfile::get_binding_for_action(const Ref p_action) const { - for (int i = 0; i < bindings.size(); i++) { - Ref binding = bindings[i]; - if (binding->get_action() == p_action) { +Ref OpenXRInteractionProfile::find_binding(const Ref p_action, const String &p_binding_path) const { + for (Ref binding : bindings) { + if (binding->get_action() == p_action && binding->get_binding_path() == p_binding_path) { return binding; } } @@ -172,11 +213,23 @@ Ref OpenXRInteractionProfile::get_binding_for_action(const Ref< return Ref(); } +Vector> OpenXRInteractionProfile::get_bindings_for_action(const Ref p_action) const { + Vector> ret_bindings; + + for (Ref binding : bindings) { + if (binding->get_action() == p_action) { + ret_bindings.push_back(binding); + } + } + + return ret_bindings; +} + void OpenXRInteractionProfile::add_binding(Ref p_binding) { ERR_FAIL_COND(p_binding.is_null()); if (!bindings.has(p_binding)) { - ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile"); + ERR_FAIL_COND_MSG(find_binding(p_binding->get_action(), p_binding->get_binding_path()).is_valid(), "There is already a binding for this action and binding path in this interaction profile."); bindings.push_back(p_binding); emit_changed(); @@ -191,11 +244,15 @@ void OpenXRInteractionProfile::remove_binding(Ref p_binding) { } } -void OpenXRInteractionProfile::add_new_binding(const Ref p_action, const char *p_paths) { +void OpenXRInteractionProfile::add_new_binding(const Ref p_action, const String &p_paths) { // This is a helper function to help build our default action sets - Ref binding = OpenXRIPBinding::new_binding(p_action, p_paths); - add_binding(binding); + PackedStringArray paths = p_paths.split(",", false); + + for (const String &path : paths) { + Ref binding = OpenXRIPBinding::new_binding(p_action, path); + add_binding(binding); + } } void OpenXRInteractionProfile::remove_binding_for_action(const Ref p_action) { diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h index 479cc3c527..952f87a09d 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.h +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -41,26 +41,29 @@ class OpenXRIPBinding : public Resource { private: Ref action; - PackedStringArray paths; + String binding_path; protected: static void _bind_methods(); public: - static Ref new_binding(const Ref p_action, const char *p_paths); // Helper function for adding a new binding + static Ref new_binding(const Ref p_action, const String &p_binding_path); // Helper function for adding a new binding. - void set_action(const Ref p_action); // Set the action for this binding - Ref get_action() const; // Get the action for this binding + void set_action(const Ref p_action); // Set the action for this binding. + Ref get_action() const; // Get the action for this binding. - int get_path_count() const; // Get the number of io paths - void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource) - PackedStringArray get_paths() const; // Get our paths (for saving to resource) + void set_binding_path(const String &path); + String get_binding_path() const; - void parse_paths(const String p_paths); // Parse a comma separated string of io paths. - - bool has_path(const String p_path) const; // Has this io path - void add_path(const String p_path); // Add an io path - void remove_path(const String p_path); // Remove an io path + // Deprecated. +#ifndef DISABLE_DEPRECATED + void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps. + PackedStringArray get_paths() const; // Get our paths (for saving to resource), needed for converted old action maps. + int get_path_count() const; // Get the number of io paths. + bool has_path(const String p_path) const; // Has this io path. + void add_path(const String p_path); // Add an io path. + void remove_path(const String p_path); // Remove an io path. +#endif // DISABLE_DEPRECATED // TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path @@ -88,11 +91,12 @@ public: void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource) Array get_bindings() const; // Get the bindings (for saving to a resource) - Ref get_binding_for_action(const Ref p_action) const; // Get our binding record for a given action + Ref find_binding(const Ref p_action, const String &p_binding_path) const; // Get our binding record + Vector> get_bindings_for_action(const Ref p_action) const; // Get our binding record for a given action void add_binding(Ref p_binding); // Add a binding object void remove_binding(Ref p_binding); // Remove a binding object - void add_new_binding(const Ref p_action, const char *p_paths); // Create a new binding for this profile + void add_new_binding(const Ref p_action, const String &p_paths); // Create a new binding for this profile void remove_binding_for_action(const Ref p_action); // Remove all bindings for this action bool has_binding_for_action(const Ref p_action); // Returns true if we have a binding for this action diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml index f274f0868e..ddd6fbe268 100644 --- a/modules/openxr/doc_classes/OpenXRIPBinding.xml +++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml @@ -4,32 +4,32 @@ Defines a binding between an [OpenXRAction] and an XR input or output. - This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". + This binding resource binds an [OpenXRAction] to an input or output. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". This would require two binding entries. - + Add an input/output path to this binding. - + Get the number of input/output paths in this binding. - + Returns [code]true[/code] if this input/output path is part of this binding. - + @@ -39,9 +39,13 @@ - [OpenXRAction] that is bound to these paths. + [OpenXRAction] that is bound to [member binding_path]. - + + Binding path that defines the input or output bound to [member action]. + [b]Note:[/b] Binding paths are suggestions, an XR runtime may choose to bind the action to a different input or output emulating this input or output. + + Paths that define the inputs or outputs bound on the device. diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index 651171358c..09a9a990ed 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -73,17 +73,19 @@ void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, con Ref action = action_map->get_action(p_action); ERR_FAIL_COND(action.is_null()); - Ref binding = interaction_profile->get_binding_for_action(action); + Ref binding = interaction_profile->find_binding(action, p_path); if (binding.is_null()) { // create a new binding binding.instantiate(); binding->set_action(action); + binding->set_binding_path(p_path); + + // add it to our interaction profile interaction_profile->add_binding(binding); interaction_profile->set_edited(true); - } - binding->add_path(p_path); - binding->set_edited(true); + binding->set_edited(true); + } // Update our toplevel paths action->set_toplevel_paths(action_map->get_top_level_paths(action)); @@ -98,15 +100,10 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, Ref action = action_map->get_action(p_action); ERR_FAIL_COND(action.is_null()); - Ref binding = interaction_profile->get_binding_for_action(action); + Ref binding = interaction_profile->find_binding(action, p_path); if (binding.is_valid()) { - binding->remove_path(p_path); - binding->set_edited(true); - - if (binding->get_path_count() == 0) { - interaction_profile->remove_binding(binding); - interaction_profile->set_edited(true); - } + interaction_profile->remove_binding(binding); + interaction_profile->set_edited(true); // Update our toplevel paths action->set_toplevel_paths(action_map->get_top_level_paths(action)); @@ -116,21 +113,22 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, } void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref p_action) { - Ref binding = interaction_profile->get_binding_for_action(p_action); - if (binding.is_valid()) { + Vector> bindings = interaction_profile->get_bindings_for_action(p_action); + if (bindings.size() > 0) { String action_name = p_action->get_name_with_set(); // for our undo/redo we process all paths undo_redo->create_action(TTR("Remove action from interaction profile")); - PackedStringArray paths = binding->get_paths(); - for (const String &path : paths) { - undo_redo->add_do_method(this, "_remove_binding", action_name, path); - undo_redo->add_undo_method(this, "_add_binding", action_name, path); + for (const Ref &binding : bindings) { + undo_redo->add_do_method(this, "_remove_binding", action_name, binding->get_binding_path()); + undo_redo->add_undo_method(this, "_add_binding", action_name, binding->get_binding_path()); } undo_redo->commit_action(false); // but we take a shortcut here :) - interaction_profile->remove_binding(binding); + for (const Ref &binding : bindings) { + interaction_profile->remove_binding(binding); + } interaction_profile->set_edited(true); // Update our toplevel paths @@ -228,9 +226,8 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co if (interaction_profile.is_valid()) { String io_path = String(p_io_path->openxr_path); Array bindings = interaction_profile->get_bindings(); - for (int i = 0; i < bindings.size(); i++) { - Ref binding = bindings[i]; - if (binding->has_path(io_path)) { + for (Ref binding : bindings) { + if (binding->get_binding_path() == io_path) { Ref action = binding->get_action(); HBoxContainer *action_hb = memnew(HBoxContainer); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 73ac529537..500a58acc3 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -300,10 +300,7 @@ void OpenXRInterface::_load_action_map() { continue; } - PackedStringArray paths = xr_binding->get_paths(); - for (int k = 0; k < paths.size(); k++) { - openxr_api->interaction_profile_add_binding(ip, action->action_rid, paths[k]); - } + openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path()); } // Now submit our suggestions From 403e53e1d33519af3700f8bcbdce827a17b6dc29 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 21 Oct 2024 17:18:43 -0700 Subject: [PATCH 20/34] Fix window exiting with no message to user if _create_window fails --- platform/windows/display_server_windows.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 21b318ee4d..c427596829 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -6400,7 +6400,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID); - ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Failed to create main window."); + } joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); From 06998a3927e1c36212ba98615c2aefe92fe5b5e0 Mon Sep 17 00:00:00 2001 From: bjornmp Date: Mon, 25 Sep 2023 00:32:43 +0200 Subject: [PATCH 21/34] Enforce that custom nodes keep their original type Enforce that custom nodes and resources created via the "Create New Node" dialog, should permanently retain their original type (script). This means: - Type continuity: It should be impossible for the user to (accidentally) clear the original script of a custom node that was created via the "Create New Node" dialog. - Extensibility: The user should be able to extend custom types as usual (create a script that inherits the original type and replace the original script of that node with his own). However, if he then clears his extension-script from that node later on, the custom type should revert to its original script instead of becoming a non-scripted type. --- editor/editor_data.cpp | 2 + editor/editor_node.cpp | 5 ++ editor/editor_properties.cpp | 1 + editor/editor_resource_picker.cpp | 23 +++++- editor/editor_resource_picker.h | 5 ++ editor/scene_tree_dock.cpp | 121 ++++++++++++++++++++++++------ editor/scene_tree_dock.h | 1 + scene/property_utils.cpp | 10 +++ scene/scene_string_names.cpp | 2 + scene/scene_string_names.h | 2 + 10 files changed, 147 insertions(+), 25 deletions(-) diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index ee16c61c89..bb02172b1a 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -547,6 +547,7 @@ Variant EditorData::instantiate_custom_type(const String &p_type, const String & if (n) { n->set_name(p_type); } + n->set_meta(SceneStringName(_custom_type_script), script); ((Object *)ob)->set_script(script); return ob; } @@ -1008,6 +1009,7 @@ Variant EditorData::script_class_instance(const String &p_class) { // Store in a variant to initialize the refcount if needed. Variant obj = ClassDB::instantiate(script->get_instance_base_type()); if (obj) { + Object::cast_to(obj)->set_meta(SceneStringName(_custom_type_script), script); obj.operator Object *()->set_script(script); } return obj; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d88fb134f1..e57328911d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4672,6 +4672,11 @@ void EditorNode::stop_child_process(OS::ProcessID p_pid) { Ref