From: Jean-Philippe Bruyère Date: Wed, 2 Mar 2022 14:14:12 +0000 (+0100) Subject: implement vkvg_set_miter_limit X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=900f794e9e08f0f7f984700800a1a819e78adb64;p=jp%2Fvkvg.git implement vkvg_set_miter_limit --- diff --git a/include/vkvg.h b/include/vkvg.h index 10d9eec..c38b59f 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -1290,6 +1290,29 @@ void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b); */ vkvg_public void vkvg_set_line_width (VkvgContext ctx, float width); +/** + * @brief set line join miter size limit. + * + * If the current line join style is set to VKVG_LINE_JOIN_MITER (see vkvg_set_line_join()), the miter limit is used to determine whether the lines should be + * joined with a bevel instead of a miter. Vkvg divides the length of the miter by the line width. If the result is greater than the miter limit, the style is converted to a bevel. + * + * The default miter limit value is 10.0, which will convert joins with interior angles less than 11 degrees to bevels instead of miters. + * For reference, a miter limit of 2.0 makes the miter cutoff at 60 degrees, and a miter limit of 1.414 makes the cutoff at 90 degrees. + * + * A miter limit for a desired angle can be computed as: miter limit = 1/sin(angle/2) + * + * @param ctx a valid vkvg @ref context + * @param limit new current miter limit value for the context. + */ +vkvg_public +void vkvg_set_miter_limit (VkvgContext ctx, float limit); +/** + * @brief Gets the current miter limit, as set by @ref vkvg_set_miter_limit(). + * @param ctx a valid vkvg @ref context + * @return the current miter limit for the context. + */ +vkvg_public +float vkvg_get_miter_limit (VkvgContext ctx); /** * @brief set line terminations for the next draw command. * @@ -1297,7 +1320,6 @@ void vkvg_set_line_width (VkvgContext ctx, float width); * @param ctx a valid vkvg @ref context * @param cap new line termination, may be one of the value of #vkvg_line_cap_t. */ - vkvg_public void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap); /** diff --git a/src/cross_os.c b/src/cross_os.c index 3fcd6e8..41ec036 100644 --- a/src/cross_os.c +++ b/src/cross_os.c @@ -22,7 +22,6 @@ #include "cross_os.h" #include #include -//#include #define _CRT_SECURE_NO_WARNINGS diff --git a/src/recording/vkvg_record_internal.c b/src/recording/vkvg_record_internal.c index a3e31cb..29c91c9 100644 --- a/src/recording/vkvg_record_internal.c +++ b/src/recording/vkvg_record_internal.c @@ -123,6 +123,7 @@ void _record (vkvg_recording_t* rec,...) { if ((cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { switch (r->cmd) { case VKVG_CMD_SET_LINE_WIDTH: + case VKVG_CMD_SET_MITER_LIMIT: STORE_FLOATS(1); break; case VKVG_CMD_SET_LINE_JOIN: @@ -280,6 +281,9 @@ void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index) { case VKVG_CMD_SET_LINE_WIDTH: vkvg_set_line_width (ctx, floats[0]); return; + case VKVG_CMD_SET_MITER_LIMIT: + vkvg_set_miter_limit (ctx, floats[0]); + return; case VKVG_CMD_SET_LINE_JOIN: vkvg_set_line_join (ctx, (vkvg_line_join_t)uints[0]); return; diff --git a/src/recording/vkvg_record_internal.h b/src/recording/vkvg_record_internal.h index 13e6b1a..c18801a 100644 --- a/src/recording/vkvg_record_internal.h +++ b/src/recording/vkvg_record_internal.h @@ -51,11 +51,12 @@ #define VKVG_CMD_ELLIPTICAL_ARC_TO (0x000C|VKVG_CMD_PATH_COMMANDS) #define VKVG_CMD_SET_LINE_WIDTH (0x0001|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_JOIN (0x0002|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_CAP (0x0003|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_OPERATOR (0x0004|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_FILL_RULE (0x0005|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_DASH (0x0006|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_MITER_LIMIT (0x0002|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_JOIN (0x0003|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_CAP (0x0004|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_OPERATOR (0x0005|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_FILL_RULE (0x0006|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_DASH (0x0007|VKVG_CMD_PATHPROPS_COMMANDS) #define VKVG_CMD_TRANSLATE (0x0001|VKVG_CMD_TRANSFORM_COMMANDS) #define VKVG_CMD_ROTATE (0x0002|VKVG_CMD_TRANSFORM_COMMANDS) diff --git a/src/vkvg_context.c b/src/vkvg_context.c index c0ae0bf..3a2b92a 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -44,6 +44,7 @@ static VkClearValue clearValues[3] = { void _init_ctx (VkvgContext ctx) { ctx->lineWidth = 1; + ctx->miterLimit = 10; ctx->curOperator = VKVG_OPERATOR_OVER; ctx->curFillRule = VKVG_FILL_RULE_NON_ZERO; ctx->bounds = (VkRect2D) {{0,0},{ctx->pSurf->width,ctx->pSurf->height}}; @@ -827,8 +828,9 @@ void _stroke_preserve (VkvgContext ctx) LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); stroke_context_t str = {0}; + str.lhMax = ctx->miterLimit * ctx->lineWidth; uint32_t ptrPath = 0; - float hw = ctx->lineWidth / 2.0f; + float hw = ctx->lineWidth / 2.0f;//may be put in stroke ctx while (ptrPath < ctx->pathPtr){ uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; @@ -1037,6 +1039,10 @@ void vkvg_set_line_width (VkvgContext ctx, float width){ RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width); ctx->lineWidth = width; } +void vkvg_set_miter_limit (VkvgContext ctx, float limit){ + RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, limit); + ctx->miterLimit = limit; +} void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap){ RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap); ctx->lineCap = cap; @@ -1323,6 +1329,7 @@ void vkvg_save (VkvgContext ctx){ memcpy (sav->dashes, ctx->dashes, sizeof(float) * ctx->dashCount); } sav->lineWidth = ctx->lineWidth; + sav->miterLimit = ctx->miterLimit; sav->curOperator= ctx->curOperator; sav->lineCap = ctx->lineCap; sav->lineWidth = ctx->lineWidth; @@ -1456,6 +1463,7 @@ void vkvg_restore (VkvgContext ctx){ } ctx->lineWidth = sav->lineWidth; + ctx->miterLimit = sav->miterLimit; ctx->curOperator= sav->curOperator; ctx->lineCap = sav->lineCap; ctx->lineJoin = sav->lineJoint; diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 6e796bf..017e46d 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -908,10 +908,10 @@ bool _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t* str, bool is vec2 v1n = vec2_div_s (v1, length_v1); float dot = vec2_dot (v0n, v1n); float det = v0n.x * v1n.y - v0n.y * v1n.x; - if (EQUF(dot,1.0f)) + if (EQUF(dot,1.0f))//colinear return false; - if (EQUF(dot,-1.0f)) { + if (EQUF(dot,-1.0f)) {//cusp (could draw line butt?) vec2 vPerp = vec2_mult_s(vec2_perp (v0n), hw); VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); @@ -927,7 +927,7 @@ bool _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t* str, bool is } - vec2 bisec_n = vec2_norm(vec2_add(v0n,v1n)); + vec2 bisec_n = vec2_norm(vec2_add(v0n,v1n));//bisec/bisec_perp are inverted names float alpha = acosf(dot); @@ -980,9 +980,10 @@ bool _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t* str, bool is if (ctx->lineJoin == VKVG_LINE_JOIN_MITER || isCurve){ - if (dot < -0.95f && rlh < lh) { - double x = (lh - rlh) * cosf (halfAlpha); + if (lh > str->lhMax) {//miter limit + double x = (lh - str->lhMax) * cosf (halfAlpha); vec2 bisecPerp = vec2_mult_s (bisec_n, x); + bisec = vec2_mult_s (bisec_n_perp, str->lhMax); if (det < 0) { v.pos = rlh_inside_pos; _add_vertex(ctx, v); @@ -1015,7 +1016,7 @@ bool _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t* str, bool is return false; } - } else { + } else {//normal miter if (det < 0) { v.pos = rlh_inside_pos; _add_vertex(ctx, v); diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 19283b0..c6cc154 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -103,6 +103,7 @@ typedef struct _vkvg_context_save_t { struct _vkvg_context_save_t* pNext; float lineWidth; + float miterLimit; uint32_t dashCount; //value count in dash array, 0 if dash not set. float dashOffset; //an offset for dash float* dashes; //an array of alternate lengths of on and off stroke. @@ -197,6 +198,7 @@ typedef struct _vkvg_context_t { bool simpleConvex; //true if path is single rect or concave closed curve. float lineWidth; + float miterLimit; uint32_t dashCount; //value count in dash array, 0 if dash not set. float dashOffset; //an offset for dash float* dashes; //an array of alternate lengths of on and off stroke. @@ -246,6 +248,7 @@ typedef struct { uint32_t cp;//current point VKVG_IBO_INDEX_TYPE firstIdx;//save first point idx for closed path + float lhMax//miter limit * line width }stroke_context_t; void _check_vertex_cache_size (VkvgContext ctx); diff --git a/tests/inverse_colinear.c b/tests/inverse_colinear.c index 47146fb..f239ba6 100644 --- a/tests/inverse_colinear.c +++ b/tests/inverse_colinear.c @@ -29,6 +29,7 @@ double pointSize = 7; float dash[] = {0, 60}; uint32_t dashCountInit = 2; uint32_t dashCount = 0; +float miterLimit = 10.0f; @@ -38,10 +39,11 @@ void draw (){ vkvg_clear(ctx); if (dashCount > 0) vkvg_set_dash(ctx, dash, dashCount,0); - vkvg_set_source_rgba(ctx,1,0,0,1); - vkvg_set_line_width(ctx,lineWidth); - vkvg_set_line_join (ctx, lineJoin); - vkvg_set_line_cap (ctx, lineCap); + vkvg_set_source_rgba (ctx,1,0,0,1); + vkvg_set_line_width (ctx,lineWidth); + vkvg_set_line_join (ctx, lineJoin); + vkvg_set_line_cap (ctx, lineCap); + vkvg_set_miter_limit (ctx, miterLimit); if (startWithArc) vkvg_arc_negative(ctx,pts[0].x,pts[0].y,200, M_PIF*1.5f, M_PIF); @@ -112,6 +114,12 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, else dash[0] = 80; break; + case GLFW_KEY_L : + if (mods & GLFW_MOD_SHIFT) + miterLimit /= 2.0f; + else + miterLimit *= 2.0f; + break; case GLFW_KEY_KP_ADD : if (ptsCount < initPtsCount) ptsCount++;