diff --git a/src/Makefile_Ector.am b/src/Makefile_Ector.am index f8b76716b6..0f8a0a5339 100644 --- a/src/Makefile_Ector.am +++ b/src/Makefile_Ector.am @@ -108,6 +108,12 @@ static_libs/rg_etc/rg_etc2.c \ static_libs/rg_etc/rg_etc1.h \ static_libs/rg_etc/etc2_encoder.c +# Triangulator static lib +triangulator_sources = \ +static_libs/triangulator/triangulator_stroker.c \ +static_libs/triangulator/triangulator_simple.c \ +$(NULL) + # And the default software backend lib_ector_libector_la_SOURCES += \ lib/ector/software/ector_renderer_software_gradient_linear.c \ @@ -120,7 +126,8 @@ lib/ector/software/ector_software_surface.c \ lib/ector/software/ector_software_buffer.c \ static_libs/freetype/sw_ft_math.c \ static_libs/freetype/sw_ft_raster.c \ -static_libs/freetype/sw_ft_stroker.c +static_libs/freetype/sw_ft_stroker.c \ +$(triangulator_sources) # And now the gl backend lib_ector_libector_la_SOURCES += \ @@ -152,6 +159,7 @@ lib_ector_libector_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -I$(top_builddir)/src/lib/ector/gl \ -I$(top_srcdir)/src/static_libs/freetype \ -I$(top_srcdir)/src/static_libs/draw \ +-I$(top_srcdir)/src/static_libs/triangulator \ @ECTOR_CFLAGS@ \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ @@ -204,3 +212,4 @@ static_libs/freetype/sw_ft_types.h \ static_libs/draw/draw.h \ static_libs/draw/draw_private.h \ $(ECTOR_GL_SHADERS_GEN) + diff --git a/src/static_libs/triangulator/triangulator_simple.c b/src/static_libs/triangulator/triangulator_simple.c new file mode 100644 index 0000000000..60f7114cdb --- /dev/null +++ b/src/static_libs/triangulator/triangulator_simple.c @@ -0,0 +1,160 @@ +#include "triangulator_simple.h" + +Triangulator_Simple * +triangulator_simple_new(void) +{ + Triangulator_Simple *st = calloc(1, sizeof(Triangulator_Simple)); + st->vertices = eina_inarray_new(sizeof(float), 0); + st->stops = eina_inarray_new(sizeof(int), 0); + return st; +} + +void +triangulator_simple_free(Triangulator_Simple *st) +{ + eina_inarray_free(st->vertices); + eina_inarray_free(st->stops); +} + +static void +_add_line(Triangulator_Simple *st, const float x, const float y) +{ + float *ptr; + + ptr = eina_inarray_grow(st->vertices, 2); + ptr[0] = x; + ptr[1] = y; + + if (x > st->maxx) + st->maxx = x; + else if (x < st->minx) + st->minx = x; + if (y > st->maxy) + st->maxy = y; + else if (y < st->miny) + st->miny = y; +} + +static void +_calculate_centroid(const Efl_Gfx_Path_Command *cmds, const double *pts, double *cx, double *cy) +{ + double sumx = 0, sumy = 0; + int count = 0; + + sumx += pts[0]; + sumy += pts[1]; + for (cmds++, count++, pts+=2; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + sumx += pts[0]; + sumy += pts[1]; + pts +=2; + count++; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + sumx += pts[0]; + sumy += pts[1]; + sumx += pts[2]; + sumy += pts[3]; + sumx += pts[4]; + sumy += pts[5]; + pts +=6; + count +=3; + break; + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: + *cx = sumx/count; + *cy = sumy/count; + return; + default: + break; + } + } + // + *cx = sumx/count; + *cy = sumy/count; +} + +void +triangulator_simple_process(Triangulator_Simple *st, const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool convex) +{ + double bw, bh, cx, cy, x, y, t, one_over_threshold_minus_1; + float *ptr; + int *stop_ptr, threshold, i; + Eina_Bezier b; + + eina_inarray_resize(st->vertices, 0); + eina_inarray_resize(st->stops, 0); + if (!convex) + { + _calculate_centroid(cmds, pts, &cx, &cy); + _add_line(st, cx, cy); + } + + cx = pts[0]; + cy = pts[1]; + // The first element is always a moveTo + _add_line(st, cx, cy); + pts += 2; + cmds++; + for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + + // add closing line for the previous contour + _add_line(st, cx, cy); + + // update stop array + stop_ptr = eina_inarray_grow(st->stops, 1); + stop_ptr[0] = eina_inarray_count(st->vertices); + + // add centroid if not convex + if (!convex) + { + _calculate_centroid(cmds, pts, &cx, &cy); + _add_line(st, cx, cy); + } + cx = pts[0]; + cy = pts[1]; + _add_line(st, cx, cy); + pts += 2; + break; + + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + + _add_line(st, pts[0], pts[1]); + pts += 2; + break; + + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + ptr = eina_inarray_nth(st->vertices, eina_inarray_count(st->vertices) - 2); + eina_bezier_values_set(&b, ptr[0], ptr[1], pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + eina_bezier_bounds_get(&b, NULL, NULL , &bw, &bh); + threshold = fminf(64, fmaxf(bw, bh) * 3.14f / 6); + if (threshold < 3) threshold = 3; + one_over_threshold_minus_1 = 1.0 / (threshold - 1); + for (i=1; istops, 1); + stop_ptr[0] = eina_inarray_count(st->vertices); +} \ 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 0000000000..e87acc6e40 --- /dev/null +++ b/src/static_libs/triangulator/triangulator_simple.h @@ -0,0 +1,43 @@ +#ifndef TRIANGULATOR_SIMPLE_H_ +#define TRIANGULATOR_SIMPLE_H_ + +#include + +typedef struct _Triangulator_Simple Triangulator_Simple; +struct _Triangulator_Simple +{ + Eina_Inarray *vertices; + Eina_Inarray *stops; //list of contours need to be drawn as separate triangle fan. + float minx; + float miny; + float maxx; + float maxy; +}; + +/** + * Creates a new simple triangulator. + * + */ +Triangulator_Simple * triangulator_simple_new(void); + +/** + * Frees the given triangulator and any associated resource. + * + * st The given triangulator. + */ +void triangulator_simple_free(Triangulator_Simple *st); + +/** + * Process the command list to generate triangle fans. + * The alogrithm handles multiple contours by providing the list of stops. + * + * cmds : commnad list + * pts : point list. + * convex : shape is convex or not. + * + * output: If the shape is convex then, the triangle fan will exactly fill the shape. but if its not convex, it will overflow + * to outside shape, in that case user has to use stencil method (2 pass drawing) to fill the shape. + */ +void triangulator_simple_process(Triangulator_Simple *st, const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool convex); + +#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 0000000000..44f7b8946b --- /dev/null +++ b/src/static_libs/triangulator/triangulator_stroker.c @@ -0,0 +1,527 @@ + +#include "triangulator_stroker.h" +#include + +#define PI 3.1415 +#define CURVE_FLATNESS PI / 8 + +Triangulator_Stroker * +triangulator_stroker_new(void) +{ + Triangulator_Stroker *stroker = calloc(1, sizeof(Triangulator_Stroker)); + stroker->vertices = eina_inarray_new(sizeof(float), 0); + stroker->arc_pts = eina_inarray_new(sizeof(float), 0); + stroker->miter_limit = 2; + return stroker; +} + +void +triangulator_stroker_free(Triangulator_Stroker *stroker) +{ + eina_inarray_free(stroker->vertices); + eina_inarray_free(stroker->arc_pts); +} + +// calculate the normal vector +static void +normal_vector(float x1, float y1, float x2, float y2, float width, + float *nx, float *ny) +{ + float pw; + float dx = x2 - x1; + float dy = y2 - y1; + + if (dx == 0) + pw = width / fabsf(dy); + else if (dy == 0) + pw = width / fabsf(dx); + else + pw = width / sqrtf(dx*dx + dy*dy); + + *nx = -dy * pw; + *ny = dx * pw; +} + +// add a line segment +static void +add_line_segment(Triangulator_Stroker *stroker, float x, float y, float vx, float vy) +{ + float *ptr; + + ptr = eina_inarray_grow(stroker->vertices, 4); + ptr[0] = x + vx; + ptr[1] = y + vy; + ptr[2] = x - vx; + ptr[3] = y - vy; +} + +static void +add_arc_points(Triangulator_Stroker *stroker, float cx, float cy, float from_x, float from_y, float to_x, float to_y) +{ + float tmp_x, tmp_y, *ptr; + float dx1 = from_x - cx; + float dy1 = from_y - cy; + float dx2 = to_x - cx; + float dy2 = to_y - cy; + int size; + + eina_inarray_resize(stroker->arc_pts, 0); + +#define ADD_NEW_POINT \ + tmp_x = dx1 * stroker->cos_theta - dy1 * stroker->sin_theta; \ + tmp_y = dx1 * stroker->sin_theta + dy1 * stroker->cos_theta; \ + dx1 = tmp_x; \ + dy1 = tmp_y; \ + ptr = eina_inarray_grow(stroker->arc_pts, 2); \ + ptr[0] = cx + dx1; \ + ptr[1] = cy + dy1; + + // while more than 180 degrees left: + while (dx1 * dy2 - dx2 * dy1 < 0) + { + ADD_NEW_POINT + } + + // while more than 90 degrees left: + while (dx1 * dx2 + dy1 * dy2 < 0) + { + ADD_NEW_POINT + } + + // while more than 0 degrees left: + while (dx1 * dy2 - dx2 * dy1 > 0) + { + ADD_NEW_POINT + } + + // remove last point which was rotated beyond [to_x, to_y]. + size = eina_inarray_count(stroker->arc_pts); + if (size) + eina_inarray_resize(stroker->arc_pts, size - 2); +} + +static void +move_to(Triangulator_Stroker *stroker, const double *pts) +{ + float x2,y2, sx, sy, *ptr=NULL, *ptr1=NULL; + int pts_count, arc_pts_count, front, end, i=0; + Eina_Bool jump; + + stroker->cx = pts[0]; + stroker->cy = pts[1]; + x2 = pts[2]; + y2 = pts[3]; + normal_vector(stroker->cx, stroker->cy, x2, y2, stroker->width, &stroker->nvx, &stroker->nvy); + + // To acheive jumps we insert zero-area tringles. This is done by + // adding two identical points in both the end of previous strip + // and beginning of next strip + jump = eina_inarray_count(stroker->vertices); + + switch (stroker->cap_style) + { + case EFL_GFX_CAP_BUTT: + if (jump) + { + ptr = eina_inarray_grow(stroker->vertices, 2); + ptr[0] = stroker->cx + stroker->nvx; + ptr[1] = stroker->cy + stroker->nvy; + } + break; + case EFL_GFX_CAP_SQUARE: + { + sx = stroker->cx - stroker->nvy; + sy = stroker->cy + stroker->nvx; + if (jump) + { + ptr = eina_inarray_grow(stroker->vertices, 2); + ptr[0] = sx + stroker->nvx; + ptr[1] = sy + stroker->nvy; + } + add_line_segment(stroker, sx, sy, stroker->nvx, stroker->nvy); + break; + } + case EFL_GFX_CAP_ROUND: + { + add_arc_points(stroker, stroker->cx, stroker->cy, + stroker->cx + stroker->nvx, stroker->cy + stroker->nvy, + stroker->cx - stroker->nvx, stroker->cy - stroker->nvy); + arc_pts_count = eina_inarray_count(stroker->arc_pts); + front = 0; + end = arc_pts_count / 2; + if (arc_pts_count) + { + eina_inarray_grow(stroker->vertices, eina_inarray_count(stroker->arc_pts) + 2 * jump); + pts_count = eina_inarray_count(stroker->vertices); + ptr1 = eina_inarray_nth(stroker->arc_pts, 0); + ptr = eina_inarray_nth(stroker->vertices, 0); + i = pts_count; + } + while (front != end) + { + ptr[--i] = ptr1[2 * end - 1]; + ptr[--i] = ptr1[2 * end - 2]; + --end; + if (front == end) + break; + ptr[--i] = ptr1[2 * front + 1]; + ptr[--i] = ptr1[2 * front + 0]; + ++front; + } + + if (jump) + { + ptr[i - 1] = ptr[i + 1]; + ptr[i - 2] = ptr[i + 0]; + } + break; + } + default: break; + } + add_line_segment(stroker, stroker->cx, stroker->cy, stroker->nvx, stroker->nvy); +} + +static void +line_to(Triangulator_Stroker *stroker, const double *pts) +{ + add_line_segment(stroker, pts[0], pts[1], stroker->nvx, stroker->nvy); + stroker->cx = pts[0]; + stroker->cy = pts[1]; +} + +static void +cubic_to(Triangulator_Stroker *stroker, const double *pts) +{ + Eina_Bezier b; + float rad, vx, vy, cx, cy, threshold_minus_1, t; + double bw, bh, x, y; + int i, threshold; + + eina_bezier_values_set(&b, stroker->cx, stroker->cy, pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + eina_bezier_bounds_get(&b, NULL, NULL, &bw, &bh); + + rad = fmaxf(bw, bh); + threshold = fminf(64, (rad + stroker->curvyness_add) * stroker->curvyness_mul); + if (threshold < 4) + threshold = 4; + threshold_minus_1 = threshold - 1; + cx = stroker->cx; + cy = stroker->cy; + + for (i = 1; i < threshold; ++i) + { + t = i / threshold_minus_1; + eina_bezier_point_at(&b, t, &x, &y); + normal_vector(cx, cy, x, y, stroker->width, &vx, &vy); + add_line_segment(stroker, x, y, vx, vy); + cx = x; + cy = y; + } + + stroker->cx = cx; + stroker->cy = cy; + + stroker->nvx = vx; + stroker->nvy = vy; +} + +static void +add_join(Triangulator_Stroker *stroker, float x , float y) +{ + int arc_pts_count, pts_count, i; + float prev_nvx, prev_nvy, xprod, px, py, qx, qy, pu, qv, ix, iy, *ptr; + + // Creates a join to the next segment (cx, cy) -> (x, y) + normal_vector(stroker->cx, stroker->cy, x, y, stroker->width, &stroker->nvx, &stroker->nvy); + + switch (stroker->join_style) + { + case EFL_GFX_JOIN_BEVEL: + break; + case EFL_GFX_JOIN_MITER: + { + // Find out on which side the join should be. + pts_count = eina_inarray_count(stroker->vertices); + ptr = eina_inarray_nth(stroker->vertices, pts_count - 2); + prev_nvx = ptr[0] - stroker->cx; + prev_nvy = ptr[1] - stroker->cy; + xprod = prev_nvx * stroker->nvy - prev_nvy * stroker->nvx; + + // If the segments are parallel, use bevel join. + if (xprod < 0.001) + break; + + // Find the corners of the previous and next segment to join. + if (xprod < 0) + { + ptr = eina_inarray_nth(stroker->vertices, pts_count - 2); + px = ptr[0]; + py = ptr[1]; + qx = stroker->cx - stroker->nvx; + qy = stroker->cy - stroker->nvy; + } + else + { + ptr = eina_inarray_nth(stroker->vertices, pts_count - 4); + px = ptr[0]; + py = ptr[1]; + qx = stroker->cx + stroker->nvx; + qy = stroker->cy - stroker->nvy; + } + + // Find intersection point. + pu = px * prev_nvx + py * prev_nvy; + qv = qx * stroker->nvx + qy * stroker->nvy; + ix = (stroker->nvx * pu - prev_nvy * qv) / xprod; + iy = (prev_nvx * qv - stroker->nvx * pu) / xprod; + + // Check that the distance to the intersection point is less than the miter limit. + if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= stroker->miter_limit * stroker->miter_limit) + { + ptr = eina_inarray_grow(stroker->vertices, 4); + ptr[0] = ix; + ptr[1] = iy; + ptr[2] = ix; + ptr[3] = iy; + } + break; + } + case EFL_GFX_JOIN_ROUND: + { + pts_count = eina_inarray_count(stroker->vertices); + ptr = eina_inarray_nth(stroker->vertices, pts_count - 2); + prev_nvx = ptr[0] - stroker->cx; + prev_nvy = ptr[1] - stroker->cy; + if (stroker->nvx * prev_nvx - stroker->nvy * prev_nvy < 0) + { + add_arc_points(stroker, 0, 0, stroker->nvx, stroker->nvy, -prev_nvx, -prev_nvy); + arc_pts_count = eina_inarray_count(stroker->arc_pts); + if (arc_pts_count) + ptr = eina_inarray_nth(stroker->arc_pts, 0); + for (i = arc_pts_count / 2; i > 0; --i) + add_line_segment(stroker, stroker->cx, stroker->cy, ptr[2 * i - 2], ptr[2 * i - 1]); + } + else + { + add_arc_points(stroker, 0, 0, -prev_nvx, -prev_nvy, stroker->nvx, stroker->nvy); + arc_pts_count = eina_inarray_count(stroker->arc_pts) / 2; + if (arc_pts_count) + ptr = eina_inarray_nth(stroker->arc_pts, 0); + for (i = 0; i < arc_pts_count / 2; ++i) + add_line_segment(stroker, stroker->cx, stroker->cy, ptr[2 * i + 0], ptr[2 * i + 1]); + } + break; + } + default: break; + } + add_line_segment(stroker, stroker->cx, stroker->cy, stroker->nvx, stroker->nvy); +} + +static void +end_cap(Triangulator_Stroker *stroker) +{ + float *ptr, *ptr1; + int front, end, pts_count, arc_pts_count, i; + + switch (stroker->cap_style) + { + case EFL_GFX_CAP_BUTT: + break; + case EFL_GFX_CAP_SQUARE: + add_line_segment(stroker, stroker->cx + stroker->nvy, stroker->cy - stroker->nvx, stroker->nvx, stroker->nvy); + break; + case EFL_GFX_CAP_ROUND: + { + pts_count = eina_inarray_count(stroker->vertices); + ptr = eina_inarray_nth(stroker->vertices, pts_count-4); + add_arc_points(stroker, stroker->cx, stroker->cy, ptr[2], ptr[3], ptr[0], ptr[1]); + arc_pts_count = eina_inarray_count(stroker->arc_pts); + if (arc_pts_count) + { + ptr = eina_inarray_grow(stroker->vertices, arc_pts_count); + ptr1 = eina_inarray_nth(stroker->arc_pts, 0); + } + front = 0; + end = arc_pts_count / 2; + i = 0; + while (front != end) + { + ptr[i++] = ptr1[2 * end - 2]; + ptr[i++] = ptr1[2 * end - 1]; + --end; + if (front == end) + break; + ptr[i++] = ptr1[2 * front + 0]; + ptr[i++] = ptr1[2 * front + 1]; + ++front; + } + break; + } + default: break; + } +} + +static void +_end_cap_or_join_closed(Triangulator_Stroker *stroker, + const double *start, + Eina_Bool implicit_close, Eina_Bool ends_at_start) +{ + int count; + float x, y, *ptr; + + if (ends_at_start) + { + add_join(stroker, start[2], start[3]); + } + else if (implicit_close) + { + add_join(stroker, start[0], start[1]); + line_to(stroker, start); + add_join(stroker, start[2], start[3]); + } + else + { + end_cap(stroker); + } + // add the invisible triangle + count = eina_inarray_count(stroker->vertices); + ptr = eina_inarray_nth(stroker->vertices, 0); + x = ptr[count-2]; + y = ptr[count-1]; + ptr = eina_inarray_grow(stroker->vertices, 2); + ptr[0] = x; + ptr[1] = y; +} + +static inline void +_skip_duplicate_points(const double **pts, const double *end_pts) +{ + while ((*pts + 2) < end_pts && (*pts)[0] == (*pts)[2] && + (*pts)[1] == (*pts)[3]) + { + *pts += 2; + } +} + +static void +_path_info_get(const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool *implicit_close, Eina_Bool *ends_at_start) +{ + int i = 0; + + *implicit_close = EINA_FALSE; + *ends_at_start = EINA_FALSE; + for (++cmds; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END ; ++cmds) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + i += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + i += 6; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: + // this path has a implicit close + *implicit_close = EINA_TRUE; + // fall through + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + if ((pts[0] == pts[i]) && (pts[1] == pts[i+1])) + *ends_at_start = EINA_TRUE; + return; + default: + break; + } + } + // this path is the last path with out implicit close. + *ends_at_start = pts[0] == pts[i] && + pts[1] == pts[i+1]; +} + +void +triangulator_stroker_process(Triangulator_Stroker *stroker, + const Efl_Gfx_Path_Command *cmds, const double *pts, int cmd_count, int pt_count) +{ + const double *end_pts = pts + pt_count; + const double *start_pts = 0; + Eina_Bool ends_at_start, implicit_close; + Efl_Gfx_Cap cap; + Efl_Gfx_Path_Command previous_type; + + if (cmd_count < 2) + return; + + eina_inarray_resize(stroker->vertices, 0); + stroker->curvyness_add = stroker->width; + stroker->curvyness_mul = CURVE_FLATNESS; + stroker->roundness = fmax(4, 2 * stroker->width * stroker->curvyness_mul); + // Over this level of segmentation, there doesn't seem to be any + // benefit, even for huge penWidth + if (stroker->roundness > 24) + stroker->roundness = 24; + + stroker->sin_theta = sinf(PI / stroker->roundness); + stroker->cos_theta = cosf(PI / stroker->roundness); + + cap = stroker->cap_style; + ends_at_start = EINA_FALSE; + implicit_close = EINA_FALSE; + previous_type = EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO; + for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + { + if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO) + _end_cap_or_join_closed(stroker, start_pts, implicit_close, ends_at_start); + + // get the sub path deatils like closed path or start at end info. + _path_info_get(cmds, pts, &implicit_close, &ends_at_start); + + start_pts = pts; + _skip_duplicate_points(&start_pts, end_pts); // Skip duplicates to find correct normal. + if (start_pts + 2 >= end_pts) + return; // Nothing to see here... + + if (ends_at_start || implicit_close) + stroker->cap_style = EFL_GFX_CAP_BUTT; + + move_to(stroker, start_pts); + stroker->cap_style = cap; + previous_type = EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO; + pts+=2; + break; + } + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1]) + { + if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO) + add_join(stroker, pts[0], pts[1]); + line_to(stroker, pts); + previous_type = EFL_GFX_PATH_COMMAND_TYPE_LINE_TO; + } + pts+=2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1] || + (float)pts[0] != (float)pts[2] || (float)pts[1] != (float)pts[3] || + (float)pts[2] != (float)pts[4] || (float)pts[3] != (float)pts[5]) + { + if (stroker->cx != (float)pts[0] || stroker->cy != (float)pts[1]) + { + if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO) + add_join(stroker, pts[0], pts[1]); + } + cubic_to(stroker, pts); + previous_type = EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO; + } + pts+=6; + break; + default: + break; + } + } + + if (previous_type != EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO) + _end_cap_or_join_closed(stroker, start_pts, implicit_close, ends_at_start); +} diff --git a/src/static_libs/triangulator/triangulator_stroker.h b/src/static_libs/triangulator/triangulator_stroker.h new file mode 100644 index 0000000000..5cc7805638 --- /dev/null +++ b/src/static_libs/triangulator/triangulator_stroker.h @@ -0,0 +1,54 @@ +#ifndef TRIANGULATOR_STROKER_H_ +#define TRIANGULATOR_STROKER_H_ + +#include + +typedef struct _Triangulator_Stroker Triangulator_Stroker; +struct _Triangulator_Stroker +{ + Eina_Inarray *vertices; + Eina_Inarray *arc_pts; // intermediate array for storing arc points + float cx, cy; // current points + float nvx, nvy; // normal vector + float width; + float miter_limit; + + int roundness; // Number of line segments in a round join + float sin_theta; // sin(roundness / 360); + float cos_theta; // cos(roundness / 360); + float curvyness_mul; + float curvyness_add; + + Efl_Gfx_Join join_style; + Efl_Gfx_Cap cap_style; +}; + +/** + * Creates a new triangulating stroker. + * + */ +Triangulator_Stroker *triangulator_stroker_new(void); + +/** + * Frees the given Stroker and any associated resource. + * + * stroker The given Stroker. + */ +void triangulator_stroker_free(Triangulator_Stroker *stroker); + +/** + * Process the command list to generate triangle strips. + * The alogrithm handles multiple contour by adding invisible triangles. + * + * cmds : commnad list + * pts : point list. + * cmd_count : number of commands. + * pt_count : number of points. + * + * output : It generates the outline in the form of triangle strips store in vertices array. + * The array can be used to copy the data to a VBO and draw the data using TRIANGLE_STRIP. + */ +void triangulator_stroker_process(Triangulator_Stroker *stroker, const Efl_Gfx_Path_Command *cmds, const double *pts, int cmd_count, int pt_count); + +#endif // TRIANGULATOR_STROKER_H_ +