VKVG_LINE_JOIN_BEVEL
} vkvg_line_join_t;
+typedef enum _vkvg_fill_rule {
+ VKVG_FILL_RULE_EVEN_ODD,
+ VKVG_FILL_RULE_NON_ZERO
+} vkvg_fill_rule_t;
+
typedef struct _vkvg_color_t{
float r;
float g;
void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y);
void vkvg_set_source (VkvgContext ctx, VkvgPattern pat);
void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op);
+void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr);
+
float vkvg_get_line_width (VkvgContext ctx);
vkvg_line_cap_t vkvg_get_line_cap (VkvgContext ctx);
vkvg_line_join_t vkvg_get_line_join (VkvgContext ctx);
vkvg_operator_t vkvg_get_operator (VkvgContext ctx);
+vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx);
VkvgPattern vkvg_get_source (VkvgContext ctx);
void vkvg_save (VkvgContext ctx);
ctx->lineWidth = 1;
ctx->pSurf = surf;
ctx->curOperator = VKVG_OPERATOR_OVER;
+ ctx->curFillRule = VKVG_FILL_RULE_EVEN_ODD;
push_constants pc = {
{.height=1},
vkvg_fill_preserve(ctx);
_clear_path(ctx);
}
-void _poly_fill (VkvgContext ctx){
- CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelinePolyFill);
-
- uint32_t ptrPath = 0;
- Vertex v = {};
- v.uv.z = -1;
-
- while (ptrPath < ctx->pathPtr){
- if (!_path_is_closed(ctx, ptrPath))
- ctx->pathes[ptrPath+1] = ctx->pathes[ptrPath];//close path by setting start and end equal
-
- uint32_t firstPtIdx = ctx->pathes[ptrPath];
- uint32_t lastPtIdx = _get_last_point_of_closed_path (ctx, ptrPath);
- uint32_t pathPointCount = lastPtIdx - ctx->pathes[ptrPath] + 1;
- uint32_t firstVertIdx = ctx->vertCount;
-
-
- for (int i = 0; i < pathPointCount; i++) {
- v.pos = ctx->points[i+firstPtIdx];
- _add_vertex(ctx, v);
- }
-
- LOG(LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, firstVertIdx, ctx->vertCount - firstVertIdx);
- CmdDraw (ctx->cmd, pathPointCount, 1, firstVertIdx ,0);
-
- ptrPath+=2;
- }
-}
void vkvg_clip_preserve (VkvgContext ctx){
if (ctx->pathPtr == 0) //nothing to fill
return;
if (ctx->pointCount * 4 > ctx->sizeIndices - ctx->indCount)//flush if vk buff is full
vkvg_flush(ctx);
- _check_cmd_buff_state(ctx);
- _poly_fill (ctx);
-
- CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineClipping);
+ if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){
+ _check_cmd_buff_state(ctx);
+ _poly_fill (ctx);
+ CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineClipping);
+ CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT);
+ }else{
+ _check_cmd_buff_state(ctx);
+ CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineClipping);
+ CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ _fill_ec(ctx);
+ CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT);
+ }
CmdDrawIndexed (ctx->cmd,6,1,0,0,0);
-
//should test current operator to bind correct pipeline
_bind_draw_pipeline (ctx);
CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
if (ctx->pointCount * 4 > ctx->sizeIndices - ctx->indCount)//flush if vk buff is full
vkvg_flush(ctx);
- _check_cmd_buff_state(ctx);
- _poly_fill (ctx);
- _bind_draw_pipeline (ctx);
- CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
- CmdDrawIndexed (ctx->cmd,6,1,0,0,0);
- CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){
+ _check_cmd_buff_state(ctx);
+ _poly_fill (ctx);
+ _bind_draw_pipeline (ctx);
+ CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ CmdDrawIndexed (ctx->cmd,6,1,0,0,0);
+ CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ }else{
+ //CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT);
+ _fill_ec(ctx);
+ //CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT);
+ }
}
void vkvg_stroke_preserve (VkvgContext ctx)
{
ctx->curOperator = op;
_bind_draw_pipeline (ctx);
}
+void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr){
+ ctx->curFillRule = fr;
+}
+vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx){
+ return ctx->curFillRule;
+}
float vkvg_get_line_width (VkvgContext ctx){
return ctx->lineWidth;
}
sav->curOperator= ctx->curOperator;
sav->lineCap = ctx->lineCap;
sav->lineWidth = ctx->lineWidth;
+ sav->curFillRule= ctx->curFillRule;
sav->selectedFont = ctx->selectedFont;
sav->selectedFont.fontFile = (char*)calloc(FONT_FILE_NAME_MAX_SIZE,sizeof(char));
ctx->lineWidth = sav->lineWidth;
ctx->curOperator= sav->curOperator;
ctx->lineCap = sav->lineCap;
- ctx->lineJoin = sav->lineJoint;
+ ctx->lineJoin = sav->lineJoint;
+ ctx->curFillRule= sav->curFillRule;
ctx->selectedFont.charSize = sav->selectedFont.charSize;
strcpy (ctx->selectedFont.fontFile, sav->selectedFont.fontFile);
_recursive_bezier(ctx, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
_recursive_bezier(ctx, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
}
+void _poly_fill (VkvgContext ctx){
+ CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelinePolyFill);
+ uint32_t ptrPath = 0;
+ Vertex v = {};
+ v.uv.z = -1;
+
+ while (ptrPath < ctx->pathPtr){
+ if (!_path_is_closed(ctx, ptrPath))
+ ctx->pathes[ptrPath+1] = ctx->pathes[ptrPath];//close path by setting start and end equal
+
+ uint32_t firstPtIdx = ctx->pathes[ptrPath];
+ uint32_t lastPtIdx = _get_last_point_of_closed_path (ctx, ptrPath);
+ uint32_t pathPointCount = lastPtIdx - ctx->pathes[ptrPath] + 1;
+ uint32_t firstVertIdx = ctx->vertCount;
+
+
+ for (int i = 0; i < pathPointCount; i++) {
+ v.pos = ctx->points[i+firstPtIdx];
+ _add_vertex(ctx, v);
+ }
+
+ LOG(LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, firstVertIdx, ctx->vertCount - firstVertIdx);
+ CmdDraw (ctx->cmd, pathPointCount, 1, firstVertIdx ,0);
+
+ ptrPath+=2;
+ }
+}
+void _fill_ec (VkvgContext ctx){
+ uint32_t ptrPath = 0;;
+ Vertex v = {};
+ v.uv.z = -1;
+
+ while (ptrPath < ctx->pathPtr){
+ if (!_path_is_closed(ctx, ptrPath))
+ //close path
+ ctx->pathes[ptrPath+1] = ctx->pathes[ptrPath];
+
+ uint32_t firstPtIdx = ctx->pathes[ptrPath];
+ uint32_t lastPtIdx = _get_last_point_of_closed_path (ctx, ptrPath);
+ uint32_t pathPointCount = lastPtIdx - ctx->pathes[ptrPath] + 1;
+ uint32_t firstVertIdx = ctx->vertCount;
+
+ ear_clip_point ecps[pathPointCount];
+ uint32_t ecps_count = pathPointCount;
+ uint32_t i = 0;
+
+ //init points link list
+ while (i < pathPointCount-1){
+ v.pos = ctx->points[i+firstPtIdx];
+ ear_clip_point ecp = {v.pos, i+firstVertIdx, &ecps[i+1]};
+ ecps[i] = ecp;
+ _add_vertex(ctx, v);
+ i++;
+ }
+ v.pos = ctx->points[i+firstPtIdx];
+ ear_clip_point ecp = {v.pos, i+firstVertIdx, ecps};
+ ecps[i] = ecp;
+ _add_vertex(ctx, v);
+
+ ear_clip_point* ecp_current = ecps;
+
+ while (ecps_count > 3) {
+ ear_clip_point* v0 = ecp_current->next,
+ *v1 = ecp_current, *v2 = ecp_current->next->next;
+ if (ecp_zcross (v0, v2, v1)<0){
+ ecp_current = ecp_current->next;
+ continue;
+ }
+ ear_clip_point* vP = v2->next;
+ bool isEar = true;
+ while (vP!=v1){
+ if (ptInTriangle (vP->pos, v0->pos, v2->pos, v1->pos)){
+ isEar = false;
+ break;
+ }
+ vP = vP->next;
+ }
+ if (isEar){
+ _add_triangle_indices (ctx, v0->idx, v1->idx, v2->idx);
+ v1->next = v2;
+ ecps_count --;
+ }else
+ ecp_current = ecp_current->next;
+ }
+ if (ecps_count == 3)
+ _add_triangle_indices(ctx, ecp_current->next->idx, ecp_current->idx, ecp_current->next->next->idx);
+
+ ptrPath+=2;
+ }
+ _record_draw_cmd(ctx);
+}
vkvg_operator_t curOperator;
vkvg_line_cap_t lineCap;
vkvg_line_join_t lineJoint;
+ vkvg_fill_rule_t curFillRule;
_vkvg_font_t selectedFont; //hold current face and size before cache addition
_vkvg_font_t* currentFont; //font ready for lookup
vkvg_operator_t curOperator;
vkvg_line_cap_t lineCap;
vkvg_line_join_t lineJoin;
+ vkvg_fill_rule_t curFillRule;
_vkvg_font_t selectedFont; //hold current face and size before cache addition
_vkvg_font_t* currentFont; //font pointing to cached fonts ready for lookup
VkClearRect clearRect;
}vkvg_context;
+typedef struct _ear_clip_point{
+ vec2 pos;
+ uint32_t idx;
+ struct _ear_clip_point* next;
+}ear_clip_point;
+
bool _current_path_is_empty (VkvgContext ctx);
void _start_sub_path (VkvgContext ctx, float x, float y);
void _check_pathes_array (VkvgContext ctx);
vec2 _get_current_position (VkvgContext ctx);
void _add_point (VkvgContext ctx, float x, float y);
-void _add_point_vec2 (VkvgContext ctx, vec2 v);
+void _add_point_vec2 (VkvgContext ctx, vec2 v);
+
+void _poly_fill (VkvgContext ctx);
+void _fill_ec (VkvgContext ctx);//earclipping fill
void _create_gradient_buff (VkvgContext ctx);
void _create_vertices_buff (VkvgContext ctx);
static inline float vec2_zcross (vec2 v1, vec2 v2){
return v1.x*v2.y-v1.y*v2.x;
}
+static inline float ecp_zcross (ear_clip_point* p0, ear_clip_point* p1, ear_clip_point* p2){
+ return vec2_zcross (vec2_sub (p1->pos, p0->pos), vec2_sub (p2->pos, p0->pos));
+}
void _recursive_bezier(VkvgContext ctx,
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
/*failOp,passOp,depthFailOp,compareOp, compareMask, writeMask, reference;*/
VkStencilOpState polyFillOpState ={VK_STENCIL_OP_KEEP,VK_STENCIL_OP_INVERT,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_CLIP_BIT,STENCIL_FILL_BIT,0};
- VkStencilOpState clipingOpState = {VK_STENCIL_OP_REPLACE,VK_STENCIL_OP_ZERO,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_NOT_EQUAL,STENCIL_FILL_BIT,STENCIL_ALL_BIT,0x2};
+ VkStencilOpState clipingOpState = {VK_STENCIL_OP_ZERO,VK_STENCIL_OP_REPLACE,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_ALL_BIT,0x2};
VkStencilOpState stencilOpState = {VK_STENCIL_OP_KEEP,VK_STENCIL_OP_ZERO,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_FILL_BIT,0x1};
VkPipelineDepthStencilStateCreateInfo dsStateCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
+ VK_DYNAMIC_STATE_STENCIL_REFERENCE,
+ VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
};
VkPipelineDynamicStateCreateInfo dynamicState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = 2,
VkPipelineShaderStageCreateInfo shaderStages[] = {vertStage,fragStage};
- pipelineCreateInfo.stageCount = 2;
+ pipelineCreateInfo.stageCount = 1;
pipelineCreateInfo.pStages = shaderStages;
pipelineCreateInfo.pVertexInputState = &vertexInputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
dsStateCreateInfo.back = dsStateCreateInfo.front = clipingOpState;
+ dynamicState.dynamicStateCount = 5;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineClipping));
dsStateCreateInfo.back = dsStateCreateInfo.front = stencilOpState;
blendAttachmentState.colorWriteMask=0xf;
dynamicState.dynamicStateCount = 3;
+ pipelineCreateInfo.stageCount = 2;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_OVER));
blendAttachmentState.alphaBlendOp = blendAttachmentState.colorBlendOp = VK_BLEND_OP_SUBTRACT;
CmdDrawIndexed = GetInstProcAddress(dev->instance, vkCmdDrawIndexed);
CmdDraw = GetInstProcAddress(dev->instance, vkCmdDraw);
CmdSetStencilCompareMask= GetInstProcAddress(dev->instance, vkCmdSetStencilCompareMask);
+ CmdSetStencilReference = GetInstProcAddress(dev->instance, vkCmdSetStencilReference);
+ CmdSetStencilWriteMask = GetInstProcAddress(dev->instance, vkCmdSetStencilWriteMask);
CmdBeginRenderPass = GetInstProcAddress(dev->instance, vkCmdBeginRenderPass);
CmdEndRenderPass = GetInstProcAddress(dev->instance, vkCmdEndRenderPass);
CmdSetViewport = GetInstProcAddress(dev->instance, vkCmdSetViewport);
PFN_vkCmdDraw CmdDraw;
PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask;
+PFN_vkCmdSetStencilReference CmdSetStencilReference;
+PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask;
PFN_vkCmdBeginRenderPass CmdBeginRenderPass;
PFN_vkCmdEndRenderPass CmdEndRenderPass;
PFN_vkCmdSetViewport CmdSetViewport;
void test_clip2(){
vkvg_surface_clear(surf);
VkvgContext ctx = vkvg_create(surf);
-
+ vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_NON_ZERO);
vkvg_rectangle(ctx, 50,50,200,200);
+ vkvg_rectangle(ctx, 100,100,250,250);
+ vkvg_clip(ctx);
+ //vkvg_rectangle(ctx, 150,150,200,200);
+
//vkvg_clip(ctx);
- vkvg_rectangle(ctx, 50,50,200,200);
+ //
/*vkvg_clip_preserve(ctx);
vkvg_set_operator(ctx, VKVG_OPERATOR_CLEAR);
vkvg_fill_preserve(ctx);*/
- vkvg_clip(ctx);
+ //vkvg_clip(ctx);
//vkvg_set_operator(ctx, VKVG_OPERATOR_OVER);
+ /*vkvg_rectangle(ctx, 200,200,220,220);
+ vkvg_set_source_rgb(ctx,1,0,0);
+ vkvg_paint(ctx);*/
+
+ vkvg_set_source_rgb(ctx,0,1,0);
+ vkvg_paint(ctx);
+
+ vkvg_rectangle(ctx, 60,60,480,480);
+ vkvg_clip(ctx);
vkvg_set_source_rgb(ctx,1,0,0);
vkvg_paint(ctx);
}
int main(int argc, char *argv[]) {
- perform_test (test_clip, 1024, 768);
+ perform_test (test_clip2, 1024, 768);
return 0;
}
#if DEBUG
dbgReport = vkh_device_create_debug_report (e->dev,
VK_DEBUG_REPORT_ERROR_BIT_EXT|
- VK_DEBUG_REPORT_INFORMATION_BIT_EXT|
VK_DEBUG_REPORT_WARNING_BIT_EXT|
VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT|
VK_DEBUG_REPORT_DEBUG_BIT_EXT);
const float w = 1024.f;
VkvgContext ctx = vkvg_create(surf);
+ vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_NON_ZERO);
vkvg_set_line_width(ctx,1);
for (int i=0; i<5000; i++) {
randomize_color(ctx);
void test(){
vkvg_surface_clear(surf);
VkvgContext ctx = vkvg_create(surf);
-
+ vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_NON_ZERO);
vkvg_set_line_width(ctx,10);
vkvg_set_source_rgba(ctx,0,0,1,0.5);
vkvg_rectangle(ctx,100,100,200,200);
-Subproject commit f9a1b07cbafbb8b96fc47a25cb27d8f8218c96c8
+Subproject commit b93c31b7ba01ccfbc12dd7e907aa6cd6a986ae81