summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/modules/flow/flow.c47
1 files changed, 35 insertions, 12 deletions
diff --git a/src/modules/flow/flow.c b/src/modules/flow/flow.c
index c9b94e4..d28f9f3 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 {
@@ -83,7 +94,7 @@ static void flow_ff_populator(void *context, unsigned size, const ff_data_t *oth
v3f_t c = v3f_rand(seedp, 0.f, 1.0f);
size_t idx = x * size * size + y * size + z;
- field[idx].direction = v3f_lerp(&other[idx].direction, &v, .75f);
+ field[idx].direction = v3f_lerp(&other[idx].direction, &v, .50f);
field[idx].color = v3f_lerp(&other[idx].color, &c, .75f);
}
}
@@ -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,20 +303,16 @@ 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 */
+
/* totally outside (above) */
if (y1 < fy1 && y2 < fy1)
continue;
@@ -324,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);
@@ -331,7 +353,8 @@ static void flow_render_fragment(til_module_context_t *context, til_stream_t *st
x1 = pos.x / (pos.z + ZCONST) * ffw + (ffw >> 1);
y1 = pos.y / (pos.z + ZCONST) * ffh + (ffh >> 1);
- (void) til_fb_fragment_put_pixel_unchecked(fragment, TIL_FB_DRAW_FLAG_TEXTURABLE, x1, y1, pixel);
+ /* XXX: now that [xy]1 are changed, unchecked can't be used, it could be done more cleverly */
+ (void) til_fb_fragment_put_pixel_checked(fragment, TIL_FB_DRAW_FLAG_TEXTURABLE, x1, y1, pixel);
}
continue;
© All Rights Reserved