summaryrefslogtreecommitdiff
path: root/src/modules/sparkler/particles.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2020-09-11 00:48:13 -0700
committerVito Caputo <vcaputo@pengaru.com>2020-09-11 01:05:40 -0700
commit85127285bff6983665275fe14d3c2b80b36a872a (patch)
tree0215b33ee3b1101b9300d790f15914fa4e2bfcdf /src/modules/sparkler/particles.c
parenta9f489265c1ebbc67a3f675d1a79a2254345b489 (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/particles.c')
-rw-r--r--src/modules/sparkler/particles.c152
1 files changed, 144 insertions, 8 deletions
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);
+}
© All Rights Reserved