summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/modules/flow/flow.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/src/modules/flow/flow.c b/src/modules/flow/flow.c
index 901eda8..4ef42ed 100644
--- a/src/modules/flow/flow.c
+++ b/src/modules/flow/flow.c
@@ -35,6 +35,17 @@ typedef struct flow_element_t {
v3f_t position_a, position_b;
v3f_t velocity; /* per-iter step + direction applicable directly to position_a */
v3f_t color;
+
+ /* In the first pass we visit each element just once for the simulation, while there
+ * the particles are projected into the 2d fragment space with those coordinates cached
+ * in the element. Then the second pass accesses these to determine if the particle is
+ * in the fragment being drawn. As-is the second pass visits all elements since they're
+ * not (yet) kept organized spatially.
+ */
+ struct {
+ unsigned x1, y1;
+ unsigned x2, y2;
+ } fragspace;
} flow_element_t;
typedef struct flow_context_t {
@@ -219,6 +230,8 @@ static void flow_render_fragment(til_module_context_t *context, til_stream_t *st
flow_element_t *e = &ctxt->elements[fragment->number * ctxt->n_elements_per_cpu];
unsigned n = ctxt->n_elements_per_cpu;
float w = ctxt->w * .5f + .5f;
+ unsigned ffw = fragment->frame_width,
+ ffh = fragment->frame_height;
/* XXX: note the fragment->number is used above as the cpu number, this is to ensure all cpu #s
* are actually used. Since our noop_fragmenter_per_cpu always produces a fragment per cpu,
@@ -261,6 +274,15 @@ static void flow_render_fragment(til_module_context_t *context, til_stream_t *st
*/
d.direction = v3f_mult_scalar(&d.direction, (float)ctxt->n_iters);
e->position_b = v3f_add(&pos, &d.direction);
+
+ /* Now do the 2D projection part and store those results in the element, where
+ * it can be quickly checked by the second pass.
+ */
+#define ZCONST 1.0f
+ e->fragspace.x1 = pos.x / (pos.z + ZCONST) * ffw + (ffw >> 1);
+ e->fragspace.y1 = pos.y / (pos.z + ZCONST) * ffh + (ffh >> 1) ;
+ e->fragspace.x2 = e->position_b.x / (e->position_b.z + ZCONST) * ffw + (ffw >> 1);
+ e->fragspace.y2 = e->position_b.y / (e->position_b.z + ZCONST) * ffh + (ffh >> 1) ;
}
return;
@@ -281,18 +303,12 @@ static void flow_render_fragment(til_module_context_t *context, til_stream_t *st
flow_element_t *e = &ctxt->elements[i];
v3f_t pos = e->position_a;
v3f_t v = e->velocity;
- unsigned x1, y1, x2, y2;
+ unsigned x1 = e->fragspace.x1,
+ y1 = e->fragspace.y1,
+ x2 = e->fragspace.x2,
+ y2 = e->fragspace.y2;
uint32_t pixel;
- /* Perspective-project the endpoints of the element's travel, this is
- * the part we can't currently avoid doing per-element per-fragment.
- */
-#define ZCONST 1.0f
- x1 = pos.x / (pos.z + ZCONST) * ffw + (ffw >> 1);
- y1 = pos.y / (pos.z + ZCONST) * ffh + (ffh >> 1) ;
- x2 = e->position_b.x / (e->position_b.z + ZCONST) * ffw + (ffw >> 1);
- y2 = e->position_b.y / (e->position_b.z + ZCONST) * ffh + (ffh >> 1) ;
-
/* for cases obviously outside the fragment, don't draw anything */
/* FIXME: these early-outs don't consider the ctxt->n_iters interpolated coordinates */
@@ -326,6 +342,10 @@ static void flow_render_fragment(til_module_context_t *context, til_stream_t *st
if (!ctxt->n_iters)
continue;
+ /* TODO: why isn't this a simple line draw of (x1,y1)..(x2,y2)?
+ * that would eliminate the cumulative error potential for going out of bounds,
+ * which is the real reason put_pixel_unchecked() can't be used in this loop.
+ */
for (unsigned j = 1; j < ctxt->n_iters - 1; j++) {
pos = v3f_add(&pos, &v);
© All Rights Reserved