aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c')
-rw-r--r--libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c b/libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c
new file mode 100644
index 0000000..06647cd
--- /dev/null
+++ b/libraries/evas/src/modules/engines/gl_common/evas_gl_polygon.c
@@ -0,0 +1,307 @@
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
10typedef struct _RGBA_Span RGBA_Span;
11typedef struct _RGBA_Edge RGBA_Edge;
12typedef struct _RGBA_Vertex RGBA_Vertex;
13
14struct _RGBA_Span
15{
16 EINA_INLIST;
17 int x, y, w;
18};
19
20struct _RGBA_Edge
21{
22 double x, dx;
23 int i;
24};
25
26struct _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
68Evas_GL_Polygon *
69evas_gl_common_poly_point_add(Evas_GL_Polygon *poly, int x, int y)
70{
71 Evas_GL_Polygon_Point *pt;
72
73 if (!poly) poly = calloc(1, sizeof(Evas_GL_Polygon));
74 if (!poly) return NULL;
75 pt = calloc(1, sizeof(Evas_GL_Polygon_Point));
76 if (!pt) return NULL;
77 pt->x = x;
78 pt->y = y;
79 poly->points = eina_list_append(poly->points, pt);
80 poly->changed = 1;
81 return poly;
82}
83
84Evas_GL_Polygon *
85evas_gl_common_poly_points_clear(Evas_GL_Polygon *poly)
86{
87 if (!poly) return NULL;
88 while (poly->points)
89 {
90 Evas_GL_Polygon_Point *pt;
91
92 pt = poly->points->data;
93 poly->points = eina_list_remove(poly->points, pt);
94 free(pt);
95 }
96 free(poly);
97 return NULL;
98}
99
100static int
101polygon_point_sorter(const void *a, const void *b)
102{
103 RGBA_Vertex *p, *q;
104
105 p = (RGBA_Vertex *)a;
106 q = (RGBA_Vertex *)b;
107 if (p->y <= q->y) return -1;
108 return 1;
109}
110
111static int
112polygon_edge_sorter(const void *a, const void *b)
113{
114 RGBA_Edge *p, *q;
115
116 p = (RGBA_Edge *)a;
117 q = (RGBA_Edge *)b;
118 if (p->x <= q->x) return -1;
119 return 1;
120}
121
122void
123evas_gl_common_poly_draw(Evas_Engine_GL_Context *gc, Evas_GL_Polygon *poly, int dx, int dy)
124{
125 Cutout_Rects *rects;
126 Cutout_Rect *r;
127 int c, cx, cy, cw, ch, cr, cg, cb, ca, i;
128 int x = 0, y = 0, w = 0, h = 0;
129
130 Eina_List *l;
131 int n, k, num_active_edges, y0, y1, *sorted_index, j;
132 RGBA_Edge *edges;
133 RGBA_Vertex *point;
134 Evas_GL_Polygon_Point *pt;
135 Eina_Inlist *spans;
136
137 /* save out clip info */
138 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;
139
140 ca = (gc->dc->col.col >> 24) & 0xff;
141 if (ca <= 0) return;
142 cr = (gc->dc->col.col >> 16) & 0xff;
143 cg = (gc->dc->col.col >> 8 ) & 0xff;
144 cb = (gc->dc->col.col ) & 0xff;
145
146 n = eina_list_count(poly->points);
147 if (n < 3) return;
148 edges = malloc(sizeof(RGBA_Edge) * n);
149 if (!edges) return;
150 point = malloc(sizeof(RGBA_Vertex) * n);
151 if (!point)
152 {
153 free(edges);
154 return;
155 }
156 sorted_index = malloc(sizeof(int) * n);
157 if (!sorted_index)
158 {
159 free(edges);
160 free(point);
161 return;
162 }
163
164 k = 0;
165 EINA_LIST_FOREACH(poly->points, l, pt)
166 {
167 point[k].x = pt->x + dx;
168 point[k].y = pt->y + dy;
169 point[k].i = k;
170 k++;
171 }
172 qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
173 for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
174 k = 0;
175
176 EINA_LIST_FOREACH(poly->points, l, pt)
177 {
178 point[k].x = pt->x + dx;
179 point[k].y = pt->y + dy;
180 point[k].i = k;
181 k++;
182 }
183
184 y0 = MAX(cy, ceil(point[sorted_index[0]].y - 0.5));
185 y1 = MIN(cy + ch - 1, floor(point[sorted_index[n - 1]].y - 0.5));
186
187 k = 0;
188 num_active_edges = 0;
189 spans = NULL;
190
191 for (y = y0; y <= y1; y++)
192 {
193 for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
194 {
195 i = sorted_index[k];
196
197 if (i > 0) j = i - 1;
198 else j = n - 1;
199 if (point[j].y <= ((double)y - 0.5))
200 {
201 POLY_EDGE_DEL(j)
202 }
203 else if (point[j].y > ((double)y + 0.5))
204 {
205 POLY_EDGE_ADD(j, y)
206 }
207 if (i < (n - 1)) j = i + 1;
208 else j = 0;
209 if (point[j].y <= ((double)y - 0.5))
210 {
211 POLY_EDGE_DEL(i)
212 }
213 else if (point[j].y > ((double)y + 0.5))
214 {
215 POLY_EDGE_ADD(i, y)
216 }
217 }
218
219 qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
220
221 for (j = 0; j < num_active_edges; j += 2)
222 {
223 int x0, x1;
224
225 x0 = ceil(edges[j].x - 0.5);
226 if (j < (num_active_edges - 1))
227 x1 = floor(edges[j + 1].x - 0.5);
228 else
229 x1 = x0;
230 if ((x1 >= cx) && (x0 < (cx + cw)) && (x0 <= x1))
231 {
232 RGBA_Span *span;
233
234 if (x0 < cx) x0 = cx;
235 if (x1 >= (cx + cw)) x1 = cx + cw - 1;
236 span = malloc(sizeof(RGBA_Span));
237 spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
238 span->y = y;
239 span->x = x0;
240 span->w = (x1 - x0) + 1;
241 }
242 edges[j].x += edges[j].dx;
243 edges[j + 1].x += edges[j + 1].dx;
244 }
245 }
246
247 free(edges);
248 free(point);
249 free(sorted_index);
250
251 evas_common_draw_context_clip_clip(gc->dc, 0, 0, gc->w, gc->h);
252
253 if (spans)
254 {
255 RGBA_Span *span;
256
257 /* no cutouts - cut right to the chase */
258 if (!gc->dc->cutout.rects)
259 {
260 EINA_INLIST_FOREACH(spans, span)
261 {
262 x = span->x;
263 y = span->y;
264 w = span->w;
265 h = 1;
266 evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca);
267 }
268 }
269 else
270 {
271 evas_common_draw_context_clip_clip(gc->dc, x, y, w, h);
272 /* our clip is 0 size.. abort */
273 if ((gc->dc->clip.w > 0) && (gc->dc->clip.h > 0))
274 {
275 rects = evas_common_draw_context_apply_cutouts(gc->dc);
276 for (i = 0; i < rects->active; ++i)
277 {
278 r = rects->rects + i;
279 if ((r->w > 0) && (r->h > 0))
280 {
281 EINA_INLIST_FOREACH(spans, span)
282 {
283 x = span->x;
284 y = span->y;
285 w = span->w;
286 h = 1;
287 RECTS_CLIP_TO_RECT(x, y, w, h, r->x, r->y, r->w, r->h);
288 if ((w > 0) && (h > 0))
289 evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca);
290 }
291 }
292 }
293 evas_common_draw_context_apply_clear_cutouts(rects);
294 }
295 }
296 while (spans)
297 {
298 span = (RGBA_Span *)spans;
299 spans = eina_inlist_remove(spans, spans);
300 free(span);
301 }
302 }
303
304 /* restore clip info */
305 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;
306
307}