gl -> polygons now work. slow - but does it matter?
authorCarsten Haitzler <raster@rasterman.com>
Sun, 27 Dec 2009 00:40:25 +0000 (00:40 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Sun, 27 Dec 2009 00:40:25 +0000 (00:40 +0000)
SVN revision: 44724

legacy/evas/src/modules/engines/gl_common/Makefile.am
legacy/evas/src/modules/engines/gl_common/evas_gl_common.h
legacy/evas/src/modules/engines/gl_common/evas_gl_polygon.c
legacy/evas/src/modules/engines/gl_common/evas_gl_rectangle.c
legacy/evas/src/modules/engines/gl_x11/evas_engine.c

index fc4ec02..3b357b6 100644 (file)
@@ -39,8 +39,8 @@ shader/tex_vert_bin_s3c6410.h \
 evas_gl_rectangle.c \
 evas_gl_texture.c \
 evas_gl_image.c \
-evas_gl_font.c 
-
+evas_gl_font.c \
+evas_gl_polygon.c
 
 #evas_gl_gradient.c \
 #evas_gl_line.c \
index 919d58f..48ab923 100644 (file)
@@ -55,12 +55,10 @@ typedef struct _Evas_GL_Texture_Pool                 Evas_GL_Texture_Pool;
 typedef struct _Evas_GL_Texture                      Evas_GL_Texture;
 typedef struct _Evas_GL_Image                        Evas_GL_Image;
 typedef struct _Evas_GL_Font_Texture                 Evas_GL_Font_Texture;
-/*
 typedef struct _Evas_GL_Polygon                      Evas_GL_Polygon;
 typedef struct _Evas_GL_Polygon_Point                Evas_GL_Polygon_Point;
+/*
 typedef struct _Evas_GL_Gradient                     Evas_GL_Gradient;
-typedef struct _Evas_GL_Font_Texture_Pool            Evas_GL_Font_Texture_Pool;
-typedef struct _Evas_GL_Font_Texture_Pool_Allocation Evas_GL_Font_Texture_Pool_Allocation;
 */
 
 struct _Evas_GL_Program
@@ -189,11 +187,10 @@ struct _Evas_GL_Font_Texture
 {
    Evas_GL_Texture *tex;
 };
-/*
+
 struct _Evas_GL_Polygon
 {
    Eina_List *points;
-   GLuint     dl;
    Eina_Bool  changed : 1;
 };
 
@@ -202,6 +199,7 @@ struct _Evas_GL_Polygon_Point
    int x, y;
 };
 
+/*
 struct _Evas_GL_Gradient
 {
    RGBA_Gradient   *grad;
@@ -209,14 +207,6 @@ struct _Evas_GL_Gradient
    int              tw, th;
    unsigned char    changed : 1;
 };
-
-struct _Evas_GL_Font_Texture_Pool
-{
-   Evas_GL_Context *gc;
-   int              w, h;
-   GLuint           texture;
-   unsigned char    rectangle : 1;
-};
 */
 
 extern Evas_GL_Program_Source shader_rect_frag_src;
@@ -297,6 +287,9 @@ void             *evas_gl_font_texture_new(void *gc, RGBA_Font_Glyph *fg);
 void              evas_gl_font_texture_free(void *);
 void              evas_gl_font_texture_draw(void *gc, void *surface, void *dc, RGBA_Font_Glyph *fg, int x, int y);
 
+Evas_GL_Polygon  *evas_gl_common_poly_point_add(Evas_GL_Polygon *poly, int x, int y);
+Evas_GL_Polygon  *evas_gl_common_poly_points_clear(Evas_GL_Polygon *poly);
+void              evas_gl_common_poly_draw(Evas_GL_Context *gc, Evas_GL_Polygon *poly);
 
 void (*glsym_glGenFramebuffers)      (GLsizei a, GLuint *b);
 void (*glsym_glBindFramebuffer)      (GLenum a, GLuint b);
@@ -322,8 +315,6 @@ void (*glsym_glDeleteFramebuffers)   (GLsizei a, const GLuint *b);
 
 
 /*
-Evas_GL_Polygon  *evas_gl_common_poly_point_add(Evas_GL_Polygon *poly, int x, int y);
-Evas_GL_Polygon  *evas_gl_common_poly_points_clear(Evas_GL_Polygon *poly);
 
 Evas_GL_Gradient *evas_gl_common_gradient_new(void);
 void              evas_gl_common_gradient_free(Evas_GL_Gradient *gr);
@@ -349,7 +340,6 @@ void              evas_gl_common_gradient_draw(Evas_GL_Context *gc, Evas_GL_Grad
 void              evas_gl_common_swap_rect(Evas_GL_Context *gc, int x, int y, int w, int h);
 
 void              evas_gl_common_line_draw(Evas_GL_Context *gc, int x1, int y1, int x2, int y2);
-void              evas_gl_common_poly_draw(Evas_GL_Context *gc, Evas_GL_Polygon *poly);
 */
 
 #endif
index 6f0ab10..1425d1c 100644 (file)
@@ -1,12 +1,69 @@
 #include "evas_gl_private.h"
 
-#ifdef _WIN32
-# define EFL_STDCALL __stdcall
-#else
-# define EFL_STDCALL
-#endif
+// FIXME: this is a verbatim copy of the software poly renderer. it just
+// use gl to draw 1 pixel high spans like software does. this is to make
+// sure rendering correctness matches the software engine but also to save
+// time in coming up with a good triangulation algorithm. if you want to
+// feel free to turn this into a real triangulation system and use gl to its
+// fullest, but as such polygons are used so little, it's not worth it.
 
-#define GLU_TESS
+typedef struct _RGBA_Span RGBA_Span;
+typedef struct _RGBA_Edge RGBA_Edge;
+typedef struct _RGBA_Vertex RGBA_Vertex;
+
+struct _RGBA_Span
+{
+   EINA_INLIST;
+   int x, y, w;
+};
+
+struct _RGBA_Edge
+{
+   double x, dx;
+   int i;
+};
+
+struct _RGBA_Vertex
+{
+   double x, y;
+   int i;
+};
+
+#define POLY_EDGE_DEL(_i)                                               \
+   {                                                                       \
+      int _j;                                                              \
+      \
+      for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++);  \
+      if (_j < num_active_edges)                                           \
+        {                                                                  \
+           num_active_edges--;                                             \
+           memmove(&(edges[_j]), &(edges[_j + 1]),                         \
+                      (num_active_edges - _j) * sizeof(RGBA_Edge));           \
+        }                                                                  \
+   }
+
+#define POLY_EDGE_ADD(_i, _y)                                           \
+   {                                                                       \
+      int _j;                                                              \
+      float _dx;                                                           \
+      RGBA_Vertex *_p, *_q;                                                \
+      if (_i < (n - 1)) _j = _i + 1;                                       \
+      else _j = 0;                                                         \
+      if (point[_i].y < point[_j].y)                                       \
+        {                                                                  \
+           _p = &(point[_i]);                                              \
+           _q = &(point[_j]);                                              \
+        }                                                                  \
+      else                                                                 \
+        {                                                                  \
+           _p = &(point[_j]);                                              \
+           _q = &(point[_i]);                                              \
+        }                                                                  \
+      edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
+      edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
+      edges[num_active_edges].i = _i;                                      \
+      num_active_edges++;                                                  \
+   }
 
 Evas_GL_Polygon *
 evas_gl_common_poly_point_add(Evas_GL_Polygon *poly, int x, int y)
@@ -36,133 +93,215 @@ evas_gl_common_poly_points_clear(Evas_GL_Polygon *poly)
        poly->points = eina_list_remove(poly->points, pt);
        free(pt);
      }
-   if (poly->dl > 0) glDeleteLists(poly->dl, 1);
    free(poly);
    return NULL;
 }
 
-#ifdef GLU_TESS
-static void EFL_STDCALL _evas_gl_tess_begin_cb(GLenum which);
-static void EFL_STDCALL _evas_gl_tess_end_cb(void);
-static void EFL_STDCALL _evas_gl_tess_error_cb(GLenum errorcode);
-static void EFL_STDCALL _evas_gl_tess_vertex_cb(GLvoid *vertex);
-static void EFL_STDCALL _evas_gl_tess_combine_cb(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **data_out);
-
-static void EFL_STDCALL
-_evas_gl_tess_begin_cb(GLenum which)
-{
-   glBegin(which);
-}
-
-static void EFL_STDCALL
-_evas_gl_tess_end_cb(void)
-{
-   glEnd();
-}
-
-static void EFL_STDCALL
-_evas_gl_tess_error_cb(GLenum errorcode __UNUSED__)
-{
-}
-
-static void EFL_STDCALL
-_evas_gl_tess_vertex_cb(GLvoid *vertex)
+static int
+polygon_point_sorter(const void *a, const void *b)
 {
-   GLdouble *v;
-
-   v = vertex;
-   glVertex2d(v[0], v[1]);
+   RGBA_Vertex *p, *q;
+   
+   p = (RGBA_Vertex *)a;
+   q = (RGBA_Vertex *)b;
+   if (p->y <= q->y) return -1;
+   return 1;
 }
 
-static void EFL_STDCALL
-_evas_gl_tess_combine_cb(GLdouble coords[3], GLdouble *vertex_data[4] __UNUSED__, GLfloat weight[4] __UNUSED__, GLdouble **data_out)
+static int
+polygon_edge_sorter(const void *a, const void *b)
 {
-   GLdouble *vertex;
-
-   vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
-   vertex[0] = coords[0];
-   vertex[1] = coords[1];
-   *data_out = vertex;
+   RGBA_Edge *p, *q;
+   
+   p = (RGBA_Edge *)a;
+   q = (RGBA_Edge *)b;
+   if (p->x <= q->x) return -1;
+   return 1;
 }
-#endif
 
 void
 evas_gl_common_poly_draw(Evas_GL_Context *gc, Evas_GL_Polygon *poly)
 {
-   int r, g, b, a;
+   Cutout_Rects *rects;
+   Cutout_Rect  *r;
+   int c, cx, cy, cw, ch, cr, cg, cb, ca, i;
+   int x, y, w, h;
+
    Eina_List *l;
-   static void *tess = NULL;
-   GLdouble *glp = NULL;
-   int i, num;
-   RGBA_Draw_Context *dc = gc->dc;
-   Evas_GL_Polygon_Point *p;
-
-   a = (dc->col.col >> 24) & 0xff;
-   r = (dc->col.col >> 16) & 0xff;
-   g = (dc->col.col >> 8 ) & 0xff;
-   b = (dc->col.col      ) & 0xff;
-   evas_gl_common_context_color_set(gc, r, g, b, a);
-   if (a < 255) evas_gl_common_context_blend_set(gc, 1);
-   else evas_gl_common_context_blend_set(gc, 0);
-   if (dc->clip.use)
-     evas_gl_common_context_clip_set(gc, 1,
-                                    dc->clip.x, dc->clip.y,
-                                    dc->clip.w, dc->clip.h);
-   else
-     evas_gl_common_context_clip_set(gc, 0,
-                                    0, 0, 0, 0);
-   evas_gl_common_context_texture_set(gc, NULL, 0, 0, 0);
-   evas_gl_common_context_read_buf_set(gc, GL_BACK);
-   evas_gl_common_context_write_buf_set(gc, GL_BACK);
-
-   if (poly->changed || poly->dl <= 0)
+   int n, k, num_active_edges, y0, y1, *sorted_index, j;
+   RGBA_Edge *edges;
+   RGBA_Vertex *point;
+   Evas_GL_Polygon_Point *pt;
+   Eina_Inlist *spans;
+   
+   /* save out clip info */
+   c = gc->dc->clip.use; cx = gc->dc->clip.x; cy = gc->dc->clip.y; cw = gc->dc->clip.w; ch = gc->dc->clip.h;
+
+   ca = (gc->dc->col.col >> 24) & 0xff;
+   if (ca <= 0) return;
+   cr = (gc->dc->col.col >> 16) & 0xff;
+   cg = (gc->dc->col.col >> 8 ) & 0xff;
+   cb = (gc->dc->col.col      ) & 0xff;
+   
+   n = eina_list_count(poly->points);
+   if (n < 3) return;
+   edges = malloc(sizeof(RGBA_Edge) * n);
+   if (!edges) return;
+   point = malloc(sizeof(RGBA_Vertex) * n);
+   if (!point)
+     {
+        free(edges);
+        return;
+     }
+   sorted_index = malloc(sizeof(int) * n);
+   if (!sorted_index)
      {
-       if (poly->dl > 0) glDeleteLists(poly->dl, 1);
-       poly->dl = glGenLists(1);
-
-       glNewList(poly->dl, GL_COMPILE_AND_EXECUTE);
-#ifdef GLU_TESS
-       if (!tess)
-         {
-            tess = gluNewTess();
-
-            gluTessCallback(tess, GLU_TESS_BEGIN, _evas_gl_tess_begin_cb);
-            gluTessCallback(tess, GLU_TESS_END, _evas_gl_tess_end_cb);
-            gluTessCallback(tess, GLU_TESS_ERROR, _evas_gl_tess_error_cb);
-            gluTessCallback(tess, GLU_TESS_VERTEX, _evas_gl_tess_vertex_cb);
-            gluTessCallback(tess, GLU_TESS_COMBINE, _evas_gl_tess_combine_cb);
-         }
-       num = 0;
-       num = eina_list_count(poly->points);
-       i = 0;
-       glp = malloc(num * 6 * sizeof(GLdouble));
-       gluTessNormal(tess, 0, 0, 1);
-       gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
-       gluTessBeginPolygon(tess, NULL);
-       gluTessBeginContour(tess);
-       EINA_LIST_FOREACH(poly->points, l, p)
-         {
-            glp[i++] = p->x;
-            glp[i++] = p->y;
-            glp[i++] = 0;
-            gluTessVertex(tess, &(glp[i - 3]), &(glp[i - 3]));
-            i += 3;
-         }
-       gluTessEndContour(tess);
-       gluTessEndPolygon(tess);
-       free(glp);
-#else
-       glBegin(GL_POLYGON);
-       EINA_LIST_FOREACH(poly->points, l, p)
-         glVertex2i(p->x, p->y);
-       glEnd();
-#endif
-       glEndList();
-
-       poly->changed = 0;
-
-       return ;
+        free(edges);
+        free(point);
+        return;
      }
+   
+   k = 0;
+   EINA_LIST_FOREACH(poly->points, l, pt)
+     {
+        point[k].x = pt->x;
+        point[k].y = pt->y;
+        point[k].i = k;
+        k++;
+     }
+   qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
+   for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
+   k = 0;
+
+   EINA_LIST_FOREACH(poly->points, l, pt)
+     {
+        point[k].x = pt->x;
+        point[k].y = pt->y;
+        point[k].i = k;
+        k++;
+     }
+   
+   y0 = MAX(cy, ceil(point[sorted_index[0]].y - 0.5));
+   y1 = MIN(cy + ch - 1, floor(point[sorted_index[n - 1]].y - 0.5));
+   
+   k = 0;
+   num_active_edges = 0;
+   spans = NULL;
+   
+   for (y = y0; y <= y1; y++)
+     {
+        for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
+          {
+             i = sorted_index[k];
+             
+             if (i > 0) j = i - 1;
+             else j = n - 1;
+             if (point[j].y <= ((double)y - 0.5))
+               {
+                  POLY_EDGE_DEL(j)
+               }
+             else if (point[j].y > ((double)y + 0.5))
+               {
+                  POLY_EDGE_ADD(j, y)
+               }
+             if (i < (n - 1)) j = i + 1;
+             else j = 0;
+             if (point[j].y <= ((double)y - 0.5))
+               {
+                  POLY_EDGE_DEL(i)
+               }
+             else if (point[j].y > ((double)y + 0.5))
+               {
+                  POLY_EDGE_ADD(i, y)
+               }
+          }
+        
+        qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
+        
+        for (j = 0; j < num_active_edges; j += 2)
+          {
+             int x0, x1;
+             
+             x0 = ceil(edges[j].x - 0.5);
+             if (j < (num_active_edges - 1))
+               x1 = floor(edges[j + 1].x - 0.5);
+             else
+               x1 = x0;
+             if ((x1 >= cx) && (x0 < (cx + cw)) && (x0 <= x1))
+               {
+                  RGBA_Span *span;
+                  
+                  if (x0 < cx) x0 = cx;
+                  if (x1 >= (cx + cw)) x1 = cx + cw - 1;
+                  span = malloc(sizeof(RGBA_Span));
+                  spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
+                  span->y = y;
+                  span->x = x0;
+                  span->w = (x1 - x0) + 1;
+               }
+             edges[j].x += edges[j].dx;
+             edges[j + 1].x += edges[j + 1].dx;
+          }
+     }
+   
+   free(edges);
+   free(point);
+   free(sorted_index);
+   
+   evas_common_draw_context_clip_clip(gc->dc, 0, 0, gc->w, gc->h);
+   
+   if (spans)
+     {
+        RGBA_Span *span;
+
+        /* no cutouts - cut right to the chase */
+        if (!gc->dc->cutout.rects)
+          {
+             EINA_INLIST_FOREACH(spans, span)
+               {
+                  x = span->x;
+                  y = span->y;
+                  w = span->w;
+                  h = 1;
+                  evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca);
+               }
+          }
+        else
+          {
+             evas_common_draw_context_clip_clip(gc->dc, x, y, w, h);
+             /* our clip is 0 size.. abort */
+             if ((gc->dc->clip.w > 0) && (gc->dc->clip.h > 0))
+               {
+                  rects = evas_common_draw_context_apply_cutouts(gc->dc);
+                  for (i = 0; i < rects->active; ++i)
+                    {
+                       r = rects->rects + i;
+                       if ((r->w > 0) && (r->h > 0))
+                         {
+                            EINA_INLIST_FOREACH(spans, span)
+                              {
+                                 x = span->x;
+                                 y = span->y;
+                                 w = span->w;
+                                 h = 1;
+                                 RECTS_CLIP_TO_RECT(x, y, w, h, r->x, r->y, r->w, r->h);
+                                 if ((w > 0) && (h > 0))
+                                   evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca);
+                              }
+                         }
+                    }
+                  evas_common_draw_context_apply_clear_cutouts(rects);
+               }
+          }
+        while (spans)
+          {
+             span = (RGBA_Span *)spans;
+             spans = eina_inlist_remove(spans, spans);
+             free(span);
+          }    
+     }       
+   
+   /* restore clip info */
+   gc->dc->clip.use = c; gc->dc->clip.x = cx; gc->dc->clip.y = cy; gc->dc->clip.w = cw; gc->dc->clip.h = ch;
 
-   glCallList(poly->dl);
 }
index 459a6bf..cd3368e 100644 (file)
@@ -13,7 +13,7 @@ evas_gl_common_rect_draw(Evas_GL_Context *gc, int x, int y, int w, int h)
    c = gc->dc->clip.use; cx = gc->dc->clip.x; cy = gc->dc->clip.y; cw = gc->dc->clip.w; ch = gc->dc->clip.h;
    
    ca = (gc->dc->col.col >> 24) & 0xff;
-//   if (ca <= 0) return;
+   if (ca <= 0) return;
    cr = (gc->dc->col.col >> 16) & 0xff;
    cg = (gc->dc->col.col >> 8 ) & 0xff;
    cb = (gc->dc->col.col      ) & 0xff;
index 26f217c..f8630c0 100644 (file)
@@ -363,8 +363,7 @@ eng_polygon_point_add(void *data, void *context __UNUSED__, void *polygon, int x
    Render_Engine *re;
 
    re = (Render_Engine *)data;
-//--//      return evas_gl_common_poly_point_add(polygon, x, y);
-   return NULL;
+   return evas_gl_common_poly_point_add(polygon, x, y);
 }
 
 static void *
@@ -373,8 +372,7 @@ eng_polygon_points_clear(void *data, void *context __UNUSED__, void *polygon)
    Render_Engine *re;
 
    re = (Render_Engine *)data;
-//--//      return evas_gl_common_poly_points_clear(polygon);
-   return NULL;
+   return evas_gl_common_poly_points_clear(polygon);
 }
 
 static void
@@ -386,7 +384,7 @@ eng_polygon_draw(void *data, void *context, void *surface, void *polygon)
    eng_window_use(re->win);
    evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
    re->win->gl_context->dc = context;
-//--//      evas_gl_common_poly_draw(re->win->gl_context, polygon);
+   evas_gl_common_poly_draw(re->win->gl_context, polygon);
 }
 
 static void