Unravel Engine C++ Reference
Loading...
Searching...
No Matches
particle_emitter_component.cpp
Go to the documentation of this file.
3
11
12namespace unravel
13{
14
15
17{
18 // Register EmitterShape enum
19
20 entt::meta_factory<EmitterShape::Enum>{}
21 .type("EmitterShape"_hs)
23 entt::attribute{"name", "EmitterShape"},
24 entt::attribute{"pretty_name", "Emitter Shape"},
25 })
26 .data<EmitterShape::Sphere>("Sphere"_hs)
28 entt::attribute{"name", "Sphere"},
29 entt::attribute{"pretty_name", "Sphere"},
30 })
31 .data<EmitterShape::Hemisphere>("Hemisphere"_hs)
33 entt::attribute{"name", "Hemisphere"},
34 entt::attribute{"pretty_name", "Hemisphere"},
35 })
36 .data<EmitterShape::Circle>("Circle"_hs)
38 entt::attribute{"name", "Circle"},
39 entt::attribute{"pretty_name", "Circle"},
40 })
41 .data<EmitterShape::Box>("Box"_hs)
43 entt::attribute{"name", "Box"},
44 entt::attribute{"pretty_name", "Box"},
45 })
46 .data<EmitterShape::Rect>("Rect"_hs)
48 entt::attribute{"name", "Rect"},
49 entt::attribute{"pretty_name", "Rectangle"},
50 });
51
52
53 entt::meta_factory<EmitterDirection::Enum>{}
54 .type("EmitterDirection"_hs)
56 entt::attribute{"name", "EmitterDirection"},
57 entt::attribute{"pretty_name", "Emitter Direction"},
58 })
59 .data<EmitterDirection::Up>("Up"_hs)
61 entt::attribute{"name", "Up"},
62 entt::attribute{"pretty_name", "Up"},
63 })
64 .data<EmitterDirection::Outward>("Outward"_hs)
66 entt::attribute{"name", "Outward"},
67 entt::attribute{"pretty_name", "Outward"},
68 });
69
70 entt::meta_factory<bx::Easing::Enum>{}
71 .type("Easing"_hs)
73 entt::attribute{"name", "Easing"},
74 entt::attribute{"pretty_name", "Easing Function"},
75 })
76 .data<bx::Easing::Linear>("Linear"_hs)
78 entt::attribute{"name", "Linear"},
79 entt::attribute{"pretty_name", "Linear"},
80 })
81 .data<bx::Easing::Step>("Step"_hs)
83 entt::attribute{"name", "Step"},
84 entt::attribute{"pretty_name", "Step"},
85 })
86 .data<bx::Easing::SmoothStep>("SmoothStep"_hs)
88 entt::attribute{"name", "SmoothStep"},
89 entt::attribute{"pretty_name", "Smooth Step"},
90 })
91 .data<bx::Easing::InQuad>("InQuad"_hs)
93 entt::attribute{"name", "InQuad"},
94 entt::attribute{"pretty_name", "In Quad"},
95 })
96 .data<bx::Easing::OutQuad>("OutQuad"_hs)
98 entt::attribute{"name", "OutQuad"},
99 entt::attribute{"pretty_name", "Out Quad"},
100 })
101 .data<bx::Easing::InOutQuad>("InOutQuad"_hs)
103 entt::attribute{"name", "InOutQuad"},
104 entt::attribute{"pretty_name", "In-Out Quad"},
105 })
106 .data<bx::Easing::InCubic>("InCubic"_hs)
108 entt::attribute{"name", "InCubic"},
109 entt::attribute{"pretty_name", "In Cubic"},
110 })
111 .data<bx::Easing::OutCubic>("OutCubic"_hs)
113 entt::attribute{"name", "OutCubic"},
114 entt::attribute{"pretty_name", "Out Cubic"},
115 })
116 .data<bx::Easing::InOutCubic>("InOutCubic"_hs)
118 entt::attribute{"name", "InOutCubic"},
119 entt::attribute{"pretty_name", "In-Out Cubic"},
120 })
121 .data<bx::Easing::InSine>("InSine"_hs)
123 entt::attribute{"name", "InSine"},
124 entt::attribute{"pretty_name", "In Sine"},
125 })
126 .data<bx::Easing::OutSine>("OutSine"_hs)
128 entt::attribute{"name", "OutSine"},
129 entt::attribute{"pretty_name", "Out Sine"},
130 })
131 .data<bx::Easing::InOutSine>("InOutSine"_hs)
133 entt::attribute{"name", "InOutSine"},
134 entt::attribute{"pretty_name", "In-Out Sine"},
135 })
136 .data<bx::Easing::InExpo>("InExpo"_hs)
138 entt::attribute{"name", "InExpo"},
139 entt::attribute{"pretty_name", "In Expo"},
140 })
141 .data<bx::Easing::OutExpo>("OutExpo"_hs)
143 entt::attribute{"name", "OutExpo"},
144 entt::attribute{"pretty_name", "Out Expo"},
145 })
146 .data<bx::Easing::InOutExpo>("InOutExpo"_hs)
148 entt::attribute{"name", "InOutExpo"},
149 entt::attribute{"pretty_name", "In-Out Expo"},
150 })
151 .data<bx::Easing::InElastic>("InElastic"_hs)
153 entt::attribute{"name", "InElastic"},
154 entt::attribute{"pretty_name", "In Elastic"},
155 })
156 .data<bx::Easing::OutElastic>("OutElastic"_hs)
158 entt::attribute{"name", "OutElastic"},
159 entt::attribute{"pretty_name", "Out Elastic"},
160 })
161 .data<bx::Easing::InOutElastic>("InOutElastic"_hs)
163 entt::attribute{"name", "InOutElastic"},
164 entt::attribute{"pretty_name", "In-Out Elastic"},
165 })
166 .data<bx::Easing::InBack>("InBack"_hs)
168 entt::attribute{"name", "InBack"},
169 entt::attribute{"pretty_name", "In Back"},
170 })
171 .data<bx::Easing::OutBack>("OutBack"_hs)
173 entt::attribute{"name", "OutBack"},
174 entt::attribute{"pretty_name", "Out Back"},
175 })
176 .data<bx::Easing::InOutBack>("InOutBack"_hs)
178 entt::attribute{"name", "InOutBack"},
179 entt::attribute{"pretty_name", "In-Out Back"},
180 })
181 .data<bx::Easing::InBounce>("InBounce"_hs)
183 entt::attribute{"name", "InBounce"},
184 entt::attribute{"pretty_name", "In Bounce"},
185 })
186 .data<bx::Easing::OutBounce>("OutBounce"_hs)
188 entt::attribute{"name", "OutBounce"},
189 entt::attribute{"pretty_name", "Out Bounce"},
190 })
191 .data<bx::Easing::InOutBounce>("InOutBounce"_hs)
193 entt::attribute{"name", "InOutBounce"},
194 entt::attribute{"pretty_name", "In-Out Bounce"},
195 });
196
197 entt::meta_factory<SimulationSpace::Enum>{}
198 .type("SimulationSpace"_hs)
200 entt::attribute{"name", "SimulationSpace"},
201 entt::attribute{"pretty_name", "Simulation Space"},
202 })
203 .data<SimulationSpace::World>("World"_hs)
205 entt::attribute{"name", "World"},
206 entt::attribute{"pretty_name", "World"},
207 })
208 .data<SimulationSpace::Local>("Local"_hs)
210 entt::attribute{"name", "Local"},
211 entt::attribute{"pretty_name", "Local"},
212 });
213
214 entt::meta_factory<particle_emitter_component>{}
215 .type("particle_emitter_component"_hs)
217 entt::attribute{"name", "particle_emitter_component"},
218 entt::attribute{"category", "RENDERING"},
219 entt::attribute{"pretty_name", "Particle Emitter"},
220 })
221 .func<&component_meta<particle_emitter_component>::exists>("component_exists"_hs)
222 .func<&component_meta<particle_emitter_component>::add>("component_add"_hs)
223 .func<&component_meta<particle_emitter_component>::remove>("component_remove"_hs)
224 .func<&component_meta<particle_emitter_component>::save>("component_save"_hs)
225 .func<&component_meta<particle_emitter_component>::load>("component_load"_hs)
227 .custom<entt::attributes>(entt::attributes{
228 entt::attribute{"name", "enabled"},
229 entt::attribute{"pretty_name", "Enabled"},
230 entt::attribute{"tooltip", "Controls whether the particle emitter actively spawns and updates particles. Disabled emitters stop emission but existing particles continue to animate."},
231 })
232 .data<&particle_emitter_component::set_loop, &particle_emitter_component::is_loop>("loop"_hs)
234 entt::attribute{"name", "loop"},
235 entt::attribute{"pretty_name", "Loop"},
236 entt::attribute{"tooltip", "Controls whether the emitter loops continuously (true) or emits only once up to max particles (false). Non-looping emitters stop emitting after reaching max particles."},
237 })
238 .data<&particle_emitter_component::set_max_particles, &particle_emitter_component::get_max_particles>("max_particles"_hs)
240 entt::attribute{"name", "max_particles"},
241 entt::attribute{"pretty_name", "Max Particles"},
242 entt::attribute{"tooltip", "Maximum number of particles that can exist simultaneously. Higher values allow more dense effects but impact performance."},
243 })
244 .data<nullptr, &particle_emitter_component::get_num_particles>("num_particles"_hs)
246 entt::attribute{"name", "num_particles"},
247 entt::attribute{"pretty_name", "Num Particles"},
248 entt::attribute{"tooltip", "Current number of active particles in the system (read-only). Updates in real-time as particles spawn and die."},
249 })
250 .data<&particle_emitter_component::set_emission_lifetime, &particle_emitter_component::get_emission_lifetime>("emission_lifetime"_hs)
252 entt::attribute{"name", "emission_lifetime"},
253 entt::attribute{"pretty_name", "Emission Lifetime"},
254 entt::attribute{"tooltip", "Duration of one complete emission cycle in seconds. Controls how long the emitter takes to spawn all particles before restarting the cycle."},
255 entt::attribute{"min", 0.0f},
256 entt::attribute{"step", 0.1f},
257 })
258 .data<&particle_emitter_component::set_lifetime, &particle_emitter_component::get_lifetime>("lifetime"_hs)
260 entt::attribute{"name", "lifetime"},
261 entt::attribute{"pretty_name", "Lifetime"},
262 entt::attribute{"tooltip", "How long each particle lives in seconds. Longer lifetimes create more persistent effects."},
263 entt::attribute{"min", 0.0f},
264 entt::attribute{"step", 0.1f},
265 })
266 .data<&particle_emitter_component::set_emission_rate, &particle_emitter_component::get_emission_rate>("emission_rate"_hs)
268 entt::attribute{"name", "emission_rate"},
269 entt::attribute{"pretty_name", "Emission Rate"},
270 entt::attribute{"tooltip", "Emission rate in particles per second. Higher values create denser particle effects. 0 = no emission."},
271 entt::attribute{"min", 0.0f},
272 })
273 .data<&particle_emitter_component::set_temporal_motion, &particle_emitter_component::get_temporal_motion>("temporal_motion"_hs)
275 entt::attribute{"name", "temporal_motion"},
276 entt::attribute{"pretty_name", "Temporal Motion"},
277 entt::attribute{"tooltip", "Controls temporal interpolation for moving emitters. 1.0 = full interpolation (smooth trails), 0.0 = no interpolation (discrete emission)."},
278 entt::attribute{"min", 0.0f},
279 entt::attribute{"max", 1.0f},
280 })
281
282 .data<&particle_emitter_component::set_gravity_scale, &particle_emitter_component::get_gravity_scale>("gravity_scale"_hs)
284 entt::attribute{"name", "gravity_scale"},
285 entt::attribute{"pretty_name", "Gravity Scale"},
286 entt::attribute{"tooltip", "Multiplier for gravity effect on particles. 0.0 = no gravity, 1.0 = Earth-like gravity, negative values = upward force."},
287 entt::attribute{"step", 0.01f},
288
289 })
290
291 .data<nullptr, &particle_emitter_component::get_world_bounds>("world_bounds"_hs)
293 entt::attribute{"name", "world_bounds"},
294 entt::attribute{"pretty_name", "World Bounds"},
295 entt::attribute{"tooltip", "Bounding box containing all particles in world space. Used for culling and optimization (read-only)."},
296 })
297 .data<&particle_emitter_component::set_emission_shape_scale, &particle_emitter_component::get_emission_shape_scale>("emission_shape_scale"_hs)
299 entt::attribute{"name", "emission_shape_scale"},
300 entt::attribute{"pretty_name", "Emitter Shape Scale"},
301 entt::attribute{"tooltip", "Scale of the emission shape. 1.0 = no scaling, 2.0 = double size, 0.5 = half size."},
302 })
303 .data<&particle_emitter_component::set_shape, &particle_emitter_component::get_shape>("shape"_hs)
305 entt::attribute{"name", "shape"},
306 entt::attribute{"pretty_name", "Emitter Shape"},
307 entt::attribute{"tooltip", "Geometric shape from which particles are spawned. Sphere = 3D ball, Hemisphere = half sphere, Circle = 2D ring, Disc = filled circle, Rect = rectangle."},
308 })
309
310 .data<&particle_emitter_component::set_direction, &particle_emitter_component::get_direction>("direction"_hs)
312 entt::attribute{"name", "direction"},
313 entt::attribute{"pretty_name", "Emitter Direction"},
314 entt::attribute{"tooltip", "Initial direction particles move when spawned. Up = particles move upward, Outward = particles move away from spawn position."},
315 })
316
317 .data<&particle_emitter_component::set_simulation_space, &particle_emitter_component::get_simulation_space>("simulation_space"_hs)
319 entt::attribute{"name", "simulation_space"},
320 entt::attribute{"pretty_name", "Simulation Space"},
321 entt::attribute{"tooltip", "Controls whether particles are simulated in world space or local space."},
322 })
323
324 .data<&particle_emitter_component::set_velocity_gradient, &particle_emitter_component::get_velocity_gradient>("velocity_gradient"_hs)
326 entt::attribute{"name", "velocity_gradient"},
327 entt::attribute{"pretty_name", "Velocity Gradient"},
328 entt::attribute{"tooltip", "Velocity range gradient over particle lifetime. Controls how particle speed changes from spawn to death."},
329 entt::attribute{"group", "Velocity over lifetime"},
330 entt::attribute{"step", 0.05f},
331
332 })
333 .data<&particle_emitter_component::set_velocity_damping, &particle_emitter_component::get_velocity_damping>("velocity_damping"_hs)
335 entt::attribute{"name", "velocity_damping"},
336 entt::attribute{"pretty_name", "Velocity Damping"},
337 entt::attribute{"tooltip", "Reduces particle velocity over time. 0.0 = no damping (particles maintain speed), 1.0 = full damping (particles stop immediately)."},
338 entt::attribute{"min", 0.0f},
339 entt::attribute{"max", 1.0f},
340 entt::attribute{"step", 0.01f},
341 entt::attribute{"group", "Velocity over lifetime"},
342
343 })
344 .data<&particle_emitter_component::set_position_easing, &particle_emitter_component::get_position_easing>("position_easing"_hs)
346 entt::attribute{"name", "position_easing"},
347 entt::attribute{"pretty_name", "Position Easing"},
348 entt::attribute{"tooltip", "Curve controlling how particles move from start to end position. Linear = constant speed, EaseIn = slow start, EaseOut = slow end."},
349 entt::attribute{"group", "Position over lifetime"},
350
351 })
352 .data<&particle_emitter_component::set_force_over_lifetime, &particle_emitter_component::get_force_over_lifetime>("force_over_lifetime"_hs)
354 entt::attribute{"name", "force_over_lifetime"},
355 entt::attribute{"pretty_name", "Force Over Lifetime"},
356 entt::attribute{"tooltip", "Additional force applied to particles throughout their lifetime. Use for wind, magnetism, or other environmental effects. Values are in world units."},
357 entt::attribute{"group", "Force over lifetime"},
358
359 })
360 .data<&particle_emitter_component::set_scale_gradient, &particle_emitter_component::get_scale_gradient>("scale_gradient"_hs)
362 entt::attribute{"name", "scale_gradient"},
363 entt::attribute{"pretty_name", "Scale Gradient"},
364 entt::attribute{"tooltip", "Scale range gradient over particle lifetime. Controls how particle size changes from spawn to death."},
365 entt::attribute{"group", "Size over lifetime"},
366
367 })
368 .data<&particle_emitter_component::set_size_by_speed_range, &particle_emitter_component::get_size_by_speed_range>("size_by_speed_range"_hs)
370 entt::attribute{"name", "size_by_speed_range"},
371 entt::attribute{"pretty_name", "Size by Speed Range"},
372 entt::attribute{"tooltip", "Size multiplier range based on particle speed. Min = size at slow speed, Max = size at fast speed. Use values like 0.5-2.0 for dramatic effects."},
373 entt::attribute{"min", 0.1f},
374 entt::attribute{"max", 5.0f},
375 entt::attribute{"group", "Size by Speed"},
376
377 })
378 .data<&particle_emitter_component::set_size_by_speed_velocity_range, &particle_emitter_component::get_size_by_speed_velocity_range>("size_by_speed_velocity_range"_hs)
380 entt::attribute{"name", "size_by_speed_velocity_range"},
381 entt::attribute{"pretty_name", "Size by Speed Velocity Range"},
382 entt::attribute{"tooltip", "Velocity range for size mapping. Particles moving at min speed get min size, particles at max speed get max size."},
383 entt::attribute{"min", 0.0f},
384 entt::attribute{"max", 100.0f},
385 entt::attribute{"group", "Size by Speed"},
386
387 })
388 .data<&particle_emitter_component::set_blend_gradient, &particle_emitter_component::get_blend_gradient>("blend_gradient"_hs)
390 entt::attribute{"name", "blend_gradient"},
391 entt::attribute{"pretty_name", "Blend Gradient"},
392 entt::attribute{"tooltip", "Opacity range gradient over particle lifetime. Controls how particle transparency changes from spawn to death."},
393 entt::attribute{"group", "Opacity over lifetime"},
394
395 })
396 .data<&particle_emitter_component::set_blend_multiplier, &particle_emitter_component::get_blend_multiplier>("blend_multiplier"_hs)
398 entt::attribute{"name", "blend_multiplier"},
399 entt::attribute{"pretty_name", "Blend Multiplier"},
400 entt::attribute{"tooltip", "Global blend multiplier for all particles regardless of lifetime. 0.0 = fully transparent, 1.0 = no change, values > 1.0 = enhanced opacity."},
401 entt::attribute{"min", 0.0f},
402 entt::attribute{"max", 1.0f},
403 entt::attribute{"step", 0.01f},
404 entt::attribute{"group", "Opacity over lifetime"},
405 })
406 .data<&particle_emitter_component::set_color_gradient, &particle_emitter_component::get_color_gradient>("color_gradient"_hs)
408 entt::attribute{"name", "color_gradient"},
409 entt::attribute{"pretty_name", "Color Gradient"},
410 entt::attribute{"tooltip", "Color gradient defining particle color over lifetime. Colors are interpolated smoothly based on gradient keyframes."},
411 entt::attribute{"group", "Color over lifetime"},
412
413 })
414 .data<&particle_emitter_component::set_color_by_speed_gradient, &particle_emitter_component::get_color_by_speed_gradient>("color_by_speed_gradient"_hs)
416 entt::attribute{"name", "color_by_speed_gradient"},
417 entt::attribute{"pretty_name", "Color by Speed Gradient"},
418 entt::attribute{"tooltip", "Color gradient applied based on particle speed. Slow particles use colors from the start of the gradient, fast particles use colors from the end."},
419 entt::attribute{"group", "Color by Speed"},
420
421 })
422 .data<&particle_emitter_component::set_color_by_speed_velocity_range, &particle_emitter_component::get_color_by_speed_velocity_range>("color_by_speed_velocity_range"_hs)
424 entt::attribute{"name", "color_by_speed_velocity_range"},
425 entt::attribute{"pretty_name", "Color by Speed Velocity Range"},
426 entt::attribute{"tooltip", "Velocity range for color mapping. Particles moving at min speed get slow color, particles at max speed get fast color."},
427 entt::attribute{"min", 0.0f},
428 entt::attribute{"group", "Color by Speed"},
429
430 })
431 .data<&particle_emitter_component::set_lifetime_by_emitter_speed_gradient, &particle_emitter_component::get_lifetime_by_emitter_speed_gradient>("lifetime_by_emitter_speed_gradient"_hs)
433 entt::attribute{"name", "lifetime_by_emitter_speed_gradient"},
434 entt::attribute{"pretty_name", "Lifetime by Emitter Speed Gradient"},
435 entt::attribute{"tooltip", "Lifetime multiplier gradient based on emitter movement speed. Allows particles to live longer/shorter based on how fast the emitter is moving."},
436 entt::attribute{"group", "Lifetime by Emitter Speed"},
437 entt::attribute{"min", 0.0f},
438 entt::attribute{"step", 0.01f},
439 })
440 .data<&particle_emitter_component::set_lifetime_by_emitter_speed_range, &particle_emitter_component::get_lifetime_by_emitter_speed_range>("lifetime_by_emitter_speed_range"_hs)
442 entt::attribute{"name", "lifetime_by_emitter_speed_range"},
443 entt::attribute{"pretty_name", "Lifetime by Emitter Speed Range"},
444 entt::attribute{"tooltip", "Emitter speed range for lifetime mapping. Emitters moving at min speed get slow gradient value, emitters at max speed get fast gradient value."},
445 entt::attribute{"min", 0.0f},
446 entt::attribute{"step", 0.01f},
447 entt::attribute{"group", "Lifetime by Emitter Speed"},
448 })
449 .data<&particle_emitter_component::set_texture, &particle_emitter_component::get_texture>("texture"_hs)
451 entt::attribute{"name", "texture"},
452 entt::attribute{"pretty_name", "Texture"},
453 entt::attribute{"tooltip", "Texture asset used to render each particle. Should be a square texture with alpha channel for best results. Common formats: smoke, fire, sparkle, etc."},
454 });
455
456}
457
459{
460 try_save(ar, ser20::make_nvp("enabled", obj.is_enabled()));
461 try_save(ar, ser20::make_nvp("shape", obj.get_shape()));
462 try_save(ar, ser20::make_nvp("direction", obj.get_direction()));
463 try_save(ar, ser20::make_nvp("simulation_space", obj.get_simulation_space()));
464 try_save(ar, ser20::make_nvp("max_particles", obj.get_max_particles()));
465
466
467 // Emission properties
468 try_save(ar, ser20::make_nvp("emission_lifetime", obj.get_emission_lifetime()));
469 try_save(ar, ser20::make_nvp("emission_shape_scale", obj.get_emission_shape_scale()));
470 try_save(ar, ser20::make_nvp("gravity_scale", obj.get_gravity_scale()));
471 try_save(ar, ser20::make_nvp("emission_rate", obj.get_emission_rate()));
472 try_save(ar, ser20::make_nvp("temporal_motion", obj.get_temporal_motion()));
473 try_save(ar, ser20::make_nvp("velocity_damping", obj.get_velocity_damping()));
474 try_save(ar, ser20::make_nvp("force_over_lifetime", obj.get_force_over_lifetime()));
475 try_save(ar, ser20::make_nvp("size_by_speed_range", obj.get_size_by_speed_range()));
476 try_save(ar, ser20::make_nvp("size_by_speed_velocity_range", obj.get_size_by_speed_velocity_range()));
477 try_save(ar, ser20::make_nvp("color_by_speed_gradient", obj.get_color_by_speed_gradient()));
478 try_save(ar, ser20::make_nvp("color_by_speed_velocity_range", obj.get_color_by_speed_velocity_range()));
479 try_save(ar, ser20::make_nvp("lifetime_by_emitter_speed_gradient", obj.get_lifetime_by_emitter_speed_gradient()));
480 try_save(ar, ser20::make_nvp("lifetime_by_emitter_speed_range", obj.get_lifetime_by_emitter_speed_range()));
481
482 // Gradient properties
483 try_save(ar, ser20::make_nvp("lifetime", obj.get_lifetime()));
484 try_save(ar, ser20::make_nvp("velocity_gradient", obj.get_velocity_gradient()));
485 try_save(ar, ser20::make_nvp("scale_gradient", obj.get_scale_gradient()));
486 try_save(ar, ser20::make_nvp("blend_gradient", obj.get_blend_gradient()));
487 try_save(ar, ser20::make_nvp("blend_multiplier", obj.get_blend_multiplier()));
488
489 // Colors
490 try_save(ar, ser20::make_nvp("color_gradient", obj.get_color_gradient()));
491
492 // Easing functions (only position easing remains)
493 try_save(ar, ser20::make_nvp("position_easing", obj.get_position_easing()));
494
495 // Texture handle
496 try_save(ar, ser20::make_nvp("texture", obj.get_texture()));
497
498 // Loop control
499 try_save(ar, ser20::make_nvp("loop", obj.is_loop()));
500}
503
505{
506 bool enabled{true};
507 if(try_load(ar, ser20::make_nvp("enabled", enabled)))
508 {
509 obj.set_enabled(enabled);
510 }
511
514 if(try_load(ar, ser20::make_nvp("shape", shape)))
515 {
516 obj.set_shape(shape);
517 }
518 if(try_load(ar, ser20::make_nvp("direction", direction)))
519 {
520 obj.set_direction(direction);
521 }
522
524 if(try_load(ar, ser20::make_nvp("simulation_space", simulation_space)))
525 {
526 obj.set_simulation_space(simulation_space);
527 }
528
529 uint32_t max_particles{1024};
530 if(try_load(ar, ser20::make_nvp("max_particles", max_particles)))
531 {
532 obj.set_max_particles(max_particles);
533 }
534
535 // Emission properties
536 std::chrono::duration<float> emission_lifetime{2.0f};
537 if(try_load(ar, ser20::make_nvp("emission_lifetime", emission_lifetime)))
538 {
539 obj.set_emission_lifetime(emission_lifetime);
540 }
541
542 math::vec3 emission_shape_scale{1.0f, 1.0f, 1.0f};
543 if(try_load(ar, ser20::make_nvp("emission_shape_scale", emission_shape_scale)))
544 {
545 obj.set_emission_shape_scale(emission_shape_scale);
546 }
547
548 float gravity_scale{0.0f};
549 if(try_load(ar, ser20::make_nvp("gravity_scale", gravity_scale)))
550 {
551 obj.set_gravity_scale(gravity_scale);
552 }
553
554 float emission_rate{50.0f};
555 if(try_load(ar, ser20::make_nvp("emission_rate", emission_rate)))
556 {
557 obj.set_emission_rate(emission_rate);
558 }
559
560 float temporal_motion{1.0f};
561 if(try_load(ar, ser20::make_nvp("temporal_motion", temporal_motion)))
562 {
563 obj.set_temporal_motion(temporal_motion);
564 }
565
566 float velocity_damping{0.0f};
567 if(try_load(ar, ser20::make_nvp("velocity_damping", velocity_damping)))
568 {
569 obj.set_velocity_damping(velocity_damping);
570 }
571
572 math::vec3 force_over_lifetime{0.0f, 0.0f, 0.0f};
573 if(try_load(ar, ser20::make_nvp("force_over_lifetime", force_over_lifetime)))
574 {
575 obj.set_force_over_lifetime(force_over_lifetime);
576 }
577
578 frange_t size_by_speed_range{1.0f, 1.0f};
579 if(try_load(ar, ser20::make_nvp("size_by_speed_range", size_by_speed_range)))
580 {
581 obj.set_size_by_speed_range(size_by_speed_range);
582 }
583
584 frange_t size_by_speed_velocity_range{0.0f, 10.0f};
585 if(try_load(ar, ser20::make_nvp("size_by_speed_velocity_range", size_by_speed_velocity_range)))
586 {
587 obj.set_size_by_speed_velocity_range(size_by_speed_velocity_range);
588 }
589
590 math::gradient<math::color> color_by_speed_gradient;
591 if(try_load(ar, ser20::make_nvp("color_by_speed_gradient", color_by_speed_gradient)))
592 {
593 obj.set_color_by_speed_gradient(color_by_speed_gradient);
594 }
595 else
596 {
597 // Legacy loading: try to load old slow/fast colors and convert to gradient
598 math::color color_by_speed_slow_color{0xffffffff};
599 math::color color_by_speed_fast_color{0xffffffff};
600 bool has_slow = try_load(ar, ser20::make_nvp("color_by_speed_slow_color", color_by_speed_slow_color));
601 bool has_fast = try_load(ar, ser20::make_nvp("color_by_speed_fast_color", color_by_speed_fast_color));
602
603 if(has_slow || has_fast)
604 {
605 math::gradient<math::color> legacy_gradient;
606 legacy_gradient.add_point(color_by_speed_slow_color, 0.0f);
607 legacy_gradient.add_point(color_by_speed_fast_color, 1.0f);
608 obj.set_color_by_speed_gradient(legacy_gradient);
609 }
610 }
611
612 frange_t color_by_speed_velocity_range{0.0f, 10.0f};
613 if(try_load(ar, ser20::make_nvp("color_by_speed_velocity_range", color_by_speed_velocity_range)))
614 {
615 obj.set_color_by_speed_velocity_range(color_by_speed_velocity_range);
616 }
617
618 math::gradient<float> lifetime_by_emitter_speed_gradient;
619 if(try_load(ar, ser20::make_nvp("lifetime_by_emitter_speed_gradient", lifetime_by_emitter_speed_gradient)))
620 {
621 obj.set_lifetime_by_emitter_speed_gradient(lifetime_by_emitter_speed_gradient);
622 }
623
624 frange_t lifetime_by_emitter_speed_range{0.0f, 10.0f};
625 if(try_load(ar, ser20::make_nvp("lifetime_by_emitter_speed_range", lifetime_by_emitter_speed_range)))
626 {
627 obj.set_lifetime_by_emitter_speed_range(lifetime_by_emitter_speed_range);
628 }
629
630 // Gradient properties
631 std::chrono::duration<float> lifetime{1.0f};
632 if(try_load(ar, ser20::make_nvp("lifetime", lifetime)))
633 {
634 obj.set_lifetime(lifetime);
635 }
636
637 math::gradient<frange_t> velocity_gradient;
638 if(try_load(ar, ser20::make_nvp("velocity_gradient", velocity_gradient)))
639 {
640 obj.set_velocity_gradient(velocity_gradient);
641 }
642
643 math::gradient<frange_t> scale_gradient;
644 if(try_load(ar, ser20::make_nvp("scale_gradient", scale_gradient)))
645 {
646 obj.set_scale_gradient(scale_gradient);
647 }
648
649 math::gradient<frange_t> blend_gradient;
650 if(try_load(ar, ser20::make_nvp("blend_gradient", blend_gradient)))
651 {
652 obj.set_blend_gradient(blend_gradient);
653 }
654
655 float blend_multiplier{1.0f};
656 if(try_load(ar, ser20::make_nvp("blend_multiplier", blend_multiplier)))
657 {
658 obj.set_blend_multiplier(blend_multiplier);
659 }
660
661 // Colors
662 // Try to load gradient first (new format)
663 math::gradient<math::color> color_gradient;
664 if(try_load(ar, ser20::make_nvp("color_gradient", color_gradient)))
665 {
666 obj.set_color_gradient(color_gradient);
667 }
668
669 // Easing functions (only position easing remains)
670 bx::Easing::Enum position_easing{};
671 if(try_load(ar, ser20::make_nvp("position_easing", position_easing)))
672 {
673 obj.set_position_easing(position_easing);
674 }
675
676 // Load old easing values for backward compatibility but ignore them
677 bx::Easing::Enum blend_easing{}, scale_easing{};
678 try_load(ar, ser20::make_nvp("blend_easing", blend_easing));
679 try_load(ar, ser20::make_nvp("scale_easing", scale_easing));
680
681 // Texture handle
683 if(try_load(ar, ser20::make_nvp("texture", texture)))
684 {
685 obj.set_texture(texture);
686 }
687
688 // Loop control
689 bool loop{true}; // Default to true for backward compatibility
690 if(try_load(ar, ser20::make_nvp("loop", loop)))
691 {
692 obj.set_loop(loop);
693 }
694}
697
698} // namespace unravel
auto add_point(const T &element, float progress) -> size_t
Definition gradient.hpp:8
Component that wraps particle system emitter functionality.
void set_enabled(bool enabled)
Sets whether the emitter is enabled.
auto is_enabled() const -> bool
Checks if the emitter is enabled.
attributes::value_type attribute
Definition reflection.h:19
std::map< std::string, meta_any > attributes
Definition reflection.h:18
BinaryInputArchive iarchive_binary_t
simd::JSONOutputArchive oarchive_associative_t
BinaryOutputArchive oarchive_binary_t
simd::JSONInputArchive iarchive_associative_t
#define REFLECT(cls)
Definition reflection.h:133
#define SAVE_INSTANTIATE(cls, Archive)
#define LOAD(cls)
auto try_save(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
#define LOAD_INSTANTIATE(cls, Archive)
#define SAVE(cls)
auto try_load(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
Represents a handle to an asset, providing access and management functions.