summaryrefslogtreecommitdiff
path: root/servers/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering')
-rw-r--r--servers/rendering/rasterizer.h4
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h2
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp235
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h38
-rw-r--r--servers/rendering/rasterizer_rd/shaders/particles.glsl238
-rw-r--r--servers/rendering/rendering_server_canvas.cpp13
-rw-r--r--servers/rendering/rendering_server_raster.h2
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h3
-rw-r--r--servers/rendering/shader_language.cpp232
-rw-r--r--servers/rendering/shader_language.h31
-rw-r--r--servers/rendering/shader_types.cpp21
11 files changed, 634 insertions, 185 deletions
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index 41dcd387de..9cb611f3b4 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -88,7 +88,7 @@ public:
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@@ -661,6 +661,8 @@ public:
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_restart(RID p_particles) = 0;
+ virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+ virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
virtual bool particles_is_inactive(RID p_particles) const = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index eb49233b98..fe31d2f76b 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -1542,7 +1542,7 @@ public:
float environment_get_fog_height(RID p_env) const;
float environment_get_fog_height_density(RID p_env) const;
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth);
virtual void environment_set_volumetric_fog_filter_active(bool p_enable);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index e09926c97e..d751f474cd 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -3119,24 +3119,40 @@ bool RasterizerStorageRD::particles_get_emitting(RID p_particles) {
return particles->emitting;
}
+void RasterizerStorageRD::_particles_free_data(Particles *particles) {
+ if (!particles->particle_buffer.is_valid()) {
+ return;
+ }
+ RD::get_singleton()->free(particles->particle_buffer);
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ RD::get_singleton()->free(particles->particle_instance_buffer);
+ particles->particles_transforms_buffer_uniform_set = RID();
+ particles->particle_buffer = RID();
+
+ if (particles->particles_sort_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->particles_sort_buffer);
+ particles->particles_sort_buffer = RID();
+ }
+
+ if (particles->emission_buffer != nullptr) {
+ particles->emission_buffer = nullptr;
+ particles->emission_buffer_data.clear();
+ RD::get_singleton()->free(particles->emission_storage_buffer);
+ particles->emission_storage_buffer = RID();
+ }
+}
+
void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
- particles->amount = p_amount;
+ if (particles->amount == p_amount) {
+ return;
+ }
- if (particles->particle_buffer.is_valid()) {
- RD::get_singleton()->free(particles->particle_buffer);
- RD::get_singleton()->free(particles->frame_params_buffer);
- RD::get_singleton()->free(particles->particle_instance_buffer);
- particles->particles_transforms_buffer_uniform_set = RID();
- particles->particle_buffer = RID();
+ _particles_free_data(particles);
- if (particles->particles_sort_buffer.is_valid()) {
- RD::get_singleton()->free(particles->particles_sort_buffer);
- particles->particles_sort_buffer = RID();
- }
- }
+ particles->amount = p_amount;
if (particles->amount > 0) {
particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount);
@@ -3150,27 +3166,6 @@ void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) {
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(particles->frame_params_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(particles->particle_buffer);
- uniforms.push_back(u);
- }
-
- particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1);
- }
-
- {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.ids.push_back(particles->particle_buffer);
uniforms.push_back(u);
@@ -3290,6 +3285,79 @@ void RasterizerStorageRD::particles_restart(RID p_particles) {
particles->restart_request = true;
}
+void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particles) {
+ ERR_FAIL_COND(particles->emission_buffer != nullptr);
+
+ particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4);
+ zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size());
+ particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw();
+ particles->emission_buffer->particle_max = particles->amount;
+
+ particles->emission_storage_buffer = RD::get_singleton()->storage_buffer_create(particles->emission_buffer_data.size(), particles->emission_buffer_data);
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ //will need to be re-created
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ particles->particles_material_uniform_set = RID();
+ }
+}
+
+void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(p_particles == p_subemitter_particles);
+
+ particles->sub_emitter = p_subemitter_particles;
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ particles->particles_material_uniform_set = RID(); //clear and force to re create sub emitting
+ }
+}
+
+void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(particles->amount == 0);
+
+ if (particles->emitting) {
+ particles->clear = true;
+ particles->emitting = false;
+ }
+
+ if (particles->emission_buffer == nullptr) {
+ _particles_allocate_emission_buffer(particles);
+ }
+
+ if (particles->inactive) {
+ //in case it was inactive, make active again
+ particles->inactive = false;
+ particles->inactive_time = 0;
+ }
+
+ int32_t idx = particles->emission_buffer->particle_count;
+ if (idx < particles->emission_buffer->particle_max) {
+ store_transform(p_transform, particles->emission_buffer->data[idx].xform);
+
+ particles->emission_buffer->data[idx].velocity[0] = p_velocity.x;
+ particles->emission_buffer->data[idx].velocity[1] = p_velocity.y;
+ particles->emission_buffer->data[idx].velocity[2] = p_velocity.z;
+
+ particles->emission_buffer->data[idx].custom[0] = p_custom.r;
+ particles->emission_buffer->data[idx].custom[1] = p_custom.g;
+ particles->emission_buffer->data[idx].custom[2] = p_custom.b;
+ particles->emission_buffer->data[idx].custom[3] = p_custom.a;
+
+ particles->emission_buffer->data[idx].color[0] = p_color.r;
+ particles->emission_buffer->data[idx].color[1] = p_color.g;
+ particles->emission_buffer->data[idx].color[2] = p_color.b;
+ particles->emission_buffer->data[idx].color[3] = p_color.a;
+
+ particles->emission_buffer->data[idx].flags = p_emit_flags;
+ particles->emission_buffer->particle_count++;
+ }
+}
+
void RasterizerStorageRD::particles_request_process(RID p_particles) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -3375,6 +3443,54 @@ RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pas
}
void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_delta) {
+ if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(p_particles->frame_params_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(p_particles->particle_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ if (p_particles->emission_storage_buffer.is_valid()) {
+ u.ids.push_back(p_particles->emission_storage_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 3;
+ Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+ if (sub_emitter) {
+ if (sub_emitter->emission_buffer == nullptr) { //no emission buffer, allocate emission buffer
+ _particles_allocate_emission_buffer(sub_emitter);
+ }
+ u.ids.push_back(sub_emitter->emission_storage_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+
+ p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1);
+ }
+
float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
ParticlesFrameParams &frame_params = p_particles->frame_params;
@@ -3416,6 +3532,36 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del
push_constant.lifetime = p_particles->lifetime;
push_constant.trail_size = 1;
push_constant.use_fractional_delta = p_particles->fractional_delta;
+ push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit);
+
+ p_particles->force_sub_emit = false; //reset
+
+ Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+
+ if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) {
+ // print_line("updating subemitter buffer");
+ int32_t zero[4] = { 0, sub_emitter->amount, 0, 0 };
+ RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero, true);
+ push_constant.can_emit = true;
+
+ if (sub_emitter->emitting) {
+ sub_emitter->emitting = false;
+ sub_emitter->clear = true; //will need to clear if it was emitting, sorry
+ }
+ //make sure the sub emitter processes particles too
+ sub_emitter->inactive = false;
+ sub_emitter->inactive_time = 0;
+
+ sub_emitter->force_sub_emit = true;
+
+ } else {
+ push_constant.can_emit = false;
+ }
+
+ if (p_particles->emission_buffer && p_particles->emission_buffer->particle_count) {
+ RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer, true);
+ p_particles->emission_buffer->particle_count = 0;
+ }
p_particles->clear = false;
@@ -3617,9 +3763,6 @@ void RasterizerStorageRD::update_particles() {
RD::get_singleton()->compute_list_end();
}
- particle_update_list = particles->update_list;
- particles->update_list = nullptr;
-
particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated
}
}
@@ -6519,6 +6662,11 @@ bool RasterizerStorageRD::free(RID p_rid) {
light->instance_dependency.instance_notify_deleted(p_rid);
light_owner.free(p_rid);
+ } else if (particles_owner.owns(p_rid)) {
+ Particles *particles = particles_owner.getornull(p_rid);
+ _particles_free_data(particles);
+ particles->instance_dependency.instance_notify_deleted(p_rid);
+ particles_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {
RenderTarget *rt = render_target_owner.getornull(p_rid);
@@ -7013,6 +7161,17 @@ RasterizerStorageRD::RasterizerStorageRD() {
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
+ actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
+ actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
+ actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY";
+ actions.renames["FLAG_EMIT_COLOR"] = "EMISSION_FLAG_HAS_COLOR";
+ actions.renames["FLAG_EMIT_CUSTOM"] = "EMISSION_FLAG_HAS_CUSTOM";
+ actions.renames["RESTART_POSITION"] = "restart_position";
+ actions.renames["RESTART_ROT_SCALE"] = "restart_rotation_scale";
+ actions.renames["RESTART_VELOCITY"] = "restart_velocity";
+ actions.renames["RESTART_COLOR"] = "restart_color";
+ actions.renames["RESTART_CUSTOM"] = "restart_custom";
+ actions.renames["emit_particle"] = "emit_particle";
actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
@@ -7075,6 +7234,8 @@ RasterizerStorageRD::RasterizerStorageRD() {
particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 0);
}
+ default_rd_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+
{
Vector<String> copy_modes;
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n");
@@ -7115,6 +7276,8 @@ RasterizerStorageRD::~RasterizerStorageRD() {
}
giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
+ RD::get_singleton()->free(default_rd_storage_buffer);
+
if (decal_atlas.textures.size()) {
ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index e09b4a52eb..cecae6bbb2 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -249,6 +249,7 @@ private:
RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ RID default_rd_storage_buffer;
/* DECAL ATLAS */
@@ -482,6 +483,25 @@ private:
float emission_transform[16];
};
+ struct ParticleEmissionBufferData {
+ };
+
+ struct ParticleEmissionBuffer {
+ struct Data {
+ float xform[16];
+ float velocity[3];
+ uint32_t flags;
+ float color[4];
+ float custom[4];
+ };
+
+ int32_t particle_count;
+ int32_t particle_max;
+ uint32_t pad1;
+ uint32_t pad2;
+ Data data[1]; //its 2020 and empty arrays are still non standard in C++
+ };
+
struct Particles {
bool inactive;
float inactive_time;
@@ -515,6 +535,8 @@ private:
bool dirty = false;
Particles *update_list = nullptr;
+ RID sub_emitter;
+
float phase;
float prev_phase;
uint64_t prev_ticks;
@@ -530,8 +552,15 @@ private:
bool clear;
+ bool force_sub_emit = false;
+
Transform emission_transform;
+ Vector<uint8_t> emission_buffer_data;
+
+ ParticleEmissionBuffer *emission_buffer = nullptr;
+ RID emission_storage_buffer;
+
Particles() :
inactive(true),
inactive_time(0.0),
@@ -562,6 +591,8 @@ private:
};
void _particles_process(Particles *p_particles, float p_delta);
+ void _particles_allocate_emission_buffer(Particles *particles);
+ void _particles_free_data(Particles *particles);
struct ParticlesShader {
struct PushConstant {
@@ -569,8 +600,11 @@ private:
uint32_t clear;
uint32_t total_particles;
uint32_t trail_size;
+
uint32_t use_fractional_delta;
- uint32_t pad[3];
+ uint32_t sub_emitter_mode;
+ uint32_t can_emit;
+ uint32_t pad;
};
ParticlesShaderRD shader;
@@ -1650,6 +1684,8 @@ public:
void particles_set_fixed_fps(RID p_particles, int p_fps);
void particles_set_fractional_delta(RID p_particles, bool p_enable);
void particles_restart(RID p_particles);
+ void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void particles_set_subemitter(RID p_particles, RID p_subemitter_particles);
void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl
index 7cdedfcbfe..3de807b57c 100644
--- a/servers/rendering/rasterizer_rd/shaders/particles.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl
@@ -66,6 +66,38 @@ layout(set = 1, binding = 1, std430) restrict buffer Particles {
}
particles;
+#define EMISSION_FLAG_HAS_POSITION 1
+#define EMISSION_FLAG_HAS_ROTATION_SCALE 2
+#define EMISSION_FLAG_HAS_VELOCITY 4
+#define EMISSION_FLAG_HAS_COLOR 8
+#define EMISSION_FLAG_HAS_CUSTOM 16
+
+struct ParticleEmission {
+ mat4 xform;
+ vec3 velocity;
+ uint flags;
+ vec4 color;
+ vec4 custom;
+};
+
+layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmission {
+ int particle_count;
+ uint pad0;
+ uint pad1;
+ uint pad2;
+ ParticleEmission data[];
+}
+src_particles;
+
+layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmission {
+ int particle_count;
+ int particle_max;
+ uint pad1;
+ uint pad2;
+ ParticleEmission data[];
+}
+dst_particles;
+
/* SET 2: MATERIAL */
#ifdef USE_MATERIAL_UNIFORMS
@@ -82,7 +114,9 @@ layout(push_constant, binding = 0, std430) uniform Params {
uint total_particles;
uint trail_size;
bool use_fractional_delta;
- uint pad[3];
+ bool sub_emitter_mode;
+ bool can_emit;
+ uint pad;
}
params;
@@ -93,6 +127,51 @@ uint hash(uint x) {
return x;
}
+bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) {
+ if (!params.can_emit) {
+ return false;
+ }
+
+ bool valid = false;
+
+ int dst_index = atomicAdd(dst_particles.particle_count, 1);
+
+ if (dst_index >= dst_particles.particle_max) {
+ atomicAdd(dst_particles.particle_count, -1);
+ return false;
+ }
+ /*
+ valid = true;
+
+ int attempts = 256; // never trust compute
+ while(attempts-- > 0) {
+ dst_index = dst_particles.particle_count;
+ if (dst_index == dst_particles.particle_max) {
+ return false; //cant emit anymore
+ }
+
+ if (atomicCompSwap(dst_particles.particle_count, dst_index, dst_index +1 ) != dst_index) {
+ continue;
+ }
+ valid=true;
+ break;
+ }
+
+ barrier();
+
+ if (!valid) {
+ return false; //gave up (attempts exhausted)
+ }
+*/
+ dst_particles.data[dst_index].xform = p_xform;
+ dst_particles.data[dst_index].velocity = p_velocity;
+ dst_particles.data[dst_index].color = p_color;
+ dst_particles.data[dst_index].custom = p_custom;
+ dst_particles.data[dst_index].flags = p_flags;
+
+ return true;
+}
+
/* clang-format off */
COMPUTE_SHADER_GLOBALS
@@ -118,76 +197,129 @@ void main() {
float mass = 1.0;
- float restart_phase = float(index) / float(params.total_particles);
+ bool restart = false;
- if (FRAME.randomness > 0.0) {
- uint seed = FRAME.cycle;
- if (restart_phase >= FRAME.system_phase) {
- seed -= uint(1);
- }
- seed *= uint(params.total_particles);
- seed += uint(index);
- float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
+ bool restart_position = false;
+ bool restart_rotation_scale = false;
+ bool restart_velocity = false;
+ bool restart_color = false;
+ bool restart_custom = false;
+
+ if (params.clear) {
+ PARTICLE.color = vec4(1.0);
+ PARTICLE.custom = vec4(0.0);
+ PARTICLE.velocity = vec3(0.0);
+ PARTICLE.is_active = false;
+ PARTICLE.xform = mat4(
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
}
- restart_phase *= (1.0 - FRAME.explosiveness);
+ if (params.sub_emitter_mode) {
+ if (!PARTICLE.is_active) {
+ int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
- bool restart = false;
+ if (src_index >= 0) {
+ PARTICLE.is_active = true;
+ restart = true;
- if (FRAME.system_phase > FRAME.prev_system_phase) {
- // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
+ PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
+ } else {
+ PARTICLE.xform[3] = vec4(0, 0, 0, 1);
+ restart_position = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
+ PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
+ PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
+ PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
+ } else {
+ PARTICLE.xform[0] = vec4(1, 0, 0, 0);
+ PARTICLE.xform[1] = vec4(0, 1, 0, 0);
+ PARTICLE.xform[2] = vec4(0, 0, 1, 0);
+ restart_rotation_scale = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
+ PARTICLE.velocity = src_particles.data[src_index].velocity;
+ } else {
+ PARTICLE.velocity = vec3(0);
+ restart_velocity = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
+ PARTICLE.color = src_particles.data[src_index].color;
+ } else {
+ PARTICLE.color = vec4(1);
+ restart_color = true;
+ }
- if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
+ PARTICLE.custom = src_particles.data[src_index].custom;
+ } else {
+ PARTICLE.custom = vec4(0);
+ restart_custom = true;
+ }
}
}
- } else if (FRAME.delta > 0.0) {
- if (restart_phase >= FRAME.prev_system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
- }
+ } else if (FRAME.emitting) {
+ float restart_phase = float(index) / float(params.total_particles);
- } else if (restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ if (FRAME.randomness > 0.0) {
+ uint seed = FRAME.cycle;
+ if (restart_phase >= FRAME.system_phase) {
+ seed -= uint(1);
}
+ seed *= uint(params.total_particles);
+ seed += uint(index);
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
}
- }
- uint current_cycle = FRAME.cycle;
+ restart_phase *= (1.0 - FRAME.explosiveness);
- if (FRAME.system_phase < restart_phase) {
- current_cycle -= uint(1);
- }
+ if (FRAME.system_phase > FRAME.prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
- uint particle_number = current_cycle * uint(params.total_particles) + particle;
+ if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
- if (restart) {
- PARTICLE.is_active = FRAME.emitting;
- }
+ } else if (FRAME.delta > 0.0) {
+ if (restart_phase >= FRAME.prev_system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
+ }
-#ifdef ENABLE_KEEP_DATA
- if (params.clear) {
-#else
- if (params.clear || restart) {
-#endif
- PARTICLE.color = vec4(1.0);
- PARTICLE.custom = vec4(0.0);
- PARTICLE.velocity = vec3(0.0);
- if (!restart) {
- PARTICLE.is_active = false;
+ } else if (restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+ }
+
+ uint current_cycle = FRAME.cycle;
+
+ if (FRAME.system_phase < restart_phase) {
+ current_cycle -= uint(1);
+ }
+
+ uint particle_number = current_cycle * uint(params.total_particles) + particle;
+
+ if (restart) {
+ PARTICLE.is_active = FRAME.emitting;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
}
- PARTICLE.xform = mat4(
- vec4(1.0, 0.0, 0.0, 0.0),
- vec4(0.0, 1.0, 0.0, 0.0),
- vec4(0.0, 0.0, 1.0, 0.0),
- vec4(0.0, 0.0, 0.0, 1.0));
}
if (PARTICLE.is_active) {
diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp
index 5c0741bb3b..07eabfd430 100644
--- a/servers/rendering/rendering_server_canvas.cpp
+++ b/servers/rendering/rendering_server_canvas.cpp
@@ -900,13 +900,12 @@ void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skelet
void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
- if (bool(canvas_item->copy_back_buffer != nullptr) != p_enable) {
- if (p_enable) {
- canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
- } else {
- memdelete(canvas_item->copy_back_buffer);
- canvas_item->copy_back_buffer = nullptr;
- }
+ if (p_enable && (canvas_item->copy_back_buffer == nullptr)) {
+ canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
+ }
+ if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) {
+ memdelete(canvas_item->copy_back_buffer);
+ canvas_item->copy_back_buffer = nullptr;
}
if (p_enable) {
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 547595f9b0..ceefcfa1fc 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -442,6 +442,8 @@ public:
BIND1R(bool, particles_is_inactive, RID)
BIND1(particles_request_process, RID)
BIND1(particles_restart, RID)
+ BIND6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+ BIND2(particles_set_subemitter, RID, RID)
BIND2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index 40aff46a3c..a8a56e7d56 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -360,11 +360,14 @@ public:
FUNC1(particles_request_process, RID)
FUNC1(particles_restart, RID)
+ FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+
FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
FUNC2(particles_set_draw_passes, RID, int)
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
FUNC2(particles_set_emission_transform, RID, const Transform &)
+ FUNC2(particles_set_subemitter, RID, RID)
FUNC1R(AABB, particles_get_current_aabb, RID)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e60f79f3a0..28c41fb2dc 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -920,13 +920,13 @@ void ShaderLanguage::clear() {
}
}
-bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
- if (p_builtin_types.has(p_identifier)) {
+bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
+ if (p_function_info.built_ins.has(p_identifier)) {
if (r_data_type) {
- *r_data_type = p_builtin_types[p_identifier].type;
+ *r_data_type = p_function_info.built_ins[p_identifier].type;
}
if (r_is_const) {
- *r_is_const = p_builtin_types[p_identifier].constant;
+ *r_is_const = p_function_info.built_ins[p_identifier].constant;
}
if (r_type) {
*r_type = IDENTIFIER_BUILTIN_VAR;
@@ -935,6 +935,20 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return true;
}
+ if (p_function_info.stage_functions.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = p_function_info.stage_functions[p_identifier].return_type;
+ }
+ if (r_is_const) {
+ *r_is_const = true;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION;
+ }
+
+ return true;
+ }
+
FunctionNode *function = nullptr;
while (p_block) {
@@ -2152,7 +2166,7 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
{ nullptr, 0 }
};
-bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
+bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
Vector<DataType> args;
@@ -2169,6 +2183,30 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
int argcount = args.size();
+ if (p_function_info.stage_functions.has(name)) {
+ //stage based function
+ const StageFunctionInfo &sf = p_function_info.stage_functions[name];
+ if (argcount != sf.arguments.size()) {
+ _set_error(vformat("Invalid number of arguments when calling stage function '%s', which expects %d arguments.", String(name), sf.arguments.size()));
+ return false;
+ }
+ //validate arguments
+ for (int i = 0; i < argcount; i++) {
+ if (args[i] != sf.arguments[i].type) {
+ _set_error(vformat("Invalid argument type when calling stage function '%s', type expected is '%s'.", String(name), String(get_datatype_name(sf.arguments[i].type))));
+ return false;
+ }
+ }
+
+ if (r_ret_type) {
+ *r_ret_type = sf.return_type;
+ }
+ if (r_ret_type_str) {
+ *r_ret_type_str = "";
+ }
+ return true;
+ }
+
bool failed_builtin = false;
bool unsupported_builtin = false;
int builtin_idx = 0;
@@ -2241,8 +2279,8 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
if (shader->uniforms.has(varname)) {
fail = true;
} else {
- if (p_builtin_types.has(varname)) {
- BuiltInInfo info = p_builtin_types[varname];
+ if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
if (info.constant) {
fail = true;
}
@@ -2278,7 +2316,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
const BlockNode *b = p_block;
bool valid = false;
while (b) {
- if (b->variables.has(var_name) || p_builtin_types.has(var_name)) {
+ if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) {
valid = true;
break;
}
@@ -2353,10 +2391,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
err += ",";
}
- if (p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && p_func->arguments[i + 1]->get_datatype() == TYPE_INT && static_cast<ConstantNode *>(p_func->arguments[i + 1])->values[0].sint < 0) {
- err += "-";
+ String arg_name;
+ if (args[i] == TYPE_STRUCT) {
+ arg_name = args2[i];
+ } else {
+ arg_name = get_datatype_name(args[i]);
}
- err += get_datatype_name(args[i]);
+ err += arg_name;
}
err += ")";
_set_error(err);
@@ -2380,6 +2421,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
return false;
}
+ int last_arg_count = 0;
+ String arg_list = "";
+
for (int i = 0; i < shader->functions.size(); i++) {
if (name != shader->functions[i].name) {
continue;
@@ -2391,21 +2435,45 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
FunctionNode *pfunc = shader->functions[i].function;
+ if (arg_list == "") {
+ for (int j = 0; j < pfunc->arguments.size(); j++) {
+ if (j > 0) {
+ arg_list += ", ";
+ }
+ String func_arg_name;
+ if (pfunc->arguments[j].type == TYPE_STRUCT) {
+ func_arg_name = pfunc->arguments[j].type_str;
+ } else {
+ func_arg_name = get_datatype_name(pfunc->arguments[j].type);
+ }
+ arg_list += func_arg_name;
+ }
+ }
if (pfunc->arguments.size() != args.size()) {
+ last_arg_count = pfunc->arguments.size();
continue;
}
bool fail = false;
for (int j = 0; j < args.size(); j++) {
- if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) {
- fail = true;
- break;
- }
if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
//all good, but it needs implicit conversion later
- } else if (args[j] != pfunc->arguments[j].type) {
+ } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str)) {
+ String func_arg_name;
+ if (pfunc->arguments[j].type == TYPE_STRUCT) {
+ func_arg_name = pfunc->arguments[j].type_str;
+ } else {
+ func_arg_name = get_datatype_name(pfunc->arguments[j].type);
+ }
+ String arg_name;
+ if (args[j] == TYPE_STRUCT) {
+ arg_name = args2[j];
+ } else {
+ arg_name = get_datatype_name(args[j]);
+ }
+ _set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
}
@@ -2441,6 +2509,12 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
}
+ if (last_arg_count > args.size()) {
+ _set_error(vformat("Too few arguments for \"%s(%s)\" call. Expected at least %s but received %s.", String(name), arg_list, last_arg_count, args.size()));
+ } else if (last_arg_count < args.size()) {
+ _set_error(vformat("Too many arguments for \"%s(%s)\" call. Expected at most %s but received %s.", String(name), arg_list, last_arg_count, args.size()));
+ }
+
return false;
}
@@ -2456,7 +2530,7 @@ bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
return true;
}
-bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
+bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg) {
TkPos pos = _get_tkpos();
Token tk = _get_token();
@@ -2478,7 +2552,7 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str
}
}
- Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *arg = _parse_and_reduce_expression(p_block, p_function_info);
if (!arg) {
return false;
@@ -3017,16 +3091,16 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
return false;
}
-bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
+bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
if (op->op == OP_INDEX) {
- return _validate_assign(op->arguments[0], p_builtin_types, r_message);
+ return _validate_assign(op->arguments[0], p_function_info, r_message);
} else if (_is_operator_assign(op->op)) {
//chained assignment
- return _validate_assign(op->arguments[1], p_builtin_types, r_message);
+ return _validate_assign(op->arguments[1], p_function_info, r_message);
} else if (op->op == OP_CALL) {
if (r_message) {
@@ -3045,7 +3119,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return false;
}
- return _validate_assign(member->owner, p_builtin_types, r_message);
+ return _validate_assign(member->owner, p_function_info, r_message);
} else if (p_node->type == Node::TYPE_VARIABLE) {
VariableNode *var = static_cast<VariableNode *>(p_node);
@@ -3071,7 +3145,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return false;
}
- if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) {
+ if (!(p_function_info.built_ins.has(var->name) && p_function_info.built_ins[var->name].constant)) {
return true;
}
} else if (p_node->type == Node::TYPE_ARRAY) {
@@ -3168,7 +3242,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
-ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
+ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
Vector<Expression> expression;
//Vector<TokenType> operators;
@@ -3184,7 +3258,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PARENTHESIS_OPEN) {
//handle subexpression
- expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return nullptr;
}
@@ -3257,7 +3331,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
int carg = -1;
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
if (carg >= 0) {
completion_type = COMPLETION_CALL_ARGUMENTS;
@@ -3271,7 +3345,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching constructor found for: '" + String(funcname->name) + "'");
return nullptr;
}
@@ -3347,7 +3421,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return nullptr;
@@ -3408,7 +3482,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return nullptr;
}
@@ -3448,7 +3522,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
nexpr = an;
} else {
- nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ nexpr = _parse_and_reduce_expression(p_block, p_function_info);
if (!nexpr) {
return nullptr;
}
@@ -3490,7 +3564,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
int carg = -1;
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
// Check if block has a variable with the same name as function to prevent shader crash.
ShaderLanguage::BlockNode *bnode = p_block;
@@ -3532,7 +3606,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching function found for: '" + String(funcname->name) + "'");
return nullptr;
}
@@ -3584,8 +3658,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (shader->uniforms.has(varname)) {
error = true;
} else {
- if (p_builtin_types.has(varname)) {
- BuiltInInfo info = p_builtin_types[varname];
+ if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
if (info.constant) {
error = true;
}
@@ -3617,7 +3691,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
return nullptr;
}
- } else if (p_builtin_types.has(varname)) {
+ } else if (p_function_info.built_ins.has(varname)) {
//a built-in
if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
return nullptr;
@@ -3672,7 +3746,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
} else {
- if (!_find_identifier(p_block, false, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
+ if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
_set_error("Unknown identifier in expression: " + String(identifier));
return nullptr;
}
@@ -3697,7 +3771,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PERIOD) {
completion_class = TAG_ARRAY;
p_block->block_tag = SubClassTag::TAG_ARRAY;
- call_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ call_expression = _parse_and_reduce_expression(p_block, p_function_info);
p_block->block_tag = SubClassTag::TAG_GLOBAL;
if (!call_expression) {
return nullptr;
@@ -3705,7 +3779,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
data_type = call_expression->get_datatype();
} else { // indexing
- index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
@@ -4085,7 +4159,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Nested array length() is not yet implemented");
return nullptr;
} else if (tk.type == TK_BRACKET_OPEN) {
- Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
@@ -4134,7 +4208,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
*/
} else if (tk.type == TK_BRACKET_OPEN) {
- Node *index = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *index = _parse_and_reduce_expression(p_block, p_function_info);
if (!index) {
return nullptr;
}
@@ -4276,7 +4350,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_assign(expr, p_builtin_types)) {
+ if (!_validate_assign(expr, p_function_info)) {
_set_error("Invalid use of increment/decrement operator in constant expression.");
return nullptr;
}
@@ -4574,7 +4648,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
for (int i = expr_pos - 1; i >= next_op; i--) {
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[i].op;
- if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) {
+ if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_function_info)) {
_set_error("Can't use increment/decrement operator in constant expression.");
return nullptr;
}
@@ -4648,7 +4722,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (_is_operator_assign(op->op)) {
String assign_message;
- if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) {
+ if (!_validate_assign(expression[next_op - 1].node, p_function_info, &assign_message)) {
_set_error(assign_message);
return nullptr;
}
@@ -4802,8 +4876,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
return p_node;
}
-ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
- ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types);
+ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
+ ShaderLanguage::Node *expr = _parse_expression(p_block, p_function_info);
if (!expr) { //errored
return nullptr;
}
@@ -4813,7 +4887,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_
return expr;
}
-Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) {
+Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one, bool p_can_break, bool p_can_continue) {
while (true) {
TkPos pos = _get_tkpos();
@@ -4897,7 +4971,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
StringName name = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(p_block, true, p_builtin_types, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
@@ -5016,7 +5090,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -5097,7 +5171,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5169,7 +5243,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
decl.initializer = nullptr;
//variable created with assignment! must parse an expression
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5229,7 +5303,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
//a sub block, just because..
BlockNode *block = alloc_node<BlockNode>();
block->parent_block = p_block;
- if (_parse_block(block, p_builtin_types, false, p_can_break, p_can_continue) != OK) {
+ if (_parse_block(block, p_function_info, false, p_can_break, p_can_continue) != OK) {
return ERR_PARSE_ERROR;
}
p_block->statements.push_back(block);
@@ -5243,7 +5317,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_IF;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5265,7 +5339,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+ Error err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue);
if (err) {
return err;
}
@@ -5276,7 +5350,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
block = alloc_node<BlockNode>();
block->parent_block = p_block;
cf->blocks.push_back(block);
- err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+ err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue);
} else {
_set_tkpos(pos); //rollback
@@ -5295,7 +5369,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_SWITCH;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5323,7 +5397,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
int prev_type = TK_CF_CASE;
while (true) { // Go-through multiple cases.
- if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) {
+ if (_parse_block(switch_block, p_function_info, true, true, false) != OK) {
return ERR_PARSE_ERROR;
}
pos = _get_tkpos();
@@ -5424,7 +5498,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(case_block);
p_block->statements.push_back(cf);
- Error err = _parse_block(case_block, p_builtin_types, false, true, false);
+ Error err = _parse_block(case_block, p_function_info, false, true, false);
if (err) {
return err;
}
@@ -5458,7 +5532,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(default_block);
p_block->statements.push_back(cf);
- Error err = _parse_block(default_block, p_builtin_types, false, true, false);
+ Error err = _parse_block(default_block, p_function_info, false, true, false);
if (err) {
return err;
}
@@ -5475,7 +5549,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
do_block = alloc_node<BlockNode>();
do_block->parent_block = p_block;
- Error err = _parse_block(do_block, p_builtin_types, true, true, true);
+ Error err = _parse_block(do_block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5499,7 +5573,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
cf->flow_op = FLOW_OP_WHILE;
}
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5516,7 +5590,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, true, true);
+ Error err = _parse_block(block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5547,11 +5621,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
init_block->parent_block = p_block;
init_block->single_statement = true;
cf->blocks.push_back(init_block);
- if (_parse_block(init_block, p_builtin_types, true, false, false) != OK) {
+ if (_parse_block(init_block, p_function_info, true, false, false) != OK) {
return ERR_PARSE_ERROR;
}
- Node *n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(init_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5569,7 +5643,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->expressions.push_back(n);
- n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ n = _parse_and_reduce_expression(init_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5587,7 +5661,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, true, true);
+ Error err = _parse_block(block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5623,7 +5697,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
} else {
_set_tkpos(pos); //rollback, wants expression
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -5725,7 +5799,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
//nothing else, so expression
_set_tkpos(pos); //rollback
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -6066,7 +6140,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
name = tk.text;
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6315,7 +6389,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//reset scope for next uniform
if (tk.type == TK_OP_ASSIGN) {
- Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
+ Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -6440,7 +6514,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6553,7 +6627,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -6634,7 +6708,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -6689,7 +6763,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
} else {
//variable created with assignment! must parse an expression
- Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!expr)
return ERR_PARSE_ERROR;
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
@@ -6726,7 +6800,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
name = tk.text;
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6749,14 +6823,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
break;
}
- Map<StringName, BuiltInInfo> builtin_types;
+ FunctionInfo builtins;
if (p_functions.has(name)) {
- builtin_types = p_functions[name].built_ins;
+ builtins = p_functions[name];
}
if (p_functions.has("global")) { // Adds global variables: 'TIME'
for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
- builtin_types.insert(E->key(), E->value());
+ builtins.built_ins.insert(E->key(), E->value());
}
}
@@ -6879,7 +6953,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
pname = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(func_node->body, false, builtin_types, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
_set_error("Redefinition of '" + String(pname) + "'");
return ERR_PARSE_ERROR;
@@ -6941,7 +7015,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
current_function = name;
- Error err = _parse_block(func_node->body, builtin_types);
+ Error err = _parse_block(func_node->body, builtins);
if (err) {
return err;
}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index faf06a9a85..0d044a21c7 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -730,8 +730,25 @@ public:
constant(p_constant) {}
};
+ struct StageFunctionInfo {
+ struct Argument {
+ StringName name;
+ DataType type;
+
+ Argument(const StringName &p_name = StringName(), DataType p_type = TYPE_VOID) {
+ name = p_name;
+ type = p_type;
+ }
+ };
+
+ Vector<Argument> arguments;
+ DataType return_type = TYPE_VOID;
+ };
+
struct FunctionInfo {
Map<StringName, BuiltInInfo> built_ins;
+ Map<StringName, StageFunctionInfo> stage_functions;
+
bool can_discard;
};
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
@@ -802,9 +819,9 @@ private:
IDENTIFIER_CONSTANT,
};
- bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
+ bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
bool _is_operator_assign(Operator p_op) const;
- bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = nullptr);
+ bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
struct BuiltinFuncDef {
@@ -837,16 +854,16 @@ private:
Error _validate_datatype(DataType p_type);
bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
- bool _validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
- bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr);
+ bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
+ bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
- Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
+ Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
- Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
- Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
+ Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ Error _parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
String _get_shader_type_list(const Set<String> &p_shader_types) const;
String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 9c4f44b928..f3ef322ad7 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -283,8 +283,29 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["compute"].can_discard = false;
+ {
+ ShaderLanguage::StageFunctionInfo emit_vertex_func;
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("xform", ShaderLanguage::TYPE_MAT4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("velocity", ShaderLanguage::TYPE_VEC3));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("color", ShaderLanguage::TYPE_VEC4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
+ emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_particle"] = emit_vertex_func;
+ }
+
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_force");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_velocity");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("keep_data");