diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-09-11 00:48:13 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-09-11 01:05:40 -0700 |
commit | 85127285bff6983665275fe14d3c2b80b36a872a (patch) | |
tree | 0215b33ee3b1101b9300d790f15914fa4e2bfcdf /src/modules/sparkler | |
parent | a9f489265c1ebbc67a3f675d1a79a2254345b489 (diff) |
module/sparkler: implement some BSP drawing settings
This commit adds a few settings for visualizing the octree BSP:
show_bsp_leafs (on/off):
Draw wireframe cubes around octree leaf nodes
show_bsp_leafs_min_depth (0,4,6,8,10):
Set minimum octree depth for leaf nodes displayed
show_bsp_matches (on/off):
Draw lines connecting BSP search matches
show_bsp_matches_affected_only (on/off):
Limit drawn BSP search matches to only matches actually
affected by the simulation
The code implementing this stuff is a bit crufty, fb_fragment_t
had to be pulled down to the sim ops for example and whether that
actually results in drawing occurring during the sim phase
depends on the config used and how the particle implementations
react to the config... it's just gross. This matters because the
caller used to know only the draw phase touched fb_fragment_t,
and because of that the fragment was zeroed after sim and before
draw in parallel. But now the caller needs to know if the config
would make sim do some drawing, and do the fragment zeroing
before sim instead, and skip the zero before draw to not lose
what sim drew. It's icky, but I'll leave it for now, at least
it's isolated to the sparkler.
Diffstat (limited to 'src/modules/sparkler')
-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; |