diff options
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.c | 307 |
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 | |||
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 * | ||
69 | evas_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 | |||
84 | Evas_GL_Polygon * | ||
85 | evas_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 | |||
100 | static int | ||
101 | polygon_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 | |||
111 | static int | ||
112 | polygon_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 | |||
122 | void | ||
123 | evas_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 | } | ||