1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <math.h>
6
7 #include "evas_common_private.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 EINA_INLIST;
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
evas_common_polygon_init(void)69 evas_common_polygon_init(void)
70 {
71 }
72
73 EAPI RGBA_Polygon_Point *
evas_common_polygon_point_add(RGBA_Polygon_Point * points,int x,int y)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 = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(points), EINA_INLIST_GET(pt));
83 return points;
84 }
85
86 EAPI RGBA_Polygon_Point *
evas_common_polygon_points_clear(RGBA_Polygon_Point * points)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 = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(points), EINA_INLIST_GET(points));
97 free(old_p);
98 }
99 }
100 return NULL;
101 }
102
103 static int
polygon_point_sorter(const void * a,const void * b)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
polygon_edge_sorter(const void * a,const void * b)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
evas_common_polygon_draw(RGBA_Image * dst,RGBA_Draw_Context * dc,RGBA_Polygon_Point * points,int x,int y)126 evas_common_polygon_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Polygon_Point *points, int x, int y)
127 {
128 RGBA_Gfx_Func func;
129 RGBA_Polygon_Point *pt;
130 RGBA_Vertex *point;
131 RGBA_Edge *edges;
132 Eina_Inlist *spans;
133 int num_active_edges;
134 int n;
135 int i, j, k;
136 int yy0, yy1, yi;
137 int ext_x, ext_y, ext_w, ext_h;
138 int *sorted_index;
139
140 if (!dst->image.data) return;
141 #ifdef HAVE_PIXMAN
142 # ifdef PIXMAN_POLY
143 pixman_op_t op = PIXMAN_OP_SRC; // _EVAS_RENDER_COPY
144 if (dc->render_op == _EVAS_RENDER_BLEND)
145 op = PIXMAN_OP_OVER;
146 # endif
147 #endif
148
149 ext_x = 0;
150 ext_y = 0;
151 ext_w = dst->cache_entry.w;
152 ext_h = dst->cache_entry.h;
153 if (dc->clip.use)
154 {
155 if (dc->clip.x > ext_x)
156 {
157 ext_w += ext_x - dc->clip.x;
158 ext_x = dc->clip.x;
159 }
160 if ((ext_x + ext_w) > (dc->clip.x + dc->clip.w))
161 {
162 ext_w = (dc->clip.x + dc->clip.w) - ext_x;
163 }
164 if (dc->clip.y > ext_y)
165 {
166 ext_h += ext_y - dc->clip.y;
167 ext_y = dc->clip.y;
168 }
169 if ((ext_y + ext_h) > (dc->clip.y + dc->clip.h))
170 {
171 ext_h = (dc->clip.y + dc->clip.h) - ext_y;
172 }
173 }
174 if ((ext_w <= 0) || (ext_h <= 0)) return;
175
176 evas_common_cpu_end_opt();
177
178 n = 0; EINA_INLIST_FOREACH(points, pt) n++;
179 if (n < 3) return;
180 edges = malloc(sizeof(RGBA_Edge) * n);
181 if (!edges) return;
182 point = malloc(sizeof(RGBA_Vertex) * n);
183 if (!point)
184 {
185 free(edges);
186 return;
187 }
188 sorted_index = malloc(sizeof(int) * n);
189 if (!sorted_index)
190 {
191 free(edges);
192 free(point);
193 return;
194 }
195
196 k = 0;
197 EINA_INLIST_FOREACH(points, pt)
198 {
199 point[k].x = pt->x + x;
200 point[k].y = pt->y + y;
201 point[k].i = k;
202 k++;
203 }
204 qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
205 for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
206 k = 0;
207 EINA_INLIST_FOREACH(points, pt)
208 {
209 point[k].x = pt->x + x;
210 point[k].y = pt->y + y;
211 point[k].i = k;
212 k++;
213 }
214
215 yy0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
216 yy1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
217
218 k = 0;
219 num_active_edges = 0;
220 spans = NULL;
221
222 for (yi = yy0; yi <= yy1; yi++)
223 {
224 for (; (k < n) && (point[sorted_index[k]].y <= ((double)yi + 0.5)); k++)
225 {
226 i = sorted_index[k];
227
228 if (i > 0) j = i - 1;
229 else j = n - 1;
230 if (point[j].y <= ((double)yi - 0.5))
231 {
232 POLY_EDGE_DEL(j)
233 }
234 else if (point[j].y > ((double)yi + 0.5))
235 {
236 POLY_EDGE_ADD(j, yi)
237 }
238 if (i < (n - 1)) j = i + 1;
239 else j = 0;
240 if (point[j].y <= ((double)yi - 0.5))
241 {
242 POLY_EDGE_DEL(i)
243 }
244 else if (point[j].y > ((double)yi + 0.5))
245 {
246 POLY_EDGE_ADD(i, yi)
247 }
248 }
249
250 qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
251
252 for (j = 0; j < num_active_edges; j += 2)
253 {
254 int x0, x1;
255
256 x0 = ceil(edges[j].x - 0.5);
257 if (j < (num_active_edges - 1))
258 x1 = floor(edges[j + 1].x - 0.5);
259 else
260 x1 = x0;
261 if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
262 {
263 RGBA_Span *span;
264
265 if (x0 < ext_x) x0 = ext_x;
266 if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
267 span = malloc(sizeof(RGBA_Span));
268 spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
269 span->y = yi;
270 span->x = x0;
271 span->w = (x1 - x0) + 1;
272 }
273 edges[j].x += edges[j].dx;
274 edges[j + 1].x += edges[j + 1].dx;
275 }
276 }
277
278 free(edges);
279 free(point);
280 free(sorted_index);
281
282 if(dc->clip.mask)
283 func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
284 else
285 func = evas_common_gfx_func_composite_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
286 if (spans)
287 {
288 RGBA_Span *span;
289
290 EINA_INLIST_FOREACH(spans, span)
291 {
292 DATA32 *ptr;
293 DATA8 *mask;
294 RGBA_Image *mask_ie;
295
296 #ifdef HAVE_PIXMAN
297 # ifdef PIXMAN_POLY
298 if ((dst->pixman.im) && (dc->col.pixman_color_image))
299 pixman_image_composite(op, dc->col.pixman_color_image,
300 NULL, dst->pixman.im,
301 span->x, span->y, 0, 0,
302 span->x, span->y, span->w, 1);
303 else
304 # endif
305 #endif
306 {
307 ptr = dst->image.data + (span->y * (dst->cache_entry.w)) + span->x;
308 if (dc->clip.mask)
309 {
310 mask_ie = dc->clip.mask;
311 mask = mask_ie->image.data8
312 + ((span->y - dc->clip.mask_y) * mask_ie->cache_entry.w)
313 + (span->x - dc->clip.mask_x);
314 func(NULL, mask, dc->col.col, ptr, span->w);
315 }
316 else
317 func(NULL, NULL, dc->col.col, ptr, span->w);
318 }
319 }
320 while (spans)
321 {
322 span = (RGBA_Span *)spans;
323 spans = eina_inlist_remove(spans, spans);
324 free(span);
325 }
326 }
327 }
328
329 EAPI void
evas_common_polygon_rgba_draw(RGBA_Image * dst,int ext_x,int ext_y,int ext_w,int ext_h,DATA32 col,int render_op,RGBA_Polygon_Point * points,int x,int y,RGBA_Image * mask_ie,int mask_x,int mask_y)330 evas_common_polygon_rgba_draw(RGBA_Image *dst, int ext_x, int ext_y, int ext_w, int ext_h, DATA32 col, int render_op, RGBA_Polygon_Point *points, int x, int y, RGBA_Image *mask_ie, int mask_x, int mask_y)
331 {
332 RGBA_Gfx_Func func;
333 RGBA_Polygon_Point *pt;
334 RGBA_Vertex *point;
335 RGBA_Edge *edges;
336 Eina_Inlist *spans;
337 int num_active_edges;
338 int n;
339 int i, j, k;
340 int yy0, yy1, yi;
341 int *sorted_index;
342
343 if (!dst->image.data) return;
344 if ((ext_w <= 0) || (ext_h <= 0)) return;
345
346 evas_common_cpu_end_opt();
347
348 n = 0; EINA_INLIST_FOREACH(points, pt) n++;
349 if (n < 3) return;
350 edges = malloc(sizeof(RGBA_Edge) * n);
351 if (!edges) return;
352 point = malloc(sizeof(RGBA_Vertex) * n);
353 if (!point)
354 {
355 free(edges);
356 return;
357 }
358 sorted_index = malloc(sizeof(int) * n);
359 if (!sorted_index)
360 {
361 free(edges);
362 free(point);
363 return;
364 }
365
366 k = 0;
367 EINA_INLIST_FOREACH(points, pt)
368 {
369 point[k].x = pt->x + x;
370 point[k].y = pt->y + y;
371 point[k].i = k;
372 k++;
373 }
374 qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
375 for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
376 k = 0;
377 EINA_INLIST_FOREACH(points, pt)
378 {
379 point[k].x = pt->x + x;
380 point[k].y = pt->y + y;
381 point[k].i = k;
382 k++;
383 }
384
385 yy0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
386 yy1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
387
388 k = 0;
389 num_active_edges = 0;
390 spans = NULL;
391
392 for (yi = yy0; yi <= yy1; yi++)
393 {
394 for (; (k < n) && (point[sorted_index[k]].y <= ((double)yi + 0.5)); k++)
395 {
396 i = sorted_index[k];
397
398 if (i > 0) j = i - 1;
399 else j = n - 1;
400 if (point[j].y <= ((double)yi - 0.5))
401 {
402 POLY_EDGE_DEL(j)
403 }
404 else if (point[j].y > ((double)yi + 0.5))
405 {
406 POLY_EDGE_ADD(j, yi)
407 }
408 if (i < (n - 1)) j = i + 1;
409 else j = 0;
410 if (point[j].y <= ((double)yi - 0.5))
411 {
412 POLY_EDGE_DEL(i)
413 }
414 else if (point[j].y > ((double)yi + 0.5))
415 {
416 POLY_EDGE_ADD(i, yi)
417 }
418 }
419
420 qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
421
422 for (j = 0; j < num_active_edges; j += 2)
423 {
424 int x0, x1;
425
426 x0 = ceil(edges[j].x - 0.5);
427 if (j < (num_active_edges - 1))
428 x1 = floor(edges[j + 1].x - 0.5);
429 else
430 x1 = x0;
431 if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
432 {
433 RGBA_Span *span;
434
435 if (x0 < ext_x) x0 = ext_x;
436 if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
437 span = malloc(sizeof(RGBA_Span));
438 spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
439 span->y = yi;
440 span->x = x0;
441 span->w = (x1 - x0) + 1;
442 }
443 edges[j].x += edges[j].dx;
444 edges[j + 1].x += edges[j + 1].dx;
445 }
446 }
447
448 free(edges);
449 free(point);
450 free(sorted_index);
451
452 if (mask_ie)
453 func = evas_common_gfx_func_composite_mask_color_span_get(col, dst->cache_entry.flags.alpha, 1, render_op);
454 else
455 func = evas_common_gfx_func_composite_color_span_get(col, dst->cache_entry.flags.alpha, 1, render_op);
456 if (spans)
457 {
458 RGBA_Span *span;
459 DATA8 *mask;
460
461 EINA_INLIST_FOREACH(spans, span)
462 {
463 DATA32 *ptr;
464
465 ptr = dst->image.data + (span->y * (dst->cache_entry.w)) + span->x;
466 if (mask_ie)
467 {
468 mask = mask_ie->image.data8
469 + ((span->y - mask_y) * mask_ie->cache_entry.w)
470 + (span->x - mask_x);
471 func(NULL, mask, col, ptr, span->w);
472 }
473 else
474 func(NULL, NULL, col, ptr, span->w);
475 }
476 while (spans)
477 {
478 span = (RGBA_Span *)spans;
479 spans = eina_inlist_remove(spans, spans);
480 free(span);
481 }
482 }
483 }
484