From 4b80ec018585a330d2ae85e633ef519892b42017 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Wed, 15 Jul 2020 16:41:03 +0200 Subject: [PATCH] solid fill & stroke --- shaders/vkvg.frag | 95 +++++ shaders/vkvg_main.frag | 15 +- shaders/vkvg_main.vert | 14 +- shaders/vkvg_text.frag | 95 +++++ shaders/vkvg_text.vert | 76 ++++ src/vkvg_context.c | 15 +- src/vkvg_context_internal.c | 34 +- src/vkvg_context_internal.h | 13 +- src/vkvg_device.c | 4 +- src/vkvg_device_internal.c | 14 +- src/vkvg_device_internal.h | 2 +- src/vkvg_fonts.c | 769 ++++++++++++++++++------------------ 12 files changed, 707 insertions(+), 439 deletions(-) create mode 100644 shaders/vkvg.frag create mode 100644 shaders/vkvg_text.frag create mode 100644 shaders/vkvg_text.vert diff --git a/shaders/vkvg.frag b/shaders/vkvg.frag new file mode 100644 index 0000000..9a28203 --- /dev/null +++ b/shaders/vkvg.frag @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018 Jean-Philippe Bruyère + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (set=0, binding = 0) uniform sampler2DArray fontMap; +layout (set=1, binding = 0) uniform sampler2D source; +layout (set=2, binding = 0) uniform _uboGrad { + vec4 cp[3]; + vec4 colors[16]; + vec4 stops[16]; + uint count; +}uboGrad; + +layout (location = 0) in vec3 inFontUV; //if it is a text drawing, inFontUV.z hold fontMap layer +layout (location = 1) in vec4 inSrc; //source bounds or color depending on pattern type +layout (location = 2) in flat int inPatType; //pattern type +layout (location = 3) in mat3x2 inMat; + +layout (location = 0) out vec4 outFragColor; + +layout (constant_id = 0) const int NUM_SAMPLES = 8; + + +#define SOLID 0 +#define SURFACE 1 +#define LINEAR 2 +#define RADIAL 3 +#define MESH 4 +#define RASTER_SOURCE 5 + +void main() +{ + vec4 c = vec4(0); + switch(inPatType){ + case SOLID: + c = inSrc; + break; + case SURFACE: + vec2 p = (gl_FragCoord.xy - inSrc.xy); + vec2 uv = vec2( + inMat[0][0] * p.x + inMat[1][0] * p.y + inMat[2][0], + inMat[0][1] * p.x + inMat[1][1] * p.y + inMat[2][1] + ); + c = texture (source, uv / inSrc.zw); + break; + case LINEAR: + //credit to Nikita Rokotyan for linear grad + float alpha = atan( -uboGrad.cp[1].y + uboGrad.cp[0].y, uboGrad.cp[1].x - uboGrad.cp[0].x ); + float gradientStartPosRotatedX = uboGrad.cp[0].x*cos(alpha) - uboGrad.cp[0].y*sin(alpha); + float gradientEndPosRotatedX = uboGrad.cp[1].x*cos(alpha) - uboGrad.cp[1].y*sin(alpha); + float d = gradientEndPosRotatedX - gradientStartPosRotatedX; + + float y = gl_FragCoord.y;//inSrc.y - gl_FragCoord.y; + float x = gl_FragCoord.x; + float xLocRotated = x*cos( alpha ) - y*sin( alpha ); + + c = mix(uboGrad.colors[0], uboGrad.colors[1], smoothstep( gradientStartPosRotatedX + uboGrad.stops[0].r*d, gradientStartPosRotatedX + uboGrad.stops[1].r*d, xLocRotated ) ); + for ( int i=1; i= 0.0) + c *= texture(fontMap, inFontUV); + + outFragColor = c; +} + +void op_CLEAR () { + outFragColor = vec4 (0); +} diff --git a/shaders/vkvg_main.frag b/shaders/vkvg_main.frag index 6649582..c076660 100644 --- a/shaders/vkvg_main.frag +++ b/shaders/vkvg_main.frag @@ -24,19 +24,17 @@ #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (set=0, binding = 0) uniform sampler2DArray fontMap; -layout (set=1, binding = 0) uniform sampler2D source; -layout (set=2, binding = 0) uniform _uboGrad { +layout (set=0, binding = 0) uniform sampler2D source; +layout (set=1, binding = 0) uniform _uboGrad { vec4 cp[3]; vec4 colors[16]; vec4 stops[16]; uint count; }uboGrad; -layout (location = 0) in vec3 inFontUV; //if it is a text drawing, inFontUV.z hold fontMap layer -layout (location = 1) in vec4 inSrc; //source bounds or color -layout (location = 2) in flat int inPatType; -layout (location = 3) in mat3x2 inMat; +layout (location = 0) in vec4 inSrc; //source bounds or color +layout (location = 1) in flat int inPatType; +layout (location = 2) in mat3x2 inMat; layout (location = 0) out vec4 outFragColor; @@ -83,9 +81,6 @@ void main() break; } - if (inFontUV.z >= 0.0) - c *= texture(fontMap, inFontUV).r; - outFragColor = c; } diff --git a/shaders/vkvg_main.vert b/shaders/vkvg_main.vert index 2826713..7bd6cf2 100644 --- a/shaders/vkvg_main.vert +++ b/shaders/vkvg_main.vert @@ -25,12 +25,11 @@ #extension GL_ARB_shading_language_420pack : enable layout (location = 0) in vec2 inPos; -layout (location = 1) in vec3 inUV; +layout (location = 1) in vec4 inColor; -layout (location = 0) out vec3 outUV; -layout (location = 1) out vec4 outSrc; -layout (location = 2) out flat int outPatType; -layout (location = 3) out mat3x2 outMat; +layout (location = 0) out vec4 outSrc; +layout (location = 1) out flat int outPatType; +layout (location = 2) out mat3x2 outMat; out gl_PerVertex { @@ -56,17 +55,14 @@ layout(push_constant) uniform PushConsts { void main() { outPatType = pc.srcType; - outSrc = pc.source; + outSrc = pc.srcType == SOLID ? inColor : pc.source; outMat = pc.matInv; if (pc.fullScreenQuad != 0) { gl_Position = vec4(vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2) * 2.0f - 1.0f, 0.0f, 1.0f); - outUV = vec3(0,0,-1); return; } - outUV = inUV; - vec2 p = vec2( pc.mat[0][0] * inPos.x + pc.mat[1][0] * inPos.y + pc.mat[2][0], pc.mat[0][1] * inPos.x + pc.mat[1][1] * inPos.y + pc.mat[2][1] diff --git a/shaders/vkvg_text.frag b/shaders/vkvg_text.frag new file mode 100644 index 0000000..9a28203 --- /dev/null +++ b/shaders/vkvg_text.frag @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018 Jean-Philippe Bruyère + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (set=0, binding = 0) uniform sampler2DArray fontMap; +layout (set=1, binding = 0) uniform sampler2D source; +layout (set=2, binding = 0) uniform _uboGrad { + vec4 cp[3]; + vec4 colors[16]; + vec4 stops[16]; + uint count; +}uboGrad; + +layout (location = 0) in vec3 inFontUV; //if it is a text drawing, inFontUV.z hold fontMap layer +layout (location = 1) in vec4 inSrc; //source bounds or color depending on pattern type +layout (location = 2) in flat int inPatType; //pattern type +layout (location = 3) in mat3x2 inMat; + +layout (location = 0) out vec4 outFragColor; + +layout (constant_id = 0) const int NUM_SAMPLES = 8; + + +#define SOLID 0 +#define SURFACE 1 +#define LINEAR 2 +#define RADIAL 3 +#define MESH 4 +#define RASTER_SOURCE 5 + +void main() +{ + vec4 c = vec4(0); + switch(inPatType){ + case SOLID: + c = inSrc; + break; + case SURFACE: + vec2 p = (gl_FragCoord.xy - inSrc.xy); + vec2 uv = vec2( + inMat[0][0] * p.x + inMat[1][0] * p.y + inMat[2][0], + inMat[0][1] * p.x + inMat[1][1] * p.y + inMat[2][1] + ); + c = texture (source, uv / inSrc.zw); + break; + case LINEAR: + //credit to Nikita Rokotyan for linear grad + float alpha = atan( -uboGrad.cp[1].y + uboGrad.cp[0].y, uboGrad.cp[1].x - uboGrad.cp[0].x ); + float gradientStartPosRotatedX = uboGrad.cp[0].x*cos(alpha) - uboGrad.cp[0].y*sin(alpha); + float gradientEndPosRotatedX = uboGrad.cp[1].x*cos(alpha) - uboGrad.cp[1].y*sin(alpha); + float d = gradientEndPosRotatedX - gradientStartPosRotatedX; + + float y = gl_FragCoord.y;//inSrc.y - gl_FragCoord.y; + float x = gl_FragCoord.x; + float xLocRotated = x*cos( alpha ) - y*sin( alpha ); + + c = mix(uboGrad.colors[0], uboGrad.colors[1], smoothstep( gradientStartPosRotatedX + uboGrad.stops[0].r*d, gradientStartPosRotatedX + uboGrad.stops[1].r*d, xLocRotated ) ); + for ( int i=1; i= 0.0) + c *= texture(fontMap, inFontUV); + + outFragColor = c; +} + +void op_CLEAR () { + outFragColor = vec4 (0); +} diff --git a/shaders/vkvg_text.vert b/shaders/vkvg_text.vert new file mode 100644 index 0000000..2826713 --- /dev/null +++ b/shaders/vkvg_text.vert @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 Jean-Philippe Bruyère + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec3 inUV; + +layout (location = 0) out vec3 outUV; +layout (location = 1) out vec4 outSrc; +layout (location = 2) out flat int outPatType; +layout (location = 3) out mat3x2 outMat; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +layout(push_constant) uniform PushConsts { + vec4 source; + vec2 size; + int srcType; + int fullScreenQuad; + mat3x2 mat; + mat3x2 matInv; +} pc; + +#define SOLID 0 +#define SURFACE 1 +#define LINEAR 2 +#define RADIAL 3 +#define MESH 4 +#define RASTER_SOURCE 5 + +void main() +{ + outPatType = pc.srcType; + outSrc = pc.source; + outMat = pc.matInv; + + if (pc.fullScreenQuad != 0) { + gl_Position = vec4(vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2) * 2.0f - 1.0f, 0.0f, 1.0f); + outUV = vec3(0,0,-1); + return; + } + + outUV = inUV; + + vec2 p = vec2( + pc.mat[0][0] * inPos.x + pc.mat[1][0] * inPos.y + pc.mat[2][0], + pc.mat[0][1] * inPos.x + pc.mat[1][1] * inPos.y + pc.mat[2][1] + ); + + gl_Position = vec4(p * vec2(2) / pc.size - vec2(1), 0.0, 1.0); +} diff --git a/src/vkvg_context.c b/src/vkvg_context.c index d696dc3..bae562b 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -145,7 +145,7 @@ VkvgContext vkvg_create(VkvgSurface surf) _create_cmd_buff (ctx); _createDescriptorPool (ctx); _init_descriptor_sets (ctx); - _update_descriptor_set (ctx, ctx->pSurf->dev->fontCache->texture, ctx->dsFont); + //_update_descriptor_set (ctx, ctx->pSurf->dev->fontCache->texture, ctx->dsFont); _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); _update_gradient_desc_set(ctx); @@ -166,7 +166,7 @@ VkvgContext vkvg_create(VkvgSurface surf) vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, "CTX Descriptor Pool"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, "CTX DescSet SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, "CTX DescSet FONT"); +// vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, "CTX DescSet FONT"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsGrad, "CTX DescSet GRADIENT"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->indices.buffer, "CTX Index Buff"); @@ -231,8 +231,8 @@ void vkvg_destroy (VkvgContext ctx) vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); vkDestroyCommandPool(dev, ctx->cmdPool, NULL); - VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; - vkFreeDescriptorSets (dev, ctx->descriptorPool, 3, dss); + VkDescriptorSet dss[] = {ctx->dsSrc, ctx->dsGrad}; + vkFreeDescriptorSets (dev, ctx->descriptorPool, 2, dss); vkDestroyDescriptorPool (dev, ctx->descriptorPool,NULL); @@ -520,7 +520,7 @@ void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, } void vkvg_fill_rectangle (VkvgContext ctx, float x, float y, float w, float h){ _vao_add_rectangle (ctx,x,y,w,h); - _record_draw_cmd(ctx); + //_record_draw_cmd(ctx); } void vkvg_rectangle (VkvgContext ctx, float x, float y, float w, float h){ @@ -842,7 +842,7 @@ void vkvg_stroke_preserve (VkvgContext ctx) else ptrPath++; } - _record_draw_cmd(ctx); + //_record_draw_cmd(ctx); } void vkvg_paint (VkvgContext ctx){ _check_cmd_buff_state (ctx); @@ -853,7 +853,8 @@ void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b) { } void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a) { - _update_cur_pattern (ctx, vkvg_pattern_create_rgba (r,g,b,a)); + ctx->curColor = CreateRgbaf(r,g,b,a); + //_update_cur_pattern (ctx, vkvg_pattern_create_rgba (r,g,b,a)); } void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y){ _update_cur_pattern (ctx, vkvg_pattern_create_for_surface(surf)); diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 29434a7..e3f4624 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -277,7 +277,7 @@ void _add_vertexf (VkvgContext ctx, float x, float y){ Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; pVert->pos.x = x; pVert->pos.y = y; - pVert->uv = (vec3){0,0,-1}; + pVert->color = ctx->curColor; ctx->vertCount++; _check_vertex_cache_size(ctx); @@ -317,10 +317,10 @@ void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_IND void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height){ Vertex v[4] = { - {{x,y}, {0,0,-1}}, - {{x,y+height}, {0,0,-1}}, - {{x+width,y}, {0,0,-1}}, - {{x+width,y+height},{0,0,-1}} + {{x,y}, ctx->curColor}, + {{x,y+height}, ctx->curColor}, + {{x+width,y}, ctx->curColor}, + {{x+width,y+height},ctx->curColor} }; VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; @@ -468,10 +468,10 @@ void _record_draw_cmd (VkvgContext ctx){ ctx->curVertOffset = ctx->vertCount; } void _flush_cmd_buff (VkvgContext ctx){ - if (!ctx->cmdStarted) + if (ctx->indCount > ctx->curIndStart) + _record_draw_cmd (ctx); + else if (!ctx->cmdStarted) return; - - _record_draw_cmd (ctx); _end_render_pass (ctx); _flush_vertices_caches (ctx); vkh_cmd_end (ctx->cmd); @@ -523,9 +523,9 @@ void _start_cmd_for_render_pass (VkvgContext ctx) { CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); - VkDescriptorSet dss[] = {ctx->dsFont,ctx->dsSrc,ctx->dsGrad}; + VkDescriptorSet dss[] = {ctx->dsSrc,ctx->dsGrad}; CmdBindDescriptorSets(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLayout, - 0, 3, dss, 0, NULL); + 0, 2, dss, 0, NULL); VkDeviceSize offsets[1] = { 0 }; CmdBindVertexBuffers(ctx->cmd, 0, 1, &ctx->vertices.buffer, offsets); @@ -730,8 +730,9 @@ void _init_descriptor_sets (VkvgContext ctx){ VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, .descriptorPool = ctx->descriptorPool, .descriptorSetCount = 1, - .pSetLayouts = &dev->dslFont }; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); + //.pSetLayouts = &dev->dslFont + }; + //VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); descriptorSetAllocateInfo.pSetLayouts = &dev->dslSrc; VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); descriptorSetAllocateInfo.pSetLayouts = &dev->dslGrad; @@ -739,7 +740,7 @@ void _init_descriptor_sets (VkvgContext ctx){ } //populate vertice buff for stroke float _build_vb_step (vkvg_context* ctx, float hw, vec2 pL, vec2 p0, vec2 pR, bool isCurve){ - Vertex v = {{0},{0,0,-1}}; + Vertex v = {{0},ctx->curColor}; //if two of the three points are equal, normal is null vec2 v0n = vec2_line_norm(pL, p0); @@ -1078,7 +1079,7 @@ void _poly_fill (VkvgContext ctx){ CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelinePolyFill); - Vertex v = {{0},{0,0,-1}}; + Vertex v = {{0},ctx->curColor}; uint32_t ptrPath = 0; uint32_t firstPtIdx = 0; @@ -1114,8 +1115,7 @@ void _poly_fill (VkvgContext ctx){ } //create fill from current path with ear clipping technic void _fill_ec (VkvgContext ctx){ - Vertex v = {0}; - v.uv.z = -1; + Vertex v = {{0},ctx->curColor}; uint32_t ptrPath = 0; uint32_t firstPtIdx = 0; @@ -1192,7 +1192,7 @@ void _fill_ec (VkvgContext ctx){ ptrPath++; free (ecps); } - _record_draw_cmd(ctx); + //_record_draw_cmd(ctx); } static const uint32_t one = 1; diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 6751090..4851375 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -35,9 +35,16 @@ #define VKVG_ARRAY_THRESHOLD 8 #define VKVG_IBO_INDEX_TYPE uint16_t +#define CreateRgba(r, g, b, a) ((a << 24) | (r << 16) | (g << 8) | b) +#ifdef VKVG_PREMULT_ALPHA + #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * a * 255.0f) << 16) | ((int)(g * a * 255.0f) << 8) | (int)(r * a * 255.0f)) +#else + #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) +#endif + typedef struct{ vec2 pos; - vec3 uv; + uint32_t color; }Vertex; typedef struct { @@ -86,12 +93,14 @@ typedef struct _vkvg_context_t { bool cmdStarted; //prevent flushing empty renderpass bool pushCstDirty;//prevent pushing to gpu if not requested VkDescriptorPool descriptorPool;//one pool per thread - VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) + //VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) VkDescriptorSet dsSrc; //source ds VkDescriptorSet dsGrad; //gradient uniform buffer VkRect2D bounds; + uint32_t curColor; + float xMin; float xMax; float yMin; diff --git a/src/vkvg_device.c b/src/vkvg_device.c index e680890..7a062b6 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -121,7 +121,7 @@ VkvgDevice vkvg_device_create_multisample(VkInstance inst, VkPhysicalDevice phy, vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, "RP clear all"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, "DSLayout SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT"); + //vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, "DSLayout GRADIENT"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, "PLLayout dev"); @@ -150,7 +150,7 @@ void vkvg_device_destroy (VkvgDevice dev) vkh_image_destroy (dev->emptyImg); vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslGrad,NULL); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslFont,NULL); + //vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslFont,NULL); vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslSrc, NULL); vkDestroyPipeline (dev->vkDev, dev->pipelinePolyFill, NULL); diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index 25d3ccf..f01bf19 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -242,8 +242,8 @@ void _setupPipelines(VkvgDevice dev) .inputRate = VK_VERTEX_INPUT_RATE_VERTEX }; VkVertexInputAttributeDescription vertexInputAttributs[2] = { - {0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(vec2)} + {0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, + {1, 0, VK_FORMAT_R8G8B8A8_UNORM, sizeof(vec2)} }; VkPipelineVertexInputStateCreateInfo vertexInputState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, @@ -261,8 +261,8 @@ void _setupPipelines(VkvgDevice dev) .codeSize = vkvg_main_vert_spv_len }; VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modVert)); #ifdef VKVG_LCD_FONT_FILTER - createInfo.pCode = (uint32_t*)vkvg_main_lcd_frag_spv; - createInfo.codeSize = vkvg_main_lcd_frag_spv_len; + createInfo.pCode = (uint32_t*)vkvg_main_frag_spv; + createInfo.codeSize = vkvg_main_frag_spv_len; #else createInfo.pCode = (uint32_t*)vkvg_main_frag_spv; createInfo.codeSize = vkvg_main_frag_spv_len; @@ -356,7 +356,7 @@ void _createDescriptorSetLayout (VkvgDevice dev) { VkDescriptorSetLayoutCreateInfo dsLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .bindingCount = 1, .pBindings = &dsLayoutBinding }; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); + //VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslSrc)); dsLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslGrad)); @@ -365,12 +365,12 @@ void _createDescriptorSetLayout (VkvgDevice dev) { {VK_SHADER_STAGE_VERTEX_BIT,0,sizeof(push_constants)}, //{VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push_constants)} }; - VkDescriptorSetLayout dsls[] = {dev->dslFont,dev->dslSrc,dev->dslGrad}; + VkDescriptorSetLayout dsls[] = {dev->dslSrc,dev->dslGrad}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pushConstantRangeCount = 1, .pPushConstantRanges = (VkPushConstantRange*)&pushConstantRange, - .setLayoutCount = 3, + .setLayoutCount = 2, .pSetLayouts = dsls }; VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout)); } diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index a6b1b3a..8c39e0d 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -81,7 +81,7 @@ typedef struct _vkvg_device_t{ #endif VkPipelineCache pipelineCache; /**< speed up startup by caching configured pipelines on disk */ VkPipelineLayout pipelineLayout; /**< layout common to all pipelines */ - VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ + //VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ VkDescriptorSetLayout dslSrc; /**< context source surface descriptors layout */ VkDescriptorSetLayout dslGrad; /**< context gradient descriptors layout */ diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 7e87fc3..794eca6 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -30,560 +30,561 @@ static int defaultFontCharSize = 12<<6; void _init_fonts_cache (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)calloc(1, sizeof(_font_cache_t)); + _font_cache_t* cache = (_font_cache_t*)calloc(1, sizeof(_font_cache_t)); - cache->config = FcInitLoadConfigAndFonts(); - if (!cache->config) { - fprintf(stderr, "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ - variables to point to 'fonts.conf' needed for FontConfig startup"); - assert(cache->config); - } + cache->config = FcInitLoadConfigAndFonts(); + if (!cache->config) { + fprintf(stderr, "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ + variables to point to 'fonts.conf' needed for FontConfig startup"); + assert(cache->config); + } - FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); + FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); #ifdef VKVG_LCD_FONT_FILTER - FT_CHECK_RESULT(FT_Library_SetLcdFilter (cache->library, FT_LCD_FILTER_LIGHT)); - cache->texFormat = FB_COLOR_FORMAT; - cache->texPixelSize = 4; + FT_CHECK_RESULT(FT_Library_SetLcdFilter (cache->library, FT_LCD_FILTER_LIGHT)); + cache->texFormat = FB_COLOR_FORMAT; + cache->texPixelSize = 4; #else - cache->texFormat = VK_FORMAT_R8_UNORM; - cache->texPixelSize = 1; + cache->texFormat = VK_FORMAT_R8_UNORM; + cache->texPixelSize = 1; #endif - cache->texLength = FONT_CACHE_INIT_LAYERS; - cache->texture = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - cache->texLength ,VMA_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + cache->texLength = FONT_CACHE_INIT_LAYERS; + cache->texture = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, + cache->texLength ,VMA_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor (cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, + VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - cache->uploadFence = vkh_fence_create((VkhDevice)dev); + cache->uploadFence = vkh_fence_create((VkhDevice)dev); - uint32_t buffLength = FONT_PAGE_SIZE*FONT_PAGE_SIZE*cache->texPixelSize; + uint32_t buffLength = FONT_PAGE_SIZE*FONT_PAGE_SIZE*cache->texPixelSize; - vkvg_buffer_create (dev, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_MEMORY_USAGE_CPU_TO_GPU, - buffLength, &cache->buff); + vkvg_buffer_create (dev, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU, + buffLength, &cache->buff); - cache->cmd = vkh_cmd_buff_create((VkhDevice)dev,dev->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY); + cache->cmd = vkh_cmd_buff_create((VkhDevice)dev,dev->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY); - //Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); + //Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; + vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + _submit_cmd (dev, &cache->cmd, cache->uploadFence); - cache->hostBuff = (uint8_t*)malloc(buffLength); - cache->pensY = (int*)calloc(cache->texLength, sizeof(int)); + cache->hostBuff = (uint8_t*)malloc(buffLength); + cache->pensY = (int*)calloc(cache->texLength, sizeof(int)); - dev->fontCache = cache; + dev->fontCache = cache; } ///increase layer count of 2d texture array used as font cache. void _increase_font_tex_array (VkvgDevice dev){ - _font_cache_t* cache = dev->fontCache; + _font_cache_t* cache = dev->fontCache; - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - vkResetCommandBuffer(cache->cmd, 0); - vkResetFences (dev->vkDev, 1, &cache->uploadFence); + vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + vkResetCommandBuffer(cache->cmd, 0); + vkResetFences (dev->vkDev, 1, &cache->uploadFence); - uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; - VkhImage newImg = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - newSize ,VMA_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; + VkhImage newImg = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, + newSize ,VMA_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor (newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, + VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,newSize}; - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; + VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,newSize}; + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .extent = {FONT_PAGE_SIZE,FONT_PAGE_SIZE,1}}; + VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .extent = {FONT_PAGE_SIZE,FONT_PAGE_SIZE,1}}; - vkCmdCopyImage (cache->cmd, vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + vkCmdCopyImage (cache->cmd, vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage (newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + _submit_cmd (dev, &cache->cmd, cache->uploadFence); + vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - _flush_all_contexes (dev); + _flush_all_contexes (dev); - cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int)); - memset (cache->pensY + cache->texLength * sizeof(int),0,FONT_CACHE_INIT_LAYERS*sizeof(int)); + cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int)); + memset (cache->pensY + cache->texLength * sizeof(int),0,FONT_CACHE_INIT_LAYERS*sizeof(int)); - vkh_image_destroy (cache->texture); - cache->texLength = newSize; - cache->texture = newImg; + vkh_image_destroy (cache->texture); + cache->texLength = newSize; + cache->texture = newImg; - VkvgContext next = dev->lastCtx; - while (next != NULL){ - _update_descriptor_set (next, next->source, next->dsSrc); - next = next->pPrev; - } + /*VkvgContext next = dev->lastCtx; + while (next != NULL){ + _update_descriptor_set (next, next->source, next->dsSrc); + next = next->pPrev; + }*/ } ///Start a new line in font cache, increase texture layer count if needed. void _init_next_line_in_tex_cache (VkvgDevice dev, _vkvg_font_t* f){ - _font_cache_t* cache = dev->fontCache; - int i; - for (i = 0; i < cache->texLength; ++i) { - if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) - continue; - f->curLine.pageIdx = (unsigned char)i; - f->curLine.penX = 0; - f->curLine.penY = cache->pensY[i]; - cache->pensY[i] += f->curLine.height; - return; - } - _flush_chars_to_tex (dev, f); - _increase_font_tex_array (dev); - _init_next_line_in_tex_cache(dev, f); + _font_cache_t* cache = dev->fontCache; + int i; + for (i = 0; i < cache->texLength; ++i) { + if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) + continue; + f->curLine.pageIdx = (unsigned char)i; + f->curLine.penX = 0; + f->curLine.penY = cache->pensY[i]; + cache->pensY[i] += f->curLine.height; + return; + } + _flush_chars_to_tex (dev, f); + _increase_font_tex_array (dev); + _init_next_line_in_tex_cache(dev, f); } void _destroy_font_cache (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)dev->fontCache; + _font_cache_t* cache = (_font_cache_t*)dev->fontCache; - //FcFini(); + //FcFini(); - free (cache->hostBuff); + free (cache->hostBuff); - for (int i = 0; i < cache->fontsCount; ++i) { - _vkvg_font_t f = cache->fonts[i]; + for (int i = 0; i < cache->fontsCount; ++i) { + _vkvg_font_t f = cache->fonts[i]; - for (int g = 0; g < f.face->num_glyphs; ++g) { - if (f.charLookup[g]!=NULL) - free(f.charLookup[g]); - } + for (int g = 0; g < f.face->num_glyphs; ++g) { + if (f.charLookup[g]!=NULL) + free(f.charLookup[g]); + } - FT_Done_Face (f.face); - hb_font_destroy (f.hb_font); + FT_Done_Face (f.face); + hb_font_destroy (f.hb_font); - free(f.charLookup); - free(f.fontFile); - } + free(f.charLookup); + free(f.fontFile); + } - free(cache->fonts); - free(cache->pensY); + free(cache->fonts); + free(cache->pensY); - vkvg_buffer_destroy (&cache->buff); - vkh_image_destroy (cache->texture); - //vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); - vkDestroyFence (dev->vkDev,cache->uploadFence,NULL); + vkvg_buffer_destroy (&cache->buff); + vkh_image_destroy (cache->texture); + //vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); + vkDestroyFence (dev->vkDev,cache->uploadFence,NULL); - free (dev->fontCache); + free (dev->fontCache); } #ifdef DEBUG //helper function void _dump_glyphs (FT_Face face){ - FT_GlyphSlot slot; - char gname[256]; + FT_GlyphSlot slot; + char gname[256]; - for (int i = 0; i < face->num_glyphs; ++i) { - FT_CHECK_RESULT(FT_Load_Glyph(face,i,FT_LOAD_RENDER)); - slot = face->glyph; + for (int i = 0; i < face->num_glyphs; ++i) { + FT_CHECK_RESULT(FT_Load_Glyph(face,i,FT_LOAD_RENDER)); + slot = face->glyph; - FT_Get_Glyph_Name(face,i,gname,256); + FT_Get_Glyph_Name(face,i,gname,256); - printf("glyph: %s (%d,%d;%d), max advance:%ld\n", gname, - slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch, - face->size->metrics.max_advance/64); - } + printf("glyph: %s (%d,%d;%d), max advance:%ld\n", gname, + slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch, + face->size->metrics.max_advance/64); + } } #endif //flush font stagging buffer to cache texture array void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) { - _font_cache_t* cache = dev->fontCache; - if (cache->stagingX == 0) - return; + _font_cache_t* cache = dev->fontCache; + if (cache->stagingX == 0) + return; - vkWaitForFences (dev->vkDev,1,&cache->uploadFence,VK_TRUE,UINT64_MAX); - vkResetCommandBuffer(cache->cmd,0); - vkResetFences (dev->vkDev,1,&cache->uploadFence); + vkWaitForFences (dev->vkDev,1,&cache->uploadFence,VK_TRUE,UINT64_MAX); + vkResetCommandBuffer(cache->cmd,0); + vkResetFences (dev->vkDev,1,&cache->uploadFence); - memcpy(cache->buff.allocInfo.pMappedData, cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); + memcpy(cache->buff.allocInfo.pMappedData, cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,f->curLine.pageIdx,1}; - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,f->curLine.pageIdx,1}; + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VkBufferImageCopy bufferCopyRegion = { .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,f->curLine.pageIdx,1}, - .bufferRowLength = FONT_PAGE_SIZE, - .bufferImageHeight = f->curLine.height, - .imageOffset = {f->curLine.penX,f->curLine.penY,0}, - .imageExtent = {FONT_PAGE_SIZE-f->curLine.penX,f->curLine.height,1}}; + VkBufferImageCopy bufferCopyRegion = { .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,f->curLine.pageIdx,1}, + .bufferRowLength = FONT_PAGE_SIZE, + .bufferImageHeight = f->curLine.height, + .imageOffset = {f->curLine.penX,f->curLine.penY,0}, + .imageExtent = {FONT_PAGE_SIZE-f->curLine.penX,f->curLine.height,1}}; - vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, - vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, + vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); + _submit_cmd (dev, &cache->cmd, cache->uploadFence); - f->curLine.penX += cache->stagingX; - cache->stagingX = 0; - memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); + f->curLine.penX += cache->stagingX; + cache->stagingX = 0; + memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); } //create a new char entry and put glyph in stagging buffer, ready for upload. _char_ref* _prepare_char (VkvgDevice dev, _vkvg_font_t* f, FT_UInt gindex){ #ifdef VKVG_LCD_FONT_FILTER - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); - FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); + FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); #else - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); #endif - FT_GlyphSlot slot = f->face->glyph; - FT_Bitmap bmp = slot->bitmap; - uint8_t* data = dev->fontCache->hostBuff; - uint32_t bmpWidth= bmp.width; //real width in pixel of char bitmap + FT_GlyphSlot slot = f->face->glyph; + FT_Bitmap bmp = slot->bitmap; + uint8_t* data = dev->fontCache->hostBuff; + uint32_t bmpWidth= bmp.width; //real width in pixel of char bitmap #ifdef VKVG_LCD_FONT_FILTER - bmpWidth /= 3; + bmpWidth /= 3; #endif - if (dev->fontCache->stagingX + f->curLine.penX + bmpWidth > FONT_PAGE_SIZE){ - _flush_chars_to_tex (dev, f); - _init_next_line_in_tex_cache (dev, f); - } + if (dev->fontCache->stagingX + f->curLine.penX + bmpWidth > FONT_PAGE_SIZE){ + _flush_chars_to_tex (dev, f); + _init_next_line_in_tex_cache (dev, f); + } - int penX = dev->fontCache->stagingX; - for(uint32_t y=0; yfontCache->stagingX; + for(uint32_t y=0; ycurLine.penX) / (float)FONT_PAGE_SIZE, - (float)f->curLine.penY / (float)FONT_PAGE_SIZE, - (float)bmpWidth, - (float)bmp.rows}; - cr->bounds = uvBounds; - cr->pageIdx = f->curLine.pageIdx; - cr->bmpDiff.x = (int16_t)slot->bitmap_left; - cr->bmpDiff.y = (int16_t)slot->bitmap_top; - - f->charLookup[gindex] = cr; - dev->fontCache->stagingX += bmpWidth; - return cr; + } + } + + _char_ref* cr = (_char_ref*)malloc(sizeof(_char_ref)); + vec4 uvBounds = { + (float)(penX + f->curLine.penX) / (float)FONT_PAGE_SIZE, + (float)f->curLine.penY / (float)FONT_PAGE_SIZE, + (float)bmpWidth, + (float)bmp.rows}; + cr->bounds = uvBounds; + cr->pageIdx = f->curLine.pageIdx; + cr->bmpDiff.x = (int16_t)slot->bitmap_left; + cr->bmpDiff.y = (int16_t)slot->bitmap_top; + + f->charLookup[gindex] = cr; + dev->fontCache->stagingX += bmpWidth; + return cr; } //set current font size for context void _set_font_size (VkvgContext ctx, uint32_t size){ - ctx->selectedFont.charSize = size << 6; - ctx->currentFont = NULL; + ctx->selectedFont.charSize = size << 6; + ctx->currentFont = NULL; } //select current font for context void _select_font_face (VkvgContext ctx, const char* name){ - _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; - - char* fontFile; - - //make pattern from font name - FcPattern* pat = FcNameParse((const FcChar8*)name); - FcConfigSubstitute(cache->config, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - // find the font - FcResult result; - FcPattern* font = FcFontMatch(cache->config, pat, &result); - if (font) - { - if (FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile) == FcResultMatch){ - memset (ctx->selectedFont.fontFile, 0, FONT_FILE_NAME_MAX_SIZE); - memcpy (ctx->selectedFont.fontFile, fontFile, FONT_FILE_NAME_MAX_SIZE); - } - } - FcPatternDestroy(pat); - FcPatternDestroy(font); - - ctx->currentFont = NULL; + _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; + + char* fontFile; + + //make pattern from font name + FcPattern* pat = FcNameParse((const FcChar8*)name); + FcConfigSubstitute(cache->config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + // find the font + FcResult result; + FcPattern* font = FcFontMatch(cache->config, pat, &result); + if (font) + { + if (FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile) == FcResultMatch){ + memset (ctx->selectedFont.fontFile, 0, FONT_FILE_NAME_MAX_SIZE); + memcpy (ctx->selectedFont.fontFile, fontFile, FONT_FILE_NAME_MAX_SIZE); + } + } + FcPatternDestroy(pat); + FcPatternDestroy(font); + + ctx->currentFont = NULL; } //try to find font in cache with same font file path and font size as selected in context. _vkvg_font_t* _tryFindVkvgFont (VkvgContext ctx){ - _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; - for (int i = 0; i < cache->fontsCount; ++i) { - if (strcmp (cache->fonts[i].fontFile, ctx->selectedFont.fontFile)==0 && cache->fonts[i].charSize == ctx->selectedFont.charSize) - return &cache->fonts[i]; - } - return NULL; + _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; + for (int i = 0; i < cache->fontsCount; ++i) { + if (strcmp (cache->fonts[i].fontFile, ctx->selectedFont.fontFile)==0 && cache->fonts[i].charSize == ctx->selectedFont.charSize) + return &cache->fonts[i]; + } + return NULL; } //try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. void _update_current_font (VkvgContext ctx) { - VkvgDevice dev = ctx->pSurf->dev; - if (ctx->currentFont == NULL){ - if (ctx->selectedFont.fontFile[0] == 0) { - ctx->selectedFont.charSize = 10 << 6; - _select_font_face (ctx, "sans"); - } - ctx->currentFont = _tryFindVkvgFont (ctx); - if (ctx->currentFont == NULL){ - //create new font in cache - _font_cache_t* cache = dev->fontCache; - cache->fontsCount++; - if (cache->fontsCount == 1) - cache->fonts = (_vkvg_font_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_t)); - else - cache->fonts = (_vkvg_font_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_t)); - - _vkvg_font_t nf = ctx->selectedFont; - if (nf.charSize == 0) - nf.charSize = defaultFontCharSize; - - nf.fontFile = (char*)calloc(FONT_FILE_NAME_MAX_SIZE,sizeof(char)); - strcpy (nf.fontFile, ctx->selectedFont.fontFile); - - FT_CHECK_RESULT(FT_New_Face(cache->library, nf.fontFile, 0, &nf.face)); - FT_CHECK_RESULT(FT_Set_Char_Size(nf.face, 0, nf.charSize, dev->hdpi, dev->vdpi )); - nf.hb_font = hb_ft_font_create(nf.face, NULL); - nf.charLookup = (_char_ref**)calloc(nf.face->num_glyphs,sizeof(_char_ref*)); - - //nf.curLine.height = (nf.face->bbox.xMax - nf.face->bbox.xMin) >> 6; - if (FT_IS_SCALABLE(nf.face)) - nf.curLine.height = FT_MulFix(nf.face->height, nf.face->size->metrics.y_scale) >> 6;// nf.face->size->metrics.height >> 6; - else - nf.curLine.height = nf.face->height >> 6; - - _init_next_line_in_tex_cache (dev, &nf); - cache->fonts[cache->fontsCount-1] = nf; - ctx->currentFont = &cache->fonts[cache->fontsCount-1]; - } - } + VkvgDevice dev = ctx->pSurf->dev; + if (ctx->currentFont == NULL){ + if (ctx->selectedFont.fontFile[0] == 0) { + ctx->selectedFont.charSize = 10 << 6; + _select_font_face (ctx, "sans"); + } + ctx->currentFont = _tryFindVkvgFont (ctx); + if (ctx->currentFont == NULL){ + //create new font in cache + _font_cache_t* cache = dev->fontCache; + cache->fontsCount++; + if (cache->fontsCount == 1) + cache->fonts = (_vkvg_font_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_t)); + else + cache->fonts = (_vkvg_font_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_t)); + + _vkvg_font_t nf = ctx->selectedFont; + if (nf.charSize == 0) + nf.charSize = defaultFontCharSize; + + nf.fontFile = (char*)calloc(FONT_FILE_NAME_MAX_SIZE,sizeof(char)); + strcpy (nf.fontFile, ctx->selectedFont.fontFile); + + FT_CHECK_RESULT(FT_New_Face(cache->library, nf.fontFile, 0, &nf.face)); + FT_CHECK_RESULT(FT_Set_Char_Size(nf.face, 0, nf.charSize, dev->hdpi, dev->vdpi )); + nf.hb_font = hb_ft_font_create(nf.face, NULL); + nf.charLookup = (_char_ref**)calloc(nf.face->num_glyphs,sizeof(_char_ref*)); + + //nf.curLine.height = (nf.face->bbox.xMax - nf.face->bbox.xMin) >> 6; + if (FT_IS_SCALABLE(nf.face)) + nf.curLine.height = FT_MulFix(nf.face->height, nf.face->size->metrics.y_scale) >> 6;// nf.face->size->metrics.height >> 6; + else + nf.curLine.height = nf.face->height >> 6; + + _init_next_line_in_tex_cache (dev, &nf); + cache->fonts[cache->fontsCount-1] = nf; + ctx->currentFont = &cache->fonts[cache->fontsCount-1]; + } + } } //Get harfBuzz buffer for provided text. hb_buffer_t * _get_hb_buffer (_vkvg_font_t* font, const char* text) { - hb_buffer_t *buf = hb_buffer_create(); + hb_buffer_t *buf = hb_buffer_create(); - const char *lng = "fr"; - hb_script_t script = HB_SCRIPT_LATIN; - script = hb_script_from_string (text, (int)strlen (text)); + const char *lng = "fr"; + hb_script_t script = HB_SCRIPT_LATIN; + script = hb_script_from_string (text, (int)strlen (text)); - hb_direction_t dir = hb_script_get_horizontal_direction(script); - //dir = HB_DIRECTION_TTB; - hb_buffer_set_direction (buf, dir); - hb_buffer_set_script (buf, script); - hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); - hb_buffer_add_utf8 (buf, text, (int)strlen(text), 0, (int)strlen(text)); + hb_direction_t dir = hb_script_get_horizontal_direction(script); + //dir = HB_DIRECTION_TTB; + hb_buffer_set_direction (buf, dir); + hb_buffer_set_script (buf, script); + hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); + hb_buffer_add_utf8 (buf, text, (int)strlen(text), 0, (int)strlen(text)); - hb_shape (font->hb_font, buf, NULL, 0); - return buf; + hb_shape (font->hb_font, buf, NULL, 0); + return buf; } //retrieve global font extends of context's current font as defined by FreeType void _font_extents (VkvgContext ctx, vkvg_font_extents_t *extents) { - _update_current_font (ctx); - - //TODO: ensure correct metrics are returned (scalled/unscalled, etc..) - FT_BBox* bbox = &ctx->currentFont->face->bbox; - FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; - extents->ascent = (float)(FT_MulFix(ctx->currentFont->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; - extents->descent= (float)(FT_MulFix(ctx->currentFont->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; - extents->height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; - extents->max_x_advance = (float)(bbox->xMax >> 6); - extents->max_y_advance = (float)(bbox->yMax >> 6); + _update_current_font (ctx); + + //TODO: ensure correct metrics are returned (scalled/unscalled, etc..) + FT_BBox* bbox = &ctx->currentFont->face->bbox; + FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; + extents->ascent = (float)(FT_MulFix(ctx->currentFont->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; + extents->descent= (float)(FT_MulFix(ctx->currentFont->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; + extents->height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; + extents->max_x_advance = (float)(bbox->xMax >> 6); + extents->max_y_advance = (float)(bbox->yMax >> 6); } //compute text extends for provided string. void _text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t *extents) { - _update_current_font (ctx); + _update_current_font (ctx); - vkvg_text_run_t tr = {0}; - _create_text_run (ctx, text, &tr); + vkvg_text_run_t tr = {0}; + _create_text_run (ctx, text, &tr); - *extents = tr.extents; + *extents = tr.extents; - _destroy_text_run (&tr); + _destroy_text_run (&tr); } void _create_text_run (VkvgContext ctx, const char* text, VkvgText textRun) { - _update_current_font (ctx); + _update_current_font (ctx); - textRun->hbBuf = _get_hb_buffer (ctx->currentFont, text); - textRun->font = ctx->currentFont; - textRun->dev = ctx->pSurf->dev; + textRun->hbBuf = _get_hb_buffer (ctx->currentFont, text); + textRun->font = ctx->currentFont; + textRun->dev = ctx->pSurf->dev; - textRun->glyph_pos = hb_buffer_get_glyph_positions (textRun->hbBuf, &textRun->glyph_count); + textRun->glyph_pos = hb_buffer_get_glyph_positions (textRun->hbBuf, &textRun->glyph_count); - unsigned int string_width_in_pixels = 0; - for (uint32_t i=0; i < textRun->glyph_count; ++i) - string_width_in_pixels += textRun->glyph_pos[i].x_advance >> 6; + unsigned int string_width_in_pixels = 0; + for (uint32_t i=0; i < textRun->glyph_count; ++i) + string_width_in_pixels += textRun->glyph_pos[i].x_advance >> 6; - FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; - textRun->extents.x_advance = (float)string_width_in_pixels; - textRun->extents.y_advance = (float)(textRun->glyph_pos[textRun->glyph_count-1].y_advance >> 6); - textRun->extents.x_bearing = -(float)(textRun->glyph_pos[0].x_offset >> 6); - textRun->extents.y_bearing = -(float)(textRun->glyph_pos[0].y_offset >> 6); + FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; + textRun->extents.x_advance = (float)string_width_in_pixels; + textRun->extents.y_advance = (float)(textRun->glyph_pos[textRun->glyph_count-1].y_advance >> 6); + textRun->extents.x_bearing = -(float)(textRun->glyph_pos[0].x_offset >> 6); + textRun->extents.y_bearing = -(float)(textRun->glyph_pos[0].y_offset >> 6); - textRun->extents.height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; - textRun->extents.width = textRun->extents.x_advance; + textRun->extents.height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; + textRun->extents.width = textRun->extents.x_advance; } void _destroy_text_run (VkvgText textRun) { - hb_buffer_destroy (textRun->hbBuf); + hb_buffer_destroy (textRun->hbBuf); } void _show_text_run (VkvgContext ctx, VkvgText tr) { - unsigned int glyph_count; - hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos (tr->hbBuf, &glyph_count); + unsigned int glyph_count; + hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos (tr->hbBuf, &glyph_count); - Vertex v = {{0},{0}}; - vec2 pen = {0,0}; + Vertex v = {{0},0}; + vec2 pen = {0,0}; - if (!_current_path_is_empty(ctx)) - pen = _get_current_position(ctx); + if (!_current_path_is_empty(ctx)) + pen = _get_current_position(ctx); - for (uint32_t i=0; i < glyph_count; ++i) { - _char_ref* cr = tr->font->charLookup[glyph_info[i].codepoint]; + for (uint32_t i=0; i < glyph_count; ++i) { + _char_ref* cr = tr->font->charLookup[glyph_info[i].codepoint]; - if (cr==NULL) - cr = _prepare_char(tr->dev, tr->font, glyph_info[i].codepoint); + if (cr==NULL) + cr = _prepare_char(tr->dev, tr->font, glyph_info[i].codepoint); - //continue; - if (cr!=NULL){ - float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; - float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; - vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyph_pos[i].x_offset >> 6), - pen.y - cr->bmpDiff.y + (tr->glyph_pos[i].y_offset >> 6)}; - v.pos = p0; + //continue; + if (cr!=NULL){ + float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; + float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; + vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyph_pos[i].x_offset >> 6), + pen.y - cr->bmpDiff.y + (tr->glyph_pos[i].y_offset >> 6)}; + v.pos = p0; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - v.uv.x = cr->bounds.x; - v.uv.y = cr->bounds.y; - v.uv.z = cr->pageIdx; - _add_vertex(ctx,v); + /* + v.uv.x = cr->bounds.x; + v.uv.y = cr->bounds.y; + v.uv.z = cr->pageIdx; + _add_vertex(ctx,v); - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx,v); - v.pos.x += cr->bounds.width; - v.pos.y = p0.y; - v.uv.x += uvWidth; - v.uv.y = cr->bounds.y; - _add_vertex(ctx,v); + v.pos.x += cr->bounds.width; + v.pos.y = p0.y; + v.uv.x += uvWidth; + v.uv.y = cr->bounds.y; + _add_vertex(ctx,v); - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx,v); +*/ + _add_tri_indices_for_rect (ctx, firstIdx); + } - _add_tri_indices_for_rect (ctx, firstIdx); - } + pen.x += (tr->glyph_pos[i].x_advance >> 6); + pen.y -= (tr->glyph_pos[i].y_advance >> 6); + } - pen.x += (tr->glyph_pos[i].x_advance >> 6); - pen.y -= (tr->glyph_pos[i].y_advance >> 6); - } + vkvg_move_to(ctx, pen.x, pen.y); - vkvg_move_to(ctx, pen.x, pen.y); - - _flush_chars_to_tex(tr->dev, tr->font); + _flush_chars_to_tex(tr->dev, tr->font); } #ifdef DEBUG void _show_texture (vkvg_context* ctx){ - Vertex vs[] = { - {{0,0}, {0,0,0}}, - {{0,FONT_PAGE_SIZE}, {0,1,0}}, - {{FONT_PAGE_SIZE,0}, {1,0,0}}, - {{FONT_PAGE_SIZE,FONT_PAGE_SIZE}, {1,1,0}} - }; + Vertex vs[] = { + {{0,0}, {0,0,0}}, + {{0,FONT_PAGE_SIZE}, {0,1,0}}, + {{FONT_PAGE_SIZE,0}, {1,0,0}}, + {{FONT_PAGE_SIZE,FONT_PAGE_SIZE}, {1,1,0}} + }; - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; - _add_vertex(ctx,vs[0]); - _add_vertex(ctx,vs[1]); - _add_vertex(ctx,vs[2]); - _add_vertex(ctx,vs[3]); + _add_vertex(ctx,vs[0]); + _add_vertex(ctx,vs[1]); + _add_vertex(ctx,vs[2]); + _add_vertex(ctx,vs[3]); - _add_tri_indices_for_rect (ctx, i); + _add_tri_indices_for_rect (ctx, i); } #endif void _show_text (VkvgContext ctx, const char* text){ - vkvg_text_run_t tr = {0}; - _create_text_run (ctx, text, &tr); + vkvg_text_run_t tr = {0}; + _create_text_run (ctx, text, &tr); - _show_text_run (ctx, &tr); + _show_text_run (ctx, &tr); - _destroy_text_run (&tr); + _destroy_text_run (&tr); - //_show_texture(ctx); return; + //_show_texture(ctx); return; } /*void testfonts(){ - FT_Library library; - FT_Face face; - FT_GlyphSlot slot; + FT_Library library; + FT_Face face; + FT_GlyphSlot slot; - assert(!FT_Init_FreeType(&library)); - assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); - assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); + assert(!FT_Init_FreeType(&library)); + assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); + assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); - //_build_face_tex(face); + //_build_face_tex(face); - hb_font_t *hb_font = hb_ft_font_create(face, NULL); - hb_buffer_t *buf = hb_buffer_create(); + hb_font_t *hb_font = hb_ft_font_create(face, NULL); + hb_buffer_t *buf = hb_buffer_create(); - const char *text = "Ленивый рыжий кот"; - const char *lng = "en"; - //"كسول الزنجبيل القط","懶惰的姜貓", + const char *text = "Ленивый рыжий кот"; + const char *lng = "en"; + //"كسول الزنجبيل القط","懶惰的姜貓", - hb_buffer_set_direction (buf, HB_DIRECTION_LTR); - hb_buffer_set_script (buf, HB_SCRIPT_LATIN); - hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); - hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); + hb_buffer_set_direction (buf, HB_DIRECTION_LTR); + hb_buffer_set_script (buf, HB_SCRIPT_LATIN); + hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); + hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); - hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); - hb_script_t sc = hb_buffer_get_script(buf); + hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); + hb_script_t sc = hb_buffer_get_script(buf); - sc = hb_unicode_script(unifc,0x0260); + sc = hb_unicode_script(unifc,0x0260); - FT_CharMap* cm = face->charmap; + FT_CharMap* cm = face->charmap; - //hb_script_to_iso15924_tag() + //hb_script_to_iso15924_tag() - FT_Done_Face ( face ); - FT_Done_FreeType( library ); + FT_Done_Face ( face ); + FT_Done_FreeType( library ); }*/ -- 2.47.3