<br>
<p align="center">
<a href="https://travis-ci.org/jpbruyere/vkvg">
- <img src="https://travis-ci.org/jpbruyere/vkvg.svg?branch=master">
+ <img src="https://img.shields.io/travis/jpbruyere/vkvg.svg?label=Linux&logo=travis&logoColor=white&message=build">
</a>
<a href="https://ci.appveyor.com/project/jpbruyere/vkvg">
- <img src="https://ci.appveyor.com/api/projects/status/github/jpbruyere/vkvg?branch=master&svg=true">
+ <img src="https://img.shields.io/appveyor/ci/jpbruyere/vkvg?label=Win64&logo=appveyor&logoColor=lightgrey">
</a>
<img src="https://img.shields.io/github/license/jpbruyere/vkvg.svg?style=flat-square">
<a href="https://www.paypal.me/GrandTetraSoftware">
</p>
</h1>
-### What is vkvg?
-**vkvg** is a multiplatform **c** library for drawing 2D vector graphics with [Vulkan](https://www.khronos.org/vulkan/). It's api follows the same pattern as [Cairo](https://www.cairographics.org/), but new functions and original drawing mechanics may be added.
+**vkvg** is an open source *2D graphics library* written in **c** using [Vulkan](https://www.khronos.org/vulkan/) as backend. It's **api** follows the same pattern as [Cairo](https://www.cairographics.org/), but new functions and original drawing mechanics may be added.
**vkvg** is in early development stage, api may change, any contribution is welcome.
-For API documentation and usage, please refer to the [Cairo](https://www.cairographics.org/) documentation.
+For API documentation and usage, please refer to the [Cairo](https://www.cairographics.org/) documentation for now.
### Current status:
### Requirements:
+- [CMake](https://cmake.org/): version > 12.
- [Vulkan](https://www.khronos.org/vulkan/)
- [FontConfig](https://www.freedesktop.org/wiki/Software/fontconfig/)
- [Freetype](https://www.freetype.org/)
-- PkgConfig (currently used only to find harbfbuzz)
- [Harfbuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/)
- GLSLC: spirv compiler, included in [LunarG SDK](https://www.lunarg.com/vulkan-sdk/) (building only)
- [xxd](https://linux.die.net/man/1/xxd): generate headers with precompiled shaders (building only)
-- [GLFW](http://www.glfw.org/) (only for running demo app)
-- CMake
+- [GLFW](http://www.glfw.org/): optional, if present tests are built.
-if glslc or xxd are not present, a precompiled version of the shaders is stored in the git tree.
+if `glslc` or `xxd` are not present, a precompiled version of the shaders is stored in the git tree.
### Building
v.uv.z = -1;
float hw = ctx->lineWidth / 2.0f;
- uint32_t i = 0, ptrPath = 0;
-
- uint32_t lastPathPointIdx, iL, iR;
+ uint32_t firstPathPointIdx = 0, lastPathPointIdx, ptrPath = 0, iL, iR;
while (ptrPath < ctx->pathPtr){
uint32_t ptrCurve = 0;
VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset);
- i = ctx->pathes[ptrPath]&PATH_ELT_MASK;
+ firstPathPointIdx = ctx->pathes[ptrPath]&PATH_ELT_MASK;
LOG(LOG_INFO_PATH, "\tPATH: start = %d; ", ctx->pathes[ptrPath]&PATH_ELT_MASK, ctx->pathes[ptrPath+1]&PATH_ELT_MASK);
LOG(LOG_INFO_PATH, "end = %d\n", lastPathPointIdx);
//prevent closing on the same position, this could be generalize
//to prevent processing of two consecutive point at the same position
- if (vec2_equ(ctx->points[i], ctx->points[lastPathPointIdx]))
+ if (vec2_equ(ctx->points[firstPathPointIdx], ctx->points[lastPathPointIdx]))
lastPathPointIdx--;
iL = lastPathPointIdx;
}else{
lastPathPointIdx = ctx->pathes[ptrPath+1]&PATH_ELT_MASK;
LOG(LOG_INFO_PATH, "end = %d\n", lastPathPointIdx);
- vec2 n = vec2_line_norm(ctx->points[i], ctx->points[i+1]);
+ vec2 n = vec2_line_norm(ctx->points[firstPathPointIdx], ctx->points[firstPathPointIdx+1]);
- vec2 p0 = ctx->points[i];
+ vec2 p0 = ctx->points[firstPathPointIdx];
vec2 vhw = vec2_mult(n,hw);
if (ctx->lineCap == VKVG_LINE_CAP_SQUARE)
_add_tri_indices_for_rect(ctx, firstIdx);
- iL = i++;
+ iL = firstPathPointIdx++;
}
if (_path_has_curves (ctx,ptrPath)) {
- while (i < lastPathPointIdx){
- if (ptrPath + ptrCurve + 2 < ctx->pathPtr && (ctx->pathes [ptrPath + 2 + ptrCurve]&PATH_ELT_MASK) == i){
- uint32_t lastCurvePoint = ctx->pathes[ptrPath + 3 + ptrCurve]&PATH_ELT_MASK;
- while (i<lastCurvePoint){
- iR = i+1;
- _build_vb_step (ctx, v, hw, iL, i, iR, true);
- iL = i++;
+ while (firstPathPointIdx < lastPathPointIdx){
+ if (ptrPath + ptrCurve + 2 < ctx->pathPtr && (ctx->pathes [ptrPath + 2 + ptrCurve]&PATH_ELT_MASK) == firstPathPointIdx){
+ uint32_t lastCurvePointIdx = ctx->pathes[ptrPath + 3 + ptrCurve]&PATH_ELT_MASK;
+ while (firstPathPointIdx < lastCurvePointIdx){
+ iR = firstPathPointIdx+1;
+ _build_vb_step (ctx, v, hw, ctx->points[iL], ctx->points[firstPathPointIdx], ctx->points[iR], true);
+ iL = firstPathPointIdx++;
}
ptrCurve += 2;
}else{
- iR = i+1;
- _build_vb_step (ctx, v, hw, iL, i, iR, false);
- iL = i++;
+ iR = firstPathPointIdx+1;
+ _build_vb_step (ctx, v, hw, ctx->points[iL], ctx->points[firstPathPointIdx], ctx->points[iR], false);
+ iL = firstPathPointIdx++;
}
}
}else{
- while (i < lastPathPointIdx){
- iR = i+1;
- _build_vb_step(ctx,v,hw,iL,i,iR, false);
- iL = i++;
+ while (firstPathPointIdx < lastPathPointIdx){
+ iR = firstPathPointIdx+1;
+ _build_vb_step (ctx, v, hw, ctx->points[iL], ctx->points[firstPathPointIdx], ctx->points[iR], false);
+ iL = firstPathPointIdx++;
}
}
if (!_path_is_closed(ctx,ptrPath)){
- vec2 n = vec2_line_norm(ctx->points[i-1], ctx->points[i]);
- vec2 p0 = ctx->points[i];
+ vec2 n = vec2_line_norm(ctx->points[firstPathPointIdx-1], ctx->points[firstPathPointIdx]);
+ vec2 p0 = ctx->points[firstPathPointIdx];
vec2 vhw = vec2_mult(n, hw);
if (ctx->lineCap == VKVG_LINE_CAP_SQUARE)
_add_triangle_indices(ctx, p+1, p, firstIdx-2);
}
- i++;
+ firstPathPointIdx++;
}else{
iR = ctx->pathes[ptrPath] & PATH_ELT_MASK;
- float cross =_build_vb_step (ctx,v,hw,iL,i,iR, false);
+ float cross = _build_vb_step (ctx, v, hw, ctx->points[iL], ctx->points[firstPathPointIdx], ctx->points[iR], false);
VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache [ctx->indCount-6];
VKVG_IBO_INDEX_TYPE ii = firstIdx;
inds[4] = ii;
inds[5] = ii+1;
}
- i++;
+ firstPathPointIdx++;
}
ptrPath+=2+ptrCurve;
VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad));
}
-float _build_vb_step (vkvg_context* ctx, Vertex v, float hw, uint32_t iL, uint32_t i, uint32_t iR, bool isCurve){
+float _build_vb_step (vkvg_context* ctx, Vertex v, float hw, vec2 pL, vec2 p0, vec2 pR, bool isCurve){
//if two of the three points are equal, normal is null
- vec2 v0n = vec2_line_norm(ctx->points[iL], ctx->points[i]);
+ vec2 v0n = vec2_line_norm(pL, p0);
if (vec2_isnan(v0n))
return 0;
- vec2 v1n = vec2_line_norm(ctx->points[i], ctx->points[iR]);
+ vec2 v1n = vec2_line_norm(p0, pR);
if (vec2_isnan(v1n))
return 0;
VKVG_IBO_INDEX_TYPE idx = ctx->vertCount - ctx->curVertOffset;
if (ctx->lineJoin == VKVG_LINE_JOIN_MITER || isCurve){
- v.pos = vec2_add(ctx->points[i], bisec);
+ v.pos = vec2_add(p0, bisec);
_add_vertex(ctx, v);
- v.pos = vec2_sub(ctx->points[i], bisec);
+ 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){
- v.pos = vec2_add (ctx->points[i], bisec);
+ v.pos = vec2_add (p0, bisec);
_add_vertex(ctx, v);
- v.pos = vec2_sub (ctx->points[i], vec2_mult (vp, hw));
+ v.pos = vec2_sub (p0, vec2_mult (vp, hw));
}else{
- v.pos = vec2_add (ctx->points[i], vec2_mult (vp, hw));
+ v.pos = vec2_add (p0, vec2_mult (vp, hw));
_add_vertex(ctx, v);
- v.pos = vec2_sub (ctx->points[i], bisec);
+ v.pos = vec2_sub (p0, bisec);
}
_add_vertex(ctx, v);
float a1 = a + alpha*2;
a-=step;
while (a > a1){
- _add_vertexf(ctx, cosf(a) * hw + ctx->points[i].x, sinf(a) * hw + ctx->points[i].y);
+ _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y);
a-=step;
}
}else{
float a1 = a + alpha*2;
a+=step;
while (a < a1){
- _add_vertexf(ctx, cosf(a) * hw + ctx->points[i].x, sinf(a) * hw + ctx->points[i].y);
+ _add_vertexf(ctx, cosf(a) * hw + p0.x, sinf(a) * hw + p0.y);
a+=step;
}
}
vp = vec2_mult (vec2_perp(v1n), hw);
if (cross<0)
- v.pos = vec2_sub (ctx->points[i], vp);
+ v.pos = vec2_sub (p0, vp);
else
- v.pos = vec2_add (ctx->points[i], vp);
+ v.pos = vec2_add (p0, vp);
_add_vertex(ctx, v);
}
/*
#ifdef DEBUG
- debugLinePoints[dlpCount] = ctx->points[i];
- debugLinePoints[dlpCount+1] = _v2add(ctx->points[i], _vec2dToVec2(_v2Multd(v0n,10)));
+ debugLinePoints[dlpCount] = p0;
+ debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v0n,10)));
dlpCount+=2;
- debugLinePoints[dlpCount] = ctx->points[i];
- debugLinePoints[dlpCount+1] = _v2add(ctx->points[i], _vec2dToVec2(_v2Multd(v1n,10)));
+ debugLinePoints[dlpCount] = p0;
+ debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v1n,10)));
dlpCount+=2;
- debugLinePoints[dlpCount] = ctx->points[i];
- debugLinePoints[dlpCount+1] = ctx->points[iR];
+ debugLinePoints[dlpCount] = p0;
+ debugLinePoints[dlpCount+1] = pR;
dlpCount+=2;
#endif*/
return cross;
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, Vertex v, float hw, uint32_t iL, uint32_t i, uint32_t iR, bool isCurve);
+float _build_vb_step (vkvg_context* ctx, Vertex v, float hw, vec2 pL, vec2 p0, vec2 pR, bool isCurve);
+void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height);
void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height);
void _bind_draw_pipeline (VkvgContext ctx);