| 1 | /**************************************************************************/ | 
|---|
| 2 | /*  cpu_particles_2d.cpp                                                  */ | 
|---|
| 3 | /**************************************************************************/ | 
|---|
| 4 | /*                         This file is part of:                          */ | 
|---|
| 5 | /*                             GODOT ENGINE                               */ | 
|---|
| 6 | /*                        https://godotengine.org                         */ | 
|---|
| 7 | /**************************************************************************/ | 
|---|
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
|---|
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
|---|
| 10 | /*                                                                        */ | 
|---|
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
|---|
| 12 | /* a copy of this software and associated documentation files (the        */ | 
|---|
| 13 | /* "Software"), to deal in the Software without restriction, including    */ | 
|---|
| 14 | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
|---|
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
|---|
| 16 | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
|---|
| 17 | /* the following conditions:                                              */ | 
|---|
| 18 | /*                                                                        */ | 
|---|
| 19 | /* The above copyright notice and this permission notice shall be         */ | 
|---|
| 20 | /* included in all copies or substantial portions of the Software.        */ | 
|---|
| 21 | /*                                                                        */ | 
|---|
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
|---|
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
|---|
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
|---|
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
|---|
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
|---|
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
|---|
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
|---|
| 29 | /**************************************************************************/ | 
|---|
| 30 |  | 
|---|
| 31 | #include "cpu_particles_2d.h" | 
|---|
| 32 |  | 
|---|
| 33 | #include "scene/2d/gpu_particles_2d.h" | 
|---|
| 34 | #include "scene/resources/atlas_texture.h" | 
|---|
| 35 | #include "scene/resources/curve_texture.h" | 
|---|
| 36 | #include "scene/resources/gradient_texture.h" | 
|---|
| 37 | #include "scene/resources/particle_process_material.h" | 
|---|
| 38 | #include "scene/scene_string_names.h" | 
|---|
| 39 |  | 
|---|
| 40 | void CPUParticles2D::set_emitting(bool p_emitting) { | 
|---|
| 41 | if (emitting == p_emitting) { | 
|---|
| 42 | return; | 
|---|
| 43 | } | 
|---|
| 44 |  | 
|---|
| 45 | emitting = p_emitting; | 
|---|
| 46 | if (emitting) { | 
|---|
| 47 | active = true; | 
|---|
| 48 | set_process_internal(true); | 
|---|
| 49 | } | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | void CPUParticles2D::set_amount(int p_amount) { | 
|---|
| 53 | ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0."); | 
|---|
| 54 |  | 
|---|
| 55 | particles.resize(p_amount); | 
|---|
| 56 | { | 
|---|
| 57 | Particle *w = particles.ptrw(); | 
|---|
| 58 |  | 
|---|
| 59 | for (int i = 0; i < p_amount; i++) { | 
|---|
| 60 | w[i].active = false; | 
|---|
| 61 | } | 
|---|
| 62 | } | 
|---|
| 63 |  | 
|---|
| 64 | particle_data.resize((8 + 4 + 4) * p_amount); | 
|---|
| 65 | RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true); | 
|---|
| 66 |  | 
|---|
| 67 | particle_order.resize(p_amount); | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | void CPUParticles2D::set_lifetime(double p_lifetime) { | 
|---|
| 71 | ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); | 
|---|
| 72 | lifetime = p_lifetime; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | void CPUParticles2D::set_one_shot(bool p_one_shot) { | 
|---|
| 76 | one_shot = p_one_shot; | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | void CPUParticles2D::set_pre_process_time(double p_time) { | 
|---|
| 80 | pre_process_time = p_time; | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | void CPUParticles2D::set_explosiveness_ratio(real_t p_ratio) { | 
|---|
| 84 | explosiveness_ratio = p_ratio; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | void CPUParticles2D::set_randomness_ratio(real_t p_ratio) { | 
|---|
| 88 | randomness_ratio = p_ratio; | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | void CPUParticles2D::set_lifetime_randomness(double p_random) { | 
|---|
| 92 | lifetime_randomness = p_random; | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | void CPUParticles2D::set_use_local_coordinates(bool p_enable) { | 
|---|
| 96 | local_coords = p_enable; | 
|---|
| 97 | set_notify_transform(!p_enable); | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | void CPUParticles2D::set_speed_scale(double p_scale) { | 
|---|
| 101 | speed_scale = p_scale; | 
|---|
| 102 | } | 
|---|
| 103 |  | 
|---|
| 104 | bool CPUParticles2D::is_emitting() const { | 
|---|
| 105 | return emitting; | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | int CPUParticles2D::get_amount() const { | 
|---|
| 109 | return particles.size(); | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | double CPUParticles2D::get_lifetime() const { | 
|---|
| 113 | return lifetime; | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | bool CPUParticles2D::get_one_shot() const { | 
|---|
| 117 | return one_shot; | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | double CPUParticles2D::get_pre_process_time() const { | 
|---|
| 121 | return pre_process_time; | 
|---|
| 122 | } | 
|---|
| 123 |  | 
|---|
| 124 | real_t CPUParticles2D::get_explosiveness_ratio() const { | 
|---|
| 125 | return explosiveness_ratio; | 
|---|
| 126 | } | 
|---|
| 127 |  | 
|---|
| 128 | real_t CPUParticles2D::get_randomness_ratio() const { | 
|---|
| 129 | return randomness_ratio; | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | double CPUParticles2D::get_lifetime_randomness() const { | 
|---|
| 133 | return lifetime_randomness; | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | bool CPUParticles2D::get_use_local_coordinates() const { | 
|---|
| 137 | return local_coords; | 
|---|
| 138 | } | 
|---|
| 139 |  | 
|---|
| 140 | double CPUParticles2D::get_speed_scale() const { | 
|---|
| 141 | return speed_scale; | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | void CPUParticles2D::set_draw_order(DrawOrder p_order) { | 
|---|
| 145 | draw_order = p_order; | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | CPUParticles2D::DrawOrder CPUParticles2D::get_draw_order() const { | 
|---|
| 149 | return draw_order; | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | void CPUParticles2D::_update_mesh_texture() { | 
|---|
| 153 | Size2 tex_size; | 
|---|
| 154 | if (texture.is_valid()) { | 
|---|
| 155 | tex_size = texture->get_size(); | 
|---|
| 156 | } else { | 
|---|
| 157 | tex_size = Size2(1, 1); | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | Vector<Vector2> vertices = { | 
|---|
| 161 | -tex_size * 0.5, | 
|---|
| 162 | -tex_size * 0.5 + Vector2(tex_size.x, 0), | 
|---|
| 163 | -tex_size * 0.5 + tex_size, | 
|---|
| 164 | -tex_size * 0.5 + Vector2(0, tex_size.y) | 
|---|
| 165 | }; | 
|---|
| 166 |  | 
|---|
| 167 | Vector<Vector2> uvs; | 
|---|
| 168 | AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); | 
|---|
| 169 | if (atlas_texure && atlas_texure->get_atlas().is_valid()) { | 
|---|
| 170 | Rect2 region_rect = atlas_texure->get_region(); | 
|---|
| 171 | Size2 atlas_size = atlas_texure->get_atlas()->get_size(); | 
|---|
| 172 | uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, region_rect.position.y / atlas_size.y)); | 
|---|
| 173 | uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, region_rect.position.y / atlas_size.y)); | 
|---|
| 174 | uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); | 
|---|
| 175 | uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); | 
|---|
| 176 | } else { | 
|---|
| 177 | uvs.push_back(Vector2(0, 0)); | 
|---|
| 178 | uvs.push_back(Vector2(1, 0)); | 
|---|
| 179 | uvs.push_back(Vector2(1, 1)); | 
|---|
| 180 | uvs.push_back(Vector2(0, 1)); | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | Vector<Color> colors = { | 
|---|
| 184 | Color(1, 1, 1, 1), | 
|---|
| 185 | Color(1, 1, 1, 1), | 
|---|
| 186 | Color(1, 1, 1, 1), | 
|---|
| 187 | Color(1, 1, 1, 1) | 
|---|
| 188 | }; | 
|---|
| 189 |  | 
|---|
| 190 | Vector<int> indices = { 0, 1, 2, 2, 3, 0 }; | 
|---|
| 191 |  | 
|---|
| 192 | Array arr; | 
|---|
| 193 | arr.resize(RS::ARRAY_MAX); | 
|---|
| 194 | arr[RS::ARRAY_VERTEX] = vertices; | 
|---|
| 195 | arr[RS::ARRAY_TEX_UV] = uvs; | 
|---|
| 196 | arr[RS::ARRAY_COLOR] = colors; | 
|---|
| 197 | arr[RS::ARRAY_INDEX] = indices; | 
|---|
| 198 |  | 
|---|
| 199 | RS::get_singleton()->mesh_clear(mesh); | 
|---|
| 200 | RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr); | 
|---|
| 201 | } | 
|---|
| 202 |  | 
|---|
| 203 | void CPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) { | 
|---|
| 204 | if (p_texture == texture) { | 
|---|
| 205 | return; | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | if (texture.is_valid()) { | 
|---|
| 209 | texture->disconnect_changed(callable_mp(this, &CPUParticles2D::_texture_changed)); | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|
| 212 | texture = p_texture; | 
|---|
| 213 |  | 
|---|
| 214 | if (texture.is_valid()) { | 
|---|
| 215 | texture->connect_changed(callable_mp(this, &CPUParticles2D::_texture_changed)); | 
|---|
| 216 | } | 
|---|
| 217 |  | 
|---|
| 218 | queue_redraw(); | 
|---|
| 219 | _update_mesh_texture(); | 
|---|
| 220 | } | 
|---|
| 221 |  | 
|---|
| 222 | void CPUParticles2D::_texture_changed() { | 
|---|
| 223 | if (texture.is_valid()) { | 
|---|
| 224 | queue_redraw(); | 
|---|
| 225 | _update_mesh_texture(); | 
|---|
| 226 | } | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | Ref<Texture2D> CPUParticles2D::get_texture() const { | 
|---|
| 230 | return texture; | 
|---|
| 231 | } | 
|---|
| 232 |  | 
|---|
| 233 | void CPUParticles2D::set_fixed_fps(int p_count) { | 
|---|
| 234 | fixed_fps = p_count; | 
|---|
| 235 | } | 
|---|
| 236 |  | 
|---|
| 237 | int CPUParticles2D::get_fixed_fps() const { | 
|---|
| 238 | return fixed_fps; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | void CPUParticles2D::set_fractional_delta(bool p_enable) { | 
|---|
| 242 | fractional_delta = p_enable; | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | bool CPUParticles2D::get_fractional_delta() const { | 
|---|
| 246 | return fractional_delta; | 
|---|
| 247 | } | 
|---|
| 248 |  | 
|---|
| 249 | PackedStringArray CPUParticles2D::get_configuration_warnings() const { | 
|---|
| 250 | PackedStringArray warnings = Node2D::get_configuration_warnings(); | 
|---|
| 251 |  | 
|---|
| 252 | CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); | 
|---|
| 253 |  | 
|---|
| 254 | if (get_material().is_null() || (mat && !mat->get_particles_animation())) { | 
|---|
| 255 | if (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 || | 
|---|
| 256 | get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) { | 
|---|
| 257 | warnings.push_back(RTR( "CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); | 
|---|
| 258 | } | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 | return warnings; | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | void CPUParticles2D::restart() { | 
|---|
| 265 | time = 0; | 
|---|
| 266 | frame_remainder = 0; | 
|---|
| 267 | cycle = 0; | 
|---|
| 268 | emitting = false; | 
|---|
| 269 |  | 
|---|
| 270 | { | 
|---|
| 271 | int pc = particles.size(); | 
|---|
| 272 | Particle *w = particles.ptrw(); | 
|---|
| 273 |  | 
|---|
| 274 | for (int i = 0; i < pc; i++) { | 
|---|
| 275 | w[i].active = false; | 
|---|
| 276 | } | 
|---|
| 277 | } | 
|---|
| 278 |  | 
|---|
| 279 | set_emitting(true); | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | void CPUParticles2D::set_direction(Vector2 p_direction) { | 
|---|
| 283 | direction = p_direction; | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 | Vector2 CPUParticles2D::get_direction() const { | 
|---|
| 287 | return direction; | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | void CPUParticles2D::set_spread(real_t p_spread) { | 
|---|
| 291 | spread = p_spread; | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | real_t CPUParticles2D::get_spread() const { | 
|---|
| 295 | return spread; | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | void CPUParticles2D::set_param_min(Parameter p_param, real_t p_value) { | 
|---|
| 299 | ERR_FAIL_INDEX(p_param, PARAM_MAX); | 
|---|
| 300 |  | 
|---|
| 301 | parameters_min[p_param] = p_value; | 
|---|
| 302 | if (parameters_min[p_param] > parameters_max[p_param]) { | 
|---|
| 303 | set_param_max(p_param, p_value); | 
|---|
| 304 | } | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | real_t CPUParticles2D::get_param_min(Parameter p_param) const { | 
|---|
| 308 | ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); | 
|---|
| 309 |  | 
|---|
| 310 | return parameters_min[p_param]; | 
|---|
| 311 | } | 
|---|
| 312 |  | 
|---|
| 313 | void CPUParticles2D::set_param_max(Parameter p_param, real_t p_value) { | 
|---|
| 314 | ERR_FAIL_INDEX(p_param, PARAM_MAX); | 
|---|
| 315 |  | 
|---|
| 316 | parameters_max[p_param] = p_value; | 
|---|
| 317 | if (parameters_min[p_param] > parameters_max[p_param]) { | 
|---|
| 318 | set_param_min(p_param, p_value); | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 | update_configuration_warnings(); | 
|---|
| 322 | } | 
|---|
| 323 |  | 
|---|
| 324 | real_t CPUParticles2D::get_param_max(Parameter p_param) const { | 
|---|
| 325 | ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); | 
|---|
| 326 |  | 
|---|
| 327 | return parameters_max[p_param]; | 
|---|
| 328 | } | 
|---|
| 329 |  | 
|---|
| 330 | static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) { | 
|---|
| 331 | Ref<Curve> curve = p_curve; | 
|---|
| 332 | if (!curve.is_valid()) { | 
|---|
| 333 | return; | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | curve->ensure_default_setup(p_min, p_max); | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) { | 
|---|
| 340 | ERR_FAIL_INDEX(p_param, PARAM_MAX); | 
|---|
| 341 |  | 
|---|
| 342 | curve_parameters[p_param] = p_curve; | 
|---|
| 343 |  | 
|---|
| 344 | switch (p_param) { | 
|---|
| 345 | case PARAM_INITIAL_LINEAR_VELOCITY: { | 
|---|
| 346 | //do none for this one | 
|---|
| 347 | } break; | 
|---|
| 348 | case PARAM_ANGULAR_VELOCITY: { | 
|---|
| 349 | _adjust_curve_range(p_curve, -360, 360); | 
|---|
| 350 | } break; | 
|---|
| 351 | case PARAM_ORBIT_VELOCITY: { | 
|---|
| 352 | _adjust_curve_range(p_curve, -500, 500); | 
|---|
| 353 | } break; | 
|---|
| 354 | case PARAM_LINEAR_ACCEL: { | 
|---|
| 355 | _adjust_curve_range(p_curve, -200, 200); | 
|---|
| 356 | } break; | 
|---|
| 357 | case PARAM_RADIAL_ACCEL: { | 
|---|
| 358 | _adjust_curve_range(p_curve, -200, 200); | 
|---|
| 359 | } break; | 
|---|
| 360 | case PARAM_TANGENTIAL_ACCEL: { | 
|---|
| 361 | _adjust_curve_range(p_curve, -200, 200); | 
|---|
| 362 | } break; | 
|---|
| 363 | case PARAM_DAMPING: { | 
|---|
| 364 | _adjust_curve_range(p_curve, 0, 100); | 
|---|
| 365 | } break; | 
|---|
| 366 | case PARAM_ANGLE: { | 
|---|
| 367 | _adjust_curve_range(p_curve, -360, 360); | 
|---|
| 368 | } break; | 
|---|
| 369 | case PARAM_SCALE: { | 
|---|
| 370 | } break; | 
|---|
| 371 | case PARAM_HUE_VARIATION: { | 
|---|
| 372 | _adjust_curve_range(p_curve, -1, 1); | 
|---|
| 373 | } break; | 
|---|
| 374 | case PARAM_ANIM_SPEED: { | 
|---|
| 375 | _adjust_curve_range(p_curve, 0, 200); | 
|---|
| 376 | } break; | 
|---|
| 377 | case PARAM_ANIM_OFFSET: { | 
|---|
| 378 | } break; | 
|---|
| 379 | default: { | 
|---|
| 380 | } | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | update_configuration_warnings(); | 
|---|
| 384 | } | 
|---|
| 385 |  | 
|---|
| 386 | Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const { | 
|---|
| 387 | ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>()); | 
|---|
| 388 |  | 
|---|
| 389 | return curve_parameters[p_param]; | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | void CPUParticles2D::set_color(const Color &p_color) { | 
|---|
| 393 | color = p_color; | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 | Color CPUParticles2D::get_color() const { | 
|---|
| 397 | return color; | 
|---|
| 398 | } | 
|---|
| 399 |  | 
|---|
| 400 | void CPUParticles2D::set_color_ramp(const Ref<Gradient> &p_ramp) { | 
|---|
| 401 | color_ramp = p_ramp; | 
|---|
| 402 | } | 
|---|
| 403 |  | 
|---|
| 404 | Ref<Gradient> CPUParticles2D::get_color_ramp() const { | 
|---|
| 405 | return color_ramp; | 
|---|
| 406 | } | 
|---|
| 407 |  | 
|---|
| 408 | void CPUParticles2D::set_color_initial_ramp(const Ref<Gradient> &p_ramp) { | 
|---|
| 409 | color_initial_ramp = p_ramp; | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | Ref<Gradient> CPUParticles2D::get_color_initial_ramp() const { | 
|---|
| 413 | return color_initial_ramp; | 
|---|
| 414 | } | 
|---|
| 415 |  | 
|---|
| 416 | void CPUParticles2D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { | 
|---|
| 417 | ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); | 
|---|
| 418 | particle_flags[p_particle_flag] = p_enable; | 
|---|
| 419 | } | 
|---|
| 420 |  | 
|---|
| 421 | bool CPUParticles2D::get_particle_flag(ParticleFlags p_particle_flag) const { | 
|---|
| 422 | ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); | 
|---|
| 423 | return particle_flags[p_particle_flag]; | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | void CPUParticles2D::set_emission_shape(EmissionShape p_shape) { | 
|---|
| 427 | ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); | 
|---|
| 428 | emission_shape = p_shape; | 
|---|
| 429 | notify_property_list_changed(); | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | void CPUParticles2D::set_emission_sphere_radius(real_t p_radius) { | 
|---|
| 433 | emission_sphere_radius = p_radius; | 
|---|
| 434 | } | 
|---|
| 435 |  | 
|---|
| 436 | void CPUParticles2D::set_emission_rect_extents(Vector2 p_extents) { | 
|---|
| 437 | emission_rect_extents = p_extents; | 
|---|
| 438 | } | 
|---|
| 439 |  | 
|---|
| 440 | void CPUParticles2D::set_emission_points(const Vector<Vector2> &p_points) { | 
|---|
| 441 | emission_points = p_points; | 
|---|
| 442 | } | 
|---|
| 443 |  | 
|---|
| 444 | void CPUParticles2D::set_emission_normals(const Vector<Vector2> &p_normals) { | 
|---|
| 445 | emission_normals = p_normals; | 
|---|
| 446 | } | 
|---|
| 447 |  | 
|---|
| 448 | void CPUParticles2D::set_emission_colors(const Vector<Color> &p_colors) { | 
|---|
| 449 | emission_colors = p_colors; | 
|---|
| 450 | } | 
|---|
| 451 |  | 
|---|
| 452 | real_t CPUParticles2D::get_emission_sphere_radius() const { | 
|---|
| 453 | return emission_sphere_radius; | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | Vector2 CPUParticles2D::get_emission_rect_extents() const { | 
|---|
| 457 | return emission_rect_extents; | 
|---|
| 458 | } | 
|---|
| 459 |  | 
|---|
| 460 | Vector<Vector2> CPUParticles2D::get_emission_points() const { | 
|---|
| 461 | return emission_points; | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | Vector<Vector2> CPUParticles2D::get_emission_normals() const { | 
|---|
| 465 | return emission_normals; | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|
| 468 | Vector<Color> CPUParticles2D::get_emission_colors() const { | 
|---|
| 469 | return emission_colors; | 
|---|
| 470 | } | 
|---|
| 471 |  | 
|---|
| 472 | CPUParticles2D::EmissionShape CPUParticles2D::get_emission_shape() const { | 
|---|
| 473 | return emission_shape; | 
|---|
| 474 | } | 
|---|
| 475 |  | 
|---|
| 476 | void CPUParticles2D::set_gravity(const Vector2 &p_gravity) { | 
|---|
| 477 | gravity = p_gravity; | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 | Vector2 CPUParticles2D::get_gravity() const { | 
|---|
| 481 | return gravity; | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 | void CPUParticles2D::set_scale_curve_x(Ref<Curve> p_scale_curve) { | 
|---|
| 485 | scale_curve_x = p_scale_curve; | 
|---|
| 486 | } | 
|---|
| 487 |  | 
|---|
| 488 | void CPUParticles2D::set_scale_curve_y(Ref<Curve> p_scale_curve) { | 
|---|
| 489 | scale_curve_y = p_scale_curve; | 
|---|
| 490 | } | 
|---|
| 491 |  | 
|---|
| 492 | void CPUParticles2D::set_split_scale(bool p_split_scale) { | 
|---|
| 493 | split_scale = p_split_scale; | 
|---|
| 494 | notify_property_list_changed(); | 
|---|
| 495 | } | 
|---|
| 496 |  | 
|---|
| 497 | Ref<Curve> CPUParticles2D::get_scale_curve_x() const { | 
|---|
| 498 | return scale_curve_x; | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 | Ref<Curve> CPUParticles2D::get_scale_curve_y() const { | 
|---|
| 502 | return scale_curve_y; | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | bool CPUParticles2D::get_split_scale() { | 
|---|
| 506 | return split_scale; | 
|---|
| 507 | } | 
|---|
| 508 |  | 
|---|
| 509 | void CPUParticles2D::_validate_property(PropertyInfo &p_property) const { | 
|---|
| 510 | if (p_property.name == "emission_sphere_radius"&& (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { | 
|---|
| 511 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 512 | } | 
|---|
| 513 |  | 
|---|
| 514 | if (p_property.name == "emission_rect_extents"&& emission_shape != EMISSION_SHAPE_RECTANGLE) { | 
|---|
| 515 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 | if ((p_property.name == "emission_point_texture"|| p_property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { | 
|---|
| 519 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 520 | } | 
|---|
| 521 |  | 
|---|
| 522 | if (p_property.name == "emission_normals"&& emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { | 
|---|
| 523 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 | if (p_property.name == "emission_points"&& emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { | 
|---|
| 527 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | if (p_property.name == "emission_colors"&& emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { | 
|---|
| 531 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 532 | } | 
|---|
| 533 | if (p_property.name.begins_with( "scale_curve_") && !split_scale) { | 
|---|
| 534 | p_property.usage = PROPERTY_USAGE_NONE; | 
|---|
| 535 | } | 
|---|
| 536 | } | 
|---|
| 537 |  | 
|---|
| 538 | static uint32_t idhash(uint32_t x) { | 
|---|
| 539 | x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b); | 
|---|
| 540 | x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b); | 
|---|
| 541 | x = (x >> uint32_t(16)) ^ x; | 
|---|
| 542 | return x; | 
|---|
| 543 | } | 
|---|
| 544 |  | 
|---|
| 545 | static real_t rand_from_seed(uint32_t &seed) { | 
|---|
| 546 | int k; | 
|---|
| 547 | int s = int(seed); | 
|---|
| 548 | if (s == 0) { | 
|---|
| 549 | s = 305420679; | 
|---|
| 550 | } | 
|---|
| 551 | k = s / 127773; | 
|---|
| 552 | s = 16807 * (s - k * 127773) - 2836 * k; | 
|---|
| 553 | if (s < 0) { | 
|---|
| 554 | s += 2147483647; | 
|---|
| 555 | } | 
|---|
| 556 | seed = uint32_t(s); | 
|---|
| 557 | return (seed % uint32_t(65536)) / 65535.0; | 
|---|
| 558 | } | 
|---|
| 559 |  | 
|---|
| 560 | void CPUParticles2D::_update_internal() { | 
|---|
| 561 | if (particles.size() == 0 || !is_visible_in_tree()) { | 
|---|
| 562 | _set_do_redraw(false); | 
|---|
| 563 | return; | 
|---|
| 564 | } | 
|---|
| 565 |  | 
|---|
| 566 | double delta = get_process_delta_time(); | 
|---|
| 567 | if (!active && !emitting) { | 
|---|
| 568 | set_process_internal(false); | 
|---|
| 569 | _set_do_redraw(false); | 
|---|
| 570 |  | 
|---|
| 571 | //reset variables | 
|---|
| 572 | time = 0; | 
|---|
| 573 | frame_remainder = 0; | 
|---|
| 574 | cycle = 0; | 
|---|
| 575 | return; | 
|---|
| 576 | } | 
|---|
| 577 | _set_do_redraw(true); | 
|---|
| 578 |  | 
|---|
| 579 | if (time == 0 && pre_process_time > 0.0) { | 
|---|
| 580 | double frame_time; | 
|---|
| 581 | if (fixed_fps > 0) { | 
|---|
| 582 | frame_time = 1.0 / fixed_fps; | 
|---|
| 583 | } else { | 
|---|
| 584 | frame_time = 1.0 / 30.0; | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | double todo = pre_process_time; | 
|---|
| 588 |  | 
|---|
| 589 | while (todo >= 0) { | 
|---|
| 590 | _particles_process(frame_time); | 
|---|
| 591 | todo -= frame_time; | 
|---|
| 592 | } | 
|---|
| 593 | } | 
|---|
| 594 |  | 
|---|
| 595 | if (fixed_fps > 0) { | 
|---|
| 596 | double frame_time = 1.0 / fixed_fps; | 
|---|
| 597 | double decr = frame_time; | 
|---|
| 598 |  | 
|---|
| 599 | double ldelta = delta; | 
|---|
| 600 | if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10 | 
|---|
| 601 | ldelta = 0.1; | 
|---|
| 602 | } else if (ldelta <= 0.0) { //unlikely but.. | 
|---|
| 603 | ldelta = 0.001; | 
|---|
| 604 | } | 
|---|
| 605 | double todo = frame_remainder + ldelta; | 
|---|
| 606 |  | 
|---|
| 607 | while (todo >= frame_time) { | 
|---|
| 608 | _particles_process(frame_time); | 
|---|
| 609 | todo -= decr; | 
|---|
| 610 | } | 
|---|
| 611 |  | 
|---|
| 612 | frame_remainder = todo; | 
|---|
| 613 |  | 
|---|
| 614 | } else { | 
|---|
| 615 | _particles_process(delta); | 
|---|
| 616 | } | 
|---|
| 617 |  | 
|---|
| 618 | _update_particle_data_buffer(); | 
|---|
| 619 | } | 
|---|
| 620 |  | 
|---|
| 621 | void CPUParticles2D::_particles_process(double p_delta) { | 
|---|
| 622 | p_delta *= speed_scale; | 
|---|
| 623 |  | 
|---|
| 624 | int pcount = particles.size(); | 
|---|
| 625 | Particle *w = particles.ptrw(); | 
|---|
| 626 |  | 
|---|
| 627 | Particle *parray = w; | 
|---|
| 628 |  | 
|---|
| 629 | double prev_time = time; | 
|---|
| 630 | time += p_delta; | 
|---|
| 631 | if (time > lifetime) { | 
|---|
| 632 | time = Math::fmod(time, lifetime); | 
|---|
| 633 | cycle++; | 
|---|
| 634 | if (one_shot && cycle > 0) { | 
|---|
| 635 | set_emitting(false); | 
|---|
| 636 | notify_property_list_changed(); | 
|---|
| 637 | } | 
|---|
| 638 | } | 
|---|
| 639 |  | 
|---|
| 640 | Transform2D emission_xform; | 
|---|
| 641 | Transform2D velocity_xform; | 
|---|
| 642 | if (!local_coords) { | 
|---|
| 643 | emission_xform = get_global_transform(); | 
|---|
| 644 | velocity_xform = emission_xform; | 
|---|
| 645 | velocity_xform[2] = Vector2(); | 
|---|
| 646 | } | 
|---|
| 647 |  | 
|---|
| 648 | double system_phase = time / lifetime; | 
|---|
| 649 |  | 
|---|
| 650 | bool should_be_active = false; | 
|---|
| 651 | for (int i = 0; i < pcount; i++) { | 
|---|
| 652 | Particle &p = parray[i]; | 
|---|
| 653 |  | 
|---|
| 654 | if (!emitting && !p.active) { | 
|---|
| 655 | continue; | 
|---|
| 656 | } | 
|---|
| 657 |  | 
|---|
| 658 | double local_delta = p_delta; | 
|---|
| 659 |  | 
|---|
| 660 | // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. | 
|---|
| 661 | // While we use time in tests later on, for randomness we use the phase as done in the | 
|---|
| 662 | // original shader code, and we later multiply by lifetime to get the time. | 
|---|
| 663 | double restart_phase = double(i) / double(pcount); | 
|---|
| 664 |  | 
|---|
| 665 | if (randomness_ratio > 0.0) { | 
|---|
| 666 | uint32_t seed = cycle; | 
|---|
| 667 | if (restart_phase >= system_phase) { | 
|---|
| 668 | seed -= uint32_t(1); | 
|---|
| 669 | } | 
|---|
| 670 | seed *= uint32_t(pcount); | 
|---|
| 671 | seed += uint32_t(i); | 
|---|
| 672 | double random = double(idhash(seed) % uint32_t(65536)) / 65536.0; | 
|---|
| 673 | restart_phase += randomness_ratio * random * 1.0 / double(pcount); | 
|---|
| 674 | } | 
|---|
| 675 |  | 
|---|
| 676 | restart_phase *= (1.0 - explosiveness_ratio); | 
|---|
| 677 | double restart_time = restart_phase * lifetime; | 
|---|
| 678 | bool restart = false; | 
|---|
| 679 |  | 
|---|
| 680 | if (time > prev_time) { | 
|---|
| 681 | // restart_time >= prev_time is used so particles emit in the first frame they are processed | 
|---|
| 682 |  | 
|---|
| 683 | if (restart_time >= prev_time && restart_time < time) { | 
|---|
| 684 | restart = true; | 
|---|
| 685 | if (fractional_delta) { | 
|---|
| 686 | local_delta = time - restart_time; | 
|---|
| 687 | } | 
|---|
| 688 | } | 
|---|
| 689 |  | 
|---|
| 690 | } else if (local_delta > 0.0) { | 
|---|
| 691 | if (restart_time >= prev_time) { | 
|---|
| 692 | restart = true; | 
|---|
| 693 | if (fractional_delta) { | 
|---|
| 694 | local_delta = lifetime - restart_time + time; | 
|---|
| 695 | } | 
|---|
| 696 |  | 
|---|
| 697 | } else if (restart_time < time) { | 
|---|
| 698 | restart = true; | 
|---|
| 699 | if (fractional_delta) { | 
|---|
| 700 | local_delta = time - restart_time; | 
|---|
| 701 | } | 
|---|
| 702 | } | 
|---|
| 703 | } | 
|---|
| 704 |  | 
|---|
| 705 | if (p.time * (1.0 - explosiveness_ratio) > p.lifetime) { | 
|---|
| 706 | restart = true; | 
|---|
| 707 | } | 
|---|
| 708 |  | 
|---|
| 709 | float tv = 0.0; | 
|---|
| 710 |  | 
|---|
| 711 | if (restart) { | 
|---|
| 712 | if (!emitting) { | 
|---|
| 713 | p.active = false; | 
|---|
| 714 | continue; | 
|---|
| 715 | } | 
|---|
| 716 | p.active = true; | 
|---|
| 717 |  | 
|---|
| 718 | /*real_t tex_linear_velocity = 0; | 
|---|
| 719 | if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { | 
|---|
| 720 | tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0); | 
|---|
| 721 | }*/ | 
|---|
| 722 |  | 
|---|
| 723 | real_t tex_angle = 1.0; | 
|---|
| 724 | if (curve_parameters[PARAM_ANGLE].is_valid()) { | 
|---|
| 725 | tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); | 
|---|
| 726 | } | 
|---|
| 727 |  | 
|---|
| 728 | real_t tex_anim_offset = 1.0; | 
|---|
| 729 | if (curve_parameters[PARAM_ANGLE].is_valid()) { | 
|---|
| 730 | tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv); | 
|---|
| 731 | } | 
|---|
| 732 |  | 
|---|
| 733 | p.seed = Math::rand(); | 
|---|
| 734 |  | 
|---|
| 735 | p.angle_rand = Math::randf(); | 
|---|
| 736 | p.scale_rand = Math::randf(); | 
|---|
| 737 | p.hue_rot_rand = Math::randf(); | 
|---|
| 738 | p.anim_offset_rand = Math::randf(); | 
|---|
| 739 |  | 
|---|
| 740 | if (color_initial_ramp.is_valid()) { | 
|---|
| 741 | p.start_color_rand = color_initial_ramp->get_color_at_offset(Math::randf()); | 
|---|
| 742 | } else { | 
|---|
| 743 | p.start_color_rand = Color(1, 1, 1, 1); | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | real_t angle1_rad = direction.angle() + Math::deg_to_rad((Math::randf() * 2.0 - 1.0) * spread); | 
|---|
| 747 | Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad)); | 
|---|
| 748 | p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf()); | 
|---|
| 749 |  | 
|---|
| 750 | real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand); | 
|---|
| 751 | p.rotation = Math::deg_to_rad(base_angle); | 
|---|
| 752 |  | 
|---|
| 753 | p.custom[0] = 0.0; // unused | 
|---|
| 754 | p.custom[1] = 0.0; // phase [0..1] | 
|---|
| 755 | p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); | 
|---|
| 756 | p.custom[3] = 0.0; | 
|---|
| 757 | p.transform = Transform2D(); | 
|---|
| 758 | p.time = 0; | 
|---|
| 759 | p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness); | 
|---|
| 760 | p.base_color = Color(1, 1, 1, 1); | 
|---|
| 761 |  | 
|---|
| 762 | switch (emission_shape) { | 
|---|
| 763 | case EMISSION_SHAPE_POINT: { | 
|---|
| 764 | //do none | 
|---|
| 765 | } break; | 
|---|
| 766 | case EMISSION_SHAPE_SPHERE: { | 
|---|
| 767 | real_t t = Math_TAU * Math::randf(); | 
|---|
| 768 | real_t radius = emission_sphere_radius * Math::randf(); | 
|---|
| 769 | p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; | 
|---|
| 770 | } break; | 
|---|
| 771 | case EMISSION_SHAPE_SPHERE_SURFACE: { | 
|---|
| 772 | real_t s = Math::randf(), t = Math_TAU * Math::randf(); | 
|---|
| 773 | real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); | 
|---|
| 774 | p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; | 
|---|
| 775 | } break; | 
|---|
| 776 | case EMISSION_SHAPE_RECTANGLE: { | 
|---|
| 777 | p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_rect_extents; | 
|---|
| 778 | } break; | 
|---|
| 779 | case EMISSION_SHAPE_POINTS: | 
|---|
| 780 | case EMISSION_SHAPE_DIRECTED_POINTS: { | 
|---|
| 781 | int pc = emission_points.size(); | 
|---|
| 782 | if (pc == 0) { | 
|---|
| 783 | break; | 
|---|
| 784 | } | 
|---|
| 785 |  | 
|---|
| 786 | int random_idx = Math::rand() % pc; | 
|---|
| 787 |  | 
|---|
| 788 | p.transform[2] = emission_points.get(random_idx); | 
|---|
| 789 |  | 
|---|
| 790 | if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) { | 
|---|
| 791 | Vector2 normal = emission_normals.get(random_idx); | 
|---|
| 792 | Transform2D m2; | 
|---|
| 793 | m2.columns[0] = normal; | 
|---|
| 794 | m2.columns[1] = normal.orthogonal(); | 
|---|
| 795 | p.velocity = m2.basis_xform(p.velocity); | 
|---|
| 796 | } | 
|---|
| 797 |  | 
|---|
| 798 | if (emission_colors.size() == pc) { | 
|---|
| 799 | p.base_color = emission_colors.get(random_idx); | 
|---|
| 800 | } | 
|---|
| 801 | } break; | 
|---|
| 802 | case EMISSION_SHAPE_MAX: { // Max value for validity check. | 
|---|
| 803 | break; | 
|---|
| 804 | } | 
|---|
| 805 | } | 
|---|
| 806 |  | 
|---|
| 807 | if (!local_coords) { | 
|---|
| 808 | p.velocity = velocity_xform.xform(p.velocity); | 
|---|
| 809 | p.transform = emission_xform * p.transform; | 
|---|
| 810 | } | 
|---|
| 811 |  | 
|---|
| 812 | } else if (!p.active) { | 
|---|
| 813 | continue; | 
|---|
| 814 | } else if (p.time > p.lifetime) { | 
|---|
| 815 | p.active = false; | 
|---|
| 816 | tv = 1.0; | 
|---|
| 817 | } else { | 
|---|
| 818 | uint32_t alt_seed = p.seed; | 
|---|
| 819 |  | 
|---|
| 820 | p.time += local_delta; | 
|---|
| 821 | p.custom[1] = p.time / lifetime; | 
|---|
| 822 | tv = p.time / p.lifetime; | 
|---|
| 823 |  | 
|---|
| 824 | real_t tex_linear_velocity = 1.0; | 
|---|
| 825 | if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { | 
|---|
| 826 | tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv); | 
|---|
| 827 | } | 
|---|
| 828 |  | 
|---|
| 829 | real_t tex_orbit_velocity = 1.0; | 
|---|
| 830 | if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { | 
|---|
| 831 | tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv); | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | real_t tex_angular_velocity = 1.0; | 
|---|
| 835 | if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { | 
|---|
| 836 | tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv); | 
|---|
| 837 | } | 
|---|
| 838 |  | 
|---|
| 839 | real_t tex_linear_accel = 1.0; | 
|---|
| 840 | if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { | 
|---|
| 841 | tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv); | 
|---|
| 842 | } | 
|---|
| 843 |  | 
|---|
| 844 | real_t tex_tangential_accel = 1.0; | 
|---|
| 845 | if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { | 
|---|
| 846 | tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv); | 
|---|
| 847 | } | 
|---|
| 848 |  | 
|---|
| 849 | real_t tex_radial_accel = 1.0; | 
|---|
| 850 | if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { | 
|---|
| 851 | tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv); | 
|---|
| 852 | } | 
|---|
| 853 |  | 
|---|
| 854 | real_t tex_damping = 1.0; | 
|---|
| 855 | if (curve_parameters[PARAM_DAMPING].is_valid()) { | 
|---|
| 856 | tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv); | 
|---|
| 857 | } | 
|---|
| 858 |  | 
|---|
| 859 | real_t tex_angle = 1.0; | 
|---|
| 860 | if (curve_parameters[PARAM_ANGLE].is_valid()) { | 
|---|
| 861 | tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); | 
|---|
| 862 | } | 
|---|
| 863 | real_t tex_anim_speed = 1.0; | 
|---|
| 864 | if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { | 
|---|
| 865 | tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv); | 
|---|
| 866 | } | 
|---|
| 867 |  | 
|---|
| 868 | real_t tex_anim_offset = 1.0; | 
|---|
| 869 | if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { | 
|---|
| 870 | tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv); | 
|---|
| 871 | } | 
|---|
| 872 |  | 
|---|
| 873 | Vector2 force = gravity; | 
|---|
| 874 | Vector2 pos = p.transform[2]; | 
|---|
| 875 |  | 
|---|
| 876 | //apply linear acceleration | 
|---|
| 877 | 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(); | 
|---|
| 878 | //apply radial acceleration | 
|---|
| 879 | Vector2 org = emission_xform[2]; | 
|---|
| 880 | Vector2 diff = pos - org; | 
|---|
| 881 | 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(); | 
|---|
| 882 | //apply tangential acceleration; | 
|---|
| 883 | Vector2 yx = Vector2(diff.y, diff.x); | 
|---|
| 884 | force += yx.length() > 0.0 ? yx.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector2(); | 
|---|
| 885 | //apply attractor forces | 
|---|
| 886 | p.velocity += force * local_delta; | 
|---|
| 887 | //orbit velocity | 
|---|
| 888 | real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed)); | 
|---|
| 889 | if (orbit_amount != 0.0) { | 
|---|
| 890 | real_t ang = orbit_amount * local_delta * Math_TAU; | 
|---|
| 891 | // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix, | 
|---|
| 892 | // but we use -ang here to reproduce its behavior. | 
|---|
| 893 | Transform2D rot = Transform2D(-ang, Vector2()); | 
|---|
| 894 | p.transform[2] -= diff; | 
|---|
| 895 | p.transform[2] += rot.basis_xform(diff); | 
|---|
| 896 | } | 
|---|
| 897 | if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { | 
|---|
| 898 | p.velocity = p.velocity.normalized() * tex_linear_velocity; | 
|---|
| 899 | } | 
|---|
| 900 |  | 
|---|
| 901 | if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) { | 
|---|
| 902 | real_t v = p.velocity.length(); | 
|---|
| 903 | real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed)); | 
|---|
| 904 | v -= damp * local_delta; | 
|---|
| 905 | if (v < 0.0) { | 
|---|
| 906 | p.velocity = Vector2(); | 
|---|
| 907 | } else { | 
|---|
| 908 | p.velocity = p.velocity.normalized() * v; | 
|---|
| 909 | } | 
|---|
| 910 | } | 
|---|
| 911 | real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand); | 
|---|
| 912 | 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)); | 
|---|
| 913 | p.rotation = Math::deg_to_rad(base_angle); //angle | 
|---|
| 914 | 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)); | 
|---|
| 915 | } | 
|---|
| 916 | //apply color | 
|---|
| 917 | //apply hue rotation | 
|---|
| 918 |  | 
|---|
| 919 | Vector2 tex_scale = Vector2(1.0, 1.0); | 
|---|
| 920 | if (split_scale) { | 
|---|
| 921 | if (scale_curve_x.is_valid()) { | 
|---|
| 922 | tex_scale.x = scale_curve_x->sample(tv); | 
|---|
| 923 | } else { | 
|---|
| 924 | tex_scale.x = 1.0; | 
|---|
| 925 | } | 
|---|
| 926 | if (scale_curve_y.is_valid()) { | 
|---|
| 927 | tex_scale.y = scale_curve_y->sample(tv); | 
|---|
| 928 | } else { | 
|---|
| 929 | tex_scale.y = 1.0; | 
|---|
| 930 | } | 
|---|
| 931 | } else { | 
|---|
| 932 | if (curve_parameters[PARAM_SCALE].is_valid()) { | 
|---|
| 933 | real_t tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv); | 
|---|
| 934 | tex_scale.x = tmp_scale; | 
|---|
| 935 | tex_scale.y = tmp_scale; | 
|---|
| 936 | } | 
|---|
| 937 | } | 
|---|
| 938 |  | 
|---|
| 939 | real_t tex_hue_variation = 0.0; | 
|---|
| 940 | if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { | 
|---|
| 941 | tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv); | 
|---|
| 942 | } | 
|---|
| 943 |  | 
|---|
| 944 | real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand); | 
|---|
| 945 | real_t hue_rot_c = Math::cos(hue_rot_angle); | 
|---|
| 946 | real_t hue_rot_s = Math::sin(hue_rot_angle); | 
|---|
| 947 |  | 
|---|
| 948 | Basis hue_rot_mat; | 
|---|
| 949 | { | 
|---|
| 950 | Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114); | 
|---|
| 951 | Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886); | 
|---|
| 952 | Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203); | 
|---|
| 953 |  | 
|---|
| 954 | for (int j = 0; j < 3; j++) { | 
|---|
| 955 | hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s; | 
|---|
| 956 | } | 
|---|
| 957 | } | 
|---|
| 958 |  | 
|---|
| 959 | if (color_ramp.is_valid()) { | 
|---|
| 960 | p.color = color_ramp->get_color_at_offset(tv) * color; | 
|---|
| 961 | } else { | 
|---|
| 962 | p.color = color; | 
|---|
| 963 | } | 
|---|
| 964 |  | 
|---|
| 965 | Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b)); | 
|---|
| 966 | p.color.r = color_rgb.x; | 
|---|
| 967 | p.color.g = color_rgb.y; | 
|---|
| 968 | p.color.b = color_rgb.z; | 
|---|
| 969 |  | 
|---|
| 970 | p.color *= p.base_color * p.start_color_rand; | 
|---|
| 971 |  | 
|---|
| 972 | if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { | 
|---|
| 973 | if (p.velocity.length() > 0.0) { | 
|---|
| 974 | p.transform.columns[1] = p.velocity.normalized(); | 
|---|
| 975 | p.transform.columns[0] = p.transform.columns[1].orthogonal(); | 
|---|
| 976 | } | 
|---|
| 977 |  | 
|---|
| 978 | } else { | 
|---|
| 979 | p.transform.columns[0] = Vector2(Math::cos(p.rotation), -Math::sin(p.rotation)); | 
|---|
| 980 | p.transform.columns[1] = Vector2(Math::sin(p.rotation), Math::cos(p.rotation)); | 
|---|
| 981 | } | 
|---|
| 982 |  | 
|---|
| 983 | //scale by scale | 
|---|
| 984 | Vector2 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand); | 
|---|
| 985 | if (base_scale.x < 0.00001) { | 
|---|
| 986 | base_scale.x = 0.00001; | 
|---|
| 987 | } | 
|---|
| 988 | if (base_scale.y < 0.00001) { | 
|---|
| 989 | base_scale.y = 0.00001; | 
|---|
| 990 | } | 
|---|
| 991 | p.transform.columns[0] *= base_scale.x; | 
|---|
| 992 | p.transform.columns[1] *= base_scale.y; | 
|---|
| 993 |  | 
|---|
| 994 | p.transform[2] += p.velocity * local_delta; | 
|---|
| 995 |  | 
|---|
| 996 | should_be_active = true; | 
|---|
| 997 | } | 
|---|
| 998 | if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) { | 
|---|
| 999 | active = false; | 
|---|
| 1000 | emit_signal(SceneStringNames::get_singleton()->finished); | 
|---|
| 1001 | } | 
|---|
| 1002 | } | 
|---|
| 1003 |  | 
|---|
| 1004 | void CPUParticles2D::_update_particle_data_buffer() { | 
|---|
| 1005 | MutexLock lock(update_mutex); | 
|---|
| 1006 |  | 
|---|
| 1007 | int pc = particles.size(); | 
|---|
| 1008 |  | 
|---|
| 1009 | int *ow; | 
|---|
| 1010 | int *order = nullptr; | 
|---|
| 1011 |  | 
|---|
| 1012 | float *w = particle_data.ptrw(); | 
|---|
| 1013 | const Particle *r = particles.ptr(); | 
|---|
| 1014 | float *ptr = w; | 
|---|
| 1015 |  | 
|---|
| 1016 | if (draw_order != DRAW_ORDER_INDEX) { | 
|---|
| 1017 | ow = particle_order.ptrw(); | 
|---|
| 1018 | order = ow; | 
|---|
| 1019 |  | 
|---|
| 1020 | for (int i = 0; i < pc; i++) { | 
|---|
| 1021 | order[i] = i; | 
|---|
| 1022 | } | 
|---|
| 1023 | if (draw_order == DRAW_ORDER_LIFETIME) { | 
|---|
| 1024 | SortArray<int, SortLifetime> sorter; | 
|---|
| 1025 | sorter.compare.particles = r; | 
|---|
| 1026 | sorter.sort(order, pc); | 
|---|
| 1027 | } | 
|---|
| 1028 | } | 
|---|
| 1029 |  | 
|---|
| 1030 | for (int i = 0; i < pc; i++) { | 
|---|
| 1031 | int idx = order ? order[i] : i; | 
|---|
| 1032 |  | 
|---|
| 1033 | Transform2D t = r[idx].transform; | 
|---|
| 1034 |  | 
|---|
| 1035 | if (!local_coords) { | 
|---|
| 1036 | t = inv_emission_transform * t; | 
|---|
| 1037 | } | 
|---|
| 1038 |  | 
|---|
| 1039 | if (r[idx].active) { | 
|---|
| 1040 | ptr[0] = t.columns[0][0]; | 
|---|
| 1041 | ptr[1] = t.columns[1][0]; | 
|---|
| 1042 | ptr[2] = 0; | 
|---|
| 1043 | ptr[3] = t.columns[2][0]; | 
|---|
| 1044 | ptr[4] = t.columns[0][1]; | 
|---|
| 1045 | ptr[5] = t.columns[1][1]; | 
|---|
| 1046 | ptr[6] = 0; | 
|---|
| 1047 | ptr[7] = t.columns[2][1]; | 
|---|
| 1048 |  | 
|---|
| 1049 | } else { | 
|---|
| 1050 | memset(ptr, 0, sizeof(float) * 8); | 
|---|
| 1051 | } | 
|---|
| 1052 |  | 
|---|
| 1053 | Color c = r[idx].color; | 
|---|
| 1054 |  | 
|---|
| 1055 | ptr[8] = c.r; | 
|---|
| 1056 | ptr[9] = c.g; | 
|---|
| 1057 | ptr[10] = c.b; | 
|---|
| 1058 | ptr[11] = c.a; | 
|---|
| 1059 |  | 
|---|
| 1060 | ptr[12] = r[idx].custom[0]; | 
|---|
| 1061 | ptr[13] = r[idx].custom[1]; | 
|---|
| 1062 | ptr[14] = r[idx].custom[2]; | 
|---|
| 1063 | ptr[15] = r[idx].custom[3]; | 
|---|
| 1064 |  | 
|---|
| 1065 | ptr += 16; | 
|---|
| 1066 | } | 
|---|
| 1067 | } | 
|---|
| 1068 |  | 
|---|
| 1069 | void CPUParticles2D::_set_do_redraw(bool p_do_redraw) { | 
|---|
| 1070 | if (do_redraw == p_do_redraw) { | 
|---|
| 1071 | return; | 
|---|
| 1072 | } | 
|---|
| 1073 | do_redraw = p_do_redraw; | 
|---|
| 1074 |  | 
|---|
| 1075 | { | 
|---|
| 1076 | MutexLock lock(update_mutex); | 
|---|
| 1077 |  | 
|---|
| 1078 | if (do_redraw) { | 
|---|
| 1079 | RS::get_singleton()->connect( "frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread)); | 
|---|
| 1080 | RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); | 
|---|
| 1081 |  | 
|---|
| 1082 | RS::get_singleton()->multimesh_set_visible_instances(multimesh, -1); | 
|---|
| 1083 | } else { | 
|---|
| 1084 | if (RS::get_singleton()->is_connected( "frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread))) { | 
|---|
| 1085 | RS::get_singleton()->disconnect( "frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread)); | 
|---|
| 1086 | } | 
|---|
| 1087 | RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); | 
|---|
| 1088 |  | 
|---|
| 1089 | RS::get_singleton()->multimesh_set_visible_instances(multimesh, 0); | 
|---|
| 1090 | } | 
|---|
| 1091 | } | 
|---|
| 1092 |  | 
|---|
| 1093 | queue_redraw(); // redraw to update render list | 
|---|
| 1094 | } | 
|---|
| 1095 |  | 
|---|
| 1096 | void CPUParticles2D::_update_render_thread() { | 
|---|
| 1097 | MutexLock lock(update_mutex); | 
|---|
| 1098 |  | 
|---|
| 1099 | RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data); | 
|---|
| 1100 | } | 
|---|
| 1101 |  | 
|---|
| 1102 | void CPUParticles2D::_notification(int p_what) { | 
|---|
| 1103 | switch (p_what) { | 
|---|
| 1104 | case NOTIFICATION_ENTER_TREE: { | 
|---|
| 1105 | set_process_internal(emitting); | 
|---|
| 1106 | } break; | 
|---|
| 1107 |  | 
|---|
| 1108 | case NOTIFICATION_EXIT_TREE: { | 
|---|
| 1109 | _set_do_redraw(false); | 
|---|
| 1110 | } break; | 
|---|
| 1111 |  | 
|---|
| 1112 | case NOTIFICATION_DRAW: { | 
|---|
| 1113 | // first update before rendering to avoid one frame delay after emitting starts | 
|---|
| 1114 | if (emitting && (time == 0)) { | 
|---|
| 1115 | _update_internal(); | 
|---|
| 1116 | } | 
|---|
| 1117 |  | 
|---|
| 1118 | if (!do_redraw) { | 
|---|
| 1119 | return; // don't add to render list | 
|---|
| 1120 | } | 
|---|
| 1121 |  | 
|---|
| 1122 | RID texrid; | 
|---|
| 1123 | if (texture.is_valid()) { | 
|---|
| 1124 | texrid = texture->get_rid(); | 
|---|
| 1125 | } | 
|---|
| 1126 |  | 
|---|
| 1127 | RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); | 
|---|
| 1128 | } break; | 
|---|
| 1129 |  | 
|---|
| 1130 | case NOTIFICATION_INTERNAL_PROCESS: { | 
|---|
| 1131 | _update_internal(); | 
|---|
| 1132 | } break; | 
|---|
| 1133 |  | 
|---|
| 1134 | case NOTIFICATION_TRANSFORM_CHANGED: { | 
|---|
| 1135 | inv_emission_transform = get_global_transform().affine_inverse(); | 
|---|
| 1136 |  | 
|---|
| 1137 | if (!local_coords) { | 
|---|
| 1138 | int pc = particles.size(); | 
|---|
| 1139 |  | 
|---|
| 1140 | float *w = particle_data.ptrw(); | 
|---|
| 1141 | const Particle *r = particles.ptr(); | 
|---|
| 1142 | float *ptr = w; | 
|---|
| 1143 |  | 
|---|
| 1144 | for (int i = 0; i < pc; i++) { | 
|---|
| 1145 | Transform2D t = inv_emission_transform * r[i].transform; | 
|---|
| 1146 |  | 
|---|
| 1147 | if (r[i].active) { | 
|---|
| 1148 | ptr[0] = t.columns[0][0]; | 
|---|
| 1149 | ptr[1] = t.columns[1][0]; | 
|---|
| 1150 | ptr[2] = 0; | 
|---|
| 1151 | ptr[3] = t.columns[2][0]; | 
|---|
| 1152 | ptr[4] = t.columns[0][1]; | 
|---|
| 1153 | ptr[5] = t.columns[1][1]; | 
|---|
| 1154 | ptr[6] = 0; | 
|---|
| 1155 | ptr[7] = t.columns[2][1]; | 
|---|
| 1156 |  | 
|---|
| 1157 | } else { | 
|---|
| 1158 | memset(ptr, 0, sizeof(float) * 8); | 
|---|
| 1159 | } | 
|---|
| 1160 |  | 
|---|
| 1161 | ptr += 16; | 
|---|
| 1162 | } | 
|---|
| 1163 | } | 
|---|
| 1164 | } break; | 
|---|
| 1165 | } | 
|---|
| 1166 | } | 
|---|
| 1167 |  | 
|---|
| 1168 | void CPUParticles2D::convert_from_particles(Node *p_particles) { | 
|---|
| 1169 | GPUParticles2D *gpu_particles = Object::cast_to<GPUParticles2D>(p_particles); | 
|---|
| 1170 | ERR_FAIL_NULL_MSG(gpu_particles, "Only GPUParticles2D nodes can be converted to CPUParticles2D."); | 
|---|
| 1171 |  | 
|---|
| 1172 | set_emitting(gpu_particles->is_emitting()); | 
|---|
| 1173 | set_amount(gpu_particles->get_amount()); | 
|---|
| 1174 | set_lifetime(gpu_particles->get_lifetime()); | 
|---|
| 1175 | set_one_shot(gpu_particles->get_one_shot()); | 
|---|
| 1176 | set_pre_process_time(gpu_particles->get_pre_process_time()); | 
|---|
| 1177 | set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio()); | 
|---|
| 1178 | set_randomness_ratio(gpu_particles->get_randomness_ratio()); | 
|---|
| 1179 | set_use_local_coordinates(gpu_particles->get_use_local_coordinates()); | 
|---|
| 1180 | set_fixed_fps(gpu_particles->get_fixed_fps()); | 
|---|
| 1181 | set_fractional_delta(gpu_particles->get_fractional_delta()); | 
|---|
| 1182 | set_speed_scale(gpu_particles->get_speed_scale()); | 
|---|
| 1183 | set_draw_order(DrawOrder(gpu_particles->get_draw_order())); | 
|---|
| 1184 | set_texture(gpu_particles->get_texture()); | 
|---|
| 1185 |  | 
|---|
| 1186 | Ref<Material> mat = gpu_particles->get_material(); | 
|---|
| 1187 | if (mat.is_valid()) { | 
|---|
| 1188 | set_material(mat); | 
|---|
| 1189 | } | 
|---|
| 1190 |  | 
|---|
| 1191 | Ref<ParticleProcessMaterial> proc_mat = gpu_particles->get_process_material(); | 
|---|
| 1192 | if (proc_mat.is_null()) { | 
|---|
| 1193 | return; | 
|---|
| 1194 | } | 
|---|
| 1195 |  | 
|---|
| 1196 | Vector3 dir = proc_mat->get_direction(); | 
|---|
| 1197 | set_direction(Vector2(dir.x, dir.y)); | 
|---|
| 1198 | set_spread(proc_mat->get_spread()); | 
|---|
| 1199 |  | 
|---|
| 1200 | set_color(proc_mat->get_color()); | 
|---|
| 1201 |  | 
|---|
| 1202 | Ref<GradientTexture1D> gt = proc_mat->get_color_ramp(); | 
|---|
| 1203 | if (gt.is_valid()) { | 
|---|
| 1204 | set_color_ramp(gt->get_gradient()); | 
|---|
| 1205 | } | 
|---|
| 1206 |  | 
|---|
| 1207 | Ref<GradientTexture1D> gti = proc_mat->get_color_initial_ramp(); | 
|---|
| 1208 | if (gti.is_valid()) { | 
|---|
| 1209 | set_color_initial_ramp(gti->get_gradient()); | 
|---|
| 1210 | } | 
|---|
| 1211 |  | 
|---|
| 1212 | set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, proc_mat->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); | 
|---|
| 1213 |  | 
|---|
| 1214 | set_emission_shape(EmissionShape(proc_mat->get_emission_shape())); | 
|---|
| 1215 | set_emission_sphere_radius(proc_mat->get_emission_sphere_radius()); | 
|---|
| 1216 | Vector2 rect_extents = Vector2(proc_mat->get_emission_box_extents().x, proc_mat->get_emission_box_extents().y); | 
|---|
| 1217 | set_emission_rect_extents(rect_extents); | 
|---|
| 1218 |  | 
|---|
| 1219 | Ref<CurveXYZTexture> scale3D = proc_mat->get_param_texture(ParticleProcessMaterial::PARAM_SCALE); | 
|---|
| 1220 | if (scale3D.is_valid()) { | 
|---|
| 1221 | split_scale = true; | 
|---|
| 1222 | scale_curve_x = scale3D->get_curve_x(); | 
|---|
| 1223 | scale_curve_y = scale3D->get_curve_y(); | 
|---|
| 1224 | } | 
|---|
| 1225 | set_gravity(Vector2(proc_mat->get_gravity().x, proc_mat->get_gravity().y)); | 
|---|
| 1226 | set_lifetime_randomness(proc_mat->get_lifetime_randomness()); | 
|---|
| 1227 |  | 
|---|
| 1228 | #define CONVERT_PARAM(m_param)                                                                  \ | 
|---|
| 1229 | set_param_min(m_param, proc_mat->get_param_min(ParticleProcessMaterial::m_param));          \ | 
|---|
| 1230 | {                                                                                           \ | 
|---|
| 1231 | Ref<CurveTexture> ctex = proc_mat->get_param_texture(ParticleProcessMaterial::m_param); \ | 
|---|
| 1232 | if (ctex.is_valid())                                                                    \ | 
|---|
| 1233 | set_param_curve(m_param, ctex->get_curve());                                        \ | 
|---|
| 1234 | }                                                                                           \ | 
|---|
| 1235 | set_param_max(m_param, proc_mat->get_param_max(ParticleProcessMaterial::m_param)); | 
|---|
| 1236 |  | 
|---|
| 1237 | CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); | 
|---|
| 1238 | CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); | 
|---|
| 1239 | CONVERT_PARAM(PARAM_ORBIT_VELOCITY); | 
|---|
| 1240 | CONVERT_PARAM(PARAM_LINEAR_ACCEL); | 
|---|
| 1241 | CONVERT_PARAM(PARAM_RADIAL_ACCEL); | 
|---|
| 1242 | CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); | 
|---|
| 1243 | CONVERT_PARAM(PARAM_DAMPING); | 
|---|
| 1244 | CONVERT_PARAM(PARAM_ANGLE); | 
|---|
| 1245 | CONVERT_PARAM(PARAM_SCALE); | 
|---|
| 1246 | CONVERT_PARAM(PARAM_HUE_VARIATION); | 
|---|
| 1247 | CONVERT_PARAM(PARAM_ANIM_SPEED); | 
|---|
| 1248 | CONVERT_PARAM(PARAM_ANIM_OFFSET); | 
|---|
| 1249 |  | 
|---|
| 1250 | #undef CONVERT_PARAM | 
|---|
| 1251 | } | 
|---|
| 1252 |  | 
|---|
| 1253 | void CPUParticles2D::_bind_methods() { | 
|---|
| 1254 | ClassDB::bind_method(D_METHOD( "set_emitting", "emitting"), &CPUParticles2D::set_emitting); | 
|---|
| 1255 | ClassDB::bind_method(D_METHOD( "set_amount", "amount"), &CPUParticles2D::set_amount); | 
|---|
| 1256 | ClassDB::bind_method(D_METHOD( "set_lifetime", "secs"), &CPUParticles2D::set_lifetime); | 
|---|
| 1257 | ClassDB::bind_method(D_METHOD( "set_one_shot", "enable"), &CPUParticles2D::set_one_shot); | 
|---|
| 1258 | ClassDB::bind_method(D_METHOD( "set_pre_process_time", "secs"), &CPUParticles2D::set_pre_process_time); | 
|---|
| 1259 | ClassDB::bind_method(D_METHOD( "set_explosiveness_ratio", "ratio"), &CPUParticles2D::set_explosiveness_ratio); | 
|---|
| 1260 | ClassDB::bind_method(D_METHOD( "set_randomness_ratio", "ratio"), &CPUParticles2D::set_randomness_ratio); | 
|---|
| 1261 | ClassDB::bind_method(D_METHOD( "set_lifetime_randomness", "random"), &CPUParticles2D::set_lifetime_randomness); | 
|---|
| 1262 | ClassDB::bind_method(D_METHOD( "set_use_local_coordinates", "enable"), &CPUParticles2D::set_use_local_coordinates); | 
|---|
| 1263 | ClassDB::bind_method(D_METHOD( "set_fixed_fps", "fps"), &CPUParticles2D::set_fixed_fps); | 
|---|
| 1264 | ClassDB::bind_method(D_METHOD( "set_fractional_delta", "enable"), &CPUParticles2D::set_fractional_delta); | 
|---|
| 1265 | ClassDB::bind_method(D_METHOD( "set_speed_scale", "scale"), &CPUParticles2D::set_speed_scale); | 
|---|
| 1266 |  | 
|---|
| 1267 | ClassDB::bind_method(D_METHOD( "is_emitting"), &CPUParticles2D::is_emitting); | 
|---|
| 1268 | ClassDB::bind_method(D_METHOD( "get_amount"), &CPUParticles2D::get_amount); | 
|---|
| 1269 | ClassDB::bind_method(D_METHOD( "get_lifetime"), &CPUParticles2D::get_lifetime); | 
|---|
| 1270 | ClassDB::bind_method(D_METHOD( "get_one_shot"), &CPUParticles2D::get_one_shot); | 
|---|
| 1271 | ClassDB::bind_method(D_METHOD( "get_pre_process_time"), &CPUParticles2D::get_pre_process_time); | 
|---|
| 1272 | ClassDB::bind_method(D_METHOD( "get_explosiveness_ratio"), &CPUParticles2D::get_explosiveness_ratio); | 
|---|
| 1273 | ClassDB::bind_method(D_METHOD( "get_randomness_ratio"), &CPUParticles2D::get_randomness_ratio); | 
|---|
| 1274 | ClassDB::bind_method(D_METHOD( "get_lifetime_randomness"), &CPUParticles2D::get_lifetime_randomness); | 
|---|
| 1275 | ClassDB::bind_method(D_METHOD( "get_use_local_coordinates"), &CPUParticles2D::get_use_local_coordinates); | 
|---|
| 1276 | ClassDB::bind_method(D_METHOD( "get_fixed_fps"), &CPUParticles2D::get_fixed_fps); | 
|---|
| 1277 | ClassDB::bind_method(D_METHOD( "get_fractional_delta"), &CPUParticles2D::get_fractional_delta); | 
|---|
| 1278 | ClassDB::bind_method(D_METHOD( "get_speed_scale"), &CPUParticles2D::get_speed_scale); | 
|---|
| 1279 |  | 
|---|
| 1280 | ClassDB::bind_method(D_METHOD( "set_draw_order", "order"), &CPUParticles2D::set_draw_order); | 
|---|
| 1281 |  | 
|---|
| 1282 | ClassDB::bind_method(D_METHOD( "get_draw_order"), &CPUParticles2D::get_draw_order); | 
|---|
| 1283 |  | 
|---|
| 1284 | ClassDB::bind_method(D_METHOD( "set_texture", "texture"), &CPUParticles2D::set_texture); | 
|---|
| 1285 | ClassDB::bind_method(D_METHOD( "get_texture"), &CPUParticles2D::get_texture); | 
|---|
| 1286 |  | 
|---|
| 1287 | ClassDB::bind_method(D_METHOD( "restart"), &CPUParticles2D::restart); | 
|---|
| 1288 |  | 
|---|
| 1289 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); | 
|---|
| 1290 | ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); | 
|---|
| 1291 | ADD_GROUP( "Time", ""); | 
|---|
| 1292 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,suffix:s"), "set_lifetime", "get_lifetime"); | 
|---|
| 1293 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); | 
|---|
| 1294 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,suffix:s"), "set_pre_process_time", "get_pre_process_time"); | 
|---|
| 1295 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); | 
|---|
| 1296 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); | 
|---|
| 1297 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); | 
|---|
| 1298 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); | 
|---|
| 1299 | ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps"); | 
|---|
| 1300 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); | 
|---|
| 1301 | ADD_GROUP( "Drawing", ""); | 
|---|
| 1302 | // No visibility_rect property contrarily to Particles2D, it's updated automatically. | 
|---|
| 1303 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); | 
|---|
| 1304 | ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); | 
|---|
| 1305 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); | 
|---|
| 1306 |  | 
|---|
| 1307 | BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); | 
|---|
| 1308 | BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); | 
|---|
| 1309 |  | 
|---|
| 1310 | //////////////////////////////// | 
|---|
| 1311 |  | 
|---|
| 1312 | ClassDB::bind_method(D_METHOD( "set_direction", "direction"), &CPUParticles2D::set_direction); | 
|---|
| 1313 | ClassDB::bind_method(D_METHOD( "get_direction"), &CPUParticles2D::get_direction); | 
|---|
| 1314 |  | 
|---|
| 1315 | ClassDB::bind_method(D_METHOD( "set_spread", "spread"), &CPUParticles2D::set_spread); | 
|---|
| 1316 | ClassDB::bind_method(D_METHOD( "get_spread"), &CPUParticles2D::get_spread); | 
|---|
| 1317 |  | 
|---|
| 1318 | ClassDB::bind_method(D_METHOD( "set_param_min", "param", "value"), &CPUParticles2D::set_param_min); | 
|---|
| 1319 | ClassDB::bind_method(D_METHOD( "get_param_min", "param"), &CPUParticles2D::get_param_min); | 
|---|
| 1320 |  | 
|---|
| 1321 | ClassDB::bind_method(D_METHOD( "set_param_max", "param", "value"), &CPUParticles2D::set_param_max); | 
|---|
| 1322 | ClassDB::bind_method(D_METHOD( "get_param_max", "param"), &CPUParticles2D::get_param_max); | 
|---|
| 1323 |  | 
|---|
| 1324 | ClassDB::bind_method(D_METHOD( "set_param_curve", "param", "curve"), &CPUParticles2D::set_param_curve); | 
|---|
| 1325 | ClassDB::bind_method(D_METHOD( "get_param_curve", "param"), &CPUParticles2D::get_param_curve); | 
|---|
| 1326 |  | 
|---|
| 1327 | ClassDB::bind_method(D_METHOD( "set_color", "color"), &CPUParticles2D::set_color); | 
|---|
| 1328 | ClassDB::bind_method(D_METHOD( "get_color"), &CPUParticles2D::get_color); | 
|---|
| 1329 |  | 
|---|
| 1330 | ClassDB::bind_method(D_METHOD( "set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp); | 
|---|
| 1331 | ClassDB::bind_method(D_METHOD( "get_color_ramp"), &CPUParticles2D::get_color_ramp); | 
|---|
| 1332 |  | 
|---|
| 1333 | ClassDB::bind_method(D_METHOD( "set_color_initial_ramp", "ramp"), &CPUParticles2D::set_color_initial_ramp); | 
|---|
| 1334 | ClassDB::bind_method(D_METHOD( "get_color_initial_ramp"), &CPUParticles2D::get_color_initial_ramp); | 
|---|
| 1335 |  | 
|---|
| 1336 | ClassDB::bind_method(D_METHOD( "set_particle_flag", "particle_flag", "enable"), &CPUParticles2D::set_particle_flag); | 
|---|
| 1337 | ClassDB::bind_method(D_METHOD( "get_particle_flag", "particle_flag"), &CPUParticles2D::get_particle_flag); | 
|---|
| 1338 |  | 
|---|
| 1339 | ClassDB::bind_method(D_METHOD( "set_emission_shape", "shape"), &CPUParticles2D::set_emission_shape); | 
|---|
| 1340 | ClassDB::bind_method(D_METHOD( "get_emission_shape"), &CPUParticles2D::get_emission_shape); | 
|---|
| 1341 |  | 
|---|
| 1342 | ClassDB::bind_method(D_METHOD( "set_emission_sphere_radius", "radius"), &CPUParticles2D::set_emission_sphere_radius); | 
|---|
| 1343 | ClassDB::bind_method(D_METHOD( "get_emission_sphere_radius"), &CPUParticles2D::get_emission_sphere_radius); | 
|---|
| 1344 |  | 
|---|
| 1345 | ClassDB::bind_method(D_METHOD( "set_emission_rect_extents", "extents"), &CPUParticles2D::set_emission_rect_extents); | 
|---|
| 1346 | ClassDB::bind_method(D_METHOD( "get_emission_rect_extents"), &CPUParticles2D::get_emission_rect_extents); | 
|---|
| 1347 |  | 
|---|
| 1348 | ClassDB::bind_method(D_METHOD( "set_emission_points", "array"), &CPUParticles2D::set_emission_points); | 
|---|
| 1349 | ClassDB::bind_method(D_METHOD( "get_emission_points"), &CPUParticles2D::get_emission_points); | 
|---|
| 1350 |  | 
|---|
| 1351 | ClassDB::bind_method(D_METHOD( "set_emission_normals", "array"), &CPUParticles2D::set_emission_normals); | 
|---|
| 1352 | ClassDB::bind_method(D_METHOD( "get_emission_normals"), &CPUParticles2D::get_emission_normals); | 
|---|
| 1353 |  | 
|---|
| 1354 | ClassDB::bind_method(D_METHOD( "set_emission_colors", "array"), &CPUParticles2D::set_emission_colors); | 
|---|
| 1355 | ClassDB::bind_method(D_METHOD( "get_emission_colors"), &CPUParticles2D::get_emission_colors); | 
|---|
| 1356 |  | 
|---|
| 1357 | ClassDB::bind_method(D_METHOD( "get_gravity"), &CPUParticles2D::get_gravity); | 
|---|
| 1358 | ClassDB::bind_method(D_METHOD( "set_gravity", "accel_vec"), &CPUParticles2D::set_gravity); | 
|---|
| 1359 |  | 
|---|
| 1360 | ClassDB::bind_method(D_METHOD( "get_split_scale"), &CPUParticles2D::get_split_scale); | 
|---|
| 1361 | ClassDB::bind_method(D_METHOD( "set_split_scale", "split_scale"), &CPUParticles2D::set_split_scale); | 
|---|
| 1362 |  | 
|---|
| 1363 | ClassDB::bind_method(D_METHOD( "get_scale_curve_x"), &CPUParticles2D::get_scale_curve_x); | 
|---|
| 1364 | ClassDB::bind_method(D_METHOD( "set_scale_curve_x", "scale_curve"), &CPUParticles2D::set_scale_curve_x); | 
|---|
| 1365 |  | 
|---|
| 1366 | ClassDB::bind_method(D_METHOD( "get_scale_curve_y"), &CPUParticles2D::get_scale_curve_y); | 
|---|
| 1367 | ClassDB::bind_method(D_METHOD( "set_scale_curve_y", "scale_curve"), &CPUParticles2D::set_scale_curve_y); | 
|---|
| 1368 |  | 
|---|
| 1369 | ClassDB::bind_method(D_METHOD( "convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles); | 
|---|
| 1370 |  | 
|---|
| 1371 | ADD_SIGNAL(MethodInfo( "finished")); | 
|---|
| 1372 |  | 
|---|
| 1373 | ADD_GROUP( "Emission Shape", "emission_"); | 
|---|
| 1374 | ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Rectangle,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); | 
|---|
| 1375 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,suffix:px"), "set_emission_sphere_radius", "get_emission_sphere_radius"); | 
|---|
| 1376 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents", PROPERTY_HINT_NONE, "suffix:px"), "set_emission_rect_extents", "get_emission_rect_extents"); | 
|---|
| 1377 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); | 
|---|
| 1378 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); | 
|---|
| 1379 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); | 
|---|
| 1380 | ADD_GROUP( "Particle Flags", "particle_flag_"); | 
|---|
| 1381 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); | 
|---|
| 1382 | ADD_GROUP( "Direction", ""); | 
|---|
| 1383 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "direction"), "set_direction", "get_direction"); | 
|---|
| 1384 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); | 
|---|
| 1385 | ADD_GROUP( "Gravity", ""); | 
|---|
| 1386 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity", PROPERTY_HINT_NONE, U "suffix:px/s\u00B2"), "set_gravity", "get_gravity"); | 
|---|
| 1387 | ADD_GROUP( "Initial Velocity", "initial_"); | 
|---|
| 1388 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); | 
|---|
| 1389 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); | 
|---|
| 1390 | ADD_GROUP( "Angular Velocity", "angular_"); | 
|---|
| 1391 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); | 
|---|
| 1392 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); | 
|---|
| 1393 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); | 
|---|
| 1394 | ADD_GROUP( "Orbit Velocity", "orbit_"); | 
|---|
| 1395 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); | 
|---|
| 1396 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); | 
|---|
| 1397 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); | 
|---|
| 1398 | ADD_GROUP( "Linear Accel", "linear_"); | 
|---|
| 1399 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); | 
|---|
| 1400 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); | 
|---|
| 1401 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL); | 
|---|
| 1402 | ADD_GROUP( "Radial Accel", "radial_"); | 
|---|
| 1403 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); | 
|---|
| 1404 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); | 
|---|
| 1405 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL); | 
|---|
| 1406 | ADD_GROUP( "Tangential Accel", "tangential_"); | 
|---|
| 1407 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); | 
|---|
| 1408 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); | 
|---|
| 1409 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); | 
|---|
| 1410 | ADD_GROUP( "Damping", ""); | 
|---|
| 1411 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING); | 
|---|
| 1412 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING); | 
|---|
| 1413 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); | 
|---|
| 1414 | ADD_GROUP( "Angle", ""); | 
|---|
| 1415 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); | 
|---|
| 1416 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); | 
|---|
| 1417 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); | 
|---|
| 1418 | ADD_GROUP( "Scale", ""); | 
|---|
| 1419 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); | 
|---|
| 1420 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE); | 
|---|
| 1421 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE); | 
|---|
| 1422 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale"); | 
|---|
| 1423 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_x", "get_scale_curve_x"); | 
|---|
| 1424 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_y", "get_scale_curve_y"); | 
|---|
| 1425 |  | 
|---|
| 1426 | ADD_GROUP( "Color", ""); | 
|---|
| 1427 | ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); | 
|---|
| 1428 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); | 
|---|
| 1429 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_initial_ramp", "get_color_initial_ramp"); | 
|---|
| 1430 |  | 
|---|
| 1431 | ADD_GROUP( "Hue Variation", "hue_"); | 
|---|
| 1432 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION); | 
|---|
| 1433 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); | 
|---|
| 1434 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION); | 
|---|
| 1435 | ADD_GROUP( "Animation", "anim_"); | 
|---|
| 1436 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); | 
|---|
| 1437 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); | 
|---|
| 1438 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED); | 
|---|
| 1439 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); | 
|---|
| 1440 | ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); | 
|---|
| 1441 | ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET); | 
|---|
| 1442 |  | 
|---|
| 1443 | BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); | 
|---|
| 1444 | BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); | 
|---|
| 1445 | BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); | 
|---|
| 1446 | BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); | 
|---|
| 1447 | BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); | 
|---|
| 1448 | BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); | 
|---|
| 1449 | BIND_ENUM_CONSTANT(PARAM_DAMPING); | 
|---|
| 1450 | BIND_ENUM_CONSTANT(PARAM_ANGLE); | 
|---|
| 1451 | BIND_ENUM_CONSTANT(PARAM_SCALE); | 
|---|
| 1452 | BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION); | 
|---|
| 1453 | BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED); | 
|---|
| 1454 | BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); | 
|---|
| 1455 | BIND_ENUM_CONSTANT(PARAM_MAX); | 
|---|
| 1456 |  | 
|---|
| 1457 | BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); | 
|---|
| 1458 | BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D. | 
|---|
| 1459 | BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D. | 
|---|
| 1460 | BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); | 
|---|
| 1461 |  | 
|---|
| 1462 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); | 
|---|
| 1463 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); | 
|---|
| 1464 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE_SURFACE); | 
|---|
| 1465 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE); | 
|---|
| 1466 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); | 
|---|
| 1467 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); | 
|---|
| 1468 | BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); | 
|---|
| 1469 | } | 
|---|
| 1470 |  | 
|---|
| 1471 | CPUParticles2D::CPUParticles2D() { | 
|---|
| 1472 | mesh = RenderingServer::get_singleton()->mesh_create(); | 
|---|
| 1473 | multimesh = RenderingServer::get_singleton()->multimesh_create(); | 
|---|
| 1474 | RenderingServer::get_singleton()->multimesh_set_mesh(multimesh, mesh); | 
|---|
| 1475 |  | 
|---|
| 1476 | set_emitting(true); | 
|---|
| 1477 | set_amount(8); | 
|---|
| 1478 | set_use_local_coordinates(false); | 
|---|
| 1479 |  | 
|---|
| 1480 | set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); | 
|---|
| 1481 | set_param_min(PARAM_ANGULAR_VELOCITY, 0); | 
|---|
| 1482 | set_param_min(PARAM_ORBIT_VELOCITY, 0); | 
|---|
| 1483 | set_param_min(PARAM_LINEAR_ACCEL, 0); | 
|---|
| 1484 | set_param_min(PARAM_RADIAL_ACCEL, 0); | 
|---|
| 1485 | set_param_min(PARAM_TANGENTIAL_ACCEL, 0); | 
|---|
| 1486 | set_param_min(PARAM_DAMPING, 0); | 
|---|
| 1487 | set_param_min(PARAM_ANGLE, 0); | 
|---|
| 1488 | set_param_min(PARAM_SCALE, 1); | 
|---|
| 1489 | set_param_min(PARAM_HUE_VARIATION, 0); | 
|---|
| 1490 | set_param_min(PARAM_ANIM_SPEED, 0); | 
|---|
| 1491 | set_param_min(PARAM_ANIM_OFFSET, 0); | 
|---|
| 1492 |  | 
|---|
| 1493 | set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0); | 
|---|
| 1494 | set_param_max(PARAM_ANGULAR_VELOCITY, 0); | 
|---|
| 1495 | set_param_max(PARAM_ORBIT_VELOCITY, 0); | 
|---|
| 1496 | set_param_max(PARAM_LINEAR_ACCEL, 0); | 
|---|
| 1497 | set_param_max(PARAM_RADIAL_ACCEL, 0); | 
|---|
| 1498 | set_param_max(PARAM_TANGENTIAL_ACCEL, 0); | 
|---|
| 1499 | set_param_max(PARAM_DAMPING, 0); | 
|---|
| 1500 | set_param_max(PARAM_ANGLE, 0); | 
|---|
| 1501 | set_param_max(PARAM_SCALE, 1); | 
|---|
| 1502 | set_param_max(PARAM_HUE_VARIATION, 0); | 
|---|
| 1503 | set_param_max(PARAM_ANIM_SPEED, 0); | 
|---|
| 1504 | set_param_max(PARAM_ANIM_OFFSET, 0); | 
|---|
| 1505 |  | 
|---|
| 1506 | for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { | 
|---|
| 1507 | particle_flags[i] = false; | 
|---|
| 1508 | } | 
|---|
| 1509 |  | 
|---|
| 1510 | set_color(Color(1, 1, 1, 1)); | 
|---|
| 1511 |  | 
|---|
| 1512 | _update_mesh_texture(); | 
|---|
| 1513 | } | 
|---|
| 1514 |  | 
|---|
| 1515 | CPUParticles2D::~CPUParticles2D() { | 
|---|
| 1516 | ERR_FAIL_NULL(RenderingServer::get_singleton()); | 
|---|
| 1517 | RS::get_singleton()->free(multimesh); | 
|---|
| 1518 | RS::get_singleton()->free(mesh); | 
|---|
| 1519 | } | 
|---|
| 1520 |  | 
|---|