move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common_16 / evas_soft16_polygon.c
1 #include <evas_common_soft16.h>
2 #include "evas_soft16_scanline_fill.c"
3 #include <math.h>
4
5 typedef struct _RGBA_Edge RGBA_Edge;
6 typedef struct _RGBA_Vertex RGBA_Vertex;
7
8 struct _RGBA_Edge
9 {
10    float x, dx;
11    int i;
12 };
13
14 struct _RGBA_Vertex
15 {
16    float x, y;
17    int i;
18 };
19
20 #define POLY_EDGE_DEL(_i)                                               \
21 {                                                                       \
22    int _j;                                                              \
23                                                                         \
24    for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++);  \
25    if (_j < num_active_edges)                                           \
26      {                                                                  \
27         num_active_edges--;                                             \
28         memmove(&(edges[_j]), &(edges[_j + 1]),                         \
29                 (num_active_edges - _j) * sizeof(RGBA_Edge));           \
30      }                                                                  \
31 }
32
33 #define POLY_EDGE_ADD(_i, _y)                                           \
34 {                                                                       \
35    int _j;                                                              \
36    float _dx;                                                           \
37    RGBA_Vertex *_p, *_q;                                                \
38    if (_i < (n - 1)) _j = _i + 1;                                       \
39    else _j = 0;                                                         \
40    if (point[_i].y < point[_j].y)                                       \
41      {                                                                  \
42         _p = &(point[_i]);                                              \
43         _q = &(point[_j]);                                              \
44      }                                                                  \
45    else                                                                 \
46      {                                                                  \
47         _p = &(point[_j]);                                              \
48         _q = &(point[_i]);                                              \
49      }                                                                  \
50    edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
51    edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
52    edges[num_active_edges].i = _i;                                      \
53    num_active_edges++;                                                  \
54 }
55
56 static int
57 polygon_point_sorter(const void *a, const void *b)
58 {
59    RGBA_Vertex *p, *q;
60
61    p = (RGBA_Vertex *)a;
62    q = (RGBA_Vertex *)b;
63    if (p->y <= q->y) return -1;
64    return 1;
65 }
66
67 static int
68 polygon_edge_sorter(const void *a, const void *b)
69 {
70    RGBA_Edge *p, *q;
71
72    p = (RGBA_Edge *)a;
73    q = (RGBA_Edge *)b;
74    if (p->x <= q->x) return -1;
75    return 1;
76 }
77
78 void
79 soft16_polygon_draw(Soft16_Image *dst, RGBA_Draw_Context *dc, RGBA_Polygon_Point *points)
80 {
81    RGBA_Polygon_Point *pt;
82    RGBA_Vertex       *point;
83    RGBA_Edge         *edges;
84    Evas_Object_List *l;
85    int                num_active_edges;
86    int                n;
87    int                i, j, k;
88    int                y0, y1, y;
89    int                ext_x, ext_y, ext_w, ext_h;
90    int               *sorted_index;
91    DATA8 alpha;
92    DATA16 rgb565;
93    DATA32 rgb565_unpack;
94
95    alpha = A_VAL(&dc->col.col) >> 3;
96    if (alpha == 0)
97      return;
98    alpha++;
99
100    rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
101                                     G_VAL(&dc->col.col),
102                                     B_VAL(&dc->col.col));
103    rgb565_unpack = RGB_565_UNPACK(rgb565);
104
105    ext_x = 0;
106    ext_y = 0;
107    ext_w = dst->cache_entry.w;
108    ext_h = dst->cache_entry.h;
109    if (dc->clip.use)
110      RECTS_CLIP_TO_RECT(ext_x, ext_y, ext_w, ext_h,
111                         dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h);
112
113    if ((ext_w <= 0) || (ext_h <= 0))
114      return;
115
116    n = 0;
117    for (l = (Evas_Object_List *)points; l; l = l->next)
118      n++;
119
120    if (n < 3)
121      return;
122
123    edges = malloc(sizeof(RGBA_Edge) * n);
124    if (!edges)
125      return;
126
127    point = malloc(sizeof(RGBA_Vertex) * n);
128    if (!point)
129      {
130         free(edges);
131         return;
132      }
133
134    sorted_index = malloc(sizeof(int) * n);
135    if (!sorted_index)
136      {
137         free(edges);
138         free(point);
139         return;
140      }
141
142    for (k = 0, l = (Evas_Object_List *)points; l; k++, l = l->next)
143      {
144         pt = (RGBA_Polygon_Point *)l;
145         point[k].x = pt->x;
146         point[k].y = pt->y;
147         point[k].i = k;
148      }
149    qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
150
151    for (k = 0; k < n; k++)
152      sorted_index[k] = point[k].i;
153
154    for (k = 0, l = (Evas_Object_List *)points; l; k++, l = l->next)
155      {
156         pt = (RGBA_Polygon_Point *)l;
157         point[k].x = pt->x;
158         point[k].y = pt->y;
159         point[k].i = k;
160      }
161
162    y0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
163    y1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
164
165    k = 0;
166    num_active_edges = 0;
167
168    for (y = y0; y <= y1; y++)
169      {
170         for (; (k < n) && (point[sorted_index[k]].y <= ((float)y + 0.5)); k++)
171           {
172              i = sorted_index[k];
173
174              if (i > 0) j = i - 1;
175              else j = n - 1;
176              if (point[j].y <= ((float)y - 0.5))
177                {
178                   POLY_EDGE_DEL(j)
179                }
180              else if (point[j].y > ((float)y + 0.5))
181                {
182                   POLY_EDGE_ADD(j, y)
183                }
184              if (i < (n - 1)) j = i + 1;
185              else j = 0;
186              if (point[j].y <= ((float)y - 0.5))
187                {
188                   POLY_EDGE_DEL(i)
189                }
190              else if (point[j].y > ((float)y + 0.5))
191                {
192                   POLY_EDGE_ADD(i, y)
193                }
194           }
195
196         qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
197
198         for (j = 0; j < num_active_edges; j += 2)
199           {
200              int x0, x1;
201
202              x0 = ceil(edges[j].x - 0.5);
203              if (j < (num_active_edges - 1))
204                x1 = floor(edges[j + 1].x - 0.5);
205              else
206                x1 = x0;
207              if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
208                {
209                   DATA16 *dst_itr;
210                   int w;
211
212                   if (x0 < ext_x) x0 = ext_x;
213                   if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
214
215                   w = (x1 - x0) + 1;
216                   dst_itr = dst->pixels + (y * dst->stride) + x0;
217
218                   if (alpha == 32)
219                     _soft16_scanline_fill_solid_solid(dst_itr, w, rgb565);
220                   else
221                     _soft16_scanline_fill_transp_solid(dst_itr, w, rgb565_unpack, alpha);
222                }
223              edges[j].x += edges[j].dx;
224              edges[j + 1].x += edges[j + 1].dx;
225           }
226      }
227
228    free(edges);
229    free(point);
230    free(sorted_index);
231 }