20 entt::meta_factory<ps_soa::emitter_shape>{}
21 .type(
"EmitterShape"_hs)
26 .data<ps_soa::emitter_shape::sphere>(
"Sphere"_hs)
31 .data<ps_soa::emitter_shape::hemisphere>(
"Hemisphere"_hs)
36 .data<ps_soa::emitter_shape::circle>(
"Circle"_hs)
41 .data<ps_soa::emitter_shape::box>(
"Box"_hs)
46 .data<ps_soa::emitter_shape::rect>(
"Rect"_hs)
53 entt::meta_factory<ps_soa::emitter_direction>{}
54 .type(
"EmitterDirection"_hs)
59 .data<ps_soa::emitter_direction::up>(
"Up"_hs)
64 .data<ps_soa::emitter_direction::outward>(
"Outward"_hs)
69 .data<ps_soa::emitter_direction::inward>(
"Inward"_hs)
75 entt::meta_factory<ps_soa::spawn_location>{}
76 .type(
"EmitterSpawnLocation"_hs)
81 .data<ps_soa::spawn_location::inside>(
"Inside"_hs)
86 .data<ps_soa::spawn_location::surface>(
"Surface"_hs)
92 entt::meta_factory<bx::Easing::Enum>{}
98 .data<bx::Easing::Linear>(
"Linear"_hs)
103 .data<bx::Easing::Step>(
"Step"_hs)
108 .data<bx::Easing::SmoothStep>(
"SmoothStep"_hs)
113 .data<bx::Easing::InQuad>(
"InQuad"_hs)
118 .data<bx::Easing::OutQuad>(
"OutQuad"_hs)
123 .data<bx::Easing::InOutQuad>(
"InOutQuad"_hs)
128 .data<bx::Easing::InCubic>(
"InCubic"_hs)
133 .data<bx::Easing::OutCubic>(
"OutCubic"_hs)
138 .data<bx::Easing::InOutCubic>(
"InOutCubic"_hs)
143 .data<bx::Easing::InSine>(
"InSine"_hs)
148 .data<bx::Easing::OutSine>(
"OutSine"_hs)
153 .data<bx::Easing::InOutSine>(
"InOutSine"_hs)
158 .data<bx::Easing::InExpo>(
"InExpo"_hs)
163 .data<bx::Easing::OutExpo>(
"OutExpo"_hs)
168 .data<bx::Easing::InOutExpo>(
"InOutExpo"_hs)
173 .data<bx::Easing::InElastic>(
"InElastic"_hs)
178 .data<bx::Easing::OutElastic>(
"OutElastic"_hs)
183 .data<bx::Easing::InOutElastic>(
"InOutElastic"_hs)
188 .data<bx::Easing::InBack>(
"InBack"_hs)
193 .data<bx::Easing::OutBack>(
"OutBack"_hs)
198 .data<bx::Easing::InOutBack>(
"InOutBack"_hs)
203 .data<bx::Easing::InBounce>(
"InBounce"_hs)
208 .data<bx::Easing::OutBounce>(
"OutBounce"_hs)
213 .data<bx::Easing::InOutBounce>(
"InOutBounce"_hs)
219 entt::meta_factory<ps_soa::simulation_space>{}
220 .type(
"SimulationSpace"_hs)
225 .data<ps_soa::simulation_space::world>(
"World"_hs)
230 .data<ps_soa::simulation_space::local>(
"Local"_hs)
236 entt::meta_factory<ps_soa::texture_mode>{}
237 .type(
"TextureMode"_hs)
242 .data<ps_soa::texture_mode::multi_channel>(
"MultiChannel"_hs)
247 .data<ps_soa::texture_mode::mask>(
"Mask"_hs)
253 entt::meta_factory<ps_soa::render_mode>{}
254 .type(
"RenderMode"_hs)
259 .data<ps_soa::render_mode::billboard>(
"Billboard"_hs)
264 .data<ps_soa::render_mode::horizontal_billboard>(
"HorizontalBillboard"_hs)
269 .data<ps_soa::render_mode::vertical_billboard>(
"VerticalBillboard"_hs)
275 entt::meta_factory<ps_soa::blend_mode>{}
276 .type(
"BlendMode"_hs)
281 .data<ps_soa::blend_mode::normal>(
"Normal"_hs)
286 .data<ps_soa::blend_mode::additive>(
"Additive"_hs)
291 .data<ps_soa::blend_mode::multiply>(
"Multiply"_hs)
297 entt::meta_factory<ps_soa::particle_sim_backend>{}
298 .type(
"ParticleSimBackend"_hs)
303 .data<ps_soa::particle_sim_backend::cpu>(
"CPU"_hs)
308 .data<ps_soa::particle_sim_backend::gpu>(
"GPU"_hs)
314 entt::meta_factory<particle_emitter_component::culling_mode>{}
315 .type(
"ParticleCullingMode"_hs)
320 .data<particle_emitter_component::culling_mode::always_simulate>(
"always_simulate"_hs)
325 .data<particle_emitter_component::culling_mode::renderer_based>(
"renderer_based"_hs)
331 entt::meta_factory<particle_emitter_component>{}
332 .type(
"particle_emitter_component"_hs)
348 entt::attribute{
"tooltip",
"Controls whether the particle emitter actively spawns and updates particles. Disabled emitters stop emission but existing particles continue to animate."},
350 .data<&particle_emitter_component::set_culling_mode, &particle_emitter_component::get_culling_mode>(
"culling_mode"_hs)
355 "Always Simulate: update even when not drawn. "
356 "Renderer Based: freeze spawn/sim when no camera drew the emitter last frame (same as animation)."},
358 .data<&particle_emitter_component::set_loop, &particle_emitter_component::is_loop>(
"loop"_hs)
362 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."},
364 .data<&particle_emitter_component::set_simulation_space, &particle_emitter_component::get_simulation_space>(
"simulation_space"_hs)
368 entt::attribute{
"tooltip",
"Controls whether particles are simulated in world space or local space."},
370 .data<&particle_emitter_component::set_simulation_backend, &particle_emitter_component::get_simulation_backend>(
"simulation_backend"_hs)
375 "CPU: batched CPU property update and instance gather (best for many mid-size emitters). "
376 "GPU: compute pack per emitter (best for a few very large emitters). Requires GPU pack shader."},
378 .data<&particle_emitter_component::set_max_particles, &particle_emitter_component::get_max_particles>(
"max_particles"_hs)
382 entt::attribute{
"tooltip",
"Maximum number of particles that can exist simultaneously. Higher values allow more dense effects but impact performance."},
384 .data<nullptr, &particle_emitter_component::get_num_particles>(
"num_particles"_hs)
388 entt::attribute{
"tooltip",
"Current number of active particles in the system (read-only). Updates in real-time as particles spawn and die."},
390 .data<nullptr, &particle_emitter_component::get_world_bounds>(
"world_bounds"_hs)
394 entt::attribute{
"tooltip",
"Bounding box containing all particles in world space. Used for culling and optimization (read-only)."},
396 .data<&particle_emitter_component::set_lifetime, &particle_emitter_component::get_lifetime>(
"lifetime"_hs)
400 entt::attribute{
"tooltip",
"How long each particle lives in seconds. Longer lifetimes create more persistent effects."},
406 .data<&particle_emitter_component::set_emission_rate, &particle_emitter_component::get_emission_rate>(
"emission_rate"_hs)
410 entt::attribute{
"tooltip",
"Emission rate in particles per second. Higher values create denser particle effects. 0 = no emission."},
414 .data<&particle_emitter_component::set_emission_lifetime, &particle_emitter_component::get_emission_lifetime>(
"emission_lifetime"_hs)
418 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."},
423 .data<&particle_emitter_component::set_start_delay, &particle_emitter_component::get_start_delay>(
"start_delay"_hs)
427 entt::attribute{
"tooltip",
"Delay in seconds before particle emission starts. Particles will begin spawning after this delay period."},
432 .data<&particle_emitter_component::set_temporal_motion, &particle_emitter_component::get_temporal_motion>(
"temporal_motion"_hs)
436 entt::attribute{
"tooltip",
"Controls temporal interpolation for moving emitters. 1.0 = full interpolation (smooth trails), 0.0 = no interpolation (discrete emission)."},
443 .data<&particle_emitter_component::set_shape, &particle_emitter_component::get_shape>(
"shape"_hs)
447 entt::attribute{
"tooltip",
"Geometric shape from which particles are spawned. Sphere = 3D ball, Hemisphere = half sphere, Circle = 2D ring, Disc = filled circle, Rect = rectangle."},
450 .data<&particle_emitter_component::set_direction, &particle_emitter_component::get_direction>(
"direction"_hs)
454 entt::attribute{
"tooltip",
"Initial direction particles move when spawned. Up = particles move upward, Outward = particles move away from spawn position, Inward = particles move towards spawn position (only visible in 3D space)."},
457 .data<&particle_emitter_component::set_spawn_location, &particle_emitter_component::get_spawn_location>(
"spawn_location"_hs)
461 entt::attribute{
"tooltip",
"Controls where particles spawn within the emission shape. Inside = particles spawn anywhere inside the shape volume/area, Surface = particles spawn only on the surface/perimeter of the shape."},
464 .data<&particle_emitter_component::set_emission_shape_position, &particle_emitter_component::get_emission_shape_position>(
"emission_shape_position"_hs)
468 entt::attribute{
"tooltip",
"Position offset of the emission shape relative to the emitter transform. Allows offsetting where particles spawn."},
471 .data<&particle_emitter_component::set_emission_shape_scale, &particle_emitter_component::get_emission_shape_scale>(
"emission_shape_scale"_hs)
475 entt::attribute{
"tooltip",
"Scale of the emission shape. 1.0 = no scaling, 2.0 = double size, 0.5 = half size."},
480 .data<&particle_emitter_component::set_velocity_gradient, &particle_emitter_component::get_velocity_gradient>(
"velocity_gradient"_hs)
484 entt::attribute{
"tooltip",
"Velocity range gradient over particle lifetime. Controls how particle speed changes from spawn to death."},
488 .data<&particle_emitter_component::set_velocity_damping, &particle_emitter_component::get_velocity_damping>(
"velocity_damping"_hs)
492 entt::attribute{
"tooltip",
"Reduces particle velocity over time. 0.0 = no damping (particles maintain speed), 1.0 = full damping (particles stop immediately)."},
498 .data<&particle_emitter_component::set_position_easing, &particle_emitter_component::get_position_easing>(
"position_easing"_hs)
502 entt::attribute{
"tooltip",
"Curve controlling how particles move from start to end position. Linear = constant speed, EaseIn = slow start, EaseOut = slow end."},
507 .data<&particle_emitter_component::set_gravity_scale, &particle_emitter_component::get_gravity_scale>(
"gravity_scale"_hs)
511 entt::attribute{
"tooltip",
"Multiplier for gravity effect on particles. 0.0 = no gravity, 1.0 = Earth-like gravity, negative values = upward force."},
515 .data<&particle_emitter_component::set_force_over_lifetime, &particle_emitter_component::get_force_over_lifetime>(
"force_over_lifetime"_hs)
519 entt::attribute{
"tooltip",
"Additional force applied to particles throughout their lifetime. Use for wind, magnetism, or other environmental effects. Values are in world units."},
524 .data<&particle_emitter_component::set_scale_gradient, &particle_emitter_component::get_scale_gradient>(
"scale_gradient"_hs)
528 entt::attribute{
"tooltip",
"Scale range gradient over particle lifetime. Controls how particle size changes from spawn to death."},
531 .data<&particle_emitter_component::set_initial_scale_3d, &particle_emitter_component::get_initial_scale_3d>(
"initial_scale_3d"_hs)
535 entt::attribute{
"tooltip",
"3D scale for particles. Allows creating rectangular particles (e.g., 2,1,1 for wide particles, 1,2,1 for tall particles). Default: 1,1,1 (square)."},
540 .data<&particle_emitter_component::set_size_by_speed_range, &particle_emitter_component::get_size_by_speed_range>(
"size_by_speed_range"_hs)
544 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."},
549 .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)
553 entt::attribute{
"tooltip",
"Velocity range for size mapping. Particles moving at min speed get min size, particles at max speed get max size."},
560 .data<&particle_emitter_component::set_color_gradient, &particle_emitter_component::get_color_gradient>(
"color_gradient"_hs)
564 entt::attribute{
"tooltip",
"Color gradient defining particle color over lifetime. Colors are interpolated smoothly based on gradient keyframes."},
567 .data<&particle_emitter_component::set_opacity, &particle_emitter_component::get_opacity>(
"opacity"_hs)
571 entt::attribute{
"tooltip",
"Global opacity for all particles regardless of lifetime. 0.0 = fully transparent, 1.0 = no change, values > 1.0 = enhanced opacity."},
577 .data<&particle_emitter_component::set_color_intensity, &particle_emitter_component::get_color_intensity>(
"color_intensity"_hs)
581 entt::attribute{
"tooltip",
"HDR multiplier for particle color. Values above 1.0 make particles glow when bloom is enabled."},
589 .data<&particle_emitter_component::set_color_by_speed_gradient, &particle_emitter_component::get_color_by_speed_gradient>(
"color_by_speed_gradient"_hs)
593 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."},
596 .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)
600 entt::attribute{
"tooltip",
"Velocity range for color mapping. Particles moving at min speed get slow color, particles at max speed get fast color."},
606 .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)
610 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."},
615 .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)
619 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."},
626 .data<&particle_emitter_component::set_render_mode, &particle_emitter_component::get_render_mode>(
"render_mode"_hs)
630 entt::attribute{
"tooltip",
"Render orientation mode. Billboard = always face camera, Horizontal = rotate around Y axis only (stay horizontal), Vertical = stay vertical (perpendicular to ground)."},
633 .data<&particle_emitter_component::set_blend_mode, &particle_emitter_component::get_blend_mode>(
"blend_mode"_hs)
637 entt::attribute{
"tooltip",
"How particles blend with the scene. Normal = alpha transparency, Additive = glowing/fire effects, Multiply = darkening/smoke."},
640 .data<&particle_emitter_component::set_align_to_direction, &particle_emitter_component::get_align_to_direction>(
"align_to_direction"_hs)
644 entt::attribute{
"tooltip",
"If enabled, particles rotate to align with their velocity direction. Useful for directional particles like arrows or sparks."},
647 .data<&particle_emitter_component::set_pivot, &particle_emitter_component::get_pivot>(
"pivot"_hs)
651 entt::attribute{
"tooltip",
"Pivot point for particle rotation and positioning. (0,0) = bottom-left, (0.5,0.5) = center (default), (1,1) = top-right. Affects both rotation and where the particle is anchored."},
659 .data<&particle_emitter_component::set_texture, &particle_emitter_component::get_texture>(
"texture"_hs)
663 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."},
666 .data<&particle_emitter_component::set_texture_mode, &particle_emitter_component::get_texture_mode>(
"texture_mode"_hs)
670 entt::attribute{
"tooltip",
"Texture mode determines how the texture is interpreted. MultiChannel = standard RGBA texture, Mask = black/white mask where black = transparent, white = opaque (particle color used)."},
673 .data<&particle_emitter_component::set_texture_sheet_tiles, &particle_emitter_component::get_texture_sheet_tiles>(
"texture_sheet_tiles"_hs)
677 entt::attribute{
"tooltip",
"Number of tiles in the texture sheet grid (X columns, Y rows). For example, a 4x4 grid contains 16 animation frames. Set to 1x1 to disable."},
682 .data<&particle_emitter_component::set_texture_sheet_cycles, &particle_emitter_component::get_texture_sheet_cycles>(
"texture_sheet_cycles"_hs)
686 entt::attribute{
"tooltip",
"Number of times the animation loops over particle lifetime. 0 = disabled, 1 = play once, 2 = play twice, etc. Higher values make the animation play faster."},
691 .data<&particle_emitter_component::set_texture_sheet_randomize, &particle_emitter_component::get_texture_sheet_randomize>(
"texture_sheet_randomize"_hs)
695 entt::attribute{
"tooltip",
"When enabled, each particle starts at a random frame in the texture sheet animation instead of frame 0. Creates visual variety."},
705 try_save(ar, ser20::make_nvp(
"enabled", obj.is_enabled()));
706 try_save(ar, ser20::make_nvp(
"culling_mode", obj.get_culling_mode()));
707 try_save(ar, ser20::make_nvp(
"shape", obj.get_shape()));
708 try_save(ar, ser20::make_nvp(
"direction", obj.get_direction()));
709 try_save(ar, ser20::make_nvp(
"spawn_location", obj.get_spawn_location()));
710 try_save(ar, ser20::make_nvp(
"simulation_space", obj.get_simulation_space()));
711 try_save(ar, ser20::make_nvp(
"simulation_backend", obj.get_simulation_backend()));
712 try_save(ar, ser20::make_nvp(
"max_particles", obj.get_max_particles()));
716 try_save(ar, ser20::make_nvp(
"emission_lifetime", obj.get_emission_lifetime()));
717 try_save(ar, ser20::make_nvp(
"emission_shape_position", obj.get_emission_shape_position()));
718 try_save(ar, ser20::make_nvp(
"emission_shape_scale", obj.get_emission_shape_scale()));
719 try_save(ar, ser20::make_nvp(
"gravity_scale", obj.get_gravity_scale()));
720 try_save(ar, ser20::make_nvp(
"emission_rate", obj.get_emission_rate()));
721 try_save(ar, ser20::make_nvp(
"temporal_motion", obj.get_temporal_motion()));
722 try_save(ar, ser20::make_nvp(
"velocity_damping", obj.get_velocity_damping()));
723 try_save(ar, ser20::make_nvp(
"force_over_lifetime", obj.get_force_over_lifetime()));
724 try_save(ar, ser20::make_nvp(
"size_by_speed_range", obj.get_size_by_speed_range()));
725 try_save(ar, ser20::make_nvp(
"size_by_speed_velocity_range", obj.get_size_by_speed_velocity_range()));
726 try_save(ar, ser20::make_nvp(
"color_by_speed_gradient", obj.get_color_by_speed_gradient()));
727 try_save(ar, ser20::make_nvp(
"color_by_speed_velocity_range", obj.get_color_by_speed_velocity_range()));
728 try_save(ar, ser20::make_nvp(
"lifetime_by_emitter_speed_gradient", obj.get_lifetime_by_emitter_speed_gradient()));
729 try_save(ar, ser20::make_nvp(
"lifetime_by_emitter_speed_range", obj.get_lifetime_by_emitter_speed_range()));
732 try_save(ar, ser20::make_nvp(
"lifetime", obj.get_lifetime()));
733 try_save(ar, ser20::make_nvp(
"velocity_gradient", obj.get_velocity_gradient()));
734 try_save(ar, ser20::make_nvp(
"scale_gradient", obj.get_scale_gradient()));
735 try_save(ar, ser20::make_nvp(
"initial_scale_3d", obj.get_initial_scale_3d()));
736 try_save(ar, ser20::make_nvp(
"opacity", obj.get_opacity()));
737 try_save(ar, ser20::make_nvp(
"color_intensity", obj.get_color_intensity()));
740 try_save(ar, ser20::make_nvp(
"color_gradient", obj.get_color_gradient()));
743 try_save(ar, ser20::make_nvp(
"position_easing", obj.get_position_easing()));
746 try_save(ar, ser20::make_nvp(
"texture", obj.get_texture()));
747 try_save(ar, ser20::make_nvp(
"texture_mode", obj.get_texture_mode()));
748 try_save(ar, ser20::make_nvp(
"render_mode", obj.get_render_mode()));
749 try_save(ar, ser20::make_nvp(
"blend_mode", obj.get_blend_mode()));
752 try_save(ar, ser20::make_nvp(
"texture_sheet_tiles", obj.get_texture_sheet_tiles()));
753 try_save(ar, ser20::make_nvp(
"texture_sheet_cycles", obj.get_texture_sheet_cycles()));
754 try_save(ar, ser20::make_nvp(
"texture_sheet_randomize", obj.get_texture_sheet_randomize()));
757 try_save(ar, ser20::make_nvp(
"loop", obj.is_loop()));
758 try_save(ar, ser20::make_nvp(
"start_delay", obj.get_start_delay()));
759 try_save(ar, ser20::make_nvp(
"align_to_direction", obj.get_align_to_direction()));
762 try_save(ar, ser20::make_nvp(
"pivot", obj.get_pivot()));
776 if(
try_load(ar, ser20::make_nvp(
"culling_mode", culling_mode)))
778 obj.set_culling_mode(culling_mode);
785 obj.set_shape(
shape);
787 if(
try_load(ar, ser20::make_nvp(
"direction", direction)))
789 obj.set_direction(direction);
793 if(
try_load(ar, ser20::make_nvp(
"spawn_location", spawn_location)))
795 obj.set_spawn_location(spawn_location);
799 if(
try_load(ar, ser20::make_nvp(
"simulation_space", simulation_space)))
801 obj.set_simulation_space(simulation_space);
805 if(
try_load(ar, ser20::make_nvp(
"simulation_backend", simulation_backend)))
807 obj.set_simulation_backend(simulation_backend);
810 uint32_t max_particles{1024};
811 if(
try_load(ar, ser20::make_nvp(
"max_particles", max_particles)))
813 obj.set_max_particles(max_particles);
817 std::chrono::duration<float> emission_lifetime{2.0f};
818 if(
try_load(ar, ser20::make_nvp(
"emission_lifetime", emission_lifetime)))
820 obj.set_emission_lifetime(emission_lifetime);
823 math::vec3 emission_shape_position{0.0f, 0.0f, 0.0f};
824 if(
try_load(ar, ser20::make_nvp(
"emission_shape_position", emission_shape_position)))
826 obj.set_emission_shape_position(emission_shape_position);
829 math::vec3 emission_shape_scale{1.0f, 1.0f, 1.0f};
830 if(
try_load(ar, ser20::make_nvp(
"emission_shape_scale", emission_shape_scale)))
832 obj.set_emission_shape_scale(emission_shape_scale);
841 float emission_rate{50.0f};
842 if(
try_load(ar, ser20::make_nvp(
"emission_rate", emission_rate)))
844 obj.set_emission_rate(emission_rate);
847 float temporal_motion{1.0f};
848 if(
try_load(ar, ser20::make_nvp(
"temporal_motion", temporal_motion)))
850 obj.set_temporal_motion(temporal_motion);
853 float velocity_damping{0.0f};
854 if(
try_load(ar, ser20::make_nvp(
"velocity_damping", velocity_damping)))
856 obj.set_velocity_damping(velocity_damping);
859 math::vec3 force_over_lifetime{0.0f, 0.0f, 0.0f};
860 if(
try_load(ar, ser20::make_nvp(
"force_over_lifetime", force_over_lifetime)))
862 obj.set_force_over_lifetime(force_over_lifetime);
865 frange_t size_by_speed_range{1.0f, 1.0f};
866 if(
try_load(ar, ser20::make_nvp(
"size_by_speed_range", size_by_speed_range)))
868 obj.set_size_by_speed_range(size_by_speed_range);
871 frange_t size_by_speed_velocity_range{0.0f, 10.0f};
872 if(
try_load(ar, ser20::make_nvp(
"size_by_speed_velocity_range", size_by_speed_velocity_range)))
874 obj.set_size_by_speed_velocity_range(size_by_speed_velocity_range);
878 if(
try_load(ar, ser20::make_nvp(
"color_by_speed_gradient", color_by_speed_gradient)))
880 obj.set_color_by_speed_gradient(color_by_speed_gradient);
887 bool has_slow =
try_load(ar, ser20::make_nvp(
"color_by_speed_slow_color", color_by_speed_slow_color));
888 bool has_fast =
try_load(ar, ser20::make_nvp(
"color_by_speed_fast_color", color_by_speed_fast_color));
890 if(has_slow || has_fast)
893 legacy_gradient.
add_point(color_by_speed_slow_color, 0.0f);
894 legacy_gradient.
add_point(color_by_speed_fast_color, 1.0f);
895 obj.set_color_by_speed_gradient(legacy_gradient);
899 frange_t color_by_speed_velocity_range{0.0f, 10.0f};
900 if(
try_load(ar, ser20::make_nvp(
"color_by_speed_velocity_range", color_by_speed_velocity_range)))
902 obj.set_color_by_speed_velocity_range(color_by_speed_velocity_range);
906 if(
try_load(ar, ser20::make_nvp(
"lifetime_by_emitter_speed_gradient", lifetime_by_emitter_speed_gradient)))
908 obj.set_lifetime_by_emitter_speed_gradient(lifetime_by_emitter_speed_gradient);
911 frange_t lifetime_by_emitter_speed_range{0.0f, 10.0f};
912 if(
try_load(ar, ser20::make_nvp(
"lifetime_by_emitter_speed_range", lifetime_by_emitter_speed_range)))
914 obj.set_lifetime_by_emitter_speed_range(lifetime_by_emitter_speed_range);
918 std::chrono::duration<float> lifetime{1.0f};
919 if(
try_load(ar, ser20::make_nvp(
"lifetime", lifetime)))
921 obj.set_lifetime(lifetime);
925 if(
try_load(ar, ser20::make_nvp(
"velocity_gradient", velocity_gradient)))
927 obj.set_velocity_gradient(velocity_gradient);
931 if(
try_load(ar, ser20::make_nvp(
"scale_gradient", scale_gradient)))
933 obj.set_scale_gradient(scale_gradient);
936 math::vec3 initial_scale_3d{1.0f, 1.0f, 1.0f};
937 if(
try_load(ar, ser20::make_nvp(
"initial_scale_3d", initial_scale_3d)))
939 obj.set_initial_scale_3d(initial_scale_3d);
942 else if(
try_load(ar, ser20::make_nvp(
"particle_scale_3d", initial_scale_3d)))
944 obj.set_initial_scale_3d(initial_scale_3d);
949 if(
try_load(ar, ser20::make_nvp(
"opacity", opacity)))
951 obj.set_opacity(opacity);
954 float color_intensity{1.0f};
955 if(
try_load(ar, ser20::make_nvp(
"color_intensity", color_intensity)))
957 obj.set_color_intensity(color_intensity);
963 if(
try_load(ar, ser20::make_nvp(
"color_gradient", color_gradient)))
965 obj.set_color_gradient(color_gradient);
969 bx::Easing::Enum position_easing{};
970 if(
try_load(ar, ser20::make_nvp(
"position_easing", position_easing)))
972 obj.set_position_easing(position_easing);
976 bx::Easing::Enum blend_easing{}, scale_easing{};
977 try_load(ar, ser20::make_nvp(
"blend_easing", blend_easing));
978 try_load(ar, ser20::make_nvp(
"scale_easing", scale_easing));
982 if(
try_load(ar, ser20::make_nvp(
"texture", texture)))
984 obj.set_texture(texture);
988 if(
try_load(ar, ser20::make_nvp(
"texture_mode", texture_mode)))
990 obj.set_texture_mode(texture_mode);
994 if(
try_load(ar, ser20::make_nvp(
"render_mode", render_mode)))
996 obj.set_render_mode(render_mode);
999 if(
try_load(ar, ser20::make_nvp(
"blend_mode", blend_mode)))
1001 obj.set_blend_mode(blend_mode);
1005 if(
try_load(ar, ser20::make_nvp(
"billboard_mode", billboard_mode)))
1007 obj.set_render_mode(billboard_mode);
1011 math::vec2 texture_sheet_tiles{1.0f, 1.0f};
1012 if(
try_load(ar, ser20::make_nvp(
"texture_sheet_tiles", texture_sheet_tiles)))
1014 obj.set_texture_sheet_tiles(texture_sheet_tiles);
1017 float texture_sheet_cycles{0.0f};
1018 if(
try_load(ar, ser20::make_nvp(
"texture_sheet_cycles", texture_sheet_cycles)))
1020 obj.set_texture_sheet_cycles(texture_sheet_cycles);
1023 bool texture_sheet_randomize{
false};
1024 if(
try_load(ar, ser20::make_nvp(
"texture_sheet_randomize", texture_sheet_randomize)))
1026 obj.set_texture_sheet_randomize(texture_sheet_randomize);
1031 if(
try_load(ar, ser20::make_nvp(
"loop", loop)))
1036 std::chrono::duration<float> start_delay{0.0f};
1037 if(
try_load(ar, ser20::make_nvp(
"start_delay", start_delay)))
1039 obj.set_start_delay(start_delay);
1042 bool align_to_direction{
false};
1043 if(
try_load(ar, ser20::make_nvp(
"align_to_direction", align_to_direction)))
1045 obj.set_align_to_direction(align_to_direction);
1048 math::vec2 pivot{0.5f, 0.5f};
1049 if(
try_load(ar, ser20::make_nvp(
"pivot", pivot)))
1051 obj.set_pivot(pivot);