From ab42b56c7155f5a1f0745b8e30ffdc1d2535f547 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sat, 11 Dec 2021 03:53:24 +0100 Subject: [PATCH] stroke context and dash context instead of static vars, radial gradient in ctx internal --- src/vectors.h | 7 ++ src/vkvg_context.c | 129 +++++++++++++++++++----------------- src/vkvg_context_internal.c | 48 ++++++++------ src/vkvg_device_internal.c | 2 +- tests/common/test.h | 1 + 5 files changed, 105 insertions(+), 82 deletions(-) diff --git a/src/vectors.h b/src/vectors.h index 0886198..872c2ee 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -174,6 +174,13 @@ vkvg_inline bool vec2d_isnan (vec2d v){ vkvg_inline float vec2_dot (vec2 a, vec2 b) { return (a.x * b.x) + (a.y * b.y); } +vkvg_inline float vec2_det (vec2 a, vec2 b) { + return a.x * b.y - a.y * b.x; +} +vkvg_inline float vec2_slope (vec2 a, vec2 b) { + return (b.y - a.y) / (b.x - a.x); +} + vkvg_inline bool vec4_equ (vec4 a, vec4 b){ return (EQUF(a.x,b.x)&EQUF(a.y,b.y)&EQUF(a.z,b.z)&EQUF(a.w,b.w)); diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 674a031..91d689b 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -745,41 +745,51 @@ void _draw_stoke_cap (VkvgContext ctx, float hw, vec2 p0, vec2 n, bool isStart) } } -static bool dashOn = true; -static uint32_t curDash = 0; //current dash index -static float curDashOffset = 0.f; //cur dash offset between defined path point and last dash segment(on/off) start -static float totDashLength = 0; //total length of dashes -static vec2 normal = {0}; - -float _draw_dashed_segment (VkvgContext ctx, float hw, vec2 pL, vec2 p, vec2 pR, bool isCurve) { - if (!dashOn)//we test in fact the next dash start, if dashOn = true => next segment is a void. +typedef struct { + bool dashOn; + uint32_t curDash; //current dash index + float curDashOffset; //cur dash offset between defined path point and last dash segment(on/off) start + float totDashLength; //total length of dashes + vec2 normal; +}dash_context_t; + +typedef struct { + uint32_t iL; + uint32_t iR; + uint32_t cp;//current point +}stroke_context_t; + +float _draw_dashed_segment (VkvgContext ctx, float hw, dash_context_t* dc, vec2 pL, vec2 p, vec2 pR, bool isCurve) { + if (!dc->dashOn)//we test in fact the next dash start, if dashOn = true => next segment is a void. _build_vb_step (ctx, hw, pL, p, pR, isCurve); vec2 d = vec2_sub (pR, p); - normal = vec2_norm (d); + dc->normal = vec2_norm (d); float segmentLength = vec2_length(d); - while (curDashOffset < segmentLength){ - vec2 p0 = vec2_add (p, vec2_mult(normal, curDashOffset)); + while (dc->curDashOffset < segmentLength){ + vec2 p0 = vec2_add (p, vec2_mult(dc->normal, dc->curDashOffset)); - _draw_stoke_cap (ctx, hw, p0, normal, dashOn); - dashOn ^= true; - curDashOffset += ctx->dashes[curDash]; - if (++curDash == ctx->dashCount) - curDash = 0; + _draw_stoke_cap (ctx, hw, p0, dc->normal, dc->dashOn); + dc->dashOn ^= true; + dc->curDashOffset += ctx->dashes[dc->curDash]; + if (++dc->curDash == ctx->dashCount) + dc->curDash = 0; } - curDashOffset -= segmentLength; - curDashOffset = fmodf(curDashOffset, totDashLength); + dc->curDashOffset -= segmentLength; + dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); return segmentLength; } -static uint32_t curPathPointIdx, lastPathPointIdx, ptrPath, iL, iR; -void _draw_segment (VkvgContext ctx, float hw, bool isCurve) { - iR = curPathPointIdx+1; + + + +void _draw_segment (VkvgContext ctx, float hw, stroke_context_t* str, dash_context_t* dc, bool isCurve) { + str->iR = str->cp + 1; if (ctx->dashCount > 0) - _draw_dashed_segment(ctx, hw, ctx->points[iL], ctx->points[curPathPointIdx], ctx->points[iR], isCurve); + _draw_dashed_segment(ctx, hw, dc, ctx->points[str->iL], ctx->points[str->cp], ctx->points[str->iR], isCurve); else - _build_vb_step (ctx, hw, ctx->points[iL], ctx->points[curPathPointIdx], ctx->points[iR], isCurve); - iL = curPathPointIdx++; + _build_vb_step (ctx, hw, ctx->points[str->iL], ctx->points[str->cp], ctx->points[str->iR], isCurve); + str->iL = str->cp++; } void vkvg_stroke_preserve (VkvgContext ctx) @@ -794,18 +804,21 @@ void vkvg_stroke_preserve (VkvgContext ctx) LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); - curPathPointIdx = lastPathPointIdx = ptrPath = iL = iR = 0; + stroke_context_t str = {0}; + uint32_t ptrPath = 0; float hw = ctx->lineWidth / 2.0f; while (ptrPath < ctx->pathPtr){ uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; - uint32_t firstPathPointIdx = curPathPointIdx; + uint32_t firstPathPointIdx = str.cp; uint32_t pathPointCount = ctx->pathes[ptrPath]&PATH_ELT_MASK; - lastPathPointIdx = curPathPointIdx + pathPointCount - 1; + uint32_t lastPathPointIdx = str.cp + pathPointCount - 1; + + dash_context_t dc = {0}; if (_path_has_curves (ctx,ptrPath)) { ptrSegment = 1; - lastSegmentPointIdx = curPathPointIdx + (ctx->pathes[ptrPath+ptrSegment]&PATH_ELT_MASK)-1; + lastSegmentPointIdx = str.cp + (ctx->pathes[ptrPath+ptrSegment]&PATH_ELT_MASK)-1; } VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); @@ -815,65 +828,63 @@ void vkvg_stroke_preserve (VkvgContext ctx) if (ctx->dashCount > 0) { //init dash stroke - dashOn = true; - curDash = 0; //current dash index - - //limit offset to total length of dashes - totDashLength = 0; + dc.dashOn = true; + dc.curDash = 0; //current dash index + dc.totDashLength = 0;//limit offset to total length of dashes for (uint32_t i=0;idashCount;i++) - totDashLength += ctx->dashes[i]; - if (totDashLength == 0){ + dc.totDashLength += ctx->dashes[i]; + if (dc.totDashLength == 0){ ctx->status = VKVG_STATUS_INVALID_DASH; return; } - curDashOffset = fmodf(ctx->dashOffset, totDashLength); //cur dash offset between defined path point and last dash segment(on/off) start - iL = lastPathPointIdx; + dc.curDashOffset = fmodf(ctx->dashOffset, dc.totDashLength); //cur dash offset between defined path point and last dash segment(on/off) start + str.iL = lastPathPointIdx; } else if (_path_is_closed(ctx,ptrPath)){ - iL = lastPathPointIdx; + str.iL = lastPathPointIdx; }else{ - _draw_stoke_cap(ctx, hw, ctx->points[curPathPointIdx], vec2_line_norm(ctx->points[curPathPointIdx], ctx->points[curPathPointIdx+1]), true); - iL = curPathPointIdx++; + _draw_stoke_cap(ctx, hw, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp], ctx->points[str.cp+1]), true); + str.iL = str.cp++; } if (_path_has_curves (ctx,ptrPath)) { - while (curPathPointIdx < lastPathPointIdx){ + while (str.cp < lastPathPointIdx){ bool curved = ctx->pathes [ptrPath + ptrSegment] & PATH_HAS_CURVES_BIT; if (lastSegmentPointIdx == lastPathPointIdx)//last segment of path, dont draw end point here lastSegmentPointIdx--; - while (curPathPointIdx <= lastSegmentPointIdx) - _draw_segment(ctx, hw, curved); + while (str.cp <= lastSegmentPointIdx) + _draw_segment(ctx, hw, &str, &dc, curved); ptrSegment ++; uint32_t cptSegPts = ctx->pathes [ptrPath + ptrSegment]&PATH_ELT_MASK; - lastSegmentPointIdx = curPathPointIdx + cptSegPts - 1; + lastSegmentPointIdx = str.cp + cptSegPts - 1; if (lastSegmentPointIdx == lastPathPointIdx && cptSegPts == 1) { //single point last segment ptrSegment++; break; } } - }else while (curPathPointIdx < lastPathPointIdx) - _draw_segment(ctx, hw, false); + }else while (str.cp < lastPathPointIdx) + _draw_segment(ctx, hw, &str, &dc, false); if (ctx->dashCount > 0) { if (_path_is_closed(ctx,ptrPath)){ - iR = firstPathPointIdx; - _draw_dashed_segment(ctx, hw, ctx->points[iL++], ctx->points[curPathPointIdx++], ctx->points[iR], false); + str.iR = firstPathPointIdx; + _draw_dashed_segment(ctx, hw, &dc, ctx->points[str.iL++], ctx->points[str.cp++], ctx->points[str.iR], false); } - if (!dashOn){ + if (!dc.dashOn){ //finishing last dash that is already started, draw end caps but not too close to start //the default gap is the next void - int32_t prevDash = (int32_t)curDash-1; + int32_t prevDash = (int32_t)dc.curDash-1; if (prevDash < 0) - curDash = ctx->dashCount-1; - float m = fminf (ctx->dashes[prevDash] - curDashOffset, ctx->dashes[curDash]); - vec2 p = vec2_sub(ctx->points[iR], vec2_mult(normal, m)); - _draw_stoke_cap (ctx, hw, p, normal, false); + dc.curDash = ctx->dashCount-1; + float m = fminf (ctx->dashes[prevDash] - dc.curDashOffset, ctx->dashes[dc.curDash]); + vec2 p = vec2_sub(ctx->points[str.iR], vec2_mult(dc.normal, m)); + _draw_stoke_cap (ctx, hw, p, dc.normal, false); } } else if (_path_is_closed(ctx,ptrPath)){ - iR = firstPathPointIdx; - float cross = _build_vb_step (ctx, hw, ctx->points[iL], ctx->points[curPathPointIdx], ctx->points[iR], false); + str.iR = firstPathPointIdx; + float cross = _build_vb_step (ctx, hw, ctx->points[str.iL], ctx->points[str.cp], ctx->points[str.iR], false); VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache [ctx->indCount-6]; VKVG_IBO_INDEX_TYPE ii = firstIdx; @@ -886,11 +897,11 @@ void vkvg_stroke_preserve (VkvgContext ctx) inds[4] = ii; inds[5] = ii+1; } - curPathPointIdx++; + str.cp++; }else - _draw_stoke_cap (ctx, hw, ctx->points[curPathPointIdx], vec2_line_norm(ctx->points[curPathPointIdx-1], ctx->points[curPathPointIdx]), false); + _draw_stoke_cap (ctx, hw, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp-1], ctx->points[str.cp]), false); - curPathPointIdx = firstPathPointIdx + pathPointCount; + str.cp = firstPathPointIdx + pathPointCount; if (ptrSegment > 0) ptrPath += ptrSegment; diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 84e62e8..2cef1ad 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -453,17 +453,18 @@ void _emit_draw_cmd_undrawn_vertices (VkvgContext ctx){ _check_vao_size(ctx); _ensure_renderpass_is_started(ctx); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - - LOG(VKVG_LOG_INFO, "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", - ctx, ctx->vertCount - ctx->curVertOffset, - ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, ctx->indCount); #ifdef VKVG_WIRED_DEBUG CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); + //CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); +#else + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + #endif + LOG(VKVG_LOG_INFO, "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", + ctx, ctx->vertCount - ctx->curVertOffset, + ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, ctx->indCount); ctx->curIndStart = ctx->indCount; ctx->curVertOffset = ctx->vertCount; @@ -644,6 +645,7 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { break; } case VKVG_PATTERN_TYPE_LINEAR: + case VKVG_PATTERN_TYPE_RADIAL: _flush_cmd_buff (ctx); if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) @@ -747,22 +749,23 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo vec2 v0n = vec2_div (v0, length_v0); vec2 v1n = vec2_div (v1, length_v1); - vec2 bisec = vec2_norm(vec2_add(v0n,v1n)); + vec2 bisec_n = vec2_norm(vec2_add(v0n,v1n)); - float dot = v0n.x * v1n.x + v0n.y * v1n.y; - float alpha = acosf(dot)/2; - float cross = v0n.x * v1n.y - v0n.y * v1n.x; + float dot = vec2_dot (v0n, v1n); + float alpha = acosf(dot); + float det = v0n.x * v1n.y - v0n.y * v1n.x; - if (cross<0) + if (det<0) alpha = -alpha; - float lh = hw / cosf(alpha); - bisec = vec2_perp(bisec); + float lh = hw / cosf(alpha/2); + bisec_n = vec2_perp(bisec_n); //limit bisectrice length, may be improved but ok for perf lh=fminf (lh, fminf (sqrtf(length_v0*length_v0+hw*hw), sqrtf(length_v1*length_v1+hw*hw))); - bisec = vec2_mult(bisec,lh); + + vec2 bisec = vec2_mult(bisec_n,lh); VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); @@ -772,9 +775,10 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo v.pos = vec2_sub(p0, bisec); _add_vertex(ctx, v); _add_tri_indices_for_rect(ctx, idx); + }else{ vec2 vp = vec2_perp(v0n); - if (cross<0){ + if (det<0){ v.pos = vec2_add (p0, bisec); _add_vertex(ctx, v); v.pos = vec2_sub (p0, vec2_mult (vp, hw)); @@ -786,7 +790,7 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo _add_vertex(ctx, v); if (ctx->lineJoin == VKVG_LINE_JOIN_BEVEL){ - if (cross<0){ + if (det<0){ _add_triangle_indices(ctx, idx, idx+2, idx+1); _add_triangle_indices(ctx, idx+2, idx+4, idx+0); _add_triangle_indices(ctx, idx, idx+3, idx+4); @@ -801,16 +805,16 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo if (vp.y < 0) a = -a; - if (cross<0){ + if (det<0){ a+=M_PIF; - float a1 = a + alpha*2; + float a1 = a + alpha; a-=step; while (a > a1){ _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); a-=step; } }else{ - float a1 = a + alpha*2; + float a1 = a + alpha; a+=step; while (a < a1){ _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); @@ -819,7 +823,7 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo } VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); _add_triangle_indices(ctx, idx, idx+2, idx+1); - if (cross<0){ + if (det<0){ for (VKVG_IBO_INDEX_TYPE p = idx+2; p < p0Idx; p++) _add_triangle_indices(ctx, p, p+1, idx); _add_triangle_indices(ctx, p0Idx, p0Idx+2, idx); @@ -834,7 +838,7 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo } vp = vec2_mult (vec2_perp(v1n), hw); - if (cross<0) + if (det<0) v.pos = vec2_sub (p0, vp); else v.pos = vec2_add (p0, vp); @@ -854,7 +858,7 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo debugLinePoints[dlpCount+1] = pR; dlpCount+=2; #endif*/ - return cross; + return det; } bool ptInTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) { diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index 602323e..af2e1df 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -375,7 +375,7 @@ void _setupPipelines(VkvgDevice dev) VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFragWired)); shaderStages[1].module = modFragWired; - inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineWired)); vkDestroyShaderModule(dev->vkDev, modFragWired, NULL); diff --git a/tests/common/test.h b/tests/common/test.h index 58fe95f..40afb80 100644 --- a/tests/common/test.h +++ b/tests/common/test.h @@ -101,6 +101,7 @@ extern float dashes[]; extern uint32_t dashes_count; VkvgContext _initCtx(); +void _parse_args (int argc, char* argv[]); /*******************************/ //run test in one step -- 2.47.3