aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/engines/directfb/polygon.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/modules/engines/directfb/polygon.c')
-rw-r--r--libraries/evas/src/modules/engines/directfb/polygon.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/engines/directfb/polygon.c b/libraries/evas/src/modules/engines/directfb/polygon.c
new file mode 100644
index 0000000..715fd84
--- /dev/null
+++ b/libraries/evas/src/modules/engines/directfb/polygon.c
@@ -0,0 +1,269 @@
1#include <math.h>
2#include "evas_engine.h"
3
4/* reduce calls to DirectFB (FillSpans), but uses twice as much memory */
5//#define USE_SPAN_RECTS 1
6
7#define MAX_SPANS 512
8typedef struct _RGBA_Edge RGBA_Edge;
9typedef struct _RGBA_Vertex RGBA_Vertex;
10
11struct _RGBA_Edge
12{
13 double x, dx;
14 int i;
15};
16
17struct _RGBA_Vertex
18{
19 double x, y;
20 int i;
21};
22
23#define POLY_EDGE_DEL(_i) \
24{ \
25 int _j; \
26 \
27 for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++); \
28 if (_j < num_active_edges) \
29 { \
30 num_active_edges--; \
31 memmove(&(edges[_j]), &(edges[_j + 1]), \
32 (num_active_edges - _j) * sizeof(RGBA_Edge)); \
33 } \
34}
35
36#define POLY_EDGE_ADD(_i, _y) \
37{ \
38 int _j; \
39 float _dx; \
40 RGBA_Vertex *_p, *_q; \
41 if (_i < (n - 1)) _j = _i + 1; \
42 else _j = 0; \
43 if (point[_i].y < point[_j].y) \
44 { \
45 _p = &(point[_i]); \
46 _q = &(point[_j]); \
47 } \
48 else \
49 { \
50 _p = &(point[_j]); \
51 _q = &(point[_i]); \
52 } \
53 edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
54 edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
55 edges[num_active_edges].i = _i; \
56 num_active_edges++; \
57}
58
59static int
60polygon_point_sorter(const void *a, const void *b)
61{
62 RGBA_Vertex *p, *q;
63
64 p = (RGBA_Vertex *)a;
65 q = (RGBA_Vertex *)b;
66 if (p->y <= q->y) return -1;
67 return 1;
68}
69
70static int
71polygon_edge_sorter(const void *a, const void *b)
72{
73 RGBA_Edge *p, *q;
74
75 p = (RGBA_Edge *)a;
76 q = (RGBA_Edge *)b;
77 if (p->x <= q->x) return -1;
78 return 1;
79}
80
81#ifndef USE_SPAN_RECTS
82typedef DFBSpan span_t;
83
84static void
85polygon_span_add(span_t *span, int y __UNUSED__, int x, int w)
86{
87 span->x = x;
88 span->w = w;
89}
90
91static void
92polygon_spans_fill(IDirectFBSurface *surface, int y, const span_t *spans, int n_spans)
93{
94 /* directfb automatically increments y for each span */
95 for (; n_spans > 0; n_spans--, spans++)
96 surface->FillSpans(surface, y, spans, 1);
97}
98#else /* USE_SPAN_RECTS */
99typedef DFBRectangle span_t;
100
101static void
102polygon_span_add(span_t *span, int y, int x, int w)
103{
104 span->x = x;
105 span->y = y;
106 span->w = w;
107 span->h = 1;
108}
109
110static void
111polygon_spans_fill(IDirectFBSurface *surface, int y, const span_t *spans, int n_spans)
112{
113 surface->FillRectangles(surface, spans, n_spans);
114}
115#endif /* USE_SPAN_RECTS */
116
117
118void
119_dfb_polygon_draw(IDirectFBSurface *surface, RGBA_Draw_Context *dc, Eina_Inlist *points, int px, int py)
120{
121 RGBA_Polygon_Point *pt;
122 RGBA_Vertex *point;
123 RGBA_Edge *edges;
124 int num_active_edges;
125 int n;
126 int i, j, k;
127 int y0, y1, y;
128 int ext_x, ext_y, ext_w, ext_h;
129 int *sorted_index;
130
131 ext_x = 0;
132 ext_y = 0;
133 surface->GetSize(surface, &ext_w, &ext_h);
134 if (dc->clip.use)
135 {
136 if (dc->clip.x > ext_x)
137 {
138 ext_w += ext_x - dc->clip.x;
139 ext_x = dc->clip.x;
140 }
141 if ((ext_x + ext_w) > (dc->clip.x + dc->clip.w))
142 {
143 ext_w = (dc->clip.x + dc->clip.w) - ext_x;
144 }
145 if (dc->clip.y > ext_y)
146 {
147 ext_h += ext_y - dc->clip.y;
148 ext_y = dc->clip.y;
149 }
150 if ((ext_y + ext_h) > (dc->clip.y + dc->clip.h))
151 {
152 ext_h = (dc->clip.y + dc->clip.h) - ext_y;
153 }
154 }
155 if ((ext_w <= 0) || (ext_h <= 0)) return;
156
157 evas_common_cpu_end_opt();
158
159 if (!_dfb_surface_set_color_from_context(surface, dc))
160 return;
161
162 n = 0; EINA_INLIST_FOREACH(points, pt) n++;
163 if (n < 3) return;
164 edges = malloc(sizeof(RGBA_Edge) * n);
165 if (!edges) return;
166 point = malloc(sizeof(RGBA_Vertex) * n);
167 if (!point)
168 {
169 free(edges);
170 return;
171 }
172 sorted_index = malloc(sizeof(int) * n);
173 if (!sorted_index)
174 {
175 free(edges);
176 free(point);
177 return;
178 }
179
180 k = 0;
181 EINA_INLIST_FOREACH(points, pt)
182 {
183 point[k].x = pt->x + px;
184 point[k].y = pt->y + py;
185 point[k].i = k;
186 k++;
187 }
188 qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
189 for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
190 k = 0;
191 EINA_INLIST_FOREACH(points, pt)
192 {
193 point[k].x = pt->x + px;
194 point[k].y = pt->y + py;
195 point[k].i = k;
196 k++;
197 }
198
199 y0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
200 y1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
201
202 k = 0;
203 num_active_edges = 0;
204
205 for (y = y0; y <= y1; y++)
206 {
207 span_t spans[MAX_SPANS];
208 unsigned int n_spans = 0;
209
210 for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
211 {
212 i = sorted_index[k];
213
214 if (i > 0) j = i - 1;
215 else j = n - 1;
216 if (point[j].y <= ((double)y - 0.5))
217 {
218 POLY_EDGE_DEL(j)
219 }
220 else if (point[j].y > ((double)y + 0.5))
221 {
222 POLY_EDGE_ADD(j, y)
223 }
224 if (i < (n - 1)) j = i + 1;
225 else j = 0;
226 if (point[j].y <= ((double)y - 0.5))
227 {
228 POLY_EDGE_DEL(i)
229 }
230 else if (point[j].y > ((double)y + 0.5))
231 {
232 POLY_EDGE_ADD(i, y)
233 }
234 }
235
236 qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
237
238 for (j = 0; j < num_active_edges; j += 2)
239 {
240 int x0, x1;
241
242 x0 = ceil(edges[j].x - 0.5);
243 if (j < (num_active_edges - 1))
244 x1 = floor(edges[j + 1].x - 0.5);
245 else
246 x1 = x0;
247 if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
248 {
249 if (n_spans == MAX_SPANS)
250 {
251 polygon_spans_fill(surface, y, spans, n_spans);
252 n_spans = 0;
253 }
254
255 polygon_span_add(spans + n_spans, y, x0, (x1 - x0) + 1);
256 n_spans++;
257 }
258 edges[j].x += edges[j].dx;
259 edges[j + 1].x += edges[j + 1].dx;
260 }
261
262 if (n_spans)
263 polygon_spans_fill(surface, y, spans, n_spans);
264 }
265
266 free(edges);
267 free(point);
268 free(sorted_index);
269}