move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_polygon_main.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include <math.h>
6
7 #include "evas_common.h"
8 #include "evas_blend_private.h"
9
10 typedef struct _RGBA_Span RGBA_Span;
11 typedef struct _RGBA_Edge RGBA_Edge;
12 typedef struct _RGBA_Vertex RGBA_Vertex;
13
14 struct _RGBA_Span
15 {
16    Evas_Object_List _list_data;
17    int x, y, w;
18 };
19
20 struct _RGBA_Edge
21 {
22    double x, dx;
23    int i;
24 };
25
26 struct _RGBA_Vertex
27 {
28    double x, y;
29    int i;
30 };
31
32 #define POLY_EDGE_DEL(_i)                                               \
33 {                                                                       \
34    int _j;                                                              \
35                                                                         \
36    for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++);  \
37    if (_j < num_active_edges)                                           \
38      {                                                                  \
39         num_active_edges--;                                             \
40         memmove(&(edges[_j]), &(edges[_j + 1]),                         \
41                 (num_active_edges - _j) * sizeof(RGBA_Edge));           \
42      }                                                                  \
43 }
44
45 #define POLY_EDGE_ADD(_i, _y)                                           \
46 {                                                                       \
47    int _j;                                                              \
48    float _dx;                                                           \
49    RGBA_Vertex *_p, *_q;                                                \
50    if (_i < (n - 1)) _j = _i + 1;                                       \
51    else _j = 0;                                                         \
52    if (point[_i].y < point[_j].y)                                       \
53      {                                                                  \
54         _p = &(point[_i]);                                              \
55         _q = &(point[_j]);                                              \
56      }                                                                  \
57    else                                                                 \
58      {                                                                  \
59         _p = &(point[_j]);                                              \
60         _q = &(point[_i]);                                              \
61      }                                                                  \
62    edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
63    edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
64    edges[num_active_edges].i = _i;                                      \
65    num_active_edges++;                                                  \
66 }
67
68 EAPI void
69 evas_common_polygon_init(void)
70 {
71 }
72
73 EAPI RGBA_Polygon_Point *
74 evas_common_polygon_point_add(RGBA_Polygon_Point *points, int x, int y)
75 {
76    RGBA_Polygon_Point *pt;
77
78    pt = malloc(sizeof(RGBA_Polygon_Point));
79    if (!pt) return points;
80    pt->x = x;
81    pt->y = y;
82    points = evas_object_list_append(points, pt);
83    return points;
84 }
85
86 EAPI RGBA_Polygon_Point *
87 evas_common_polygon_points_clear(RGBA_Polygon_Point *points)
88 {
89    if (points)
90      {
91         while (points)
92           {
93              RGBA_Polygon_Point *old_p;
94
95              old_p = points;
96              points = evas_object_list_remove(points, points);
97              free(old_p);
98           }
99      }
100    return NULL;
101 }
102
103 static int
104 polygon_point_sorter(const void *a, const void *b)
105 {
106    RGBA_Vertex *p, *q;
107
108    p = (RGBA_Vertex *)a;
109    q = (RGBA_Vertex *)b;
110    if (p->y <= q->y) return -1;
111    return 1;
112 }
113
114 static int
115 polygon_edge_sorter(const void *a, const void *b)
116 {
117    RGBA_Edge *p, *q;
118
119    p = (RGBA_Edge *)a;
120    q = (RGBA_Edge *)b;
121    if (p->x <= q->x) return -1;
122    return 1;
123 }
124
125 EAPI void
126 evas_common_polygon_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Polygon_Point *points)
127 {
128    RGBA_Gfx_Func      func;
129    RGBA_Polygon_Point *pt;
130    RGBA_Vertex       *point;
131    RGBA_Edge         *edges;
132    Evas_Object_List  *spans, *l;
133    int                num_active_edges;
134    int                n;
135    int                i, j, k;
136    int                y0, y1, y;
137    int                ext_x, ext_y, ext_w, ext_h;
138    int               *sorted_index;
139
140    ext_x = 0;
141    ext_y = 0;
142    ext_w = dst->cache_entry.w;
143    ext_h = dst->cache_entry.h;
144    if (dc->clip.use)
145      {
146         if (dc->clip.x > ext_x)
147           {
148              ext_w += ext_x - dc->clip.x;
149              ext_x = dc->clip.x;
150           }
151         if ((ext_x + ext_w) > (dc->clip.x + dc->clip.w))
152           {
153              ext_w = (dc->clip.x + dc->clip.w) - ext_x;
154           }
155         if (dc->clip.y > ext_y)
156           {
157              ext_h += ext_y - dc->clip.y;
158              ext_y = dc->clip.y;
159           }
160         if ((ext_y + ext_h) > (dc->clip.y + dc->clip.h))
161           {
162              ext_h = (dc->clip.y + dc->clip.h) - ext_y;
163           }
164      }
165    if ((ext_w <= 0) || (ext_h <= 0)) return;
166
167    evas_common_cpu_end_opt();
168
169    n = 0; for (l = (Evas_Object_List *)points; l; l = l->next) n++;
170    if (n < 3) return;
171    edges = malloc(sizeof(RGBA_Edge) * n);
172    if (!edges) return;
173    point = malloc(sizeof(RGBA_Vertex) * n);
174    if (!point)
175      {
176         free(edges);
177         return;
178      }
179    sorted_index = malloc(sizeof(int) * n);
180    if (!sorted_index)
181      {
182         free(edges);
183         free(point);
184         return;
185      }
186
187    k = 0;
188    for (l = (Evas_Object_List *)points; l; l = l->next)
189      {
190         pt = (RGBA_Polygon_Point *)l;
191         point[k].x = pt->x;
192         point[k].y = pt->y;
193         point[k].i = k;
194         k++;
195      }
196    qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
197    for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
198    k = 0;
199    for (l = (Evas_Object_List *)points; l; l = l->next)
200      {
201         pt = (RGBA_Polygon_Point *)l;
202         point[k].x = pt->x;
203         point[k].y = pt->y;
204         point[k].i = k;
205         k++;
206      }
207
208    y0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
209    y1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
210
211    k = 0;
212    num_active_edges = 0;
213    spans = NULL;
214
215    for (y = y0; y <= y1; y++)
216      {
217         for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
218           {
219              i = sorted_index[k];
220
221              if (i > 0) j = i - 1;
222              else j = n - 1;
223              if (point[j].y <= ((double)y - 0.5))
224                {
225                   POLY_EDGE_DEL(j)
226                }
227              else if (point[j].y > ((double)y + 0.5))
228                {
229                   POLY_EDGE_ADD(j, y)
230                }
231              if (i < (n - 1)) j = i + 1;
232              else j = 0;
233              if (point[j].y <= ((double)y - 0.5))
234                {
235                   POLY_EDGE_DEL(i)
236                }
237              else if (point[j].y > ((double)y + 0.5))
238                {
239                   POLY_EDGE_ADD(i, y)
240                }
241           }
242
243         qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
244
245         for (j = 0; j < num_active_edges; j += 2)
246           {
247              int x0, x1;
248
249              x0 = ceil(edges[j].x - 0.5);
250              if (j < (num_active_edges - 1))
251                x1 = floor(edges[j + 1].x - 0.5);
252              else
253                x1 = x0;
254              if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
255                {
256                   RGBA_Span *span;
257
258                   if (x0 < ext_x) x0 = ext_x;
259                   if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
260                   span = malloc(sizeof(RGBA_Span));
261                   spans = evas_object_list_append(spans, span);
262                   span->y = y;
263                   span->x = x0;
264                   span->w = (x1 - x0) + 1;
265                }
266              edges[j].x += edges[j].dx;
267              edges[j + 1].x += edges[j + 1].dx;
268           }
269      }
270
271    free(edges);
272    free(point);
273    free(sorted_index);
274
275    func = evas_common_gfx_func_composite_color_span_get(dc->col.col, dst, 1, dc->render_op);
276    if (spans)
277      {
278         for (l = spans; l; l = l->next)
279           {
280              RGBA_Span *span;
281              DATA32 *ptr;
282
283              span = (RGBA_Span *)l;
284 #ifdef EVAS_SLI
285              if (((span->y) % dc->sli.h) == dc->sli.y)
286 #endif
287                {
288                   ptr = dst->image.data + (span->y * (dst->cache_entry.w)) + span->x;
289                   func(NULL, NULL, dc->col.col, ptr, span->w);
290                }
291           }
292         while (spans)
293           {
294              RGBA_Span *span;
295
296              span = (RGBA_Span *)spans;
297              spans = evas_object_list_remove(spans, spans);
298              free(span);
299           }
300      }
301 }