]> O.S.I.I.S - jp/vkvg.git/commitdiff
implement vkvg_set_miter_limit
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 2 Mar 2022 14:14:12 +0000 (15:14 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 2 Mar 2022 14:14:12 +0000 (15:14 +0100)
include/vkvg.h
src/cross_os.c
src/recording/vkvg_record_internal.c
src/recording/vkvg_record_internal.h
src/vkvg_context.c
src/vkvg_context_internal.c
src/vkvg_context_internal.h
tests/inverse_colinear.c

index 10d9eec78d0f99571b156f8c5740841df14d33af..c38b59f98450ea5f72e82eebac3597ddede20fe3 100644 (file)
@@ -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);
 /**
index 3fcd6e898801c8a01e08235f8be27690c783f45a..41ec036e3fceb8f76adc701b9d0a711484c9d070 100644 (file)
@@ -22,7 +22,6 @@
 #include "cross_os.h"
 #include <sys/types.h>
 #include <sys/stat.h>
-//#include <unistd.h>
 
 #define _CRT_SECURE_NO_WARNINGS
 
index a3e31cbb89b0fd7b2929a62426614a061ea826e6..29c91c9e51bed665b1fa47b59240424a46bd9b15 100644 (file)
@@ -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;
index 13e6b1a5e0172d4dcc6eea90da27126cdb68faa8..c18801ac7eb9925e90e8b24d6cb15588a709803b 100644 (file)
 #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)
index c0ae0bf3e5fcf7c3d318ee74dba4c20ebb569db1..3a2b92a0d32b517ac4a4a2ef9aa67cc692872c20 100644 (file)
@@ -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;
index 6e796bfbc9eed0bb3e5a37167c0accc770ef4669..017e46d19f622ec934b608c75c78301e0512dfb4 100644 (file)
@@ -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);
index 19283b0c5daab7cf8e58ec8cb30d5bcab2906dc4..c6cc1547cc3c0f87e2a97cddd16479a5314538f7 100644 (file)
@@ -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);
index 47146fb5894940882d2995accc21d1ea14f78782..f239ba64445c1b7aff9dec0a2c59263b2247a507 100644 (file)
@@ -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++;