* clutter/cogl/gles/cogl-primitives.c: (_cogl_path_fill_nodes):

scanline rasterizer fallback for GLES without working stencil
buffer (would benefit from optimization/smarter choice of
datastructures).
This commit is contained in:
Øyvind Kolås 2008-04-30 16:57:21 +00:00
parent 96f679a18b
commit 97b3499c52

View File

@ -199,6 +199,12 @@ _cogl_path_stroke_nodes ()
GE( glDrawArrays (GL_LINE_STRIP, 0, ctx->path_nodes_size) );
}
static gint compare_ints (gconstpointer a,
gconstpointer b)
{
return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
}
static void
_cogl_path_fill_nodes ()
{
@ -209,6 +215,13 @@ _cogl_path_fill_nodes ()
guint bounds_w;
guint bounds_h;
bounds_x = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.x);
bounds_y = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.y);
bounds_w = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x);
bounds_h = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.y - ctx->path_nodes_min.y);
#if GOT_WORKING_STENCIL_BUFFER
GE( glClear (GL_STENCIL_BUFFER_BIT) );
GE( glEnable (GL_STENCIL_TEST) );
@ -226,14 +239,99 @@ _cogl_path_fill_nodes ()
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
bounds_x = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.x);
bounds_y = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.y);
bounds_w = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x);
bounds_h = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.y - ctx->path_nodes_min.y);
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
GE( glDisable (GL_STENCIL_TEST) );
#endif
{
GSList *scanlines[bounds_h];
/* This is our edge list it stores intersections between our curve and
* scanlines */
gint i;
gint prev_x;
gint prev_y;
gint first_x;
gint first_y;
/* clear scanline intersection lists */
for (i=0; i < bounds_h; i++)
scanlines[i]=NULL;
first_x = prev_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].x);
first_y = prev_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].y);
/* saturate scanline intersection list */
for (i=1; i<ctx->path_nodes_size; i++)
{
gint dest_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].x);
gint dest_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].y);
gint ydir;
gint dx;
gint dy;
gint y;
fill_close:
dx = dest_x - prev_x;
dy = dest_y - prev_y;
if (dy < 0)
ydir = -1;
else
ydir = 1;
/* do linear interpolation between vertexes */
for (y=prev_y; y!= dest_y; y += ydir)
{
if (y-bounds_y >= 0 &&
y-bounds_y < bounds_h)
{
gint x = prev_x + (dx * (y-prev_y)) / dy;
scanlines[ y - bounds_y ]=
g_slist_insert_sorted (scanlines[ y - bounds_y],
GINT_TO_POINTER(x),
compare_ints);
}
}
prev_x = dest_x;
prev_y = dest_y;
/* if we're on the last knot, fake the first vertex being a next one */
if (ctx->path_nodes_size == i+1)
{
dest_x = first_x;
dest_y = first_y;
i++; /* to make the loop finally end */
goto fill_close;
}
}
/* for each scanline */
for (i=0; i < bounds_h; i++)
{
GSList *iter = scanlines[i];
while (iter)
{
GSList *next = iter->next;
gint startx, endx;
if (!next)
break;
startx = GPOINTER_TO_INT (iter->data);
endx = GPOINTER_TO_INT (next->data);
/* draw the segments that should be visible */
cogl_rectangle (startx, i + bounds_y, endx - startx, 1);
iter = next->next;
}
if (scanlines[i])
g_slist_free (scanlines[i]);
}
}
}
void