1 #include "evas_gl_private.h"
2
3 // FIXME: this is a verbatim copy of the software poly renderer. it just
4 // use gl to draw 1 pixel high spans like software does. this is to make
5 // sure rendering correctness matches the software engine but also to save
6 // time in coming up with a good triangulation algorithm. if you want to
7 // feel free to turn this into a real triangulation system and use gl to its
8 // fullest, but as such polygons are used so little, it's not worth it.
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 Evas_GL_Polygon *
evas_gl_common_poly_point_add(Evas_GL_Polygon * poly,int x,int y)69 evas_gl_common_poly_point_add(Evas_GL_Polygon *poly, int x, int y)
70 {
71 Evas_GL_Polygon_Point *pt;
72
73 pt = calloc(1, sizeof(Evas_GL_Polygon_Point));
74 if (!pt) return NULL;
75
76 if (!poly) poly = calloc(1, sizeof(Evas_GL_Polygon));
77 if (!poly)
78 {
79 free(pt);
80 return NULL;
81 }
82
83 pt->x = x;
84 pt->y = y;
85 poly->points = eina_list_append(poly->points, pt);
86 poly->changed = 1;
87 return poly;
88 }
89
90 Evas_GL_Polygon *
evas_gl_common_poly_points_clear(Evas_GL_Polygon * poly)91 evas_gl_common_poly_points_clear(Evas_GL_Polygon *poly)
92 {
93 if (!poly) return NULL;
94 while (poly->points)
95 {
96 Evas_GL_Polygon_Point *pt;
97
98 pt = poly->points->data;
99 poly->points = eina_list_remove(poly->points, pt);
100 free(pt);
101 }
102 free(poly);
103 return NULL;
104 }
105
106 static int
polygon_point_sorter(const void * a,const void * b)107 polygon_point_sorter(const void *a, const void *b)
108 {
109 RGBA_Vertex *p, *q;
110
111 p = (RGBA_Vertex *)a;
112 q = (RGBA_Vertex *)b;
113 if (p->y <= q->y) return -1;
114 return 1;
115 }
116
117 static int
polygon_edge_sorter(const void * a,const void * b)118 polygon_edge_sorter(const void *a, const void *b)
119 {
120 RGBA_Edge *p, *q;
121
122 p = (RGBA_Edge *)a;
123 q = (RGBA_Edge *)b;
124 if (p->x <= q->x) return -1;
125 return 1;
126 }
127
128 void
evas_gl_common_poly_draw(Evas_Engine_GL_Context * gc,Evas_GL_Polygon * poly,int dx,int dy)129 evas_gl_common_poly_draw(Evas_Engine_GL_Context *gc, Evas_GL_Polygon *poly, int dx, int dy)
130 {
131 Cutout_Rect *r;
132 int c, cx, cy, cw, ch, cr, cg, cb, ca, i;
133 int x = 0, y = 0, w = 0, h = 0;
134 Evas_GL_Texture *mtex = NULL;
135 Eina_Bool mask_smooth = EINA_FALSE;
136 Eina_Bool mask_color = EINA_FALSE;
137 int mx = 0, my = 0, mw = 0, mh = 0;
138 Evas_GL_Image *mask;
139
140 Eina_List *l;
141 int n, k, num_active_edges, yy0, yy1, *sorted_index, j;
142 RGBA_Edge *edges;
143 RGBA_Vertex *point;
144 Evas_GL_Polygon_Point *pt;
145 Eina_Inlist *spans;
146
147 /* save out clip info */
148 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;
149
150 ca = (gc->dc->col.col >> 24) & 0xff;
151 if (ca <= 0) return;
152 cr = (gc->dc->col.col >> 16) & 0xff;
153 cg = (gc->dc->col.col >> 8 ) & 0xff;
154 cb = (gc->dc->col.col ) & 0xff;
155
156 mask = gc->dc->clip.mask;
157 if (mask)
158 {
159 evas_gl_common_image_update(gc, mask);
160 mtex = mask->tex;
161 if (mtex && mtex->pt && mtex->pt->w && mtex->pt->h)
162 {
163 // canvas coords
164 mx = gc->dc->clip.mask_x;
165 my = gc->dc->clip.mask_y;
166 mw = mask->w;
167 mh = mask->h;
168 mask_smooth = mask->scaled.smooth;
169 mask_color = gc->dc->clip.mask_color;
170 }
171 else mtex = NULL;
172 }
173
174 n = eina_list_count(poly->points);
175 if (n < 3) return;
176 edges = malloc(sizeof(RGBA_Edge) * n);
177 if (!edges) return;
178 point = malloc(sizeof(RGBA_Vertex) * n);
179 if (!point)
180 {
181 free(edges);
182 return;
183 }
184 sorted_index = malloc(sizeof(int) * n);
185 if (!sorted_index)
186 {
187 free(edges);
188 free(point);
189 return;
190 }
191
192 k = 0;
193 EINA_LIST_FOREACH(poly->points, l, pt)
194 {
195 point[k].x = pt->x + dx;
196 point[k].y = pt->y + dy;
197 point[k].i = k;
198 k++;
199 }
200 qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
201 for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
202 k = 0;
203
204 EINA_LIST_FOREACH(poly->points, l, pt)
205 {
206 point[k].x = pt->x + dx;
207 point[k].y = pt->y + dy;
208 point[k].i = k;
209 k++;
210 }
211
212 yy0 = MAX(cy, ceil(point[sorted_index[0]].y - 0.5));
213 yy1 = MIN(cy + ch - 1, floor(point[sorted_index[n - 1]].y - 0.5));
214
215 k = 0;
216 num_active_edges = 0;
217 spans = NULL;
218
219 for (y = yy0; y <= yy1; y++)
220 {
221 for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
222 {
223 i = sorted_index[k];
224
225 if (i > 0) j = i - 1;
226 else j = n - 1;
227 if (point[j].y <= ((double)y - 0.5))
228 {
229 POLY_EDGE_DEL(j)
230 }
231 else if (point[j].y > ((double)y + 0.5))
232 {
233 POLY_EDGE_ADD(j, y)
234 }
235 if (i < (n - 1)) j = i + 1;
236 else j = 0;
237 if (point[j].y <= ((double)y - 0.5))
238 {
239 POLY_EDGE_DEL(i)
240 }
241 else if (point[j].y > ((double)y + 0.5))
242 {
243 POLY_EDGE_ADD(i, y)
244 }
245 }
246
247 qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
248
249 for (j = 0; j < num_active_edges; j += 2)
250 {
251 int x0, x1;
252
253 x0 = ceil(edges[j].x - 0.5);
254 if (j < (num_active_edges - 1))
255 x1 = floor(edges[j + 1].x - 0.5);
256 else
257 x1 = x0;
258 if ((x1 >= cx) && (x0 < (cx + cw)) && (x0 <= x1))
259 {
260 RGBA_Span *span;
261
262 if (x0 < cx) x0 = cx;
263 if (x1 >= (cx + cw)) x1 = cx + cw - 1;
264 span = malloc(sizeof(RGBA_Span));
265 spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
266 span->y = y;
267 span->x = x0;
268 span->w = (x1 - x0) + 1;
269 }
270 edges[j].x += edges[j].dx;
271 edges[j + 1].x += edges[j + 1].dx;
272 }
273 }
274
275 free(edges);
276 free(point);
277 free(sorted_index);
278
279 evas_common_draw_context_clip_clip(gc->dc, 0, 0, gc->shared->w, gc->shared->h);
280
281 if (spans)
282 {
283 RGBA_Span *span;
284
285 /* no cutouts - cut right to the chase */
286 if (!gc->dc->cutout.rects)
287 {
288 EINA_INLIST_FOREACH(spans, span)
289 {
290 x = span->x;
291 y = span->y;
292 w = span->w;
293 h = 1;
294 evas_gl_common_context_rectangle_push(gc, x, y, w, h,
295 cr, cg, cb, ca,
296 mtex, mx, my, mw, mh,
297 mask_smooth, mask_color);
298 }
299 }
300 else
301 {
302 /* our clip is 0 size.. abort */
303 if ((gc->dc->clip.w > 0) && (gc->dc->clip.h > 0))
304 {
305 _evas_gl_common_cutout_rects = evas_common_draw_context_apply_cutouts(gc->dc, _evas_gl_common_cutout_rects);
306 for (i = 0; i < _evas_gl_common_cutout_rects->active; ++i)
307 {
308 r = _evas_gl_common_cutout_rects->rects + i;
309 if ((r->w > 0) && (r->h > 0))
310 {
311 EINA_INLIST_FOREACH(spans, span)
312 {
313 x = span->x;
314 y = span->y;
315 w = span->w;
316 h = 1;
317 RECTS_CLIP_TO_RECT(x, y, w, h, r->x, r->y, r->w, r->h);
318 if ((w > 0) && (h > 0))
319 evas_gl_common_context_rectangle_push(gc, x, y, w, h,
320 cr, cg, cb, ca,
321 mtex, mx, my, mw, mh,
322 mask_smooth, mask_color);
323 }
324 }
325 }
326 evas_common_draw_context_cutouts_free(_evas_gl_common_cutout_rects);
327 }
328 }
329 while (spans)
330 {
331 span = (RGBA_Span *)spans;
332 spans = eina_inlist_remove(spans, spans);
333 free(span);
334 }
335 }
336
337 /* restore clip info */
338 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;
339
340 }
341