2018-01-22 16:28:33 +00:00
|
|
|
#include "data/rasterizer.h"
|
2019-04-05 11:27:48 +00:00
|
|
|
#include "data/blob.h"
|
|
|
|
#include "data/textureData.h"
|
2018-12-12 07:49:48 +00:00
|
|
|
#include "resources/VarelaRound.ttf.h"
|
2019-04-05 11:04:52 +00:00
|
|
|
#include "lib/utf.h"
|
2018-07-05 08:55:09 +00:00
|
|
|
#include "lib/stb/stb_truetype.h"
|
2017-07-14 15:18:25 +00:00
|
|
|
#include "msdfgen-c.h"
|
2019-04-05 11:27:48 +00:00
|
|
|
#include <stdlib.h>
|
2018-07-05 08:55:09 +00:00
|
|
|
#include <math.h>
|
2017-07-14 15:18:25 +00:00
|
|
|
|
2019-01-12 06:37:54 +00:00
|
|
|
Rasterizer* lovrRasterizerInit(Rasterizer* rasterizer, Blob* blob, float size) {
|
2018-07-05 08:55:09 +00:00
|
|
|
stbtt_fontinfo* font = &rasterizer->font;
|
2018-12-12 07:49:48 +00:00
|
|
|
unsigned char* data = blob ? blob->data : VarelaRound_ttf;
|
2018-07-05 08:55:09 +00:00
|
|
|
if (!stbtt_InitFont(font, data, stbtt_GetFontOffsetForIndex(data, 0))) {
|
|
|
|
lovrThrow("Problem loading font");
|
2017-04-02 12:55:21 +00:00
|
|
|
}
|
|
|
|
|
2018-07-29 08:26:12 +00:00
|
|
|
lovrRetain(blob);
|
2018-01-22 16:28:33 +00:00
|
|
|
rasterizer->blob = blob;
|
|
|
|
rasterizer->size = size;
|
2018-07-05 08:55:09 +00:00
|
|
|
rasterizer->scale = stbtt_ScaleForMappingEmToPixels(font, size);
|
|
|
|
rasterizer->glyphCount = font->numGlyphs;
|
2017-02-06 05:05:09 +00:00
|
|
|
|
2018-07-05 08:55:09 +00:00
|
|
|
int ascent, descent, linegap;
|
|
|
|
stbtt_GetFontVMetrics(font, &ascent, &descent, &linegap);
|
|
|
|
rasterizer->ascent = roundf(ascent * rasterizer->scale);
|
|
|
|
rasterizer->descent = roundf(descent * rasterizer->scale);
|
|
|
|
rasterizer->height = roundf((ascent - descent + linegap) * rasterizer->scale);
|
|
|
|
|
|
|
|
int x0, y0, x1, y1;
|
|
|
|
stbtt_GetFontBoundingBox(font, &x0, &y0, &x1, &y1);
|
|
|
|
rasterizer->advance = roundf(x1 * rasterizer->scale);
|
2017-02-06 05:05:09 +00:00
|
|
|
|
2018-01-22 16:28:33 +00:00
|
|
|
return rasterizer;
|
2017-01-30 02:37:56 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
void lovrRasterizerDestroy(void* ref) {
|
|
|
|
Rasterizer* rasterizer = ref;
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(Blob, rasterizer->blob);
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
2018-01-23 02:49:45 +00:00
|
|
|
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t character) {
|
2018-07-05 08:55:09 +00:00
|
|
|
return stbtt_FindGlyphIndex(&rasterizer->font, character) != 0;
|
2018-01-23 02:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str) {
|
2019-03-17 07:58:01 +00:00
|
|
|
const char* end = str + strlen(str);
|
2018-01-23 02:49:45 +00:00
|
|
|
unsigned int codepoint;
|
|
|
|
size_t bytes;
|
|
|
|
|
|
|
|
bool hasGlyphs = true;
|
|
|
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
|
|
|
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, codepoint);
|
|
|
|
str += bytes;
|
|
|
|
}
|
|
|
|
return hasGlyphs;
|
|
|
|
}
|
|
|
|
|
2018-01-22 16:28:33 +00:00
|
|
|
void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, Glyph* glyph) {
|
2018-07-05 08:55:09 +00:00
|
|
|
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, character);
|
2018-11-12 01:17:42 +00:00
|
|
|
lovrAssert(glyphIndex, "No font glyph found for character code %d, try using Rasterizer:hasGlyphs", character);
|
2017-01-30 02:37:56 +00:00
|
|
|
|
2018-07-05 08:55:09 +00:00
|
|
|
// Trace glyph outline
|
|
|
|
stbtt_vertex* vertices;
|
|
|
|
int vertexCount = stbtt_GetGlyphShape(&rasterizer->font, glyphIndex, &vertices);
|
2017-07-14 15:18:25 +00:00
|
|
|
msShape* shape = msShapeCreate();
|
2018-07-05 08:55:09 +00:00
|
|
|
msContour* contour = NULL;
|
|
|
|
float x = 0;
|
|
|
|
float y = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < vertexCount; i++) {
|
|
|
|
stbtt_vertex vertex = vertices[i];
|
|
|
|
float x2 = vertex.x * rasterizer->scale;
|
|
|
|
float y2 = vertex.y * rasterizer->scale;
|
|
|
|
|
|
|
|
switch (vertex.type) {
|
|
|
|
case STBTT_vmove:
|
|
|
|
contour = msShapeAddContour(shape);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STBTT_vline:
|
|
|
|
msContourAddLinearEdge(contour, x, y, x2, y2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STBTT_vcurve: {
|
|
|
|
float cx = vertex.cx * rasterizer->scale;
|
|
|
|
float cy = vertex.cy * rasterizer->scale;
|
|
|
|
msContourAddQuadraticEdge(contour, x, y, cx, cy, x2, y2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case STBTT_vcubic: {
|
|
|
|
float cx1 = vertex.cx * rasterizer->scale;
|
|
|
|
float cy1 = vertex.cy * rasterizer->scale;
|
|
|
|
float cx2 = vertex.cx1 * rasterizer->scale;
|
|
|
|
float cy2 = vertex.cy1 * rasterizer->scale;
|
|
|
|
msContourAddCubicEdge(contour, x, y, cx1, cy1, cx2, cy2, x2, y2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x = x2;
|
|
|
|
y = y2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int advance, bearing;
|
|
|
|
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2018-07-05 08:55:09 +00:00
|
|
|
int x0, y0, x1, y1;
|
|
|
|
stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1);
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2018-07-05 08:55:09 +00:00
|
|
|
bool empty = stbtt_IsGlyphEmpty(&rasterizer->font, glyphIndex);
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2018-07-05 08:55:09 +00:00
|
|
|
// Initialize glyph data
|
2017-02-05 06:21:41 +00:00
|
|
|
glyph->x = 0;
|
|
|
|
glyph->y = 0;
|
2018-07-05 08:55:09 +00:00
|
|
|
glyph->w = empty ? 0 : ceilf((x1 - x0) * rasterizer->scale);
|
|
|
|
glyph->h = empty ? 0 : ceilf((y1 - y0) * rasterizer->scale);
|
2017-07-14 16:53:05 +00:00
|
|
|
glyph->tw = glyph->w + 2 * GLYPH_PADDING;
|
|
|
|
glyph->th = glyph->h + 2 * GLYPH_PADDING;
|
2018-07-05 08:55:09 +00:00
|
|
|
glyph->dx = empty ? 0 : roundf(bearing * rasterizer->scale);
|
|
|
|
glyph->dy = empty ? 0 : roundf(y1 * rasterizer->scale);
|
|
|
|
glyph->advance = roundf(advance * rasterizer->scale);
|
2018-08-21 01:14:33 +00:00
|
|
|
glyph->data = lovrTextureDataCreate(glyph->tw, glyph->th, 0, FORMAT_RGB);
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2017-07-14 15:18:25 +00:00
|
|
|
// Render SDF
|
2017-07-14 16:53:05 +00:00
|
|
|
float tx = GLYPH_PADDING + -glyph->dx;
|
|
|
|
float ty = GLYPH_PADDING + glyph->h - glyph->dy;
|
2017-07-14 15:18:25 +00:00
|
|
|
msShapeNormalize(shape);
|
|
|
|
msEdgeColoringSimple(shape, 3.0, 0);
|
2018-07-17 21:53:21 +00:00
|
|
|
msGenerateMSDF(glyph->data->blob.data, glyph->tw, glyph->th, shape, 4., 1, 1, tx, ty);
|
2017-07-14 15:18:25 +00:00
|
|
|
msShapeDestroy(shape);
|
2017-01-30 02:37:56 +00:00
|
|
|
}
|
2017-02-08 06:11:20 +00:00
|
|
|
|
2018-01-22 16:28:33 +00:00
|
|
|
int lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t left, uint32_t right) {
|
2018-07-05 08:55:09 +00:00
|
|
|
return stbtt_GetCodepointKernAdvance(&rasterizer->font, left, right) * rasterizer->scale;
|
2017-02-08 06:11:20 +00:00
|
|
|
}
|