diff options
-rw-r--r-- | src/modules/sparkler/bsp.c | 56 | ||||
-rw-r--r-- | src/modules/sparkler/bsp.h | 2 | ||||
-rw-r--r-- | src/modules/sparkler/burst.c | 27 | ||||
-rw-r--r-- | src/modules/sparkler/list.h | 2 | ||||
-rw-r--r-- | src/modules/sparkler/particle.c | 6 | ||||
-rw-r--r-- | src/modules/sparkler/particle.h | 31 | ||||
-rw-r--r-- | src/modules/sparkler/particles.c | 152 | ||||
-rw-r--r-- | src/modules/sparkler/particles.h | 6 | ||||
-rw-r--r-- | src/modules/sparkler/rocket.c | 8 | ||||
-rw-r--r-- | src/modules/sparkler/simple.c | 6 | ||||
-rw-r--r-- | src/modules/sparkler/spark.c | 6 | ||||
-rw-r--r-- | src/modules/sparkler/sparkler.c | 78 | ||||
-rw-r--r-- | src/modules/sparkler/xplode.c | 6 |
13 files changed, 333 insertions, 53 deletions
diff --git a/src/modules/sparkler/bsp.c b/src/modules/sparkler/bsp.c index ae5a20e..f55501a 100644 --- a/src/modules/sparkler/bsp.c +++ b/src/modules/sparkler/bsp.c @@ -574,3 +574,59 @@ void bsp_search_sphere(bsp_t *bsp, v3f_t *center, float radius_min, float radius _bsp_search_sphere(bsp, &bsp->root, &search, &aabb_min, &aabb_max); } + + +static void _bsp_walk_leaves(const bsp_t *bsp, const bsp_node_t *node, unsigned depth, const v3f_t *aabb_min, const v3f_t *aabb_max, void (*cb)(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data), void *cb_data) +{ + v3f_t oaabb_min, oaabb_max; + + /* if node is a leaf, call cb with the occupants, then return. */ + if (!node->octrants) + return cb(bsp, &node->occupants, depth, aabb_min, aabb_max, cb_data); + + /* node is a parent, recur on each octrant with appropriately adjusted aabb_min:aabb_max values */ + /* if any of the octrants absolutely overlaps the search sphere, skip the others by returning. */ +#define walk_octrant(_oid, _aabb_min, _aabb_max) \ + _bsp_walk_leaves(bsp, &node->octrants[_oid], depth + 1, _aabb_min, _aabb_max, cb, cb_data); + + /* OCT_XL_YL_ZL and OCT_XR_YR_ZR AABBs don't require tedious composition */ + walk_octrant(OCT_XL_YL_ZL, aabb_min, &node->center); + walk_octrant(OCT_XR_YR_ZR, &node->center, aabb_max); + + /* the rest are stitched together requiring temp storage and tedium */ + v3f_set(&oaabb_min, node->center.x, aabb_min->y, aabb_min->z); + v3f_set(&oaabb_max, aabb_max->x, node->center.y, node->center.z); + walk_octrant(OCT_XR_YL_ZL, &oaabb_min, &oaabb_max); + + v3f_set(&oaabb_min, aabb_min->x, node->center.y, aabb_min->z); + v3f_set(&oaabb_max, node->center.x, aabb_max->y, node->center.z); + walk_octrant(OCT_XL_YR_ZL, &oaabb_min, &oaabb_max); + + v3f_set(&oaabb_min, node->center.x, node->center.y, aabb_min->z); + v3f_set(&oaabb_max, aabb_max->x, aabb_max->y, node->center.z); + walk_octrant(OCT_XR_YR_ZL, &oaabb_min, &oaabb_max); + + v3f_set(&oaabb_min, aabb_min->x, aabb_min->y, node->center.z); + v3f_set(&oaabb_max, node->center.x, node->center.y, aabb_max->z); + walk_octrant(OCT_XL_YL_ZR, &oaabb_min, &oaabb_max); + + v3f_set(&oaabb_min, node->center.x, aabb_min->y, node->center.z); + v3f_set(&oaabb_max, aabb_max->x, node->center.y, aabb_max->z); + walk_octrant(OCT_XR_YL_ZR, &oaabb_min, &oaabb_max); + + v3f_set(&oaabb_min, aabb_min->x, node->center.y, node->center.z); + v3f_set(&oaabb_max, node->center.x, aabb_max->y, aabb_max->z); + walk_octrant(OCT_XL_YR_ZR, &oaabb_min, &oaabb_max); + +#undef walk_octrant +} + + +/* traverse the bsp tree calling cb for every leaf node, no discriminating of positions */ +void bsp_walk_leaves(const bsp_t *bsp, void (*cb)(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data), void *cb_data) +{ + v3f_t aabb_min = v3f_init(-1.0f, -1.0f, -1.0f); + v3f_t aabb_max = v3f_init(1.0f, 1.0f, 1.0f); + + _bsp_walk_leaves(bsp, &bsp->root, 0, &aabb_min, &aabb_max, cb, cb_data); +} diff --git a/src/modules/sparkler/bsp.h b/src/modules/sparkler/bsp.h index f5ce303..3ca0c02 100644 --- a/src/modules/sparkler/bsp.h +++ b/src/modules/sparkler/bsp.h @@ -25,4 +25,6 @@ void bsp_delete_occupant(bsp_t *bsp, bsp_occupant_t *occupant); void bsp_move_occupant(bsp_t *bsp, bsp_occupant_t *occupant, v3f_t *position); void bsp_search_sphere(bsp_t *bsp, v3f_t *center, float radius_min, float radius_max, void (*cb)(bsp_t *, list_head_t *, void *), void *cb_data); +void bsp_walk_leaves(const bsp_t *bsp, void (*cb)(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data), void *cb_data); + #endif diff --git a/src/modules/sparkler/burst.c b/src/modules/sparkler/burst.c index 72cde03..b5ad365 100644 --- a/src/modules/sparkler/burst.c +++ b/src/modules/sparkler/burst.c @@ -18,7 +18,7 @@ typedef struct _burst_ctxt_t { } burst_ctxt_t; -static int burst_init(particles_t *particles, particle_t *p) +static int burst_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { burst_ctxt_t *ctxt = p->ctxt; @@ -43,9 +43,13 @@ static inline void thrust_part(particle_t *burst, particle_t *victim, float dist typedef struct burst_sphere_t { - particle_t *center; + particles_t *particles; + particle_t *center, *last; + fb_fragment_t *fragment; float radius_min; float radius_max; + unsigned trace_matches:1; + unsigned trace_affected:1; } burst_sphere_t; @@ -64,7 +68,7 @@ static void burst_cb(bsp_t *bsp, list_head_t *occupants, void *_s) list_for_each_entry(o, occupants, occupants) { particle_t *p = container_of(o, particle_t, occupant); float d_sq; - + if (p->props->virtual) { /* don't move virtual particles (includes ourself) */ continue; @@ -75,13 +79,22 @@ static void burst_cb(bsp_t *bsp, list_head_t *occupants, void *_s) if (d_sq > rmin_sq && d_sq < rmax_sq) { /* displace the part relative to the burst origin */ thrust_part(s->center, p, d_sq); + + if (s->trace_affected) { + particles_draw_line(s->particles, &s->last->props->position, &p->props->position, s->fragment); + s->last = p; + } } + if (s->trace_matches) { + particles_draw_line(s->particles, &s->last->props->position, &p->props->position, s->fragment); + s->last = p; + } } } -static particle_status_t burst_sim(particles_t *particles, particle_t *p) +static particle_status_t burst_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { burst_ctxt_t *ctxt = p->ctxt; bsp_t *bsp = particles_bsp(particles); /* XXX see note above about bsp_occupant_t */ @@ -94,7 +107,11 @@ static particle_status_t burst_sim(particles_t *particles, particle_t *p) /* affect neighbors for the shock-wave */ s.radius_min = (1.0f - ((float)ctxt->longevity / ctxt->lifetime)) * 0.075f; s.radius_max = s.radius_min + .01f; - s.center = p; + s.center = s.last = p; + s.trace_matches = (conf->show_bsp_matches && !conf->show_bsp_matches_affected_only); + s.trace_affected = (conf->show_bsp_matches && conf->show_bsp_matches_affected_only); + s.particles = particles; + s.fragment = f; bsp_search_sphere(bsp, &p->props->position, s.radius_min, s.radius_max, burst_cb, &s); return PARTICLE_ALIVE; diff --git a/src/modules/sparkler/list.h b/src/modules/sparkler/list.h index 48bca36..04cafd6 100644 --- a/src/modules/sparkler/list.h +++ b/src/modules/sparkler/list.h @@ -130,7 +130,7 @@ static inline void list_move_tail(struct list_head *list, * list_empty - tests whether a list is empty * @head: the list to test. */ -static inline int list_empty(struct list_head *head) +static inline int list_empty(const struct list_head *head) { return head->next == head; } diff --git a/src/modules/sparkler/particle.c b/src/modules/sparkler/particle.c index 0e3d2c8..76d0c70 100644 --- a/src/modules/sparkler/particle.c +++ b/src/modules/sparkler/particle.c @@ -1,14 +1,14 @@ #include "particle.h" /* convert a particle to a new type */ -void particle_convert(particles_t *particles, 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) { - particle_cleanup(particles, p); + particle_cleanup(particles, conf, p); if (props) { *p->props = *props; } if (ops) { p->ops = ops; } - particle_init(particles, p); + particle_init(particles, conf, p); } diff --git a/src/modules/sparkler/particle.h b/src/modules/sparkler/particle.h index c63024d..a5999ee 100644 --- a/src/modules/sparkler/particle.h +++ b/src/modules/sparkler/particle.h @@ -22,13 +22,14 @@ typedef enum particle_status_t { typedef struct particle_t particle_t; 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 *, particle_t *); /* initialize the particle, called after allocating context (optional) */ - void (*cleanup)(particles_t *, particle_t *); /* cleanup function, called before freeing context (optional) */ - particle_status_t (*sim)(particles_t *, particle_t *); /* simulate the particle for another cycle (required) */ - void (*draw)(particles_t *, particle_t *, int, int, fb_fragment_t *); /* draw the particle, 3d->2d projection has been done already (optional) */ + int (*init)(particles_t *, const particles_conf_t *, particle_t *); /* 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 *, fb_fragment_t *); /* simulate the particle for another cycle (required) */ + void (*draw)(particles_t *, const particles_conf_t *, particle_t *, int, int, fb_fragment_t *); /* draw the particle, 3d->2d projection has been done already (optional) */ } particle_ops_t; struct particle_t { @@ -47,34 +48,38 @@ struct particle_t { #define INHERIT_PROPS NULL -static inline int particle_init(particles_t *particles, particle_t *p) { +static inline int particle_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { if (p->ops->init) { - return p->ops->init(particles, p); + return p->ops->init(particles, conf, p); } return 1; } -static inline void particle_cleanup(particles_t *particles, particle_t *p) { +static inline void particle_cleanup(particles_t *particles, const particles_conf_t *conf, particle_t *p) { if (p->ops->cleanup) { - p->ops->cleanup(particles, p); + p->ops->cleanup(particles, conf, p); } } -static inline particle_status_t particle_sim(particles_t *particles, particle_t *p) { - return p->ops->sim(particles, p); +/* XXX: fragment is supplied to ops->sim() only for debugging/overlay purposes, if particles_conf_t.show_bsp_matches for + * example is true, then sim may draw into fragment, and the callers shouldn't zero the fragment between sim and draw but + * instead should zero it before sim. It's kind of janky, not a fan. + */ +static inline particle_status_t particle_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { + return p->ops->sim(particles, conf, p, f); } -static inline void particle_draw(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f) { +static inline void particle_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { if (p->ops->draw) { - p->ops->draw(particles, p, x, y, f); + p->ops->draw(particles, conf, p, x, y, f); } } -void particle_convert(particles_t *particles, 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); #endif diff --git a/src/modules/sparkler/particles.c b/src/modules/sparkler/particles.c index b43c57b..d4677b7 100644 --- a/src/modules/sparkler/particles.c +++ b/src/modules/sparkler/particles.c @@ -78,7 +78,7 @@ static inline void _particles_free_particle(particles_t *particles, _particle_t { assert(p); - particle_cleanup(particles, &p->public); + particle_cleanup(particles, &particles->conf, &p->public); chunker_free(p); } @@ -157,7 +157,7 @@ static inline int _particles_add_particle(particles_t *particles, list_head_t *l p->public.ctxt = p->context; } - if (!particle_init(particles, &p->public)) { + if (!particle_init(particles, &particles->conf, &p->public)) { /* 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. */ @@ -237,7 +237,7 @@ static inline void _particles_draw(particles_t *particles, list_head_t *list, fb x = (p->props.position.x / (p->props.position.z - ZCONST) * w2) + w2; y = (p->props.position.y / (p->props.position.z - ZCONST) * h2) + h2; - particle_draw(particles, &p->public, x, y, fragment); + particle_draw(particles, &particles->conf, &p->public, x, y, fragment); if (!list_empty(&p->children)) { _particles_draw(particles, &p->children, fragment); @@ -246,16 +246,134 @@ static inline void _particles_draw(particles_t *particles, list_head_t *list, fb } +/* TODO: maybe polish up and move into fb.c? */ +static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) +{ + int x_delta = x2 - x1; + int y_delta = y2 - y1; + int sdx = x_delta < 0 ? -1 : 1; + int sdy = y_delta < 0 ? -1 : 1; + + x_delta = abs(x_delta); + y_delta = abs(y_delta); + + if (x_delta >= y_delta) { + /* X-major */ + for (int minor = 0, x = 0; x <= x_delta; x++, x1 += sdx, minor += y_delta) { + if (minor >= x_delta) { + y1 += sdy; + minor -= x_delta; + } + + fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + } + } else { + /* Y-major */ + for (int minor = 0, y = 0; y <= y_delta; y++, y1 += sdy, minor += x_delta) { + if (minor >= y_delta) { + x1 += sdx; + minor -= y_delta; + } + + fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + } + } +} + + +static void draw_edge(fb_fragment_t *fragment, const v3f_t *a, const v3f_t *b) +{ + float w2 = fragment->frame_width * .5f, h2 = fragment->frame_height * .5f; + int x1, y1, x2, y2; + + /* project the 3d coordinates onto the 2d plane */ + x1 = (a->x / (a->z - ZCONST) * w2) + w2; + y1 = (a->y / (a->z - ZCONST) * h2) + h2; + x2 = (b->x / (b->z - ZCONST) * w2) + w2; + y2 = (b->y / (b->z - ZCONST) * h2) + h2; + + draw_line(fragment, x1, y1, x2, y2); +} + + +static void draw_bv(fb_fragment_t *fragment, const v3f_t *bv_min, const v3f_t *bv_max) +{ + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_max->y, bv_min->z}, + &(v3f_t){bv_max->x, bv_max->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_max->y, bv_min->z}, + &(v3f_t){bv_min->x, bv_max->y, bv_max->z}); + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_max->y, bv_min->z}, + &(v3f_t){bv_min->x, bv_min->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_min->y, bv_min->z}, + &(v3f_t){bv_max->x, bv_min->y, bv_max->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_min->y, bv_min->z}, + &(v3f_t){bv_min->x, bv_min->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_min->y, bv_min->z}, + &(v3f_t){bv_max->x, bv_max->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_max->y, bv_max->z}, + &(v3f_t){bv_min->x, bv_max->y, bv_max->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_max->y, bv_max->z}, + &(v3f_t){bv_max->x, bv_max->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_max->x, bv_max->y, bv_max->z}, + &(v3f_t){bv_max->x, bv_min->y, bv_max->z}); + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_min->y, bv_max->z}, + &(v3f_t){bv_min->x, bv_min->y, bv_min->z}); + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_min->y, bv_max->z}, + &(v3f_t){bv_min->x, bv_max->y, bv_max->z}); + draw_edge(fragment, + &(v3f_t){bv_min->x, bv_min->y, bv_max->z}, + &(v3f_t){bv_max->x, bv_min->y, bv_max->z}); +} + + +/* something to encapsulate these pointers for passing through as one to draw_leaf() */ +typedef struct draw_leafs_t { + particles_t *particles; + fb_fragment_t *fragment; +} draw_leafs_t; + + +/* callback for bsp_walk_leaves() when show_bsp_leafs is enabled */ +static void draw_leaf(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data) +{ + draw_leafs_t *draw = cb_data; + + if (list_empty(occupants)) + return; + + if (depth < draw->particles->conf.show_bsp_leafs_min_depth) + return; + + draw_bv(draw->fragment, bv_min, bv_max); +} + + /* draw all of the particles, currently called in heirarchical order */ void particles_draw(particles_t *particles, fb_fragment_t *fragment) { + draw_leafs_t draw = { .particles = particles, .fragment = fragment }; + assert(particles); _particles_draw(particles, &particles->active, fragment); + + if (particles->conf.show_bsp_leafs) + bsp_walk_leaves(particles->bsp, draw_leaf, &draw); } -static inline particle_status_t _particles_sim(particles_t *particles, list_head_t *list) +static inline particle_status_t _particles_sim(particles_t *particles, list_head_t *list, fb_fragment_t *fragment) { particle_status_t ret = PARTICLE_DEAD, s; _particle_t *p, *_p; @@ -264,11 +382,11 @@ static inline particle_status_t _particles_sim(particles_t *particles, list_head assert(list); list_for_each_entry_safe(p, _p, list, siblings) { - if ((s = particle_sim(particles, &p->public)) == PARTICLE_ALIVE) { + if ((s = particle_sim(particles, &particles->conf, &p->public, fragment)) == PARTICLE_ALIVE) { ret = PARTICLE_ALIVE; if (!list_empty(&p->children) && - _particles_sim(particles, &p->children) == PARTICLE_ALIVE) { + _particles_sim(particles, &p->children, fragment) == PARTICLE_ALIVE) { ret = PARTICLE_ALIVE; } } else { @@ -282,11 +400,11 @@ static inline particle_status_t _particles_sim(particles_t *particles, list_head /* simulate the particles, call the sim method of every particle in the heirarchy, this is what makes the particles dynamic */ /* if any paticle is still living, we return PARTICLE_ALIVE, to inform the caller when everything's dead */ -particle_status_t particles_sim(particles_t *particles) +particle_status_t particles_sim(particles_t *particles, fb_fragment_t *fragment) { assert(particles); - return _particles_sim(particles, &particles->active); + return _particles_sim(particles, &particles->active, fragment); } @@ -357,3 +475,21 @@ void particles_age(particles_t *particles) _particles_age(particles, &particles->active); } + + +/* draw a line expressed in world-space positions a to b into fragment, this is intended for + * instrumentation/overlay debugging type purposes... + */ +void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, fb_fragment_t *fragment) +{ + float w2 = fragment->frame_width * .5f, h2 = fragment->frame_height * .5f; + int x1, y1, x2, y2; + + /* project the 3d coordinates onto the 2d plane */ + x1 = (a->x / (a->z - ZCONST) * w2) + w2; + y1 = (a->y / (a->z - ZCONST) * h2) + h2; + x2 = (b->x / (b->z - ZCONST) * w2) + w2; + y2 = (b->y / (b->z - ZCONST) * h2) + h2; + + draw_line(fragment, x1, y1, x2, y2); +} diff --git a/src/modules/sparkler/particles.h b/src/modules/sparkler/particles.h index b191b6e..9d6e3af 100644 --- a/src/modules/sparkler/particles.h +++ b/src/modules/sparkler/particles.h @@ -9,18 +9,22 @@ typedef struct particles_conf_t { unsigned show_bsp_leafs:1; unsigned show_bsp_matches:1; + unsigned show_bsp_matches_affected_only:1; + unsigned show_bsp_leafs_min_depth; } particles_conf_t; typedef struct particles_t particles_t; +typedef struct v3f_t v3f_t; particles_t * particles_new(const particles_conf_t *conf); void particles_draw(particles_t *particles, fb_fragment_t *fragment); -particle_status_t particles_sim(particles_t *particles); +particle_status_t particles_sim(particles_t *particles, 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); bsp_t * particles_bsp(particles_t *particles); +void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, fb_fragment_t *fragment); #endif diff --git a/src/modules/sparkler/rocket.c b/src/modules/sparkler/rocket.c index b56c324..50e1ff5 100644 --- a/src/modules/sparkler/rocket.c +++ b/src/modules/sparkler/rocket.c @@ -28,7 +28,7 @@ typedef struct rocket_ctxt_t { } rocket_ctxt_t; -static int rocket_init(particles_t *particles, particle_t *p) +static int rocket_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { rocket_ctxt_t *ctxt = p->ctxt; @@ -54,7 +54,7 @@ static int rocket_init(particles_t *particles, particle_t *p) } -static particle_status_t rocket_sim(particles_t *particles, particle_t *p) +static particle_status_t rocket_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { rocket_ctxt_t *ctxt = p->ctxt; int i, n_sparks; @@ -120,7 +120,7 @@ static particle_status_t rocket_sim(particles_t *particles, particle_t *p) } -static void rocket_draw(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f) +static void rocket_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { rocket_ctxt_t *ctxt = p->ctxt; @@ -132,7 +132,7 @@ static void rocket_draw(particles_t *particles, particle_t *p, int x, int y, fb_ } -static void rocket_cleanup(particles_t *particles, particle_t *p) +static void rocket_cleanup(particles_t *particles, const particles_conf_t *conf, particle_t *p) { rockets_cnt--; } diff --git a/src/modules/sparkler/simple.c b/src/modules/sparkler/simple.c index 7c7d415..8db15b1 100644 --- a/src/modules/sparkler/simple.c +++ b/src/modules/sparkler/simple.c @@ -23,7 +23,7 @@ typedef struct _simple_ctxt_t { } simple_ctxt_t; -static int simple_init(particles_t *particles, particle_t *p) +static int simple_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { simple_ctxt_t *ctxt = p->ctxt; @@ -54,7 +54,7 @@ static int simple_init(particles_t *particles, particle_t *p) } -static particle_status_t simple_sim(particles_t *particles, particle_t *p) +static particle_status_t simple_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { simple_ctxt_t *ctxt = p->ctxt; @@ -95,7 +95,7 @@ static particle_status_t simple_sim(particles_t *particles, particle_t *p) } -static void simple_draw(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f) +static void simple_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { simple_ctxt_t *ctxt = p->ctxt; diff --git a/src/modules/sparkler/spark.c b/src/modules/sparkler/spark.c index 16268a9..c432bf5 100644 --- a/src/modules/sparkler/spark.c +++ b/src/modules/sparkler/spark.c @@ -18,7 +18,7 @@ typedef struct _spark_ctxt_t { } spark_ctxt_t; -static int spark_init(particles_t *particles, particle_t *p) +static int spark_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { spark_ctxt_t *ctxt = p->ctxt; @@ -32,7 +32,7 @@ static int spark_init(particles_t *particles, particle_t *p) } -static particle_status_t spark_sim(particles_t *particles, particle_t *p) +static particle_status_t spark_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { spark_ctxt_t *ctxt = p->ctxt; @@ -45,7 +45,7 @@ static particle_status_t spark_sim(particles_t *particles, particle_t *p) } -static void spark_draw(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f) +static void spark_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { spark_ctxt_t *ctxt = p->ctxt; diff --git a/src/modules/sparkler/sparkler.c b/src/modules/sparkler/sparkler.c index 20a56c7..b673d0c 100644 --- a/src/modules/sparkler/sparkler.c +++ b/src/modules/sparkler/sparkler.c @@ -74,7 +74,10 @@ static void sparkler_prepare_frame(void *context, unsigned ticks, unsigned ncpus *res_fragmenter = sparkler_fragmenter; ctxt->n_cpus = ncpus; - particles_sim(ctxt->particles); + if (sparkler_conf.show_bsp_matches) + fb_fragment_zero(fragment); + + particles_sim(ctxt->particles, fragment); particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS / 4); particles_age(ctxt->particles); } @@ -85,7 +88,9 @@ static void sparkler_render_fragment(void *context, unsigned ticks, unsigned cpu { sparkler_context_t *ctxt = context; - fb_fragment_zero(fragment); + if (!sparkler_conf.show_bsp_matches) + fb_fragment_zero(fragment); + particles_draw(ctxt->particles, fragment); } @@ -96,11 +101,13 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett const char *show_bsp_leafs; const char *show_bsp_matches; const char *values[] = { - "on", "off", + "on", NULL }; + /* TODO: return -EINVAL on parse errors? */ + show_bsp_leafs = settings_get_value(settings, "show_bsp_leafs"); if (!show_bsp_leafs) { int r; @@ -117,6 +124,40 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett return 1; } + if (!strcasecmp(show_bsp_leafs, "on")) { + const char *show_bsp_leafs_min_depth; + + sparkler_conf.show_bsp_leafs = 1; + + show_bsp_leafs_min_depth = settings_get_value(settings, "show_bsp_leafs_min_depth"); + if (!show_bsp_leafs_min_depth) { + const char *depth_values[] = { + "0", + "4", + "6", + "8", + "10", + NULL + }; + int r; + + r = setting_desc_clone(&(setting_desc_t){ + .name = "Show BSP Leaf Node Bounding Boxes Minimum Depth", + .key = "show_bsp_leafs_min_depth", + .preferred = "8", + .values = depth_values, + }, next_setting); + if (r < 0) + return r; + + return 1; + } + + sscanf(show_bsp_leafs_min_depth, "%u", &sparkler_conf.show_bsp_leafs_min_depth); + } else { + sparkler_conf.show_bsp_leafs = 0; + } + show_bsp_matches = settings_get_value(settings, "show_bsp_matches"); if (!show_bsp_matches) { int r; @@ -133,17 +174,36 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett return 1; } - /* TODO: return -EINVAL on parse errors? */ - if (!strcasecmp(show_bsp_leafs, "on")) - sparkler_conf.show_bsp_leafs = 1; - else - sparkler_conf.show_bsp_leafs = 0; - if (!strcasecmp(show_bsp_matches, "on")) sparkler_conf.show_bsp_matches = 1; else sparkler_conf.show_bsp_matches = 0; + if (!strcasecmp(show_bsp_matches, "on")) { + const char *show_bsp_matches_affected_only; + + show_bsp_matches_affected_only = settings_get_value(settings, "show_bsp_matches_affected_only"); + if (!show_bsp_matches_affected_only) { + int r; + + r = setting_desc_clone(&(setting_desc_t){ + .name = "Show Only Affected BSP Search Matches", + .key = "show_bsp_matches_affected_only", + .preferred = "off", + .values = values, + }, next_setting); + if (r < 0) + return r; + + return 1; + } + + if (!strcasecmp(show_bsp_matches_affected_only, "on")) + sparkler_conf.show_bsp_matches_affected_only = 1; + else + sparkler_conf.show_bsp_matches_affected_only = 0; + } + return 0; } diff --git a/src/modules/sparkler/xplode.c b/src/modules/sparkler/xplode.c index 8b191cd..4d6ee36 100644 --- a/src/modules/sparkler/xplode.c +++ b/src/modules/sparkler/xplode.c @@ -21,7 +21,7 @@ typedef struct _xplode_ctxt_t { } xplode_ctxt_t; -static int xplode_init(particles_t *particles, particle_t *p) +static int xplode_init(particles_t *particles, const particles_conf_t *conf, particle_t *p) { xplode_ctxt_t *ctxt = p->ctxt; @@ -36,7 +36,7 @@ static int xplode_init(particles_t *particles, particle_t *p) } -static particle_status_t xplode_sim(particles_t *particles, particle_t *p) +static particle_status_t xplode_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { xplode_ctxt_t *ctxt = p->ctxt; @@ -57,7 +57,7 @@ static particle_status_t xplode_sim(particles_t *particles, particle_t *p) } -static void xplode_draw(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f) +static void xplode_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { xplode_ctxt_t *ctxt = p->ctxt; uint32_t color; |