Move text measuring to Rasterizer

This commit is contained in:
Josip Miskovic 2021-10-12 00:31:43 +02:00 committed by Bjorn
parent 0a2f968850
commit 09cc73a988
4 changed files with 71 additions and 41 deletions

View File

@ -54,6 +54,19 @@ static int l_lovrRasterizerHasGlyphs(lua_State* L) {
return 1;
}
static int l_lovrRasterizerGetWidth(lua_State* L) {
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
size_t length;
const char* string = luaL_checklstring(L, 2, &length);
float wrap = luax_optfloat(L, 4, 0.f);
float width, height;
uint32_t lineCount, glyphCount;
lovrRasterizerMeasure(rasterizer, string, length, wrap, &width, &height, &lineCount, &glyphCount);
lua_pushnumber(L, width);
lua_pushnumber(L, lineCount + 1);
return 2;
}
const luaL_Reg lovrRasterizer[] = {
{ "getHeight", l_lovrRasterizerGetHeight },
{ "getAdvance", l_lovrRasterizerGetAdvance },
@ -62,5 +75,6 @@ const luaL_Reg lovrRasterizer[] = {
{ "getLineHeight", l_lovrRasterizerGetLineHeight },
{ "getGlyphCount", l_lovrRasterizerGetGlyphCount },
{ "hasGlyphs", l_lovrRasterizerHasGlyphs },
{ "getWidth", l_lovrRasterizerGetWidth },
{ NULL, NULL }
};

View File

@ -184,3 +184,54 @@ void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, uint32_
int32_t lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t left, uint32_t right) {
return stbtt_GetCodepointKernAdvance(&rasterizer->font, left, right) * rasterizer->scale;
}
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
float x = 0.f;
const char* end = str + length;
size_t bytes;
unsigned int previous = '\0';
unsigned int codepoint;
*width = 0.f;
*lineCount = 0;
*glyphCount = 0;
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
if (codepoint == '\n' || (wrap && x > wrap && codepoint == ' ')) {
*width = MAX(*width, x);
(*lineCount)++;
x = 0.f;
previous = '\0';
str += bytes;
continue;
}
// Tabs
if (codepoint == '\t') {
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, ' ');
int advance, bearing;
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
x += advance * 4.f;
str += bytes;
continue;
}
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
int advance, bearing;
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
int x0, y0, x1, y1;
stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1);
float w = ceilf((x1 - x0) * rasterizer->scale);
float h = ceilf((y1 - y0) * rasterizer->scale);
if (w > 0 && h > 0) {
(*glyphCount)++;
}
x += roundf(advance * rasterizer->scale) + lovrRasterizerGetKerning(rasterizer, previous, codepoint);
previous = codepoint;
str += bytes;
}
*width = MAX(*width, x);
*height = ((*lineCount + 1) * lovrRasterizerGetHeight(rasterizer));
}

View File

@ -1,5 +1,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#pragma once
@ -32,3 +33,4 @@ bool lovrRasterizerHasGlyph(Rasterizer* fontData, uint32_t character);
bool lovrRasterizerHasGlyphs(Rasterizer* fontData, const char* str);
void lovrRasterizerLoadGlyph(Rasterizer* fontData, uint32_t character, uint32_t padding, double spread, Glyph* glyph);
int32_t lovrRasterizerGetKerning(Rasterizer* fontData, uint32_t left, uint32_t right);
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* height, uint32_t* lineCount, uint32_t* glyphCount);

View File

@ -200,47 +200,10 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
}
void lovrFontMeasure(Font* font, const char* str, size_t length, float wrap, float* width, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
float x = 0.f;
const char* end = str + length;
size_t bytes;
unsigned int previous = '\0';
unsigned int codepoint;
float scale = 1.f / font->pixelDensity;
*width = 0.f;
*lineCount = 0;
*glyphCount = 0;
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
if (codepoint == '\n' || (wrap && x * scale > wrap && codepoint == ' ')) {
*width = MAX(*width, x * scale);
(*lineCount)++;
x = 0.f;
previous = '\0';
str += bytes;
continue;
}
// Tabs
if (codepoint == '\t') {
Glyph* space = lovrFontGetGlyph(font, ' ');
x += space->advance * 4.f;
str += bytes;
continue;
}
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
if (glyph->w > 0 && glyph->h > 0) {
(*glyphCount)++;
}
x += glyph->advance + lovrFontGetKerning(font, previous, codepoint);
previous = codepoint;
str += bytes;
}
*width = MAX(*width, x * scale);
*height = ((*lineCount + 1) * lovrRasterizerGetHeight(font->rasterizer) * font->lineHeight) * (font->flip ? -1 : 1);
wrap *= font->pixelDensity;
lovrRasterizerMeasure(font->rasterizer, str, length, wrap, width, height, lineCount, glyphCount);
*width /= font->pixelDensity;
*height *= font->lineHeight * (font->flip ? -1 : 1);
}
uint32_t lovrFontGetPadding(Font* font) {