* clutter/cogl/gles/cogl-primitives.c: (_cogl_path_fill_nodes):
authorØyvind Kolås <pippin@openedhand.com>
Wed, 30 Apr 2008 16:57:21 +0000 (16:57 +0000)
committerØyvind Kolås <pippin@openedhand.com>
Wed, 30 Apr 2008 16:57:21 +0000 (16:57 +0000)
scanline rasterizer fallback for GLES without working stencil
buffer (would benefit from optimization/smarter choice of
datastructures).

ChangeLog
clutter/cogl/gles/cogl-primitives.c

index e054174..39774c6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-04-30  Øyvind Kolås  <pippin@o-hand.com>
+
+       * 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).
+
 2008-04-30  Emmanuele Bassi  <ebassi@openedhand.com>
 
        * clutter/clutter-effect.c:
index 7c9c098..df0eeba 100644 (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 ()
 {
@@ -208,6 +214,13 @@ _cogl_path_fill_nodes ()
   guint bounds_y;
   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) );
 
@@ -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