diff options
43 files changed, 514 insertions, 306 deletions
diff --git a/SConstruct b/SConstruct index 031f421a63..534d5bd95d 100644 --- a/SConstruct +++ b/SConstruct @@ -565,7 +565,7 @@ if selected_platform in platform_list: if read_scu_limit != 0: max_includes_per_scu = read_scu_limit - methods.set_scu_folders(scu_builders.generate_scu_files(env["verbose"], max_includes_per_scu)) + methods.set_scu_folders(scu_builders.generate_scu_files(max_includes_per_scu)) # Must happen after the flags' definition, as configure is when most flags # are actually handled to change compile options, etc. diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 72bfc2dcc7..c3295d854f 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -737,7 +737,7 @@ The object's X axis will always face the camera. </constant> <constant name="BILLBOARD_PARTICLES" value="3" enum="BillboardMode"> - Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties. + Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes (flipbook animation). Enables [code]particles_anim_*[/code] properties. The [member ParticleProcessMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play. </constant> <constant name="TEXTURE_CHANNEL_RED" value="0" enum="TextureChannel"> diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index 54c8689ab0..dd731c6c0f 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -48,14 +48,16 @@ </methods> <members> <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8"> - Number of particles emitted in one emission cycle. + The number of particles to emit in one emission cycle. The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. Higher values will increase GPU requirements, even if not all particles are visible at a given time or if [member amount_ratio] is decreased. + [b]Note:[/b] Changing this value will cause the particle system to restart. To avoid this, change [member amount_ratio] instead. </member> <member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0"> The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time. - [b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. + [b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. If you don't intend to change the number of particles emitted while the particles are emitting, make sure [member amount_ratio] is set to [code]1[/code] and change [member amount] to your liking instead. </member> <member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="1.0"> - Multiplier for particle's collision radius. [code]1.0[/code] corresponds to the size of the sprite. + Multiplier for particle's collision radius. [code]1.0[/code] corresponds to the size of the sprite. If particles appear to sink into the ground when colliding, increase this value. If particles appear to float when colliding, decrease this value. Only effective if [member ParticleProcessMaterial.collision_mode] is [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT]. + [b]Note:[/b] Particles always have a spherical collision shape. </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="1"> Particle draw order. Uses [enum DrawOrder] values. @@ -80,7 +82,7 @@ Enables particle interpolation, which makes the particle movement smoother when their [member fixed_fps] is lower than the screen refresh rate. </member> <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0"> - Amount of time each particle will exist. + The amount of time each particle will exist (in seconds). The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. </member> <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false"> If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated. @@ -101,10 +103,12 @@ Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles. </member> <member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath("")"> - The [NodePath] to the [GPUParticles2D] used for sub-emissions. + Path to another [GPUParticles2D] node that will be used as a subemitter (see [member ParticleProcessMaterial.sub_emitter_mode]). Subemitters can be used to achieve effects such as fireworks, sparks on collision, bubbles popping into water drops, and more. + [b]Note:[/b] When [member sub_emitter] is set, the target [GPUParticles2D] node will no longer emit particles on its own. </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> - Particle texture. If [code]null[/code], particles will be squares. + Particle texture. If [code]null[/code], particles will be squares with a size of 1×1 pixels. + [b]Note:[/b] To use a flipbook texture, assign a new [CanvasItemMaterial] to the [GPUParticles2D]'s [member CanvasItem.material] property, then enable [member CanvasItemMaterial.particles_animation] and set [member CanvasItemMaterial.particles_anim_h_frames], [member CanvasItemMaterial.particles_anim_v_frames], and [member CanvasItemMaterial.particles_anim_loop] to match the flipbook texture. </member> <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false"> If [code]true[/code], enables particle trails using a mesh skinning system. diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index dc7e51b7d7..398905ea13 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -61,13 +61,16 @@ </methods> <members> <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8"> - Number of particles to emit. + The number of particles to emit in one emission cycle. The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. Higher values will increase GPU requirements, even if not all particles are visible at a given time or if [member amount_ratio] is decreased. + [b]Note:[/b] Changing this value will cause the particle system to restart. To avoid this, change [member amount_ratio] instead. </member> <member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0"> The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time. - [b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. + [b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. If you don't intend to change the number of particles emitted while the particles are emitting, make sure [member amount_ratio] is set to [code]1[/code] and change [member amount] to your liking instead. </member> <member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="0.01"> + The base diameter for particle collision in meters. If particles appear to sink into the ground when colliding, increase this value. If particles appear to float when colliding, decrease this value. Only effective if [member ParticleProcessMaterial.collision_mode] is [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT]. + [b]Note:[/b] Particles always have a spherical collision shape. </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles3D.DrawOrder" default="0"> Particle draw order. Uses [enum DrawOrder] values. @@ -110,7 +113,7 @@ Enables particle interpolation, which makes the particle movement smoother when their [member fixed_fps] is lower than the screen refresh rate. </member> <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0"> - Amount of time each particle will exist. + The amount of time each particle will exist (in seconds). The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. </member> <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false"> If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated. @@ -131,6 +134,8 @@ Speed scaling ratio. A value of [code]0[/code] can be used to pause the particles. </member> <member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath("")"> + Path to another [GPUParticles3D] node that will be used as a subemitter (see [member ParticleProcessMaterial.sub_emitter_mode]). Subemitters can be used to achieve effects such as fireworks, sparks on collision, bubbles popping into water drops, and more. + [b]Note:[/b] When [member sub_emitter] is set, the target [GPUParticles3D] node will no longer emit particles on its own. </member> <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false"> If [code]true[/code], enables particle trails using a mesh skinning system. Designed to work with [RibbonTrailMesh] and [TubeTrailMesh]. @@ -143,8 +148,9 @@ <member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0"> </member> <member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB(-4, -4, -4, 8, 8, 8)"> - The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active. + The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active. [member GeometryInstance3D.extra_cull_margin] is added on each of the AABB's axes. Particle collisions and attraction will only occur within this area. Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool. + [b]Note:[/b] [member visibility_aabb] is overridden by [member GeometryInstance3D.custom_aabb] if that property is set to a non-default value. </member> </members> <signals> diff --git a/doc/classes/LightmapGIData.xml b/doc/classes/LightmapGIData.xml index 09c4383829..db6c9e70ca 100644 --- a/doc/classes/LightmapGIData.xml +++ b/doc/classes/LightmapGIData.xml @@ -54,8 +54,12 @@ </method> </methods> <members> - <member name="light_texture" type="TextureLayered" setter="set_light_texture" getter="get_light_texture"> + <member name="light_texture" type="TextureLayered" setter="set_light_texture" getter="get_light_texture" is_deprecated="true"> The lightmap atlas texture generated by the lightmapper. + [i]Deprecated.[/i] The lightmap atlas can now have multiple textures. See [member lightmap_textures]. + </member> + <member name="lightmap_textures" type="TextureLayered[]" setter="set_lightmap_textures" getter="get_lightmap_textures" default="[]"> + The lightmap atlas textures generated by the lightmapper. </member> </members> </class> diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index b7f55184f0..79dccbbaa4 100644 --- a/doc/classes/ParticleProcessMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -114,7 +114,7 @@ Minimum equivalent of [member anim_speed_max]. </member> <member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true"> - True if the interaction with particle attractors is enabled. + If [code]true[/code], interaction with particle attractors is enabled. In 3D, attraction only occurs within the area defined by the [GPUParticles3D] node's [member GPUParticles3D.visibility_aabb]. </member> <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce"> The particles' bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). Only effective if [member collision_mode] is [constant COLLISION_RIGID]. @@ -124,11 +124,11 @@ </member> <member name="collision_mode" type="int" setter="set_collision_mode" getter="get_collision_mode" enum="ParticleProcessMaterial.CollisionMode" default="0"> The particles' collision mode. - [b]Note:[/b] 3D Particles can only collide with [GPUParticlesCollision3D] nodes, not [PhysicsBody3D] nodes. To make particles collide with various objects, you can add [GPUParticlesCollision3D] nodes as children of [PhysicsBody3D] nodes. + [b]Note:[/b] 3D Particles can only collide with [GPUParticlesCollision3D] nodes, not [PhysicsBody3D] nodes. To make particles collide with various objects, you can add [GPUParticlesCollision3D] nodes as children of [PhysicsBody3D] nodes. In 3D, collisions only occur within the area defined by the [GPUParticles3D] node's [member GPUParticles3D.visibility_aabb]. [b]Note:[/b] 2D Particles can only collide with [LightOccluder2D] nodes, not [PhysicsBody2D] nodes. </member> <member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false"> - Should collision take scale into account. + If [code]true[/code], [member GPUParticles3D.collision_base_size] is multiplied by the particle's effective scale (see [member scale_min], [member scale_max], [member scale_curve], and [member scale_over_velocity_curve]). </member> <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. @@ -316,16 +316,22 @@ Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. </member> <member name="sub_emitter_amount_at_collision" type="int" setter="set_sub_emitter_amount_at_collision" getter="get_sub_emitter_amount_at_collision"> - Sub particle amount on collision. - Maximum amount set in the sub particles emitter. + The amount of particles to spawn from the subemitter node when a collision occurs. When combined with [constant COLLISION_HIDE_ON_CONTACT] on the main particles material, this can be used to achieve effects such as raindrops hitting the ground. + [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. </member> <member name="sub_emitter_amount_at_end" type="int" setter="set_sub_emitter_amount_at_end" getter="get_sub_emitter_amount_at_end"> + The amount of particles to spawn from the subemitter node when the particle expires. + [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. </member> <member name="sub_emitter_frequency" type="float" setter="set_sub_emitter_frequency" getter="get_sub_emitter_frequency"> + The frequency at which particles should be emitted from the subemitter node. One particle will be spawned every [member sub_emitter_frequency] seconds. + [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. </member> <member name="sub_emitter_keep_velocity" type="bool" setter="set_sub_emitter_keep_velocity" getter="get_sub_emitter_keep_velocity" default="false"> + If [code]true[/code], the subemitter inherits the parent particle's velocity when it spawns. </member> <member name="sub_emitter_mode" type="int" setter="set_sub_emitter_mode" getter="get_sub_emitter_mode" enum="ParticleProcessMaterial.SubEmitterMode" default="0"> + The particle subemitter mode (see [member GPUParticles2D.sub_emitter] and [member GPUParticles3D.sub_emitter]). </member> <member name="tangential_accel_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's tangential acceleration will vary along this [CurveTexture]. diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp index 4c9d610935..c92cfea9af 100644 --- a/drivers/egl/egl_manager.cpp +++ b/drivers/egl/egl_manager.cpp @@ -34,6 +34,7 @@ #if defined(EGL_STATIC) #define KHRONOS_STATIC 1 +#define GLAD_EGL_VERSION_1_5 true extern "C" EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); #undef KHRONOS_STATIC #endif diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1f10f4b353..21e14c1ec9 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1906,7 +1906,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b } // Render shadows -void RasterizerSceneGLES3::_render_shadows(const RenderDataGLES3 *p_render_data) { +void RasterizerSceneGLES3::_render_shadows(const RenderDataGLES3 *p_render_data, const Size2i &p_viewport_size) { GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton(); LocalVector<int> cube_shadows; @@ -1942,20 +1942,20 @@ void RasterizerSceneGLES3::_render_shadows(const RenderDataGLES3 *p_render_data) // Render cubemap shadows. for (const int &index : cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size); } // Render directional shadows. for (uint32_t i = 0; i < directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[directional_shadows[i]].pass, p_render_data->render_shadows[directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[directional_shadows[i]].pass, p_render_data->render_shadows[directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size); } // Render positional shadows (Spotlight and Omnilight with dual-paraboloid). for (uint32_t i = 0; i < shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[shadows[i]].pass, p_render_data->render_shadows[shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[shadows[i]].pass, p_render_data->render_shadows[shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size); } } } -void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, RenderingMethod::RenderInfo *p_render_info) { +void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size) { GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -2093,7 +2093,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, render_data.instances = &p_instances; render_data.render_info = p_render_info; - _setup_environment(&render_data, true, Vector2(1, 1), false, Color(), use_pancake, shadow_bias); + _setup_environment(&render_data, true, p_viewport_size, false, Color(), use_pancake, shadow_bias); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { render_data.screen_mesh_lod_threshold = 0.0; @@ -2271,7 +2271,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ // If we're rendering right-side up, then we need to change the winding order. glFrontFace(GL_CW); } - _render_shadows(&render_data); + _render_shadows(&render_data, screen_size); _setup_lights(&render_data, true, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count, render_data.directional_shadow_count); _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, flip_y, clear_color, false); @@ -3289,6 +3289,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() { // Quality settings. use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"); + positional_soft_shadow_filter_set_quality((RS::ShadowQuality)(int)GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality")); + directional_soft_shadow_filter_set_quality((RS::ShadowQuality)(int)GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality")); + { // Setup Lights diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index da60d571bf..7d3c8896da 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -516,8 +516,8 @@ private: void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count, uint32_t &r_directional_shadow_count); void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias = 0.0); void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false); - void _render_shadows(const RenderDataGLES3 *p_render_data); - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadows(const RenderDataGLES3 *p_render_data, const Size2i &p_viewport_size = Size2i(1, 1)); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1)); template <PassMode p_pass_mode> _FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false); diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 3213fa3775..88ee749ed6 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -217,8 +217,23 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) if (new_surface.vertex_data.size()) { glGenBuffers(1, &s->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer"); - s->vertex_buffer_size = new_surface.vertex_data.size(); + // If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array + // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer + // But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw. + // This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small + // this should still be a net win for bandwidth. + // If we do this, then the last normal will read past the end of the array. So we need to pad the array with dummy data. + if (!(new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (new_surface.format & RS::ARRAY_FORMAT_NORMAL) && !(new_surface.format & RS::ARRAY_FORMAT_TANGENT)) { + // Unfortunately, we need to copy the buffer, which is fine as doing a resize triggers a CoW anyway. + Vector<uint8_t> new_vertex_data; + new_vertex_data.resize_zeroed(new_surface.vertex_data.size() + sizeof(uint16_t) * 2); + memcpy(new_vertex_data.ptrw(), new_surface.vertex_data.ptr(), new_surface.vertex_data.size()); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_vertex_data.size(), new_vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer"); + s->vertex_buffer_size = new_vertex_data.size(); + } else { + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer"); + s->vertex_buffer_size = new_surface.vertex_data.size(); + } } if (new_surface.attribute_data.size()) { @@ -461,6 +476,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.format = s.format; if (s.vertex_buffer != 0) { sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size); + + // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding. + if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) { + sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2); + } } if (s.attribute_buffer != 0) { diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index b7b62d78a0..fcc1dee3e2 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -713,18 +713,20 @@ void TextureStorage::texture_free(RID p_texture) { memdelete(t->canvas_texture); } - if (t->tex_id != 0) { - if (!t->is_external) { - GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id); + bool must_free_data = false; + if (t->is_proxy) { + if (t->proxy_to.is_valid()) { + Texture *proxy_to = texture_owner.get_or_null(t->proxy_to); + if (proxy_to) { + proxy_to->proxies.erase(p_texture); + } } - t->tex_id = 0; + } else { + must_free_data = t->tex_id != 0 && !t->is_external; } - - if (t->is_proxy && t->proxy_to.is_valid()) { - Texture *proxy_to = texture_owner.get_or_null(t->proxy_to); - if (proxy_to) { - proxy_to->proxies.erase(p_texture); - } + if (must_free_data) { + GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id); + t->tex_id = 0; } texture_atlas_remove_texture(p_texture); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8c3637663d..3d431ae67e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1811,11 +1811,18 @@ void EditorNode::save_all_scenes() { _save_all_scenes(); } -void EditorNode::save_scene_list(Vector<String> p_scene_filenames) { +void EditorNode::save_scene_if_open(const String &p_scene_path) { + int idx = editor_data.get_edited_scene_from_path(p_scene_path); + if (idx >= 0) { + _save_scene(p_scene_path, idx); + } +} + +void EditorNode::save_scene_list(const HashSet<String> &p_scene_paths) { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { Node *scene = editor_data.get_edited_scene_root(i); - if (scene && (p_scene_filenames.find(scene->get_scene_file_path()) >= 0)) { + if (scene && p_scene_paths.has(scene->get_scene_file_path())) { _save_scene(scene->get_scene_file_path(), i); } } diff --git a/editor/editor_node.h b/editor/editor_node.h index 7d85055ac2..bc7da69e75 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -912,7 +912,8 @@ public: PopupMenu *get_export_as_menu(); void save_all_scenes(); - void save_scene_list(Vector<String> p_scene_filenames); + void save_scene_if_open(const String &p_scene_path); + void save_scene_list(const HashSet<String> &p_scene_paths); void save_before_run(); void try_autosave(); void restart_editor(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index afefd38b20..ea043b42d1 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -733,7 +733,11 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa _update_tree(get_uncollapsed_paths(), false, p_select_in_favorites, true); if (display_mode != DISPLAY_MODE_TREE_ONLY) { _update_file_list(false); - files->get_v_scroll_bar()->set_value(0); + + // Reset the scroll for a directory. + if (p_path.ends_with("/")) { + files->get_v_scroll_bar()->set_value(0); + } } String file_name = p_path.get_file(); @@ -1160,9 +1164,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorites) { String fpath = p_path; if (fpath.ends_with("/")) { - if (fpath != "res://") { - fpath = fpath.substr(0, fpath.length() - 1); - } + // Ignore a directory. } else if (fpath != "Favorites") { if (FileAccess::exists(fpath + ".import")) { Ref<ConfigFile> config; @@ -1377,7 +1379,7 @@ void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Ve } } -void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const { +void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const HashSet<String> &p_renames, HashSet<String> &r_file_owners) const { for (int i = 0; i < p_efsd->get_subdir_count(); i++) { _find_file_owners(p_efsd->get_subdir(i), p_renames, r_file_owners); } @@ -1385,7 +1387,7 @@ void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> deps = p_efsd->get_file_deps(i); for (int j = 0; j < deps.size(); j++) { if (p_renames.has(deps[j])) { - r_file_owners.push_back(p_efsd->get_file_path(i)); + r_file_owners.insert(p_efsd->get_file_path(i)); break; } } @@ -1580,14 +1582,15 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str } } -void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const { +void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const { // The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. // 2) ResourceLoader can use the new paths without needing to call rescan. List<String> scenes_to_reload; - for (int i = 0; i < p_file_owners.size(); ++i) { + for (const String &E : p_file_owners) { // Because we haven't called a rescan yet the found remap might still be an old path itself. - const String file = p_renames.has(p_file_owners[i]) ? p_renames[p_file_owners[i]] : p_file_owners[i]; + const HashMap<String, String>::ConstIterator I = p_renames.find(E); + const String file = I ? I->value : E; print_verbose("Remapping dependencies for: " + file); const Error err = ResourceLoader::rename_dependencies(file, p_renames); if (err == OK) { @@ -1595,7 +1598,7 @@ void FileSystemDock::_update_dependencies_after_move(const HashMap<String, Strin scenes_to_reload.push_back(file); } } else { - EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + p_file_owners[i] + "\n"); + EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + E + "\n"); } } @@ -1689,7 +1692,7 @@ void FileSystemDock::_make_scene_confirm() { int idx = EditorNode::get_singleton()->new_scene(); EditorNode::get_editor_data().set_scene_path(idx, scene_path); EditorNode::get_singleton()->set_edited_scene(make_scene_dialog->create_scene_root()); - EditorNode::get_singleton()->save_scene_list({ scene_path }); + EditorNode::get_singleton()->save_scene_if_open(scene_path); } void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) { @@ -1792,7 +1795,7 @@ void FileSystemDock::_rename_operation_confirm() { } HashMap<String, ResourceUID::ID> uids; - Vector<String> file_owners; // The files that use these moved/renamed resource files. + HashSet<String> file_owners; // The files that use these moved/renamed resource files. _before_move(uids, file_owners); HashMap<String, String> file_renames; @@ -1923,7 +1926,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } HashMap<String, ResourceUID::ID> uids; - Vector<String> file_owners; // The files that use these moved/renamed resource files. + HashSet<String> file_owners; // The files that use these moved/renamed resource files. _before_move(uids, file_owners); bool is_moved = false; @@ -1955,11 +1958,11 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } } -void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const { - Vector<String> renamed_files; +void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, HashSet<String> &r_file_owners) const { + HashSet<String> renamed_files; for (int i = 0; i < to_move.size(); i++) { if (to_move[i].is_file) { - renamed_files.push_back(to_move[i].path); + renamed_files.insert(to_move[i].path); ResourceUID::ID uid = ResourceLoader::get_resource_uid(to_move[i].path); if (uid != ResourceUID::INVALID_ID) { r_uids[to_move[i].path] = uid; @@ -1972,7 +1975,7 @@ void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vect current_folder = folders.front()->get(); for (int j = 0; j < current_folder->get_file_count(); j++) { const String file_path = current_folder->get_file_path(j); - renamed_files.push_back(file_path); + renamed_files.insert(file_path); ResourceUID::ID uid = ResourceLoader::get_resource_uid(file_path); if (uid != ResourceUID::INVALID_ID) { r_uids[file_path] = uid; @@ -2493,6 +2496,7 @@ Control *FileSystemDock::create_tooltip_for_path(const String &p_path) const { // No tooltip for directory. return nullptr; } + ERR_FAIL_COND_V(!FileAccess::exists(p_path), nullptr); const String type = ResourceLoader::get_resource_type(p_path); Control *tooltip = EditorResourceTooltipPlugin::make_default_tooltip(p_path); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 104def71c8..1cde735cb8 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -266,11 +266,11 @@ private: void _update_import_dock(); void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const; - void _find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const; + void _find_file_owners(EditorFileSystemDirectory *p_efsd, const HashSet<String> &p_renames, HashSet<String> &r_file_owners) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, HashMap<String, String> &p_file_renames, HashMap<String, String> &p_folder_renames); void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; - void _before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const; - void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const; + void _before_move(HashMap<String, ResourceUID::ID> &r_uids, HashSet<String> &r_file_owners) const; + void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const; void _update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const; void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const; void _update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames); diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp index 6704347877..adeea51dae 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/post_import_plugin_skeleton_renamer.cpp @@ -31,6 +31,7 @@ #include "post_import_plugin_skeleton_renamer.h" #include "editor/import/scene_import_settings.h" +#include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" @@ -119,19 +120,17 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p // Rename bones in all Nodes by calling method. { - Array vargs; - vargs.push_back(p_base_scene); - vargs.push_back(skeleton); Dictionary rename_map_dict; for (HashMap<String, String>::Iterator E = p_rename_map.begin(); E; ++E) { rename_map_dict[E->key] = E->value; } - vargs.push_back(rename_map_dict); - TypedArray<Node> nodes = p_base_scene->find_children("*"); + TypedArray<Node> nodes = p_base_scene->find_children("*", "BoneAttachment3D"); while (nodes.size()) { - Node *nd = Object::cast_to<Node>(nodes.pop_back()); - nd->callv("_notify_skeleton_bones_renamed", vargs); + BoneAttachment3D *attachment = Object::cast_to<BoneAttachment3D>(nodes.pop_back()); + if (attachment) { + attachment->notify_skeleton_bones_renamed(p_base_scene, skeleton, rename_map_dict); + } } } } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f9c989dc20..e3c575c127 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -669,7 +669,11 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R fixed_name = _fixstr(name, "convcolonly"); } - ERR_FAIL_COND_V(fixed_name.is_empty(), nullptr); + if (fixed_name.is_empty()) { + p_node->set_owner(nullptr); + memdelete(p_node); + ERR_FAIL_V_MSG(nullptr, vformat("Skipped node `%s` because its name is empty after removing the suffix.", name)); + } ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); if (mi) { diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index bc8c8f6f79..a15875fd93 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -289,43 +289,40 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return false; } - const PosVertex insert = closest_edge_point(gpoint); - - if (insert.valid()) { - Vector<Vector2> vertices = _get_polygon(insert.polygon); - - if (vertices.size() < (_is_line() ? 2 : 3)) { - vertices.push_back(cpoint); - undo_redo->create_action(TTR("Edit Polygon")); - selected_point = Vertex(insert.polygon, vertices.size()); - _action_set_polygon(insert.polygon, vertices); - _commit_action(); - return true; - } else { - edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); - vertices.insert(edited_point.vertex, edited_point.pos); - pre_move_edit = vertices; - selected_point = Vertex(edited_point.polygon, edited_point.vertex); - edge_point = PosVertex(); - - undo_redo->create_action(TTR("Insert Point")); - _action_set_polygon(insert.polygon, vertices); - _commit_action(); - return true; - } + const PosVertex closest = closest_point(gpoint); + if (closest.valid()) { + pre_move_edit = _get_polygon(closest.polygon); + edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); + selected_point = closest; + edge_point = PosVertex(); + canvas_item_editor->update_viewport(); + return true; } else { - //look for points to move - const PosVertex closest = closest_point(gpoint); - - if (closest.valid()) { - pre_move_edit = _get_polygon(closest.polygon); - edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); - selected_point = closest; - edge_point = PosVertex(); - canvas_item_editor->update_viewport(); - return true; - } else { - selected_point = Vertex(); + selected_point = Vertex(); + + const PosVertex insert = closest_edge_point(gpoint); + if (insert.valid()) { + Vector<Vector2> vertices = _get_polygon(insert.polygon); + + if (vertices.size() < (_is_line() ? 2 : 3)) { + vertices.push_back(cpoint); + undo_redo->create_action(TTR("Edit Polygon")); + selected_point = Vertex(insert.polygon, vertices.size()); + _action_set_polygon(insert.polygon, vertices); + _commit_action(); + return true; + } else { + edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); + vertices.insert(edited_point.vertex, edited_point.pos); + pre_move_edit = vertices; + selected_point = Vertex(edited_point.polygon, edited_point.vertex); + edge_point = PosVertex(); + + undo_redo->create_action(TTR("Insert Point")); + _action_set_polygon(insert.polygon, vertices); + _commit_action(); + return true; + } } } } else { @@ -437,24 +434,28 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) canvas_item_editor->update_viewport(); } else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) { - const PosVertex onEdgeVertex = closest_edge_point(gpoint); - - if (onEdgeVertex.valid()) { - hover_point = Vertex(); - edge_point = onEdgeVertex; + const PosVertex new_hover_point = closest_point(gpoint); + if (hover_point != new_hover_point) { + hover_point = new_hover_point; canvas_item_editor->update_viewport(); - } else { - if (edge_point.valid()) { - edge_point = PosVertex(); - canvas_item_editor->update_viewport(); - } + } - const PosVertex new_hover_point = closest_point(gpoint); - if (hover_point != new_hover_point) { - hover_point = new_hover_point; + bool edge_hover = false; + if (!hover_point.valid()) { + const PosVertex on_edge_vertex = closest_edge_point(gpoint); + + if (on_edge_vertex.valid()) { + hover_point = Vertex(); + edge_point = on_edge_vertex; canvas_item_editor->update_viewport(); + edge_hover = true; } } + + if (!edge_hover && edge_point.valid()) { + edge_point = PosVertex(); + canvas_item_editor->update_viewport(); + } } } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 16d281d037..22596c09d1 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2520,9 +2520,7 @@ void ScriptEditor::save_current_script() { // If built-in script, save the scene instead. const String scene_path = resource->get_path().get_slice("::", 0); if (!scene_path.is_empty()) { - Vector<String> scene_to_save; - scene_to_save.push_back(scene_path); - EditorNode::get_singleton()->save_scene_list(scene_to_save); + EditorNode::get_singleton()->save_scene_if_open(scene_path); } } else { EditorNode::get_singleton()->save_resource(resource); @@ -2534,7 +2532,7 @@ void ScriptEditor::save_current_script() { } void ScriptEditor::save_all_scripts() { - Vector<String> scenes_to_save; + HashSet<String> scenes_to_save; for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); @@ -2583,7 +2581,7 @@ void ScriptEditor::save_all_scripts() { // For built-in scripts, save their scenes instead. const String scene_path = edited_res->get_path().get_slice("::", 0); if (!scene_path.is_empty() && !scenes_to_save.has(scene_path)) { - scenes_to_save.push_back(scene_path); + scenes_to_save.insert(scene_path); } } } diff --git a/methods.py b/methods.py index d68316f0f0..7a7758e24b 100644 --- a/methods.py +++ b/methods.py @@ -96,9 +96,6 @@ def add_source_files_scu(self, sources, files, allow_gen=False): if section_name not in (_scu_folders): return False - if self["verbose"]: - print("SCU building " + section_name) - # Add all the gen.cpp files in the SCU directory add_source_files_orig(self, sources, subdir + "scu/scu_*.gen.cpp", True) return True diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index b723ecc185..d31411b26b 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -662,6 +662,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a uint32_t op_signature = _code_ptr[ip + 5]; uint32_t actual_signature = (a->get_type() << 8) | (b->get_type()); +#ifdef DEBUG_ENABLED + if (op == Variant::OP_DIVIDE || op == Variant::OP_MODULE) { + // Don't optimize division and modulo since there's not check for division by zero with validated calls. + op_signature = 0xFFFF; + _code_ptr[ip + 5] = op_signature; + } +#endif + // Check if this is the first run. If so, store the current signature for the optimized path. if (unlikely(op_signature == 0)) { static Mutex initializer_mutex; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs index df35091596..147ef852b3 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -230,6 +230,31 @@ namespace Godot.SourceGenerators location?.SourceTree?.FilePath)); } + public static void ReportOnlyNodesShouldExportNodes( + GeneratorExecutionContext context, + ISymbol exportedMemberSymbol + ) + { + var locations = exportedMemberSymbol.Locations; + var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault(); + bool isField = exportedMemberSymbol is IFieldSymbol; + + string message = $"Types not derived from Node should not export Node {(isField ? "fields" : "properties")}"; + + string description = $"{message}. Node export is only supported in Node-derived classes."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0107", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + location, + location?.SourceTree?.FilePath)); + } + public static void ReportSignalDelegateMissingSuffix( GeneratorExecutionContext context, INamedTypeSymbol delegateSymbol) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 5866db5144..c7fd45238d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -32,7 +32,7 @@ namespace Godot.SourceGenerators disabledGenerators != null && disabledGenerators.Split(';').Contains(generatorName)); - public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyName, string typeFullName) + public static bool InheritsFrom(this ITypeSymbol? symbol, string assemblyName, string typeFullName) { while (symbol != null) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index fc0bfbf084..253e24f092 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -170,6 +170,15 @@ namespace Godot.SourceGenerators continue; } + if (marshalType == MarshalType.GodotObjectOrDerived) + { + if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && + propertyType.InheritsFrom("GodotSharp", "Godot.Node")) + { + Common.ReportOnlyNodesShouldExportNodes(context, property); + } + } + var propertyDeclarationSyntax = property.DeclaringSyntaxReferences .Select(r => r.GetSyntax() as PropertyDeclarationSyntax).FirstOrDefault(); @@ -265,6 +274,15 @@ namespace Godot.SourceGenerators continue; } + if (marshalType == MarshalType.GodotObjectOrDerived) + { + if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && + fieldType.InheritsFrom("GodotSharp", "Godot.Node")) + { + Common.ReportOnlyNodesShouldExportNodes(context, field); + } + } + EqualsValueClauseSyntax? initializer = field.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType<VariableDeclaratorSyntax>() diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp index 1115d92f58..65ef07e284 100644 --- a/modules/noise/noise.cpp +++ b/modules/noise/noise.cpp @@ -54,6 +54,9 @@ Vector<Ref<Image>> Noise::_get_seamless_image(int p_width, int p_height, int p_d Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const { Vector<Ref<Image>> images = _get_seamless_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_blend_skirt, p_normalize); + if (images.size() == 0) { + return Ref<Image>(); + } return images[0]; } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 6eca32fbb6..3b19cb5566 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -472,7 +472,13 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); if (atlas_source && atlas_source->has_tile(r_cell_data.cell.get_atlas_coords()) && atlas_source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) { is_valid = true; - tile_y_sort_origin = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)->get_y_sort_origin(); + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); + } + tile_y_sort_origin = tile_data->get_y_sort_origin(); } } @@ -652,7 +658,7 @@ void TileMapLayer::_physics_update() { const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); if (forced_cleanup) { // Clean everything. for (KeyValue<Vector2i, CellData> &kv : tile_map) { @@ -902,7 +908,7 @@ void TileMapLayer::_navigation_update() { NavigationServer2D *ns = NavigationServer2D::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); // ----------- Layer level processing ----------- if (forced_cleanup) { diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 3b30bbf8b6..60fb6f87c9 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -333,7 +333,7 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) { } } #ifdef TOOLS_ENABLED -void BoneAttachment3D::_notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Dictionary p_rename_map) { +void BoneAttachment3D::notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Dictionary p_rename_map) { const Skeleton3D *parent = nullptr; if (use_external_skeleton) { if (external_skeleton_node_cache.is_valid()) { @@ -370,9 +370,6 @@ void BoneAttachment3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton); ClassDB::bind_method(D_METHOD("set_external_skeleton", "external_skeleton"), &BoneAttachment3D::set_external_skeleton); ClassDB::bind_method(D_METHOD("get_external_skeleton"), &BoneAttachment3D::get_external_skeleton); -#ifdef TOOLS_ENABLED - ClassDB::bind_method(D_METHOD("_notify_skeleton_bones_renamed"), &BoneAttachment3D::_notify_skeleton_bones_renamed); -#endif // TOOLS_ENABLED ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx"); diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 327cbaa0ab..bfa3db476d 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -65,11 +65,12 @@ protected: void _notification(int p_what); static void _bind_methods(); + +public: #ifdef TOOLS_ENABLED - virtual void _notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Dictionary p_rename_map); + virtual void notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Dictionary p_rename_map); #endif // TOOLS_ENABLED -public: virtual PackedStringArray get_configuration_warnings() const override; void set_bone_name(const String &p_name); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 5175363538..4ba039becd 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -97,11 +97,16 @@ Array LightmapGIData::_get_user_data() const { return ret; } -void LightmapGIData::_set_light_textures_data(const Array &p_data) { - ERR_FAIL_COND(p_data.is_empty()); +void LightmapGIData::set_lightmap_textures(const TypedArray<TextureLayered> &p_data) { + light_textures = p_data; + if (p_data.is_empty()) { + light_texture = Ref<TextureLayered>(); + _reset_lightmap_textures(); + return; + } if (p_data.size() == 1) { - set_light_texture(p_data[0]); + light_texture = p_data[0]; } else { Vector<Ref<Image>> images; for (int i = 0; i < p_data.size(); i++) { @@ -116,73 +121,13 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) { combined_texture.instantiate(); combined_texture->create_from_images(images); - set_light_texture(combined_texture); + light_texture = combined_texture; } + _reset_lightmap_textures(); } -Array LightmapGIData::_get_light_textures_data() const { - Array ret; - if (light_texture.is_null() || light_texture->get_layers() == 0) { - return ret; - } - - Vector<Ref<Image>> images; - for (int i = 0; i < light_texture->get_layers(); i++) { - images.push_back(light_texture->get_layer_data(i)); - } - - int slice_count = images.size(); - int slice_width = images[0]->get_width(); - int slice_height = images[0]->get_height(); - - int slices_per_texture = Image::MAX_HEIGHT / slice_height; - int texture_count = Math::ceil(slice_count / (float)slices_per_texture); - - ret.resize(texture_count); - - String base_name = get_path().get_basename(); - - int last_count = slice_count % slices_per_texture; - for (int i = 0; i < texture_count; i++) { - int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; - - Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); - - for (int j = 0; j < texture_slice_count; j++) { - texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); - } - - String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr"; - - Ref<ConfigFile> config; - config.instantiate(); - - if (FileAccess::exists(texture_path + ".import")) { - config->load(texture_path + ".import"); - } - - config->set_value("remap", "importer", "2d_array_texture"); - config->set_value("remap", "type", "CompressedTexture2DArray"); - if (!config->has_section_key("params", "compress/mode")) { - // User may want another compression, so leave it be, but default to VRAM uncompressed. - config->set_value("params", "compress/mode", 3); - } - config->set_value("params", "compress/channel_pack", 1); - config->set_value("params", "mipmaps/generate", false); - config->set_value("params", "slices/horizontal", 1); - config->set_value("params", "slices/vertical", texture_slice_count); - - config->save(texture_path + ".import"); - - Error err = texture_image->save_exr(texture_path, false); - ERR_FAIL_COND_V(err, ret); - ResourceLoader::import(texture_path); - Ref<TextureLayered> t = ResourceLoader::load(texture_path); //if already loaded, it will be updated on refocus? - ERR_FAIL_COND_V(t.is_null(), ret); - ret[i] = t; - } - - return ret; +TypedArray<TextureLayered> LightmapGIData::get_lightmap_textures() const { + return light_textures; } RID LightmapGIData::get_rid() const { @@ -193,18 +138,13 @@ void LightmapGIData::clear() { users.clear(); } -void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) { - light_texture = p_light_texture; +void LightmapGIData::_reset_lightmap_textures() { RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); } -Ref<TextureLayered> LightmapGIData::get_light_texture() const { - return light_texture; -} - void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) { uses_spherical_harmonics = p_enable; - RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); + _reset_lightmap_textures(); } bool LightmapGIData::is_using_spherical_harmonics() const { @@ -282,15 +222,35 @@ Dictionary LightmapGIData::_get_probe_data() const { return d; } +#ifndef DISABLE_DEPRECATED +void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) { + TypedArray<TextureLayered> arr; + arr.append(p_light_texture); + set_lightmap_textures(arr); +} + +Ref<TextureLayered> LightmapGIData::get_light_texture() const { + if (light_textures.is_empty()) { + return Ref<TextureLayered>(); + } + return light_textures.get(0); +} + +void LightmapGIData::_set_light_textures_data(const Array &p_data) { + set_lightmap_textures(p_data); +} + +Array LightmapGIData::_get_light_textures_data() const { + return Array(light_textures); +} +#endif + void LightmapGIData::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data); ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data); - ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); - ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture); - - ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data); - ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data); + ClassDB::bind_method(D_METHOD("set_lightmap_textures", "light_textures"), &LightmapGIData::set_lightmap_textures); + ClassDB::bind_method(D_METHOD("get_lightmap_textures"), &LightmapGIData::get_lightmap_textures); ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics); ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics); @@ -303,11 +263,21 @@ void LightmapGIData::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data); ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); // property usage default but no save - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_NO_EDITOR), "set_lightmap_textures", "get_lightmap_textures"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data"); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); + ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture); + + ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data); + ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data"); +#endif } LightmapGIData::LightmapGIData() { @@ -1099,6 +1069,68 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa return BAKE_ERROR_MESHES_INVALID; } + // POSTBAKE: Save Textures. + + TypedArray<TextureLayered> textures; + { + Vector<Ref<Image>> images; + images.resize(lightmapper->get_bake_texture_count()); + for (int i = 0; i < images.size(); i++) { + images.set(i, lightmapper->get_bake_texture(i)); + } + + int slice_count = images.size(); + int slice_width = images[0]->get_width(); + int slice_height = images[0]->get_height(); + + int slices_per_texture = Image::MAX_HEIGHT / slice_height; + int texture_count = Math::ceil(slice_count / (float)slices_per_texture); + + textures.resize(texture_count); + + String base_path = p_image_data_path.get_basename(); + + int last_count = slice_count % slices_per_texture; + for (int i = 0; i < texture_count; i++) { + int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; + + Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); + + for (int j = 0; j < texture_slice_count; j++) { + texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); + } + + String texture_path = texture_count > 1 ? base_path + "_" + itos(i) + ".exr" : base_path + ".exr"; + + Ref<ConfigFile> config; + config.instantiate(); + + if (FileAccess::exists(texture_path + ".import")) { + config->load(texture_path + ".import"); + } + + config->set_value("remap", "importer", "2d_array_texture"); + config->set_value("remap", "type", "CompressedTexture2DArray"); + if (!config->has_section_key("params", "compress/mode")) { + // User may want another compression, so leave it be, but default to VRAM uncompressed. + config->set_value("params", "compress/mode", 3); + } + config->set_value("params", "compress/channel_pack", 1); + config->set_value("params", "mipmaps/generate", false); + config->set_value("params", "slices/horizontal", 1); + config->set_value("params", "slices/vertical", texture_slice_count); + + config->save(texture_path + ".import"); + + Error err = texture_image->save_exr(texture_path, false); + ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE); + ResourceLoader::import(texture_path); + Ref<TextureLayered> t = ResourceLoader::load(texture_path); // If already loaded, it will be updated on refocus? + ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE); + textures[i] = t; + } + } + /* POSTBAKE: Save Light Data */ Ref<LightmapGIData> gi_data; @@ -1110,18 +1142,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa gi_data.instantiate(); } - Ref<Texture2DArray> texture; - { - Vector<Ref<Image>> images; - for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) { - images.push_back(lightmapper->get_bake_texture(i)); - } - - texture.instantiate(); - texture->create_from_images(images); - } - - gi_data->set_light_texture(texture); + gi_data->set_lightmap_textures(textures); gi_data->set_uses_spherical_harmonics(directional); for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) { diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index b65d7f8c78..fec0075693 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -44,6 +44,7 @@ class LightmapGIData : public Resource { RES_BASE_EXTENSION("lmbake") Ref<TextureLayered> light_texture; + TypedArray<TextureLayered> light_textures; bool uses_spherical_harmonics = false; bool interior = false; @@ -65,8 +66,8 @@ class LightmapGIData : public Resource { Array _get_user_data() const; void _set_probe_data(const Dictionary &p_data); Dictionary _get_probe_data() const; - void _set_light_textures_data(const Array &p_data); - Array _get_light_textures_data() const; + + void _reset_lightmap_textures(); protected: static void _bind_methods(); @@ -80,9 +81,14 @@ public: int get_user_lightmap_slice_index(int p_user) const; void clear_users(); +#ifndef DISABLE_DEPRECATED void set_light_texture(const Ref<TextureLayered> &p_light_texture); Ref<TextureLayered> get_light_texture() const; + void _set_light_textures_data(const Array &p_data); + Array _get_light_textures_data() const; +#endif + void set_uses_spherical_harmonics(bool p_enable); bool is_using_spherical_harmonics() const; @@ -98,6 +104,9 @@ public: void clear(); + void set_lightmap_textures(const TypedArray<TextureLayered> &p_data); + TypedArray<TextureLayered> get_lightmap_textures() const; + virtual RID get_rid() const override; LightmapGIData(); ~LightmapGIData(); diff --git a/scene/3d/multimesh_instance_3d.cpp b/scene/3d/multimesh_instance_3d.cpp index 2158005f5f..55d6e49e6c 100644 --- a/scene/3d/multimesh_instance_3d.cpp +++ b/scene/3d/multimesh_instance_3d.cpp @@ -49,6 +49,26 @@ Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const { return multimesh; } +Array MultiMeshInstance3D::get_meshes() const { + if (multimesh.is_null() || multimesh->get_mesh().is_null() || multimesh->get_transform_format() != MultiMesh::TransformFormat::TRANSFORM_3D) { + return Array(); + } + + int count = multimesh->get_visible_instance_count(); + if (count == -1) { + count = multimesh->get_instance_count(); + } + + Ref<Mesh> mesh = multimesh->get_mesh(); + + Array results; + for (int i = 0; i < count; i++) { + results.push_back(multimesh->get_instance_transform(i)); + results.push_back(mesh); + } + return results; +} + AABB MultiMeshInstance3D::get_aabb() const { if (multimesh.is_null()) { return AABB(); diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h index cd18281b91..404f31d1e3 100644 --- a/scene/3d/multimesh_instance_3d.h +++ b/scene/3d/multimesh_instance_3d.h @@ -47,6 +47,8 @@ public: void set_multimesh(const Ref<MultiMesh> &p_multimesh); Ref<MultiMesh> get_multimesh() const; + Array get_meshes() const; + virtual AABB get_aabb() const override; MultiMeshInstance3D(); diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 43906b2586..8250083a9f 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -314,9 +314,21 @@ Ref<CameraAttributes> VoxelGI::get_camera_attributes() const { return camera_attributes; } +static bool is_node_voxel_bakeable(Node3D *p_node) { + if (!p_node->is_visible_in_tree()) { + return false; + } + + GeometryInstance3D *geometry = Object::cast_to<GeometryInstance3D>(p_node); + if (geometry != nullptr && geometry->get_gi_mode() != GeometryInstance3D::GI_MODE_STATIC) { + return false; + } + return true; +} + void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); - if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) { + if (mi && is_node_voxel_bakeable(mi)) { Ref<Mesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { AABB aabb = mesh->get_aabb(); @@ -338,8 +350,15 @@ void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { Node3D *s = Object::cast_to<Node3D>(p_at_node); if (s) { - if (s->is_visible_in_tree()) { - Array meshes = p_at_node->call("get_meshes"); + if (is_node_voxel_bakeable(s)) { + Array meshes; + MultiMeshInstance3D *multi_mesh = Object::cast_to<MultiMeshInstance3D>(p_at_node); + if (multi_mesh) { + meshes = multi_mesh->get_meshes(); + } else { + meshes = p_at_node->call("get_meshes"); + } + for (int i = 0; i < meshes.size(); i += 2) { Transform3D mxf = meshes[i]; Ref<Mesh> mesh = meshes[i + 1]; diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index fec4bc2b05..99392e9ba0 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -383,6 +383,8 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material } void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) { + ERR_FAIL_COND_MSG(!p_xform.is_finite(), "Invalid mesh bake transform."); + for (int i = 0; i < p_mesh->get_surface_count(); i++) { if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { continue; //only triangles diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 29e6d3d10d..d8abb36c8d 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -334,6 +334,12 @@ void TabBar::_shape(int p_tab) { void TabBar::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (scroll_to_selected) { + ensure_tab_visible(current); + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { Input *input = Input::get_singleton(); @@ -1745,7 +1751,10 @@ void TabBar::_bind_methods() { ADD_SIGNAL(MethodInfo("tab_hovered", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("active_tab_rearranged", PropertyInfo(Variant::INT, "idx_to"))); - ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); + // "current_tab" property must come after "tab_count", otherwise the property isn't loaded correctly. + ADD_ARRAY_COUNT("Tabs", "tab_count", "set_tab_count", "get_tab_count", "tab_"); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1"), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy"); @@ -1756,8 +1765,6 @@ void TabBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_to_selected"), "set_scroll_to_selected", "get_scroll_to_selected"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_with_rmb"), "set_select_with_rmb", "get_select_with_rmb"); - ADD_ARRAY_COUNT("Tabs", "tab_count", "set_tab_count", "get_tab_count", "tab_"); - BIND_ENUM_CONSTANT(ALIGNMENT_LEFT); BIND_ENUM_CONSTANT(ALIGNMENT_CENTER); BIND_ENUM_CONSTANT(ALIGNMENT_RIGHT); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 7d85468799..aa9400847f 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -143,6 +143,13 @@ void TabContainer::_notification(int p_what) { } } break; + case NOTIFICATION_POST_ENTER_TREE: { + if (setup_current_tab >= 0) { + set_current_tab(setup_current_tab); + setup_current_tab = -1; + } + } break; + case NOTIFICATION_READY: case NOTIFICATION_RESIZED: { _update_margins(); @@ -528,6 +535,10 @@ int TabContainer::get_tab_count() const { } void TabContainer::set_current_tab(int p_current) { + if (!is_inside_tree()) { + setup_current_tab = p_current; + return; + } tab_bar->set_current_tab(p_current); } @@ -912,7 +923,7 @@ void TabContainer::_bind_methods() { ADD_SIGNAL(MethodInfo("pre_popup_pressed")); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1"), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front"); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index b249576e28..450143cd0c 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -47,6 +47,7 @@ class TabContainer : public Container { bool theme_changing = false; Vector<Control *> children_removing; bool drag_to_rearrange_enabled = false; + int setup_current_tab = -1; struct ThemeCache { int side_margin = 0; diff --git a/scu_builders.py b/scu_builders.py index aaf83c30d5..71427eb717 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -7,7 +7,7 @@ from os.path import normpath, basename base_folder_path = str(Path(__file__).parent) + "/" base_folder_only = os.path.basename(os.path.normpath(base_folder_path)) -_verbose = False +_verbose = True # Set manually for debug prints _scu_folders = set() _max_includes_per_scu = 1024 @@ -35,7 +35,7 @@ def find_files_in_folder(folder, sub_folder, include_list, extension, sought_exc abs_folder = base_folder_path + folder + "/" + sub_folder if not os.path.isdir(abs_folder): - print("ERROR " + abs_folder + " not found.") + print("SCU: ERROR: %s not found." % abs_folder) return include_list, found_exceptions os.chdir(abs_folder) @@ -67,9 +67,10 @@ def write_output_file(file_count, include_list, start_line, end_line, output_fol # create os.mkdir(output_folder) if not os.path.isdir(output_folder): - print("ERROR " + output_folder + " could not be created.") + print("SCU: ERROR: %s could not be created." % output_folder) return - print("CREATING folder " + output_folder) + if _verbose: + print("SCU: Creating folder: %s" % output_folder) file_text = "" @@ -79,8 +80,6 @@ def write_output_file(file_count, include_list, start_line, end_line, output_fol li = line + "\n" file_text += li - # print(file_text) - num_string = "" if file_count > 0: num_string = "_" + str(file_count) @@ -88,7 +87,7 @@ def write_output_file(file_count, include_list, start_line, end_line, output_fol short_filename = output_filename_prefix + num_string + ".gen." + extension output_filename = output_folder + "/" + short_filename if _verbose: - print("generating: " + short_filename) + print("SCU: Generating: %s" % short_filename) output_path = Path(output_filename) output_path.write_text(file_text, encoding="utf8") @@ -97,7 +96,7 @@ def write_output_file(file_count, include_list, start_line, end_line, output_fol def write_exception_output_file(file_count, exception_string, output_folder, output_filename_prefix, extension): output_folder = os.path.abspath(output_folder) if not os.path.isdir(output_folder): - print("ERROR " + output_folder + " does not exist.") + print("SCU: ERROR: %s does not exist." % output_folder) return file_text = exception_string + "\n" @@ -110,10 +109,8 @@ def write_exception_output_file(file_count, exception_string, output_folder, out output_filename = output_folder + "/" + short_filename if _verbose: - print("generating: " + short_filename) + print("SCU: Generating: " + short_filename) - # print("text: " + file_text) - # return output_path = Path(output_filename) output_path.write_text(file_text, encoding="utf8") @@ -242,15 +239,15 @@ def process_folder(folders, sought_exceptions=[], includes_per_scu=0, extension= ) -def generate_scu_files(verbose, max_includes_per_scu): +def generate_scu_files(max_includes_per_scu): print("=============================") print("Single Compilation Unit Build") print("=============================") - global _verbose - _verbose = verbose + global _max_includes_per_scu _max_includes_per_scu = max_includes_per_scu - print("Generating SCU build files... (max includes per scu " + str(_max_includes_per_scu) + ")") + + print("SCU: Generating build files... (max includes per SCU: %d)" % _max_includes_per_scu) curr_folder = os.path.abspath("./") @@ -334,4 +331,7 @@ def generate_scu_files(verbose, max_includes_per_scu): # Finally change back the path to the calling folder os.chdir(curr_folder) + if _verbose: + print("SCU: Processed folders: %s" % sorted(_scu_folders)) + return _scu_folders diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 768701329b..270a34d541 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1390,6 +1390,11 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo sdfgi->store_probes(); } + Size2i viewport_size = Size2i(1, 1); + if (rb.is_valid()) { + viewport_size = rb->get_internal_size(); + } + p_render_data->cube_shadows.clear(); p_render_data->shadows.clear(); p_render_data->directional_shadows.clear(); @@ -1412,7 +1417,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //cube shadows are rendered in their own way for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size); } if (p_render_data->directional_shadows.size()) { @@ -1442,11 +1447,11 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, viewport_size); } //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, viewport_size); } _render_shadow_process(); @@ -2310,7 +2315,7 @@ void RenderForwardClustered::_render_buffers_debug_draw(const RenderDataRD *p_re } } -void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -2465,7 +2470,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas if (render_cubemap) { //rendering to cubemap - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_viewport_size); if (finalize_cubemap) { _render_shadow_process(); _render_shadow_end(); @@ -2483,7 +2488,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_viewport_size); } } @@ -2496,7 +2501,7 @@ void RenderForwardClustered::_render_shadow_begin() { scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -2520,7 +2525,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page render_data.instances = &p_instances; render_data.render_info = p_render_info; - _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index); + _setup_environment(&render_data, true, p_viewport_size, !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { scene_data.screen_mesh_lod_threshold = 0.0; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 46deb30cde..6077fb4bde 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -593,9 +593,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1)); void _render_shadow_begin(); - void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1)); void _render_shadow_process(); void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 3710ac0eed..da55b68109 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -591,7 +591,6 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding. if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) { - Vector<uint8_t> new_vertex_data; sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2); } } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index cc42c5a3fb..d0a62ddb4d 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -441,16 +441,15 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint const Vector3 *src = array.ptr(); - // Setting vertices means regenerating the AABB. - AABB aabb; + r_aabb = AABB(); if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { // First we need to generate the AABB for the entire surface. for (int i = 0; i < p_vertex_array_len; i++) { if (i == 0) { - aabb = AABB(src[i], SMALL_VEC3); + r_aabb = AABB(src[i], SMALL_VEC3); } else { - aabb.expand_to(src[i]); + r_aabb.expand_to(src[i]); } } @@ -459,7 +458,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint if (!using_normals_tangents) { // Early out if we are only setting vertex positions. for (int i = 0; i < p_vertex_array_len; i++) { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -507,7 +506,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Store vertex position + angle. { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -543,7 +542,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Store vertex position + angle. { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -562,14 +561,12 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { - aabb = AABB(src[i], SMALL_VEC3); + r_aabb = AABB(src[i], SMALL_VEC3); } else { - aabb.expand_to(src[i]); + r_aabb.expand_to(src[i]); } } } - - r_aabb = aabb; } } break; diff --git a/tests/core/variant/test_variant.h b/tests/core/variant/test_variant.h index 93ae3b4c43..54ca06c6c4 100644 --- a/tests/core/variant/test_variant.h +++ b/tests/core/variant/test_variant.h @@ -980,45 +980,45 @@ TEST_CASE("[Variant] Assignment To Vec2 from Bool,Int,Float,String,Vec2i,Vec3,Ve CHECK(basis_v.get_type() == Variant::VECTOR2); Variant aabb_v = AABB(); - string_v = "Hello"; - aabb_v = string_v; - CHECK(aabb_v == Variant("Hello")); - string_v = "Hello there"; - aabb_v = string_v; - CHECK(aabb_v.get_type() == Variant::STRING); + vec2_v = Vector2(2.2f, 3.5f); + aabb_v = vec2_v; + CHECK(aabb_v == Variant(Vector2(2.2f, 3.5f))); + vec2_v = Vector2(-5.4f, -7.9f); + aabb_v = vec2_v; + CHECK(aabb_v.get_type() == Variant::VECTOR2); Variant quaternion_v = Quaternion(); - string_v = "Hello"; - quaternion_v = string_v; - CHECK(quaternion_v == Variant("Hello")); - string_v = "Hello there"; - quaternion_v = string_v; - CHECK(quaternion_v.get_type() == Variant::STRING); + vec2_v = Vector2(2.2f, 3.5f); + quaternion_v = vec2_v; + CHECK(quaternion_v == Variant(Vector2(2.2f, 3.5f))); + vec2_v = Vector2(-5.4f, -7.9f); + quaternion_v = vec2_v; + CHECK(quaternion_v.get_type() == Variant::VECTOR2); Variant projection_v = Projection(); - string_v = "Hello"; - projection_v = string_v; - CHECK(projection_v == Variant("Hello")); - string_v = "Hello there"; - projection_v = string_v; - CHECK(projection_v.get_type() == Variant::STRING); + vec2_v = Vector2(2.2f, 3.5f); + projection_v = vec2_v; + CHECK(projection_v == Variant(Vector2(2.2f, 3.5f))); + vec2_v = Vector2(-5.4f, -7.9f); + projection_v = vec2_v; + CHECK(projection_v.get_type() == Variant::VECTOR2); Variant rid_v = RID(); - string_v = "Hello"; - rid_v = string_v; - CHECK(rid_v == Variant("Hello")); - string_v = "Hello there"; - rid_v = string_v; - CHECK(rid_v.get_type() == Variant::STRING); + vec2_v = Vector2(2.2f, 3.5f); + rid_v = vec2_v; + CHECK(rid_v == Variant(Vector2(2.2f, 3.5f))); + vec2_v = Vector2(-5.4f, -7.9f); + rid_v = vec2_v; + CHECK(rid_v.get_type() == Variant::VECTOR2); Object obj_one = Object(); Variant object_v = &obj_one; - string_v = "Hello"; - object_v = string_v; - CHECK(object_v == Variant("Hello")); - string_v = "Hello there"; - object_v = string_v; - CHECK(object_v.get_type() == Variant::STRING); + vec2_v = Vector2(2.2f, 3.5f); + object_v = vec2_v; + CHECK(object_v == Variant(Vector2(2.2f, 3.5f))); + vec2_v = Vector2(-5.4f, -7.9f); + object_v = vec2_v; + CHECK(object_v.get_type() == Variant::VECTOR2); } TEST_CASE("[Variant] Assignment To Vec2i from Bool,Int,Float,String,Vec2,Vec3,Vec3i,Vec4,Vec4i,Rect2,Rect2i,Trans2d,Trans3d,Color,Call,Plane,Basis,AABB,Quant,Proj,RID,and Object") { |
