_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)
{
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
}
} 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;
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);
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);
}
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);
}
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;
}
/*
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;
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);
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);
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);
--- /dev/null
+#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<ptsCount; i++)
+ vkvg_line_to(ctx,pts[i].x,pts[i].y);
+ if (isClosed)
+ vkvg_close_path(ctx);
+
+ if (hoverPt>=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<ptsCount; i++) {
+ if (x > 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;
+}