|
@@ -29,6 +29,7 @@
|
|
|
/**************************************************************************/
|
|
|
|
|
|
#include "cpu_particles_2d.h"
|
|
|
+#include "cpu_particles_2d.compat.inc"
|
|
|
|
|
|
#include "scene/2d/gpu_particles_2d.h"
|
|
|
#include "scene/resources/atlas_texture.h"
|
|
@@ -261,7 +262,7 @@ PackedStringArray CPUParticles2D::get_configuration_warnings() const {
|
|
|
return warnings;
|
|
|
}
|
|
|
|
|
|
-void CPUParticles2D::restart() {
|
|
|
+void CPUParticles2D::restart(bool p_keep_seed) {
|
|
|
time = 0;
|
|
|
frame_remainder = 0;
|
|
|
cycle = 0;
|
|
@@ -275,6 +276,9 @@ void CPUParticles2D::restart() {
|
|
|
w[i].active = false;
|
|
|
}
|
|
|
}
|
|
|
+ if (!p_keep_seed && !use_fixed_seed) {
|
|
|
+ seed = Math::rand();
|
|
|
+ }
|
|
|
|
|
|
set_emitting(true);
|
|
|
}
|
|
@@ -506,6 +510,30 @@ bool CPUParticles2D::get_split_scale() {
|
|
|
return split_scale;
|
|
|
}
|
|
|
|
|
|
+void CPUParticles2D::set_use_fixed_seed(bool p_use_fixed_seed) {
|
|
|
+ if (p_use_fixed_seed == use_fixed_seed) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ use_fixed_seed = p_use_fixed_seed;
|
|
|
+ notify_property_list_changed();
|
|
|
+}
|
|
|
+
|
|
|
+bool CPUParticles2D::get_use_fixed_seed() const {
|
|
|
+ return use_fixed_seed;
|
|
|
+}
|
|
|
+
|
|
|
+void CPUParticles2D::set_seed(uint32_t p_seed) {
|
|
|
+ seed = p_seed;
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t CPUParticles2D::get_seed() const {
|
|
|
+ return seed;
|
|
|
+}
|
|
|
+
|
|
|
+void CPUParticles2D::request_particles_process(real_t p_requested_process_time) {
|
|
|
+ _requested_process_time = p_requested_process_time;
|
|
|
+}
|
|
|
+
|
|
|
void CPUParticles2D::_validate_property(PropertyInfo &p_property) const {
|
|
|
if (p_property.name == "emitting") {
|
|
|
p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
|
|
@@ -537,6 +565,10 @@ void CPUParticles2D::_validate_property(PropertyInfo &p_property) const {
|
|
|
if (p_property.name.begins_with("scale_curve_") && !split_scale) {
|
|
|
p_property.usage = PROPERTY_USAGE_NONE;
|
|
|
}
|
|
|
+
|
|
|
+ if (p_property.name == "seed" && !use_fixed_seed) {
|
|
|
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static uint32_t idhash(uint32_t x) {
|
|
@@ -579,25 +611,28 @@ void CPUParticles2D::_update_internal() {
|
|
|
return;
|
|
|
}
|
|
|
_set_do_redraw(true);
|
|
|
-
|
|
|
+ double frame_time;
|
|
|
+ if (fixed_fps > 0) {
|
|
|
+ frame_time = 1.0 / fixed_fps;
|
|
|
+ } else {
|
|
|
+ frame_time = 1.0 / 30.0;
|
|
|
+ }
|
|
|
+ double todo = _requested_process_time;
|
|
|
+ _requested_process_time = 0;
|
|
|
if (time == 0 && pre_process_time > 0.0) {
|
|
|
- double frame_time;
|
|
|
- if (fixed_fps > 0) {
|
|
|
- frame_time = 1.0 / fixed_fps;
|
|
|
- } else {
|
|
|
- frame_time = 1.0 / 30.0;
|
|
|
- }
|
|
|
-
|
|
|
- double todo = pre_process_time;
|
|
|
-
|
|
|
- while (todo >= 0) {
|
|
|
- _particles_process(frame_time);
|
|
|
- todo -= frame_time;
|
|
|
- }
|
|
|
+ todo += pre_process_time;
|
|
|
}
|
|
|
+ real_t tmp_speed = speed_scale;
|
|
|
+ speed_scale = 1.0;
|
|
|
+ while (todo > 0) {
|
|
|
+ _particles_process(frame_time);
|
|
|
+ todo -= frame_time;
|
|
|
+ }
|
|
|
+ speed_scale = tmp_speed;
|
|
|
+
|
|
|
+ todo = 0.0;
|
|
|
|
|
|
if (fixed_fps > 0) {
|
|
|
- double frame_time = 1.0 / fixed_fps;
|
|
|
double decr = frame_time;
|
|
|
|
|
|
double ldelta = delta;
|
|
@@ -606,13 +641,12 @@ void CPUParticles2D::_update_internal() {
|
|
|
} else if (ldelta <= 0.0) { //unlikely but..
|
|
|
ldelta = 0.001;
|
|
|
}
|
|
|
- double todo = frame_remainder + ldelta;
|
|
|
+ todo = frame_remainder + ldelta;
|
|
|
|
|
|
while (todo >= frame_time) {
|
|
|
_particles_process(frame_time);
|
|
|
todo -= decr;
|
|
|
}
|
|
|
-
|
|
|
frame_remainder = todo;
|
|
|
|
|
|
} else {
|
|
@@ -667,13 +701,13 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
double restart_phase = double(i) / double(pcount);
|
|
|
|
|
|
if (randomness_ratio > 0.0) {
|
|
|
- uint32_t seed = cycle;
|
|
|
+ uint32_t _seed = cycle;
|
|
|
if (restart_phase >= system_phase) {
|
|
|
- seed -= uint32_t(1);
|
|
|
+ _seed -= uint32_t(1);
|
|
|
}
|
|
|
- seed *= uint32_t(pcount);
|
|
|
- seed += uint32_t(i);
|
|
|
- double random = double(idhash(seed) % uint32_t(65536)) / 65536.0;
|
|
|
+ _seed *= uint32_t(pcount);
|
|
|
+ _seed += uint32_t(i);
|
|
|
+ double random = double(idhash(_seed) % uint32_t(65536)) / 65536.0;
|
|
|
restart_phase += randomness_ratio * random * 1.0 / double(pcount);
|
|
|
}
|
|
|
|
|
@@ -734,22 +768,23 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
|
|
|
}
|
|
|
|
|
|
- p.seed = Math::rand();
|
|
|
+ p.seed = seed + uint32_t(i) + i + cycle;
|
|
|
+ uint32_t _seed = p.seed;
|
|
|
|
|
|
- p.angle_rand = Math::randf();
|
|
|
- p.scale_rand = Math::randf();
|
|
|
- p.hue_rot_rand = Math::randf();
|
|
|
- p.anim_offset_rand = Math::randf();
|
|
|
+ p.angle_rand = rand_from_seed(_seed);
|
|
|
+ p.scale_rand = rand_from_seed(_seed);
|
|
|
+ p.hue_rot_rand = rand_from_seed(_seed);
|
|
|
+ p.anim_offset_rand = rand_from_seed(_seed);
|
|
|
|
|
|
if (color_initial_ramp.is_valid()) {
|
|
|
- p.start_color_rand = color_initial_ramp->get_color_at_offset(Math::randf());
|
|
|
+ p.start_color_rand = color_initial_ramp->get_color_at_offset(rand_from_seed(_seed));
|
|
|
} else {
|
|
|
p.start_color_rand = Color(1, 1, 1, 1);
|
|
|
}
|
|
|
|
|
|
- real_t angle1_rad = direction.angle() + Math::deg_to_rad((Math::randf() * 2.0 - 1.0) * spread);
|
|
|
+ real_t angle1_rad = direction.angle() + Math::deg_to_rad((rand_from_seed(_seed) * 2.0 - 1.0) * spread);
|
|
|
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
|
|
|
- p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf());
|
|
|
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)rand_from_seed(_seed));
|
|
|
|
|
|
real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
|
|
|
p.rotation = Math::deg_to_rad(base_angle);
|
|
@@ -757,7 +792,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
p.custom[0] = 0.0; // unused
|
|
|
p.custom[1] = 0.0; // phase [0..1]
|
|
|
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand);
|
|
|
- p.custom[3] = (1.0 - Math::randf() * lifetime_randomness);
|
|
|
+ p.custom[3] = (1.0 - rand_from_seed(_seed) * lifetime_randomness);
|
|
|
p.transform = Transform2D();
|
|
|
p.time = 0;
|
|
|
p.lifetime = lifetime * p.custom[3];
|
|
@@ -768,17 +803,17 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
//do none
|
|
|
} break;
|
|
|
case EMISSION_SHAPE_SPHERE: {
|
|
|
- real_t t = Math_TAU * Math::randf();
|
|
|
- real_t radius = emission_sphere_radius * Math::randf();
|
|
|
+ real_t t = Math_TAU * rand_from_seed(_seed);
|
|
|
+ real_t radius = emission_sphere_radius * rand_from_seed(_seed);
|
|
|
p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius;
|
|
|
} break;
|
|
|
case EMISSION_SHAPE_SPHERE_SURFACE: {
|
|
|
- real_t s = Math::randf(), t = Math_TAU * Math::randf();
|
|
|
+ real_t s = rand_from_seed(_seed), t = Math_TAU * rand_from_seed(_seed);
|
|
|
real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
|
|
|
p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius;
|
|
|
} break;
|
|
|
case EMISSION_SHAPE_RECTANGLE: {
|
|
|
- p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_rect_extents;
|
|
|
+ p.transform[2] = Vector2(rand_from_seed(_seed) * 2.0 - 1.0, rand_from_seed(_seed) * 2.0 - 1.0) * emission_rect_extents;
|
|
|
} break;
|
|
|
case EMISSION_SHAPE_POINTS:
|
|
|
case EMISSION_SHAPE_DIRECTED_POINTS: {
|
|
@@ -819,8 +854,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
p.active = false;
|
|
|
tv = 1.0;
|
|
|
} else {
|
|
|
- uint32_t alt_seed = p.seed;
|
|
|
-
|
|
|
+ uint32_t _seed = p.seed;
|
|
|
p.time += local_delta;
|
|
|
p.custom[1] = p.time / lifetime;
|
|
|
tv = p.time / p.lifetime;
|
|
@@ -878,18 +912,18 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
Vector2 pos = p.transform[2];
|
|
|
|
|
|
//apply linear acceleration
|
|
|
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector2();
|
|
|
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(_seed)) : Vector2();
|
|
|
//apply radial acceleration
|
|
|
Vector2 org = emission_xform[2];
|
|
|
Vector2 diff = pos - org;
|
|
|
- force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector2();
|
|
|
+ force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(_seed)) : Vector2();
|
|
|
//apply tangential acceleration;
|
|
|
Vector2 yx = Vector2(diff.y, diff.x);
|
|
|
- force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector2();
|
|
|
+ force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(_seed))) : Vector2();
|
|
|
//apply attractor forces
|
|
|
p.velocity += force * local_delta;
|
|
|
//orbit velocity
|
|
|
- real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
|
|
|
+ real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(_seed));
|
|
|
if (orbit_amount != 0.0) {
|
|
|
real_t ang = orbit_amount * local_delta * Math_TAU;
|
|
|
// Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix,
|
|
@@ -904,7 +938,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
|
|
|
if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
|
|
|
real_t v = p.velocity.length();
|
|
|
- real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
|
|
|
+ real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(_seed));
|
|
|
v -= damp * local_delta;
|
|
|
if (v < 0.0) {
|
|
|
p.velocity = Vector2();
|
|
@@ -913,9 +947,9 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
|
|
}
|
|
|
}
|
|
|
real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
|
|
|
- base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
|
|
|
+ base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(_seed));
|
|
|
p.rotation = Math::deg_to_rad(base_angle); //angle
|
|
|
- p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed));
|
|
|
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(_seed));
|
|
|
}
|
|
|
//apply color
|
|
|
//apply hue rotation
|
|
@@ -1267,6 +1301,7 @@ void CPUParticles2D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles2D::set_fixed_fps);
|
|
|
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles2D::set_fractional_delta);
|
|
|
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles2D::set_speed_scale);
|
|
|
+ ClassDB::bind_method(D_METHOD("request_particles_process", "process_time"), &CPUParticles2D::request_particles_process);
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles2D::is_emitting);
|
|
|
ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles2D::get_amount);
|
|
@@ -1280,6 +1315,11 @@ void CPUParticles2D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles2D::get_fixed_fps);
|
|
|
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles2D::get_fractional_delta);
|
|
|
ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles2D::get_speed_scale);
|
|
|
+ ClassDB::bind_method(D_METHOD("set_use_fixed_seed", "use_fixed_seed"), &CPUParticles2D::set_use_fixed_seed);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_use_fixed_seed"), &CPUParticles2D::get_use_fixed_seed);
|
|
|
+
|
|
|
+ ClassDB::bind_method(D_METHOD("set_seed", "seed"), &CPUParticles2D::set_seed);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_seed"), &CPUParticles2D::get_seed);
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles2D::set_draw_order);
|
|
|
|
|
@@ -1288,7 +1328,7 @@ void CPUParticles2D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &CPUParticles2D::set_texture);
|
|
|
ClassDB::bind_method(D_METHOD("get_texture"), &CPUParticles2D::get_texture);
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart);
|
|
|
+ ClassDB::bind_method(D_METHOD("restart", "keep_seed"), &CPUParticles2D::restart, DEFVAL(false));
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); // FIXME: Evaluate support for `exp` in integer properties, or remove this.
|
|
@@ -1299,6 +1339,8 @@ void CPUParticles2D::_bind_methods() {
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_fixed_seed"), "set_use_fixed_seed", "get_use_fixed_seed");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "seed", PROPERTY_HINT_RANGE, "0," + itos(UINT32_MAX) + ",1"), "set_seed", "get_seed");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
|