From 20d097ab1fe8ef5b62f4169f4353cc0074c27e4b Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 30 Aug 2023 13:45:07 -0700 Subject: sparkler: parameterize particles Having everything in fixed defines severely constrains the diversity of particle behaviors and appearances. This commit has been sitting around bitrotting since 2017, but now that there's all this settings infra. and randomizing via rtv, it seems worth landing, so I've rebased and am merging to prevent a bitrot->rebase recurrence. As-is, this commit ~minimally establishes a somewhat streamlined parameterizing mechanism w/X-Macro patterns, while wiring up a few of the obvious use cases surrounding xplode/burst, colorizing the default sparkler explosions while at it. It appears that when I first hacked this up I did some experimentation with parameters as well, so there are some tweaks to the behavior as opposed to a strict conversion of the fixed defines to parameters. They seem minor enough to just leave be. Plus a few minor optimizations like converting divides to multiplies were in there. Future commits can now wire up settings to choose from parameter presets for different sparklers... --- src/modules/sparkler/burst.c | 38 ++++++++++++++++------- src/modules/sparkler/burst.h | 9 ++++++ src/modules/sparkler/burst_params.def | 7 +++++ src/modules/sparkler/params_def.def | 21 +++++++++++++ src/modules/sparkler/params_undef.def | 19 ++++++++++++ src/modules/sparkler/particle.c | 12 ++++++-- src/modules/sparkler/particle.h | 14 +++++---- src/modules/sparkler/particles.c | 30 +++++++++++++----- src/modules/sparkler/particles.h | 6 ++-- src/modules/sparkler/rocket.c | 56 +++++++++++++++++++++------------- src/modules/sparkler/simple.c | 15 ++++----- src/modules/sparkler/spark.c | 3 +- src/modules/sparkler/sparkler.c | 4 +-- src/modules/sparkler/xplode.c | 49 +++++++++++++++++------------ src/modules/sparkler/xplode.h | 9 ++++++ src/modules/sparkler/xplode_params.def | 8 +++++ 16 files changed, 219 insertions(+), 81 deletions(-) create mode 100644 src/modules/sparkler/burst.h create mode 100644 src/modules/sparkler/burst_params.def create mode 100644 src/modules/sparkler/params_def.def create mode 100644 src/modules/sparkler/params_undef.def create mode 100644 src/modules/sparkler/xplode.h create mode 100644 src/modules/sparkler/xplode_params.def (limited to 'src/modules') diff --git a/src/modules/sparkler/burst.c b/src/modules/sparkler/burst.c index cf35b31..ae74e26 100644 --- a/src/modules/sparkler/burst.c +++ b/src/modules/sparkler/burst.c @@ -1,6 +1,8 @@ +#include #include #include "bsp.h" +#include "burst.h" #include "container.h" #include "particle.h" #include "particles.h" @@ -9,21 +11,33 @@ /* a "burst" (shockwave) particle type */ /* this doesn't draw anything, it just pushes neighbors away in an increasing radius */ -#define BURST_FORCE 0.01f -#define BURST_MAX_LIFETIME 8 - typedef struct _burst_ctxt_t { - int longevity; - int lifetime; +#define PARAMS_DECLARE_STRUCT +#include "burst_params.def" + int age; } burst_ctxt_t; -static int burst_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) +static int burst_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { burst_ctxt_t *ctxt = p->ctxt; - ctxt->longevity = ctxt->lifetime = BURST_MAX_LIFETIME; +#define PARAMS_ASSIGN_DEFAULTS +#include "burst_params.def" + + for (; n_params; n_params--) { + switch (va_arg(params, burst_param_t)) { +#define PARAMS_IMPLEMENT_SWITCH +#include "burst_params.def" + default: + return 0; + } + } + p->props->virtual = 1; + ctxt->age = ctxt->duration; + p->props->velocity = 0; /* burst should be stationary */ + p->props->mass = 0; /* no mass prevents gravity's effects */ return 1; } @@ -31,14 +45,15 @@ static int burst_init(particles_t *particles, const particles_conf_t *conf, part static inline void thrust_part(particle_t *burst, particle_t *victim, float distance_sq) { - v3f_t direction = v3f_sub(&victim->props->position, &burst->props->position); + burst_ctxt_t *ctxt = burst->ctxt; + v3f_t direction = v3f_sub(&victim->props->position, &burst->props->position); /* TODO: normalize is expensive, see about removing these. */ direction = v3f_normalize(&direction); victim->props->direction = v3f_add(&victim->props->direction, &direction); victim->props->direction = v3f_normalize(&victim->props->direction); - victim->props->velocity += BURST_FORCE; + victim->props->velocity += ctxt->force; } @@ -100,12 +115,13 @@ static particle_status_t burst_sim(particles_t *particles, const particles_conf_ bsp_t *bsp = particles_bsp(particles); /* XXX see note above about bsp_occupant_t */ burst_sphere_t s; - if (!ctxt->longevity || (ctxt->longevity--) <= 0) { + if (!ctxt->duration || (ctxt->duration--) <= 0) { return PARTICLE_DEAD; } /* affect neighbors for the shock-wave */ - s.radius_min = (1.0f - ((float)ctxt->longevity / ctxt->lifetime)) * 0.075f; + /* TODO: ctxt->radius should probably describe the max radius, and the min - .01f... FIXME later. */ + s.radius_min = (1.0f - ((float)ctxt->duration / ctxt->age)) * ctxt->radius; s.radius_max = s.radius_min + .01f; s.center = s.last = p; s.trace_matches = (conf->show_bsp_matches && !conf->show_bsp_matches_affected_only); diff --git a/src/modules/sparkler/burst.h b/src/modules/sparkler/burst.h new file mode 100644 index 0000000..ea5095e --- /dev/null +++ b/src/modules/sparkler/burst.h @@ -0,0 +1,9 @@ +#ifndef _BURST_H +#define _BURST_H + +typedef enum burst_param_t { +#define PARAMS_DECLARE_ENUM +#include "burst_params.def" +} burst_param_t; + +#endif diff --git a/src/modules/sparkler/burst_params.def b/src/modules/sparkler/burst_params.def new file mode 100644 index 0000000..97d66ae --- /dev/null +++ b/src/modules/sparkler/burst_params.def @@ -0,0 +1,7 @@ +#include "params_def.def" + +param(radius, 0.075f, BURST_PARAM_RADIUS_FLOAT, float, double) /* eventual radius of burst */ +param(force, 0.01f, BURST_PARAM_FORCE_FLOAT, float, double) /* how much to accelerate victims */ +param(duration, 7, BURST_PARAM_DURATION_UINT, unsigned, unsigned) /* how many steps to perform the burst */ + +#include "params_undef.def" diff --git a/src/modules/sparkler/params_def.def b/src/modules/sparkler/params_def.def new file mode 100644 index 0000000..cd27423 --- /dev/null +++ b/src/modules/sparkler/params_def.def @@ -0,0 +1,21 @@ +#ifdef PARAMS_DECLARE_ENUM +#define param(_member, _default, _sym, _ctxt_type, _va_type) \ + _sym, +#endif + +#ifdef PARAMS_DECLARE_STRUCT +#define param(_member, _default, _sym, _ctxt_type, _va_type) \ + _ctxt_type _member; +#endif + +#ifdef PARAMS_IMPLEMENT_SWITCH +#define param(_member, _default, _sym, _ctxt_type, _va_type) \ + case _sym: \ + ctxt->_member = va_arg(params, _va_type); \ + break; +#endif + +#ifdef PARAMS_ASSIGN_DEFAULTS +#define param(_member, _default, _sym, _ctxt_type, _va_type) \ + ctxt->_member = _default; +#endif diff --git a/src/modules/sparkler/params_undef.def b/src/modules/sparkler/params_undef.def new file mode 100644 index 0000000..f8f8440 --- /dev/null +++ b/src/modules/sparkler/params_undef.def @@ -0,0 +1,19 @@ +#ifdef param +#undef param +#endif + +#ifdef PARAMS_DECLARE_ENUM +#undef PARAMS_DECLARE_ENUM +#endif + +#ifdef PARAMS_DECLARE_STRUCT +#undef PARAMS_DECLARE_STRUCT +#endif + +#ifdef PARAMS_IMPLEMENT_SWITCH +#undef PARAMS_IMPLEMENT_SWITCH +#endif + +#ifdef PARAMS_ASSIGN_DEFAULTS +#undef PARAMS_ASSIGN_DEFAULTS +#endif diff --git a/src/modules/sparkler/particle.c b/src/modules/sparkler/particle.c index 76d0c70..a3184ea 100644 --- a/src/modules/sparkler/particle.c +++ b/src/modules/sparkler/particle.c @@ -1,8 +1,14 @@ +#include + #include "particle.h" /* convert a particle to a new type */ -void particle_convert(particles_t *particles, const particles_conf_t *conf, particle_t *p, particle_props_t *props, particle_ops_t *ops) +void particle_convert(particles_t *particles, const particles_conf_t *conf, particle_t *p, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...) { + va_list ap; + + va_start(ap, n_params); + particle_cleanup(particles, conf, p); if (props) { *p->props = *props; @@ -10,5 +16,7 @@ void particle_convert(particles_t *particles, const particles_conf_t *conf, part if (ops) { p->ops = ops; } - particle_init(particles, conf, p); + particle_init(particles, conf, p, n_params, ap); + + va_end(ap); } diff --git a/src/modules/sparkler/particle.h b/src/modules/sparkler/particle.h index a7c4138..491dc65 100644 --- a/src/modules/sparkler/particle.h +++ b/src/modules/sparkler/particle.h @@ -1,6 +1,8 @@ #ifndef _PARTICLE_H #define _PARTICLE_H +#include + #include "til_fb.h" #include "bsp.h" @@ -26,10 +28,10 @@ typedef struct particles_t particles_t; typedef struct particles_conf_t particles_conf_t; typedef struct particle_ops_t { - unsigned context_size; /* size of the particle context (0 for none) */ - int (*init)(particles_t *, const particles_conf_t *, particle_t *); /* initialize the particle, called after allocating context (optional) */ + unsigned context_size; /* size of the particle context (0 for none) */ + int (*init)(particles_t *, const particles_conf_t *, particle_t *, unsigned, va_list); /* initialize the particle, called after allocating context (optional) */ void (*cleanup)(particles_t *, const particles_conf_t *, particle_t *); /* cleanup function, called before freeing context (optional) */ - particle_status_t (*sim)(particles_t *, const particles_conf_t *, particle_t *, til_fb_fragment_t *); /* simulate the particle for another cycle (required) */ + particle_status_t (*sim)(particles_t *, const particles_conf_t *, particle_t *, til_fb_fragment_t *); /* simulate the particle for another cycle (required) */ void (*draw)(particles_t *, const particles_conf_t *, particle_t *, int, int, til_fb_fragment_t *); /* draw the particle, 3d->2d projection has been done already (optional) */ } particle_ops_t; @@ -49,9 +51,9 @@ struct particle_t { #define INHERIT_PROPS NULL -static inline int particle_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { +static inline int particle_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { if (p->ops->init) { - return p->ops->init(particles, conf, p); + return p->ops->init(particles, conf, p, n_params, params); } return 1; @@ -81,6 +83,6 @@ static inline void particle_draw(particles_t *particles, const particles_conf_t } -void particle_convert(particles_t *particles, const particles_conf_t *conf, particle_t *p, particle_props_t *props, particle_ops_t *ops); +void particle_convert(particles_t *particles, const particles_conf_t *conf, particle_t *p, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...); #endif diff --git a/src/modules/sparkler/particles.c b/src/modules/sparkler/particles.c index f6adf13..8fc93a2 100644 --- a/src/modules/sparkler/particles.c +++ b/src/modules/sparkler/particles.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -128,7 +129,7 @@ static void particles_reap_particle(particles_t *particles, _particle_t *particl /* add a particle to the specified list */ -static inline int _particles_add_particle(particles_t *particles, list_head_t *list, particle_props_t *props, particle_ops_t *ops) +static inline int _particles_add_particle(particles_t *particles, list_head_t *list, particle_props_t *props, particle_ops_t *ops, unsigned n_params, va_list ap) { _particle_t *p; @@ -158,7 +159,7 @@ static inline int _particles_add_particle(particles_t *particles, list_head_t *l p->public.ctxt = p->context; } - if (!particle_init(particles, &particles->conf, &p->public)) { + if (!particle_init(particles, &particles->conf, &p->public, n_params, ap)) { /* XXX FIXME this shouldn't be normal, we don't want to allocate * particles that cannot be initialized. the rockets today set a cap * by failing initialization, that's silly. */ @@ -175,36 +176,49 @@ static inline int _particles_add_particle(particles_t *particles, list_head_t *l /* add a new "top-level" particle of the specified props and ops taking from the provided parts list */ -int particles_add_particle(particles_t *particles, particle_props_t *props, particle_ops_t *ops) +int particles_add_particle(particles_t *particles, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...) { + int ret; + va_list ap; + assert(particles); - return _particles_add_particle(particles, &particles->active, props, ops); + va_start(ap, n_params); + ret = _particles_add_particle(particles, &particles->active, props, ops, n_params, ap); + va_end(ap); + + return ret; } /* spawn a new child particle from a parent, initializing it via inheritance if desired */ -void particles_spawn_particle(particles_t *particles, particle_t *parent, particle_props_t *props, particle_ops_t *ops) +void particles_spawn_particle(particles_t *particles, particle_t *parent, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...) { + va_list ap; _particle_t *p = container_of(parent, _particle_t, public); assert(particles); assert(parent); - _particles_add_particle(particles, &p->children, props ? props : parent->props, ops ? ops : parent->ops); + va_start(ap, n_params); + _particles_add_particle(particles, &p->children, props ? props : parent->props, ops ? ops : parent->ops, n_params, ap); + va_end(ap); } /* plural version of particle_add(); adds multiple "top-level" particles of uniform props and ops */ -void particles_add_particles(particles_t *particles, particle_props_t *props, particle_ops_t *ops, int num) +void particles_add_particles(particles_t *particles, particle_props_t *props, particle_ops_t *ops, unsigned num, unsigned n_params, ...) { + va_list ap; int i; assert(particles); + va_start(ap, n_params); for (i = 0; i < num; i++) { - _particles_add_particle(particles, &particles->active, props, ops); + _particles_add_particle(particles, &particles->active, props, ops, n_params, ap); } + va_end(ap); } diff --git a/src/modules/sparkler/particles.h b/src/modules/sparkler/particles.h index a419e2c..d3add36 100644 --- a/src/modules/sparkler/particles.h +++ b/src/modules/sparkler/particles.h @@ -23,9 +23,9 @@ void particles_draw(particles_t *particles, til_fb_fragment_t *fragment); particle_status_t particles_sim(particles_t *particles, til_fb_fragment_t *fragment); void particles_age(particles_t *particles); void particles_free(particles_t *particles); -int particles_add_particle(particles_t *particles, particle_props_t *props, particle_ops_t *ops); -void particles_spawn_particle(particles_t *particles, particle_t *parent, particle_props_t *props, particle_ops_t *ops); -void particles_add_particles(particles_t *particles, particle_props_t *props, particle_ops_t *ops, int num); +int particles_add_particle(particles_t *particles, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...); +void particles_spawn_particle(particles_t *particles, particle_t *parent, particle_props_t *props, particle_ops_t *ops, unsigned n_params, ...); +void particles_add_particles(particles_t *particles, particle_props_t *props, particle_ops_t *ops, unsigned num, unsigned n_params, ...); bsp_t * particles_bsp(particles_t *particles); void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, til_fb_fragment_t *fragment); diff --git a/src/modules/sparkler/rocket.c b/src/modules/sparkler/rocket.c index 8afceb4..e0b17a2 100644 --- a/src/modules/sparkler/rocket.c +++ b/src/modules/sparkler/rocket.c @@ -1,10 +1,13 @@ +#include #include #include "til_fb.h" +#include "burst.h" #include "helpers.h" #include "particle.h" #include "particles.h" +#include "xplode.h" /* a "rocket" particle type */ #define ROCKET_MAX_DECAY_RATE 20 @@ -28,8 +31,16 @@ typedef struct rocket_ctxt_t { float last_velocity; /* cache velocity to sense violent accelerations and explode when they happen */ } rocket_ctxt_t; +static unsigned xplode_colors[] = { + 0xffff00, + 0xff0000, + 0xff00ff, + 0x00ffff, + 0x0000ff, + 0x00ff00, +}; -static int rocket_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) +static int rocket_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { rocket_ctxt_t *ctxt = p->ctxt; @@ -41,9 +52,9 @@ static int rocket_init(particles_t *particles, const particles_conf_t *conf, par ctxt->decay_rate = rand_within_range(conf->seedp, ROCKET_MIN_DECAY_RATE, ROCKET_MAX_DECAY_RATE); ctxt->longevity = rand_within_range(conf->seedp, ROCKET_MIN_LIFETIME, ROCKET_MAX_LIFETIME); - ctxt->wander.x = (float)(rand_within_range(conf->seedp, 0, 628) - 314) / 10000.0f; - ctxt->wander.y = (float)(rand_within_range(conf->seedp, 0, 628) - 314) / 10000.0f; - ctxt->wander.z = (float)(rand_within_range(conf->seedp, 0, 628) - 314) / 10000.0f; + ctxt->wander.x = (float)(rand_within_range(conf->seedp, 0, 628) - 314) * .0001; + ctxt->wander.y = (float)(rand_within_range(conf->seedp, 0, 628) - 314) * .0001; + ctxt->wander.z = (float)(rand_within_range(conf->seedp, 0, 628) - 314) * .0001; ctxt->wander = v3f_normalize(&ctxt->wander); ctxt->last_velocity = p->props->velocity; @@ -63,31 +74,34 @@ static particle_status_t rocket_sim(particles_t *particles, const particles_conf if (!ctxt->longevity || (ctxt->longevity -= ctxt->decay_rate) <= 0 || p->props->velocity - ctxt->last_velocity > p->props->velocity * .05) { /* explode if accelerated too hard (burst) */ - int n_xplode; + int n_xplode; + unsigned color = xplode_colors[rand_within_range(conf->seedp, 0, nelems(xplode_colors))]; /* on death we explode */ ctxt->longevity = 0; - /* add a burst shockwave particle at our location - * TODO: need way to supply particle-type-specific parameters at spawn (burst size should derive from n_xplode) - */ - particles_spawn_particle(particles, p, NULL, &burst_ops); - /* add a bunch of new explosion particles */ - /* TODO: also particle-type-specific parameters, colors! rocket bursts should be able to vary the color. */ + /* how many explosion particles? */ n_xplode = rand_within_range(conf->seedp, ROCKETS_XPLODE_MIN_SIZE, ROCKETS_XPLODE_MAX_SIZE); + + /* add a burst shockwave particle at our location, scale force + * and radius according to explosion size. + */ + particles_spawn_particle(particles, p, NULL, &burst_ops, 1, BURST_PARAM_FORCE_FLOAT, (float)n_xplode * 0.00001f); + + /* add the explosion particles */ for (i = 0; i < n_xplode; i++) { particle_props_t props = *p->props; particle_ops_t *ops = &xplode_ops; - props.direction.x = ((float)(rand_within_range(conf->seedp, 0, 314159 * 2) - 314159) / 100000.0); - props.direction.y = ((float)(rand_within_range(conf->seedp, 0, 314159 * 2) - 314159) / 100000.0); - props.direction.z = ((float)(rand_within_range(conf->seedp, 0, 314159 * 2) - 314159) / 100000.0); + props.direction.x = ((float)(rand_within_range(conf->seedp, 0, 31415900 * 2) - 31415900) * .0000001); + props.direction.y = ((float)(rand_within_range(conf->seedp, 0, 31415900 * 2) - 31415900) * .0000001); + props.direction.z = ((float)(rand_within_range(conf->seedp, 0, 31415900 * 2) - 31415900) * .0000001); props.direction = v3f_normalize(&props.direction); //props->velocity = ((float)rand_within_range(100, 200) / 100000.0); - props.velocity = ((float)rand_within_range(conf->seedp, 100, 300) / 100000.0); - particles_spawn_particle(particles, p, &props, ops); + props.velocity = ((float)rand_within_range(conf->seedp, 100, 400) * .00001); + particles_spawn_particle(particles, p, &props, ops, 1, XPLODE_PARAM_COLOR_UINT, color); } return PARTICLE_DEAD; } @@ -106,13 +120,13 @@ static particle_status_t rocket_sim(particles_t *particles, const particles_conf props.direction = v3f_negate(&props.direction); - props.direction.x += (float)(rand_within_range(conf->seedp, 0, 40) - 20) / 100.0; - props.direction.y += (float)(rand_within_range(conf->seedp, 0, 40) - 20) / 100.0; - props.direction.z += (float)(rand_within_range(conf->seedp, 0, 40) - 20) / 100.0; + props.direction.x += (float)(rand_within_range(conf->seedp, 0, 40) - 20) * .01; + props.direction.y += (float)(rand_within_range(conf->seedp, 0, 40) - 20) * .01; + props.direction.z += (float)(rand_within_range(conf->seedp, 0, 40) - 20) * .01; props.direction = v3f_normalize(&props.direction); - props.velocity = (float)rand_within_range(conf->seedp, 10, 50) / 100000.0; - particles_spawn_particle(particles, p, &props, &spark_ops); + props.velocity = (float)rand_within_range(conf->seedp, 10, 50) * .00001; + particles_spawn_particle(particles, p, &props, &spark_ops, 0); } ctxt->last_velocity = p->props->velocity; diff --git a/src/modules/sparkler/simple.c b/src/modules/sparkler/simple.c index 3bc3076..74b3d58 100644 --- a/src/modules/sparkler/simple.c +++ b/src/modules/sparkler/simple.c @@ -1,3 +1,4 @@ +#include #include #include "til_fb.h" @@ -24,7 +25,7 @@ typedef struct _simple_ctxt_t { } simple_ctxt_t; -static int simple_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) +static int simple_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { simple_ctxt_t *ctxt = p->ctxt; @@ -78,17 +79,17 @@ static particle_status_t simple_sim(particles_t *particles, const particles_conf if (i == (SIMPLE_MAX_SPAWN - 2)) { ops = &rocket_ops; - props.velocity = (float)rand_within_range(conf->seedp, 60, 100) / 1000000.0; + props.velocity = (float)rand_within_range(conf->seedp, 60, 100) * .000001; } else { - props.velocity = (float)rand_within_range(conf->seedp, 30, 100) / 10000.0; + props.velocity = (float)rand_within_range(conf->seedp, 30, 400) * .00001; } - props.direction.x += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) / 100.0; - props.direction.y += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) / 100.0; - props.direction.z += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) / 100.0; + props.direction.x += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) * .01; + props.direction.y += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) * .01; + props.direction.z += (float)(rand_within_range(conf->seedp, 0, 315 * 2) - 315) * .01; props.direction = v3f_normalize(&props.direction); - particles_spawn_particle(particles, p, &props, ops); // XXX + particles_spawn_particle(particles, p, &props, ops, 0); // XXX } } diff --git a/src/modules/sparkler/spark.c b/src/modules/sparkler/spark.c index 3e45cc8..6866999 100644 --- a/src/modules/sparkler/spark.c +++ b/src/modules/sparkler/spark.c @@ -1,3 +1,4 @@ +#include #include #include "til_fb.h" @@ -19,7 +20,7 @@ typedef struct _spark_ctxt_t { } spark_ctxt_t; -static int spark_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) +static int spark_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { spark_ctxt_t *ctxt = p->ctxt; diff --git a/src/modules/sparkler/sparkler.c b/src/modules/sparkler/sparkler.c index 1e7e171..76f1c9b 100644 --- a/src/modules/sparkler/sparkler.c +++ b/src/modules/sparkler/sparkler.c @@ -55,7 +55,7 @@ static til_module_context_t * sparkler_create_context(const til_module_t *module return NULL; } - particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS); + particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS, 0); return &ctxt->til_module_context; } @@ -81,7 +81,7 @@ static void sparkler_prepare_frame(til_module_context_t *context, til_stream_t * til_fb_fragment_clear(fragment); particles_sim(ctxt->particles, fragment); - particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS / 4); + particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS / 4, 0); particles_age(ctxt->particles); } diff --git a/src/modules/sparkler/xplode.c b/src/modules/sparkler/xplode.c index 1534369..bf50a10 100644 --- a/src/modules/sparkler/xplode.c +++ b/src/modules/sparkler/xplode.c @@ -1,3 +1,4 @@ +#include #include #include "til_fb.h" @@ -5,31 +6,38 @@ #include "helpers.h" #include "particle.h" #include "particles.h" +#include "xplode.h" -/* a "xplode" particle type, emitted by rockets in large numbers at the end of their lifetime */ -#define XPLODE_MAX_DECAY_RATE 10 -#define XPLODE_MIN_DECAY_RATE 5 -#define XPLODE_MAX_LIFETIME 150 -#define XPLODE_MIN_LIFETIME 5 +/* a "xplode" particle type, emitted by rockets in large numbers at the end of their duration */ extern particle_ops_t spark_ops; particle_ops_t xplode_ops; typedef struct _xplode_ctxt_t { - int decay_rate; - int longevity; - int lifetime; +#define PARAMS_DECLARE_STRUCT +#include "xplode_params.def" + int remaining; } xplode_ctxt_t; -static int xplode_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) +static int xplode_init(particles_t *particles, const particles_conf_t *conf, particle_t *p, unsigned n_params, va_list params) { xplode_ctxt_t *ctxt = p->ctxt; - ctxt->decay_rate = rand_within_range(conf->seedp, XPLODE_MIN_DECAY_RATE, XPLODE_MAX_DECAY_RATE); - ctxt->lifetime = ctxt->longevity = rand_within_range(conf->seedp, XPLODE_MIN_LIFETIME, XPLODE_MAX_LIFETIME); +#define PARAMS_ASSIGN_DEFAULTS +#include "xplode_params.def" - p->props->drag = 10.9; + for (; n_params; n_params--) { + switch (va_arg(params, xplode_param_t)) { +#define PARAMS_IMPLEMENT_SWITCH +#include "xplode_params.def" + default: + return 0; + } + } + + ctxt->remaining = ctxt->duration; + p->props->drag = 10.5; p->props->mass = 0.3; p->props->virtual = 0; @@ -41,17 +49,17 @@ static particle_status_t xplode_sim(particles_t *particles, const particles_conf { xplode_ctxt_t *ctxt = p->ctxt; - if (!ctxt->longevity || (ctxt->longevity -= ctxt->decay_rate) <= 0) { - ctxt->longevity = 0; + if (!ctxt->remaining || (ctxt->remaining -= ctxt->decay_rate) <= 0) { + ctxt->remaining = 0; return PARTICLE_DEAD; } /* litter some small sparks behind the explosion particle */ - if (!(ctxt->lifetime % 30)) { + if (!(ctxt->duration % 30)) { particle_props_t props = *p->props; - props.velocity = (float)rand_within_range(conf->seedp, 10, 50) / 10000.0; - particles_spawn_particle(particles, p, &props, &xplode_ops); + props.velocity = (float)rand_within_range(conf->seedp, 10, 50) * .0001; + particles_spawn_particle(particles, p, &props, &xplode_ops, 1, XPLODE_PARAM_COLOR_UINT, ctxt->color); } return PARTICLE_ALIVE; @@ -63,13 +71,14 @@ static void xplode_draw(particles_t *particles, const particles_conf_t *conf, pa xplode_ctxt_t *ctxt = p->ctxt; uint32_t color; - if (!should_draw_expire_if_oob(particles, p, x, y, f, &ctxt->longevity)) + if (!should_draw_expire_if_oob(particles, p, x, y, f, &ctxt->remaining)) return; - if (ctxt->longevity == ctxt->lifetime) { + if (ctxt->remaining == ctxt->duration) { + /* always start with a white flash */ color = makergb(0xff, 0xff, 0xa0, 1.0); } else { - color = makergb(0xff, 0xff, 0x00, ((float)ctxt->longevity / ctxt->lifetime)); + color = makergb((ctxt->color & 0xff0000) >> 16, (ctxt->color & 0xff00) >> 8, ctxt->color & 0xff, ((float)ctxt->remaining / ctxt->duration)); } til_fb_fragment_put_pixel_unchecked(f, 0, x, y, color); diff --git a/src/modules/sparkler/xplode.h b/src/modules/sparkler/xplode.h new file mode 100644 index 0000000..d0bac58 --- /dev/null +++ b/src/modules/sparkler/xplode.h @@ -0,0 +1,9 @@ +#ifndef _XPLODE_H +#define _XPLODE_H + +typedef enum xplode_param_t { +#define PARAMS_DECLARE_ENUM +#include "xplode_params.def" +} xplode_param_t; + +#endif diff --git a/src/modules/sparkler/xplode_params.def b/src/modules/sparkler/xplode_params.def new file mode 100644 index 0000000..dacb920 --- /dev/null +++ b/src/modules/sparkler/xplode_params.def @@ -0,0 +1,8 @@ +#include "params_def.def" + +param(color, 0xffff00, XPLODE_PARAM_COLOR_UINT, unsigned, unsigned) +param(decay_rate, rand_within_range(conf->seedp, 6, 10), XPLODE_PARAM_DECAY_INT, int, int) +param(duration, rand_within_range(conf->seedp, 50, 150), XPLODE_PARAM_DURATION_INT, int, int) + +#include "params_undef.def" + -- cgit v1.2.3