*/
vkvg_public
vkvg_status_t vkvg_rounded_rectangle (VkvgContext ctx, float x, float y, float w, float h, float radius);
+/**
+* @brief Add an axis aligned rectangle with rounded corners defined in both axis to the current path.
+*
+* Adds a closed sub-path rectangle of the given size to the current path at position (x, y).
+* @param ctx The vkvg context pointer.
+* @param x The x coordinate of the top left corner of the rectangle to emit.
+* @param y The y coordinate of the top left corner of the rectangle to emit.
+* @param w The width in pixel of the rectangle to draw.
+* @param h The height in pixel of the rectangle to draw.
+* @param rx The horizontal radius of the corners.
+* @param ry The vertical radius of the corners.
+* @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0.
+*/
+vkvg_public
+void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry);
+vkvg_public
+void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle);
+vkvg_public
+void vkvg_elliptic_arc (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi);
/**
* @brief Stroke command
*
void vkvg_get_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){
memcpy ((void*)matrix, &ctx->pushConsts.mat, sizeof(vkvg_matrix_t));
}
+
+void vkvg_elliptic_arc (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi) {
+ float x1, y1;
+ vkvg_get_current_point(ctx, &x1, &y1);
+ _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, counterClockWise, rx, ry, phi);
+}
+
+void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) {
+ if (ctx->status)
+ return;
+
+ float width_two_thirds = radiusX * 4 / 3;
+
+ float dx1 = sinf(rotationAngle) * radiusY;
+ float dy1 = cosf(rotationAngle) * radiusY;
+ float dx2 = cosf(rotationAngle) * width_two_thirds;
+ float dy2 = sinf(rotationAngle) * width_two_thirds;
+
+ float topCenterX = x - dx1;
+ float topCenterY = y + dy1;
+ float topRightX = topCenterX + dx2;
+ float topRightY = topCenterY + dy2;
+ float topLeftX = topCenterX - dx2;
+ float topLeftY = topCenterY - dy2;
+
+ float bottomCenterX = x + dx1;
+ float bottomCenterY = y - dy1;
+ float bottomRightX = bottomCenterX + dx2;
+ float bottomRightY = bottomCenterY + dy2;
+ float bottomLeftX = bottomCenterX - dx2;
+ float bottomLeftY = bottomCenterY - dy2;
+
+ vkvg_move_to (ctx, bottomCenterX, bottomCenterY);
+ vkvg_curve_to (ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY);
+ vkvg_curve_to (ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY);
+ vkvg_close_path (ctx);
+}
+void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry){
+ vkvg_move_to (ctx, x+rx, y);
+ vkvg_line_to (ctx, x+w-rx, y);
+ vkvg_elliptic_arc(ctx, x+w, y+ry, false, true, rx, ry, 0);
+
+ vkvg_line_to (ctx, x+w, y+h-ry);
+ vkvg_elliptic_arc(ctx, x+w-rx, y+h, false, true, rx, ry, 0);
+
+ vkvg_line_to (ctx, x+rx, y+h);
+ vkvg_elliptic_arc(ctx, x, y+h-ry , false, true, rx, ry, 0);
+
+ vkvg_line_to (ctx, x, y+ry);
+ vkvg_elliptic_arc(ctx, x+rx, y , false, true, rx, ry, 0);
+
+ vkvg_close_path(ctx);
+}
}
#pragma warning(default:4127)
+void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi) {
+ if (ctx->status)
+ return;
+
+ if (_rx==0||_ry==0) {
+ if (_current_path_is_empty(ctx))
+ vkvg_move_to(ctx, x1, y1);
+ vkvg_line_to(ctx, x2, y2);
+ return;
+ }
+ float rx = fabsf(_rx);
+ float ry = fabsf(_ry);
+
+ mat2 m = {
+ { cosf (phi), sinf (phi)},
+ {-sinf (phi), cosf (phi)}
+ };
+ vec2 p = {(x1 - x2)/2, (y1 - y2)/2};
+ vec2 p1 = mat2_mult_vec2 (m, p);
+
+ //radii corrections
+ double lambda = powf (p1.x, 2) / powf (rx, 2) + powf (p1.y, 2) / powf (ry, 2);
+ if (lambda > 1) {
+ lambda = sqrtf (lambda);
+ rx *= lambda;
+ ry *= lambda;
+ }
+
+ p = (vec2){rx * p1.y / ry, -ry * p1.x / rx};
+
+ vec2 cp = vec2_mult_s (p, sqrtf (fabsf (
+ (powf (rx,2) * powf (ry,2) - powf (rx,2) * powf (p1.y, 2) - powf (ry,2) * powf (p1.x, 2)) /
+ (powf (rx,2) * powf (p1.y, 2) + powf (ry,2) * powf (p1.x, 2))
+ )));
+
+ if (largeArc == counterClockWise)
+ vec2_inv(&cp);
+
+ m = (mat2) {
+ {cosf (phi),-sinf (phi)},
+ {sinf (phi), cosf (phi)}
+ };
+ p = (vec2){(x1 + x2)/2, (y1 + y2)/2};
+ vec2 c = vec2_add (mat2_mult_vec2(m, cp) , p);
+
+ vec2 u = vec2_unit_x;
+ vec2 v = {(p1.x-cp.x)/rx, (p1.y-cp.y)/ry};
+ double sa = acosf (vec2_dot (u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u))));
+ if (isnanf(sa))
+ sa=M_PIF;
+ if (u.x*v.y-u.y*v.x < 0)
+ sa = -sa;
+
+ u = v;
+ v = (vec2) {(-p1.x-cp.x)/rx, (-p1.y-cp.y)/ry};
+ double delta_theta = acosf (vec2_dot (u, v) / (fabsf(vec2_length (v)) * fabsf(vec2_length (u))));
+ if (isnanf(delta_theta))
+ delta_theta=M_PIF;
+ if (u.x*v.y-u.y*v.x < 0)
+ delta_theta = -delta_theta;
+
+ if (counterClockWise) {
+ if (delta_theta < 0)
+ delta_theta += M_PIF * 2.0;
+ } else if (delta_theta > 0)
+ delta_theta -= M_PIF * 2.0;
+
+ m = (mat2) {
+ {cosf (phi),-sinf (phi)},
+ {sinf (phi), cosf (phi)}
+ };
+
+ double theta = sa;
+ double ea = sa + delta_theta;
+
+ float step = _get_arc_step(ctx, fminf (rx, ry))*0.1f;
+
+ p = (vec2) {
+ rx * cosf (theta),
+ ry * sinf (theta)
+ };
+ vec2 xy = vec2_add (mat2_mult_vec2 (m, p), c);
+
+ if (_current_path_is_empty(ctx)){
+ _set_curve_start (ctx);
+ _add_point (ctx, xy.x, xy.y);
+ }else{
+ vkvg_line_to(ctx, xy.x, xy.y);
+ _set_curve_start (ctx);
+ }
+
+ _set_curve_start (ctx);
+
+ if (sa < ea) {
+ theta += step;
+ while (theta < ea) {
+ p = (vec2) {
+ rx * cosf (theta),
+ ry * sinf (theta)
+ };
+ xy = vec2_add (mat2_mult_vec2 (m, p), c);
+ _add_point (ctx, xy.x, xy.y);
+ theta += step;
+ }
+ } else {
+ theta -= step;
+ while (theta > ea) {
+ p = (vec2) {
+ rx * cosf (theta),
+ ry * sinf (theta)
+ };
+ xy = vec2_add (mat2_mult_vec2 (m, p), c);
+ _add_point (ctx, xy.x, xy.y);
+ theta -= step;
+ }
+ }
+ p = (vec2) {
+ rx * cosf (ea),
+ ry * sinf (ea)
+ };
+ xy = vec2_add (mat2_mult_vec2 (m, p), c);
+ _add_point (ctx, xy.x, xy.y);
+ _set_curve_end(ctx);
+}
+
+
//Even-Odd inside test with stencil buffer implementation.
void _poly_fill (VkvgContext ctx){
//we anticipate the check for vbo buffer size, ibo is not used in poly_fill
void _bezier (VkvgContext ctx,
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4);
+
+void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi);
#endif