From: Jean-Philippe Bruyère Date: Sat, 11 Dec 2021 04:11:15 +0000 (+0100) Subject: move internal stroke func and struct to vkvg_context_internal X-Git-Tag: v0.2.0~35 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=f599ac7967995dc2d953f9f1f8e51d97b7ea95fb;p=jp%2Fvkvg.git move internal stroke func and struct to vkvg_context_internal --- diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 91d689b..d87c41a 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -673,124 +673,6 @@ void vkvg_fill_preserve (VkvgContext ctx){ _ensure_renderpass_is_started(ctx); _fill_ec(ctx); } -void _draw_stoke_cap (VkvgContext ctx, float hw, vec2 p0, vec2 n, bool isStart) { - Vertex v = {{0},ctx->curColor,{0,0,-1}}; - - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - if (isStart){ - vec2 vhw = vec2_mult(n,hw); - - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_sub(p0, vhw); - - vhw = vec2_perp(vhw); - - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - float step = M_PIF / fmaxf(hw, 4.f); - float a = acosf(n.x) + M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a + M_PIF; - - a+=step; - while (a < a1){ - _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); - a+=step; - } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) - _add_triangle_indices(ctx, p0Idx+1, p, p+1); - firstIdx = p0Idx; - } - - v.pos = vec2_add(p0, vhw); - _add_vertex(ctx, v); - v.pos = vec2_sub(p0, vhw); - _add_vertex(ctx, v); - - _add_tri_indices_for_rect(ctx, firstIdx); - }else{ - vec2 vhw = vec2_mult(n, hw); - - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_add(p0, vhw); - - vhw = vec2_perp(vhw); - - v.pos = vec2_add(p0, vhw); - _add_vertex(ctx, v); - v.pos = vec2_sub(p0, vhw); - _add_vertex(ctx, v); - - firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - float step = M_PIF / fmaxf(hw, 4.f); - float a = acosf(n.x)+ M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a - M_PIF; - - a-=step; - while ( a > a1){ - _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); - a-=step; - } - - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); - for (VKVG_IBO_INDEX_TYPE p = firstIdx-1 ; p < p0Idx; p++) - _add_triangle_indices(ctx, p+1, p, firstIdx-2); - } - } -} - -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); - dc->normal = vec2_norm (d); - float segmentLength = vec2_length(d); - - while (dc->curDashOffset < segmentLength){ - vec2 p0 = vec2_add (p, vec2_mult(dc->normal, dc->curDashOffset)); - - _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; - } - dc->curDashOffset -= segmentLength; - dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); - return segmentLength; -} - - - -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, dc, ctx->points[str->iL], ctx->points[str->cp], ctx->points[str->iR], isCurve); - else - _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) { @@ -870,7 +752,11 @@ void vkvg_stroke_preserve (VkvgContext ctx) if (ctx->dashCount > 0) { if (_path_is_closed(ctx,ptrPath)){ str.iR = firstPathPointIdx; - _draw_dashed_segment(ctx, hw, &dc, ctx->points[str.iL++], ctx->points[str.cp++], ctx->points[str.iR], false); + + _draw_dashed_segment(ctx, hw, &str, &dc, false); + + str.iL++; + str.cp++; } if (!dc.dashOn){ //finishing last dash that is already started, draw end caps but not too close to start @@ -884,7 +770,7 @@ void vkvg_stroke_preserve (VkvgContext ctx) } } else if (_path_is_closed(ctx,ptrPath)){ str.iR = firstPathPointIdx; - float cross = _build_vb_step (ctx, hw, ctx->points[str.iL], ctx->points[str.cp], ctx->points[str.iR], false); + float cross = _build_vb_step (ctx, hw, &str, false); VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache [ctx->indCount-6]; VKVG_IBO_INDEX_TYPE ii = firstIdx; diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 2cef1ad..bd1593b 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -737,8 +737,11 @@ void _init_descriptor_sets (VkvgContext ctx){ VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad)); } //populate vertice buff for stroke -float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bool isCurve){ +float _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t* str, bool isCurve){ Vertex v = {{0},ctx->curColor, {0,0,-1}}; + vec2 pL = ctx->points[str->iL]; + vec2 p0 = ctx->points[str->cp]; + vec2 pR = ctx->points[str->iR]; vec2 v0 = vec2_sub(p0, pL); vec2 v1 = vec2_sub(pR, p0); @@ -762,7 +765,7 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo 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))); + //lh=fminf (lh, fminf (sqrtf(length_v0*length_v0+hw*hw), sqrtf(length_v1*length_v1+hw*hw))); vec2 bisec = vec2_mult(bisec_n,lh); @@ -823,7 +826,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 (det<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); @@ -838,11 +841,13 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo } vp = vec2_mult (vec2_perp(v1n), hw); - if (det<0) + if (det < 0) v.pos = vec2_sub (p0, vp); else v.pos = vec2_add (p0, vp); _add_vertex(ctx, v); + str->has_prev_v0n = true; + str->prev_v0n = v0n; } /* @@ -861,6 +866,111 @@ float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bo return det; } +void _draw_stoke_cap (VkvgContext ctx, float hw, vec2 p0, vec2 n, bool isStart) { + Vertex v = {{0},ctx->curColor,{0,0,-1}}; + + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + if (isStart){ + vec2 vhw = vec2_mult(n,hw); + + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_sub(p0, vhw); + + vhw = vec2_perp(vhw); + + if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ + float step = M_PIF / fmaxf(hw, 4.f); + float a = acosf(n.x) + M_PIF_2; + if (n.y < 0) + a = M_PIF-a; + float a1 = a + M_PIF; + + a+=step; + while (a < a1){ + _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); + a+=step; + } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) + _add_triangle_indices(ctx, p0Idx+1, p, p+1); + firstIdx = p0Idx; + } + + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); + + _add_tri_indices_for_rect(ctx, firstIdx); + }else{ + vec2 vhw = vec2_mult(n, hw); + + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_add(p0, vhw); + + vhw = vec2_perp(vhw); + + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); + + firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + + if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ + float step = M_PIF / fmaxf(hw, 4.f); + float a = acosf(n.x)+ M_PIF_2; + if (n.y < 0) + a = M_PIF-a; + float a1 = a - M_PIF; + + a-=step; + while ( a > a1){ + _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y); + a-=step; + } + + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); + for (VKVG_IBO_INDEX_TYPE p = firstIdx-1 ; p < p0Idx; p++) + _add_triangle_indices(ctx, p+1, p, firstIdx-2); + } + } +} +float _draw_dashed_segment (VkvgContext ctx, float hw, stroke_context_t* str, dash_context_t* dc, bool isCurve) { + //vec2 pL = ctx->points[str->iL]; + vec2 p = ctx->points[str->cp]; + vec2 pR = ctx->points[str->iR]; + + if (!dc->dashOn)//we test in fact the next dash start, if dashOn = true => next segment is a void. + _build_vb_step (ctx, hw, str, isCurve); + + vec2 d = vec2_sub (pR, p); + dc->normal = vec2_norm (d); + float segmentLength = vec2_length(d); + + while (dc->curDashOffset < segmentLength){ + vec2 p0 = vec2_add (p, vec2_mult(dc->normal, dc->curDashOffset)); + + _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; + } + dc->curDashOffset -= segmentLength; + dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); + return segmentLength; +} +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, str, dc, isCurve); + else + _build_vb_step (ctx, hw, str, isCurve); + str->iL = str->cp++; +} + bool ptInTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) { float dX = p.x-p2.x; float dY = p.y-p2.y; diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 9c6f962..1fa7830 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -191,6 +191,23 @@ typedef struct _ear_clip_point{ struct _ear_clip_point* next; }ear_clip_point; +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 iR2; + uint32_t cp;//current point + bool has_prev_v0n;//true if set + vec2 prev_v0n;//store previous left normal for path correction +}stroke_context_t; + void _check_vertex_cache_size(VkvgContext ctx); void _resize_vertex_cache (VkvgContext ctx, uint32_t newSize); void _check_index_cache_size(VkvgContext ctx); @@ -213,6 +230,10 @@ void _add_point (VkvgContext ctx, float x, float y); void _resetMinMax (VkvgContext ctx); +void _draw_stoke_cap (VkvgContext ctx, float hw, vec2 p0, vec2 n, bool isStart); +void _draw_segment (VkvgContext ctx, float hw, stroke_context_t* str, dash_context_t* dc, bool isCurve); +float _draw_dashed_segment (VkvgContext ctx, float hw, stroke_context_t *str, dash_context_t* dc, bool isCurve); + void _poly_fill (VkvgContext ctx); void _fill_ec (VkvgContext ctx);//earclipping fill void _draw_full_screen_quad (VkvgContext ctx, bool useScissor); @@ -224,7 +245,8 @@ void _add_vertexf (VkvgContext ctx, float x, float y); void _set_vertex (VkvgContext ctx, uint32_t idx, Vertex v); void _add_triangle_indices (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); -float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bool isCurve); +float _build_vb_step (vkvg_context* ctx, float hw, stroke_context_t *str, bool isCurve); + void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height); void _bind_draw_pipeline (VkvgContext ctx); diff --git a/tests/inverse_colinear.c b/tests/inverse_colinear.c new file mode 100644 index 0000000..5799aec --- /dev/null +++ b/tests/inverse_colinear.c @@ -0,0 +1,148 @@ +#include "test.h" +#include "vectors.h" + +vkvg_fill_rule_t fillrule = VKVG_FILL_RULE_NON_ZERO; +static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; +float lineWidth = 50.0f; +vkvg_line_join_t lineJoin = VKVG_LINE_JOIN_MITER; +vkvg_line_cap_t lineCap = VKVG_LINE_CAP_BUTT; +bool isClosed = false; + +int ptsCount = 4; +int initPtsCount = 4; +vec2 pts[] = { + {150,150}, + {200,300}, + {250,150}, + {280,350}, +}; +int hoverPt = -1; +double pointSize = 7; + + +void draw (){ + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + vkvg_set_source_rgba(ctx,1,0,0,1); + vkvg_set_line_width(ctx,lineWidth); + vkvg_set_line_join (ctx, line_join); + vkvg_move_to(ctx,pts[0].x,pts[0].y); + for (int i=1; i=0) { + vkvg_stroke_preserve(ctx); + vkvg_set_line_width(ctx,2); + vkvg_set_source_rgba(ctx,0,0,0,1); + vkvg_stroke(ctx); + vkvg_set_source_rgba(ctx,0.5f,0.5f,1.0f,0.7f); + vkvg_arc(ctx, pts[hoverPt].x, pts[hoverPt].y, pointSize, 0, M_PIF*2); + vkvg_fill_preserve(ctx); + vkvg_stroke(ctx); + } else + vkvg_stroke(ctx); + + //draw_v(ctx, 200, 20, VKVG_LINE_JOIN_BEVEL); + //draw_v(ctx, 300, 80, VKVG_LINE_JOIN_ROUND); + vkvg_destroy(ctx); +} +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + switch (key) { + case GLFW_KEY_ESCAPE : + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_C : + isClosed ^= true; + break; + case GLFW_KEY_KP_ADD : + if (ptsCount < initPtsCount) + ptsCount++; + break; + case GLFW_KEY_KP_SUBTRACT : + if (ptsCount > 1) + ptsCount--; + break; + } +} +static void mouse_move_callback(GLFWwindow* window, double x, double y){ + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt].x = x; + pts[hoverPt].y = y; + } else { + for (int i=0; i pts[i].x - pointSize && + x < pts[i].x + pointSize && + y > pts[i].y - pointSize && + y < pts[i].y + pointSize) { + hoverPt = i; + return; + } + } + hoverPt = -1; + } +} +static void scroll_callback(GLFWwindow* window, double x, double y){ + if (y<0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; +} +static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; +} + + + +int main(int argc, char* argv[]) { + _parse_args (argc, argv); + VkEngine e; + e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + + VkhPresenter r = e->renderer; + vkengine_set_key_callback (e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); + + bool deferredResolve = false; + + device = vkvg_device_create_from_vk_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, samples, deferredResolve); + surf = vkvg_surface_create(device, test_width, test_height); + + vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + + while (!vkengine_should_close (e)) { + glfwPollEvents(); + + draw (); + + if (!vkh_presenter_draw (r)){ + vkh_presenter_get_size (r, &test_width, &test_height); + vkvg_surface_destroy (surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); + + vkvg_surface_destroy (surf); + + vkvg_device_destroy (device); + + vkengine_destroy (e); + + return 0; +}