summaryrefslogtreecommitdiff
path: root/src/static_libs
diff options
context:
space:
mode:
authorSubhransu Mohanty <sub.mohanty@samsung.com>2016-11-28 11:21:33 -0800
committerCedric BAIL <cedric@osg.samsung.com>2016-11-28 11:35:27 -0800
commit98b0408a4eed5c2beafd4f396b64ca54fb00270f (patch)
tree8cdd5e934685b0d6a121b26ab9cc10328a44ff69 /src/static_libs
parent6584c6cc27913710e8e76b2278307c5696374576 (diff)
triangulator: add a static_lib for triangulation. idea is to keep all the algorithm for triangulation in one place 1. shape outline triangulation using triangle strips. 2. shape filling using curve flattning and polygon triangulation.
Reviewers: Hermet, cedric Reviewed By: cedric Subscribers: raster, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D3896
Diffstat (limited to 'src/static_libs')
-rw-r--r--src/static_libs/triangulator/triangulator_simple.c160
-rw-r--r--src/static_libs/triangulator/triangulator_simple.h43
-rw-r--r--src/static_libs/triangulator/triangulator_stroker.c527
-rw-r--r--src/static_libs/triangulator/triangulator_stroker.h54
4 files changed, 784 insertions, 0 deletions
diff --git a/src/static_libs/triangulator/triangulator_simple.c b/src/static_libs/triangulator/triangulator_simple.c
new file mode 100644
index 0000000..60f7114
--- /dev/null
+++ b/src/static_libs/triangulator/triangulator_simple.c
@@ -0,0 +1,160 @@
1#include "triangulator_simple.h"
2
3Triangulator_Simple *
4triangulator_simple_new(void)
5{
6 Triangulator_Simple *st = calloc(1, sizeof(Triangulator_Simple));
7 st->vertices = eina_inarray_new(sizeof(float), 0);
8 st->stops = eina_inarray_new(sizeof(int), 0);
9 return st;
10}
11
12void
13triangulator_simple_free(Triangulator_Simple *st)
14{
15 eina_inarray_free(st->vertices);
16 eina_inarray_free(st->stops);
17}
18
19static void
20_add_line(Triangulator_Simple *st, const float x, const float y)
21{
22 float *ptr;
23
24 ptr = eina_inarray_grow(st->vertices, 2);
25 ptr[0] = x;
26 ptr[1] = y;
27
28 if (x > st->maxx)
29 st->maxx = x;
30 else if (x < st->minx)
31 st->minx = x;
32 if (y > st->maxy)
33 st->maxy = y;
34 else if (y < st->miny)
35 st->miny = y;
36}
37
38static void
39_calculate_centroid(const Efl_Gfx_Path_Command *cmds, const double *pts, double *cx, double *cy)
40{
41 double sumx = 0, sumy = 0;
42 int count = 0;
43
44 sumx += pts[0];
45 sumy += pts[1];
46 for (cmds++, count++, pts+=2; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
47 {
48 switch (*cmds)
49 {
50 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
51 sumx += pts[0];
52 sumy += pts[1];
53 pts +=2;
54 count++;
55 break;
56 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
57 sumx += pts[0];
58 sumy += pts[1];
59 sumx += pts[2];
60 sumy += pts[3];
61 sumx += pts[4];
62 sumy += pts[5];
63 pts +=6;
64 count +=3;
65 break;
66 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
67 case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
68 *cx = sumx/count;
69 *cy = sumy/count;
70 return;
71 default:
72 break;
73 }
74 }
75 //
76 *cx = sumx/count;
77 *cy = sumy/count;
78}
79
80void
81triangulator_simple_process(Triangulator_Simple *st, const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool convex)
82{
83 double bw, bh, cx, cy, x, y, t, one_over_threshold_minus_1;
84 float *ptr;
85 int *stop_ptr, threshold, i;
86 Eina_Bezier b;
87
88 eina_inarray_resize(st->vertices, 0);
89 eina_inarray_resize(st->stops, 0);
90 if (!convex)
91 {
92 _calculate_centroid(cmds, pts, &cx, &cy);
93 _add_line(st, cx, cy);
94 }
95
96 cx = pts[0];
97 cy = pts[1];
98 // The first element is always a moveTo
99 _add_line(st, cx, cy);
100 pts += 2;
101 cmds++;
102 for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
103 {
104 switch (*cmds)
105 {
106 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
107
108 // add closing line for the previous contour
109 _add_line(st, cx, cy);
110
111 // update stop array
112 stop_ptr = eina_inarray_grow(st->stops, 1);
113 stop_ptr[0] = eina_inarray_count(st->vertices);
114
115 // add centroid if not convex
116 if (!convex)
117 {
118 _calculate_centroid(cmds, pts, &cx, &cy);
119 _add_line(st, cx, cy);
120 }
121 cx = pts[0];
122 cy = pts[1];
123 _add_line(st, cx, cy);
124 pts += 2;
125 break;
126
127 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
128
129 _add_line(st, pts[0], pts[1]);
130 pts += 2;
131 break;
132
133 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
134 ptr = eina_inarray_nth(st->vertices, eina_inarray_count(st->vertices) - 2);
135 eina_bezier_values_set(&b, ptr[0], ptr[1], pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
136 eina_bezier_bounds_get(&b, NULL, NULL , &bw, &bh);
137 threshold = fminf(64, fmaxf(bw, bh) * 3.14f / 6);
138 if (threshold < 3) threshold = 3;
139 one_over_threshold_minus_1 = 1.0 / (threshold - 1);
140 for (i=1; i<threshold; ++i)
141 {
142 t = i * one_over_threshold_minus_1;
143 eina_bezier_point_at(&b, t, &x, &y);
144 _add_line(st, x, y);
145 }
146 pts += 6;
147 break;
148 case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
149 case EFL_GFX_PATH_COMMAND_TYPE_LAST:
150 case EFL_GFX_PATH_COMMAND_TYPE_END:
151 break;
152 }
153 }
154 // add closing line for the previous contour
155 _add_line(st, cx, cy);
156
157 // update stop array
158 stop_ptr = eina_inarray_grow(st->stops, 1);
159 stop_ptr[0] = eina_inarray_count(st->vertices);
160} \ No newline at end of file
diff --git a/src/static_libs/triangulator/triangulator_simple.h b/src/static_libs/triangulator/triangulator_simple.h
new file mode 100644
index 0000000..e87acc6
--- /dev/null
+++ b/src/static_libs/triangulator/triangulator_simple.h
@@ -0,0 +1,43 @@
1#ifndef TRIANGULATOR_SIMPLE_H_
2#define TRIANGULATOR_SIMPLE_H_
3
4#include <Efl.h>
5
6typedef struct _Triangulator_Simple Triangulator_Simple;
7struct _Triangulator_Simple
8{
9 Eina_Inarray *vertices;
10 Eina_Inarray *stops; //list of contours need to be drawn as separate triangle fan.
11 float minx;
12 float miny;
13 float maxx;
14 float maxy;
15};
16
17/**
18 * Creates a new simple triangulator.
19 *
20 */
21Triangulator_Simple * triangulator_simple_new(void);
22
23/**
24 * Frees the given triangulator and any associated resource.
25 *
26 * st The given triangulator.
27 */
28void triangulator_simple_free(Triangulator_Simple *st);
29
30/**
31 * Process the command list to generate triangle fans.
32 * The alogrithm handles multiple contours by providing the list of stops.
33 *
34 * cmds : commnad list
35 * pts : point list.
36 * convex : shape is convex or not.
37 *
38 * output: If the shape is convex then, the triangle fan will exactly fill the shape. but if its not convex, it will overflow
39 * to outside shape, in that case user has to use stencil method (2 pass drawing) to fill the shape.
40 */
41void triangulator_simple_process(Triangulator_Simple *st, const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool convex);
42
43#endif // #endif // TRIANGULATOR_SIMPLE_H_ \ No newline at end of file
diff --git a/src/static_libs/triangulator/triangulator_stroker.c b/src/static_libs/triangulator/triangulator_stroker.c
new file mode 100644
index 0000000..44f7b89
--- /dev/null
+++ b/src/static_libs/triangulator/triangulator_stroker.c
@@ -0,0 +1,527 @@
1
2#include "triangulator_stroker.h"
3#include <math.h>
4
5#define PI 3.1415
6#define CURVE_FLATNESS PI / 8
7
8Triangulator_Stroker *
9triangulator_stroker_new(void)
10{
11 Triangulator_Stroker *stroker = calloc(1, sizeof(Triangulator_Stroker));
12 stroker->vertices = eina_inarray_new(sizeof(float), 0);
13 stroker->arc_pts = eina_inarray_new(sizeof(float), 0);
14 stroker->miter_limit = 2;
15 return stroker;
16}
17
18void
19triangulator_stroker_free(Triangulator_Stroker *stroker)
20{
21 eina_inarray_free(stroker->vertices);
22 eina_inarray_free(stroker->arc_pts);
23}
24
25// calculate the normal vector
26static void
27normal_vector(float x1, float y1, float x2, float y2, float width,
28 float *nx, float *ny)
29{
30 float pw;
31 float dx = x2 - x1;
32 float dy = y2 - y1;
33
34 if (dx == 0)
35 pw = width / fabsf(dy);
36 else if (dy == 0)
37 pw = width / fabsf(dx);
38 else
39 pw = width / sqrtf(dx*dx + dy*dy);
40
41 *nx = -dy * pw;
42 *ny = dx * pw;
43}
44
45// add a line segment
46static void
47add_line_segment(Triangulator_Stroker *stroker, float x, float y, float vx, float vy)
48{
49 float *ptr;
50
51 ptr = eina_inarray_grow(stroker->vertices, 4);
52 ptr[0] = x + vx;
53 ptr[1] = y + vy;
54 ptr[2] = x - vx;
55 ptr[3] = y - vy;
56}
57
58static void
59add_arc_points(Triangulator_Stroker *stroker, float cx, float cy, float from_x, float from_y, float to_x, float to_y)
60{
61 float tmp_x, tmp_y, *ptr;
62 float dx1 = from_x - cx;
63 float dy1 = from_y - cy;
64 float dx2 = to_x - cx;
65 float dy2 = to_y - cy;
66 int size;
67
68 eina_inarray_resize(stroker->arc_pts, 0);
69
70#define ADD_NEW_POINT \
71 tmp_x = dx1 * stroker->cos_theta - dy1 * stroker->sin_theta; \
72 tmp_y = dx1 * stroker->sin_theta + dy1 * stroker->cos_theta; \
73 dx1 = tmp_x; \
74 dy1 = tmp_y; \
75 ptr = eina_inarray_grow(stroker->arc_pts, 2); \
76 ptr[0] = cx + dx1; \
77 ptr[1] = cy + dy1;
78
79 // while more than 180 degrees left:
80 while (dx1 * dy2 - dx2 * dy1 < 0)
81 {
82 ADD_NEW_POINT
83 }
84
85 // while more than 90 degrees left:
86 while (dx1 * dx2 + dy1 * dy2 < 0)
87 {
88 ADD_NEW_POINT
89 }
90
91 // while more than 0 degrees left:
92 while (dx1 * dy2 - dx2 * dy1 > 0)
93 {
94 ADD_NEW_POINT
95 }
96
97 // remove last point which was rotated beyond [to_x, to_y].
98 size = eina_inarray_count(stroker->arc_pts);
99 if (size)
100 eina_inarray_resize(stroker->arc_pts, size - 2);
101}
102
103static void
104move_to(Triangulator_Stroker *stroker, const double *pts)
105{
106 float x2,y2, sx, sy, *ptr=NULL, *ptr1=NULL;
107 int pts_count, arc_pts_count, front, end, i=0;
108 Eina_Bool jump;
109
110 stroker->cx = pts[0];
111 stroker->cy = pts[1];
112 x2 = pts[2];
113 y2 = pts[3];
114 normal_vector(stroker->cx, stroker->cy, x2, y2, stroker->width, &stroker->nvx, &stroker->nvy);
115
116 // To acheive jumps we insert zero-area tringles. This is done by
117 // adding two identical points in both the end of previous strip
118 // and beginning of next strip
119 jump = eina_inarray_count(stroker->vertices);
120
121 switch (stroker->cap_style)
122 {
123 case EFL_GFX_CAP_BUTT:
124 if (jump)
125 {
126 ptr = eina_inarray_grow(stroker->vertices, 2);
127 ptr[0] = stroker->cx + stroker->nvx;
128 ptr[1] = stroker->cy + stroker->nvy;
129 }
130 break;
131 case EFL_GFX_CAP_SQUARE:
132 {
133 sx = stroker->cx - stroker->nvy;
134 sy = stroker->cy + stroker->nvx;
135 if (jump)
136 {
137 ptr = eina_inarray_grow(stroker->vertices, 2);
138 ptr[0] = sx + stroker->nvx;
139 ptr[1] = sy + stroker->nvy;
140 }
141 add_line_segment(stroker, sx, sy, stroker->nvx, stroker->nvy);
142 break;
143 }
144 case EFL_GFX_CAP_ROUND:
145 {
146 add_arc_points(stroker, stroker->cx, stroker->cy,
147 stroker->cx + stroker->nvx, stroker->cy + stroker->nvy,
148 stroker->cx - stroker->nvx, stroker->cy - stroker->nvy);
149 arc_pts_count = eina_inarray_count(stroker->arc_pts);
150 front = 0;
151 end = arc_pts_count / 2;
152 if (arc_pts_count)
153 {
154 eina_inarray_grow(stroker->vertices, eina_inarray_count(stroker->arc_pts) + 2 * jump);
155 pts_count = eina_inarray_count(stroker->vertices);
156 ptr1 = eina_inarray_nth(stroker->arc_pts, 0);
157 ptr = eina_inarray_nth(stroker->vertices, 0);
158 i = pts_count;
159 }
160 while (front != end)
161 {
162 ptr[--i] = ptr1[2 * end - 1];
163 ptr[--i] = ptr1[2 * end - 2];
164 --end;
165 if (front == end)
166 break;
167 ptr[--i] = ptr1[2 * front + 1];
168 ptr[--i] = ptr1[2 * front + 0];
169 ++front;
170 }
171
172 if (jump)
173 {
174 ptr[i - 1] = ptr[i + 1];
175 ptr[i - 2] = ptr[i + 0];
176 }
177 break;
178 }
179 default: break;
180 }
181 add_line_segment(stroker, stroker->cx, stroker->cy, stroker->nvx, stroker->nvy);
182}
183
184static void
185line_to(Triangulator_Stroker *stroker, const double *pts)
186{
187 add_line_segment(stroker, pts[0], pts[1], stroker->nvx, stroker->nvy);
188 stroker->cx = pts[0];
189 stroker->cy = pts[1];
190}
191
192static void
193cubic_to(Triangulator_Stroker *stroker, const double *pts)
194{
195 Eina_Bezier b;
196 float rad, vx, vy, cx, cy, threshold_minus_1, t;
197 double bw, bh, x, y;
198 int i, threshold;
199
200 eina_bezier_values_set(&b, stroker->cx, stroker->cy, pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
201 eina_bezier_bounds_get(&b, NULL, NULL, &bw, &bh);
202
203 rad = fmaxf(bw, bh);
204 threshold = fminf(64, (rad + stroker->curvyness_add) * stroker->curvyness_mul);
205 if (threshold < 4)
206 threshold = 4;
207 threshold_minus_1 = threshold - 1;
208 cx = stroker->cx;
209 cy = stroker->cy;
210
211 for (i = 1; i < threshold; ++i)
212 {
213 t = i / threshold_minus_1;
214 eina_bezier_point_at(&b, t, &x, &y);
215 normal_vector(cx, cy, x, y, stroker->width, &vx, &vy);
216 add_line_segment(stroker, x, y, vx, vy);
217 cx = x;
218 cy = y;
219 }
220
221 stroker->cx = cx;
222 stroker->cy = cy;
223
224 stroker->nvx = vx;
225 stroker->nvy = vy;
226}
227
228static void
229add_join(Triangulator_Stroker *stroker, float x , float y)
230{
231 int arc_pts_count, pts_count, i;
232 float prev_nvx, prev_nvy, xprod, px, py, qx, qy, pu, qv, ix, iy, *ptr;
233
234 // Creates a join to the next segment (cx, cy) -> (x, y)
235 normal_vector(stroker->cx, stroker->cy, x, y, stroker->width, &stroker->nvx, &stroker->nvy);
236
237 switch (stroker->join_style)
238 {
239 case EFL_GFX_JOIN_BEVEL:
240 break;
241 case EFL_GFX_JOIN_MITER:
242 {
243 // Find out on which side the join should be.
244 pts_count = eina_inarray_count(stroker->vertices);
245 ptr = eina_inarray_nth(stroker->vertices, pts_count - 2);
246 prev_nvx = ptr[0] - stroker->cx;
247 prev_nvy = ptr[1] - stroker->cy;
248 xprod = prev_nvx * stroker->nvy - prev_nvy * stroker->nvx;
249
250 // If the segments are parallel, use bevel join.
251 if (xprod < 0.001)
252 break;
253
254 // Find the corners of the previous and next segment to join.
255 if (xprod < 0)
256 {
257 ptr = eina_inarray_nth(stroker->vertices, pts_count - 2);
258 px = ptr[0];
259 py = ptr[1];
260 qx = stroker->cx - stroker->nvx;
261 qy = stroker->cy - stroker->nvy;
262 }
263 else
264 {
265 ptr = eina_inarray_nth(stroker->vertices, pts_count - 4);
266 px = ptr[0];
267 py = ptr[1];
268 qx = stroker->cx + stroker->nvx;
269 qy = stroker->cy - stroker->nvy;
270 }
271
272 // Find intersection point.
273 pu = px * prev_nvx + py * prev_nvy;
274 qv = qx * stroker->nvx + qy * stroker->nvy;
275 ix = (stroker->nvx * pu - prev_nvy * qv) / xprod;
276 iy = (prev_nvx * qv - stroker->nvx * pu) / xprod;
277
278 // Check that the distance to the intersection point is less than the miter limit.
279 if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= stroker->miter_limit * stroker->miter_limit)
280 {
281 ptr = eina_inarray_grow(stroker->vertices, 4);
282 ptr[0] = ix;
283 ptr[1] = iy;
284 ptr[2] = ix;
285 ptr[3] = iy;
286 }
287 break;
288 }
289 case EFL_GFX_JOIN_ROUND:
290 {
291 pts_count = eina_inarray_count(stroker->vertices);
292 ptr = eina_inarray_nth(stroker->vertices, pts_count - 2);
293 prev_nvx = ptr[0] - stroker->cx;
294 prev_nvy = ptr[1] - stroker->cy;
295 if (stroker->nvx * prev_nvx - stroker->nvy * prev_nvy < 0)
296 {
297 add_arc_points(stroker, 0, 0, stroker->nvx, stroker->nvy, -prev_nvx, -prev_nvy);
298 arc_pts_count = eina_inarray_count(stroker->arc_pts);
299 if (arc_pts_count)
300 ptr = eina_inarray_nth(stroker->arc_pts, 0);
301 for (i = arc_pts_count / 2; i > 0; --i)
302 add_line_segment(stroker, stroker->cx, stroker->cy, ptr[2 * i - 2], ptr[2 * i - 1]);
303 }
304 else
305 {
306 add_arc_points(stroker, 0, 0, -prev_nvx, -prev_nvy, stroker->nvx, stroker->nvy);
307 arc_pts_count = eina_inarray_count(stroker->arc_pts) / 2;
308 if (arc_pts_count)
309 ptr = eina_inarray_nth(stroker->arc_pts, 0);
310 for (i = 0; i < arc_pts_count / 2; ++i)
311 add_line_segment(stroker, stroker->cx, stroker->cy, ptr[2 * i + 0], ptr[2 * i + 1]);
312 }
313 break;
314 }
315 default: break;
316 }
317 add_line_segment(stroker, stroker->cx, stroker->cy, stroker->nvx, stroker->nvy);
318}
319
320static void
321end_cap(Triangulator_Stroker *stroker)
322{
323 float *ptr, *ptr1;
324 int front, end, pts_count, arc_pts_count, i;
325
326 switch (stroker->cap_style)
327 {
328 case EFL_GFX_CAP_BUTT:
329 break;
330 case EFL_GFX_CAP_SQUARE:
331 add_line_segment(stroker, stroker->cx + stroker->nvy, stroker->cy - stroker->nvx, stroker->nvx, stroker->nvy);
332 break;
333 case EFL_GFX_CAP_ROUND:
334 {
335 pts_count = eina_inarray_count(stroker->vertices);
336 ptr = eina_inarray_nth(stroker->vertices, pts_count-4);
337 add_arc_points(stroker, stroker->cx, stroker->cy, ptr[2], ptr[3], ptr[0], ptr[1]);
338 arc_pts_count = eina_inarray_count(stroker->arc_pts);
339 if (arc_pts_count)
340 {
341 ptr = eina_inarray_grow(stroker->vertices, arc_pts_count);
342 ptr1 = eina_inarray_nth(stroker->arc_pts, 0);
343 }
344 front = 0;
345 end = arc_pts_count / 2;
346 i = 0;
347 while (front != end)
348 {
349 ptr[i++] = ptr1[2 * end - 2];
350 ptr[i++] = ptr1[2 * end - 1];
351 --end;
352 if (front == end)
353 break;
354 ptr[i++] = ptr1[2 * front + 0];
355 ptr[i++] = ptr1[2 * front + 1];
356 ++front;
357 }
358 break;
359 }
360 default: break;
361 }
362}
363
364static void
365_end_cap_or_join_closed(Triangulator_Stroker *stroker,
366 const double *start,
367 Eina_Bool implicit_close, Eina_Bool ends_at_start)
368{
369 int count;
370 float x, y, *ptr;
371
372 if (ends_at_start)
373 {
374 add_join(stroker, start[2], start[3]);
375 }
376 else if (implicit_close)
377 {
378 add_join(stroker, start[0], start[1]);
379 line_to(stroker, start);
380 add_join(stroker, start[2], start[3]);
381 }
382 else
383 {
384 end_cap(stroker);
385 }
386 // add the invisible triangle
387 count = eina_inarray_count(stroker->vertices);
388 ptr = eina_inarray_nth(stroker->vertices, 0);
389 x = ptr[count-2];
390 y = ptr[count-1];
391 ptr = eina_inarray_grow(stroker->vertices, 2);
392 ptr[0] = x;
393 ptr[1] = y;
394}
395
396static inline void
397_skip_duplicate_points(const double **pts, const double *end_pts)
398{
399 while ((*pts + 2) < end_pts && (*pts)[0] == (*pts)[2] &&
400 (*pts)[1] == (*pts)[3])
401 {
402 *pts += 2;
403 }
404}
405
406static void
407_path_info_get(const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool *implicit_close, Eina_Bool *ends_at_start)
408{
409 int i = 0;
410
411 *implicit_close = EINA_FALSE;
412 *ends_at_start = EINA_FALSE;
413 for (++cmds; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END ; ++cmds)
414 {
415 switch (*cmds)
416 {
417 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
418 i += 2;
419 break;
420 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
421 i += 6;
422 break;
423 case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
424 // this path has a implicit close
425 *implicit_close = EINA_TRUE;
426 // fall through
427 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
428 if ((pts[0] == pts[i]) && (pts[1] == pts[i+1]))
429 *ends_at_start = EINA_TRUE;
430 return;
431 default:
432 break;
433 }
434 }
435 // this path is the last path with out implicit close.
436 *ends_at_start = pts[0] == pts[i] &&
437 pts[1] == pts[i+1];
438}
439
440void
441triangulator_stroker_process(Triangulator_Stroker *stroker,
442 const Efl_Gfx_Path_Command *cmds, const double *pts, int cmd_count, int pt_count)
443{
444 const double *end_pts = pts + pt_count;
445 const double *start_pts = 0;
446 Eina_Bool ends_at_start, implicit_close;
447 Efl_Gfx_Cap cap;
448 Efl_Gfx_Path_Command previous_type;
449
450 if (cmd_count < 2)
451 return;
452
453 eina_inarray_resize(stroker->vertices, 0);
454 stroker->curvyness_add = stroker->width;
455 stroker->curvyness_mul = CURVE_FLATNESS;
456 stroker->roundness = fmax(4, 2 * stroker->width * stroker->curvyness_mul);
457 // Over this level of segmentation, there doesn't seem to be any
458 // benefit, even for huge penWidth
459 if (stroker->roundness > 24)
460 stroker->roundness = 24;
461
462 stroker->sin_theta = sinf(PI / stroker->roundness);
463 stroker->cos_theta = cosf(PI / stroker->roundness);
464
465 cap = stroker->cap_style;
466 ends_at_start = EINA_FALSE;
467 implicit_close = EINA_FALSE;
468 previous_type = EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO;
469 for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
470 {
471 switch (*cmds)
472 {
473 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
474 {
475 if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
476 _end_cap_or_join_closed(stroker, start_pts, implicit_close, ends_at_start);
477
478 // get the sub path deatils like closed path or start at end info.
479 _path_info_get(cmds, pts, &implicit_close, &ends_at_start);
480
481 start_pts = pts;
482 _skip_duplicate_points(&start_pts, end_pts); // Skip duplicates to find correct normal.
483 if (start_pts + 2 >= end_pts)
484 return; // Nothing to see here...
485
486 if (ends_at_start || implicit_close)
487 stroker->cap_style = EFL_GFX_CAP_BUTT;
488
489 move_to(stroker, start_pts);
490 stroker->cap_style = cap;
491 previous_type = EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO;
492 pts+=2;
493 break;
494 }
495 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
496 if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1])
497 {
498 if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
499 add_join(stroker, pts[0], pts[1]);
500 line_to(stroker, pts);
501 previous_type = EFL_GFX_PATH_COMMAND_TYPE_LINE_TO;
502 }
503 pts+=2;
504 break;
505 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
506 if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1] ||
507 (float)pts[0] != (float)pts[2] || (float)pts[1] != (float)pts[3] ||
508 (float)pts[2] != (float)pts[4] || (float)pts[3] != (float)pts[5])
509 {
510 if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1])
511 {
512 if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
513 add_join(stroker, pts[0], pts[1]);
514 }
515 cubic_to(stroker, pts);
516 previous_type = EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO;
517 }
518 pts+=6;
519 break;
520 default:
521 break;
522 }
523 }
524
525 if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
526 _end_cap_or_join_closed(stroker, start_pts, implicit_close, ends_at_start);
527}
diff --git a/src/static_libs/triangulator/triangulator_stroker.h b/src/static_libs/triangulator/triangulator_stroker.h
new file mode 100644
index 0000000..5cc7805
--- /dev/null
+++ b/src/static_libs/triangulator/triangulator_stroker.h
@@ -0,0 +1,54 @@
1#ifndef TRIANGULATOR_STROKER_H_
2#define TRIANGULATOR_STROKER_H_
3
4#include <Efl.h>
5
6typedef struct _Triangulator_Stroker Triangulator_Stroker;
7struct _Triangulator_Stroker
8{
9 Eina_Inarray *vertices;
10 Eina_Inarray *arc_pts; // intermediate array for storing arc points
11 float cx, cy; // current points
12 float nvx, nvy; // normal vector
13 float width;
14 float miter_limit;
15
16 int roundness; // Number of line segments in a round join
17 float sin_theta; // sin(roundness / 360);
18 float cos_theta; // cos(roundness / 360);
19 float curvyness_mul;
20 float curvyness_add;
21
22 Efl_Gfx_Join join_style;
23 Efl_Gfx_Cap cap_style;
24};
25
26/**
27 * Creates a new triangulating stroker.
28 *
29 */
30Triangulator_Stroker *triangulator_stroker_new(void);
31
32/**
33 * Frees the given Stroker and any associated resource.
34 *
35 * stroker The given Stroker.
36 */
37void triangulator_stroker_free(Triangulator_Stroker *stroker);
38
39/**
40 * Process the command list to generate triangle strips.
41 * The alogrithm handles multiple contour by adding invisible triangles.
42 *
43 * cmds : commnad list
44 * pts : point list.
45 * cmd_count : number of commands.
46 * pt_count : number of points.
47 *
48 * output : It generates the outline in the form of triangle strips store in vertices array.
49 * The array can be used to copy the data to a VBO and draw the data using TRIANGLE_STRIP.
50 */
51void triangulator_stroker_process(Triangulator_Stroker *stroker, const Efl_Gfx_Path_Command *cmds, const double *pts, int cmd_count, int pt_count);
52
53#endif // TRIANGULATOR_STROKER_H_
54