Compare commits

...
Author SHA1 Message Date
asarium 34bcb03ef8 Add text rendering using signed distance fonts
Signed distance fonts have the advantage that they can be used to apply
complicated effects at runtime without having to rerender the text on
the CPU. This would make it possible to add support for rendering the
outline of the text using a different color but this currently only
renders the text like before.
2017-12-19 13:22:50 +01:00
8 changed files with 1461 additions and 117 deletions

No files matched your search

+13
View File
@@ -52,6 +52,9 @@ float strokeMask() {
}
#endif
// The value the distance field has when the pixel is exactly on the edge. This needs to match the values in fontstash.h!
const float ON_EDGE_DISTANCE = 180.0 / 255.0;
void main(void) {
vec4 result;
float scissor = scissorMask(fpos);
@@ -90,6 +93,16 @@ void main(void) {
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
if (texType == 1) color = vec4(color.xyz*color.w,color.w); if (texType == 2) color = vec4(color.x); color *= scissor;
result = color * innerCol;
} else if (type == 4) { // Distance vector text
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
float dist = color.r;
float width = fwidth(dist) / 2.0;
float alpha = smoothstep(ON_EDGE_DISTANCE - width, ON_EDGE_DISTANCE + width, dist);
color = innerCol * alpha;
result = color * scissor;
}
outColor = result;
}
+23
View File
@@ -48,6 +48,10 @@ void nvgRenderTriangles(void* userptr, NVGpaint* paint, NVGscissor* scissor, con
auto renderer = static_cast<NanoVGRenderer*>(userptr);
renderer->renderTriangles(paint, scissor, verts, nverts);
}
void nvgRenderText(void* userptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts) {
auto renderer = static_cast<NanoVGRenderer*>(userptr);
renderer->renderText(paint, scissor, verts, nverts);
}
void nvgRenderFill(void* userptr,
NVGpaint* paint,
NVGscissor* scissor,
@@ -162,6 +166,7 @@ NVGcontext* createNanoVGContext() {
params.renderViewport = nvgViewport;
params.renderTriangles = nvgRenderTriangles;
params.renderText = nvgRenderText;
params.renderFill = nvgRenderFill;
params.renderStroke = nvgRenderStroke;
params.renderFlush = nvgRenderFlush;
@@ -347,6 +352,24 @@ void NanoVGRenderer::renderTriangles(NVGpaint* paint, NVGscissor* scissor, const
uniformData->type = NanoVGShaderType::Image;
}
void NanoVGRenderer::renderText(NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts) {
_vertices.insert(_vertices.end(), verts, verts + nverts);
auto call = addDrawCall();
call->type = CallType::Triangles;
call->triangleCount = static_cast<uint32_t>(nverts);
call->triangleOffset = static_cast<uint32_t>(addVertices(verts, static_cast<size_t>(nverts)));
call->image = paint->image;
call->uniformIndex = addUniformData(1);
auto uniformData = &_uniformData[call->uniformIndex];
auto succcess = convertPaint(uniformData, paint, scissor, 1.0f, 1.0f, -1.0f);
Assertion(succcess, "Failed to convert paint, probably caused by an invalid texture handle.");
uniformData->type = NanoVGShaderType::Text;
}
void NanoVGRenderer::renderStroke(NVGpaint* paint,
NVGscissor* scissor,
float fringe,
+2
View File
@@ -140,6 +140,8 @@ class NanoVGRenderer {
void renderTriangles(NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void renderText(NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void renderFlush();
void renderCancel();
+40 -35
View File
@@ -292,10 +292,40 @@ int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float
return 1;
}
void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
float scaleX, float scaleY, int glyph)
void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int padding, int outWidth, int outHeight, int outStride,
float scale, int glyph)
{
stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
unsigned char onedge_value = 180;
float pixel_dist_scale = onedge_value / (float)padding;
int width, height;
unsigned char* sdf = stbtt_GetGlyphSDF(&font->font,
scale,
glyph,
padding,
onedge_value,
pixel_dist_scale,
&width,
&height,
NULL,
NULL);
if (sdf == NULL) {
// There is no glyph available here
return;
}
unsigned char* data = output;
unsigned char* input = sdf;
for (int y = 0; y < height; ++y) {
memcpy(data, input, width);
data += outStride;
input += width;
}
stbtt_FreeSDF(sdf, font->font.userdata);
}
int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
@@ -988,26 +1018,6 @@ static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int
}
}
static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
{
int alpha;
float sigma;
(void)stash;
if (blur < 1)
return;
// Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
fons__blurRows(dst, w, h, dstStride, alpha);
fons__blurCols(dst, w, h, dstStride, alpha);
fons__blurRows(dst, w, h, dstStride, alpha);
fons__blurCols(dst, w, h, dstStride, alpha);
// fons__blurrows(dst, w, h, dstStride, alpha);
// fons__blurcols(dst, w, h, dstStride, alpha);
}
static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
short isize, short iblur)
{
@@ -1017,12 +1027,12 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
unsigned int h;
float size = isize/10.0f;
int pad, added;
unsigned char* bdst;
unsigned char* dst;
if (isize < 2) return NULL;
if (iblur < 2) iblur = 2;
if (iblur > 20) iblur = 20;
pad = iblur+2;
pad = iblur + 2;
// Reset allocator.
stash->nscratch = 0;
@@ -1050,7 +1060,9 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
}
if (added == 0) return NULL;
if (added == 0) {
return NULL;
}
// Init glyph.
glyph = fons__allocGlyph(font);
@@ -1072,8 +1084,8 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
font->lut[h] = font->nglyphs-1;
// Rasterize
dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
fons__tt_renderGlyphBitmap(&font->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g);
dst = &stash->texData[(glyph->x0 + pad - iblur) + (glyph->y0 + pad - iblur) * stash->params.width];
fons__tt_renderGlyphBitmap(&font->font, dst, iblur, gw, gh, stash->params.width, scale, g);
// Make sure there is one pixel empty border.
dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
@@ -1096,13 +1108,6 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
}
}*/
// Blur
if (iblur > 0) {
stash->nscratch = 0;
bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
}
stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
+7 -7
View File
@@ -2289,7 +2289,7 @@ static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts)
paint.innerColor.a *= state->alpha;
paint.outerColor.a *= state->alpha;
ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts);
ctx->params.renderText(ctx->params.userPtr, &paint, &state->scissor, verts, nverts);
ctx->drawCallCount++;
ctx->textTriCount += nverts/3;
@@ -2345,12 +2345,12 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
nvgTransformPoint(&c[6],&c[7], state->xform, q.x0*invscale, q.y1*invscale);
// Create triangles
if (nverts+6 <= cverts) {
nvg__vset(&verts[nverts], roundf(c[0]), roundf(c[1]), q.s0, q.t0); nverts++;
nvg__vset(&verts[nverts], roundf(c[4]), roundf(c[5]), q.s1, q.t1); nverts++;
nvg__vset(&verts[nverts], roundf(c[2]), roundf(c[3]), q.s1, q.t0); nverts++;
nvg__vset(&verts[nverts], roundf(c[0]), roundf(c[1]), q.s0, q.t0); nverts++;
nvg__vset(&verts[nverts], roundf(c[6]), roundf(c[7]), q.s0, q.t1); nverts++;
nvg__vset(&verts[nverts], roundf(c[4]), roundf(c[5]), q.s1, q.t1); nverts++;
nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
nvg__vset(&verts[nverts], c[2], c[3], q.s1, q.t0); nverts++;
nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
nvg__vset(&verts[nverts], c[6], c[7], q.s0, q.t1); nverts++;
nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
}
}
+1
View File
@@ -594,6 +594,7 @@ struct NVGparams {
void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void (*renderText)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void (*renderDelete)(void* uptr);
};
typedef struct NVGparams NVGparams;
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -123,7 +123,7 @@ struct model_uniform_data {
};
enum class NanoVGShaderType: int32_t {
FillGradient = 0, FillImage = 1, Simple = 2, Image = 3
FillGradient = 0, FillImage = 1, Simple = 2, Image = 3, Text = 4
};
struct nanovg_draw_data {
float scissorMat[12]; // matrices are actually 3 vec4s