font scaling fixes
continuous-integration/drone/push Build is passing Details

pull/1/head
cosmonaut 2023-12-07 22:53:24 -08:00
parent d99ef4d2c2
commit 355e98bb19
2 changed files with 36 additions and 29 deletions

View File

@ -114,7 +114,8 @@ WELLSPRINGAPI Wellspring_Font* Wellspring_CreateFont(
const uint8_t *fontBytes,
uint32_t fontBytesLength,
const uint8_t *atlasJsonBytes,
uint32_t atlasJsonBytesLength
uint32_t atlasJsonBytesLength,
float *pPixelsPerEm
);
/* Batches are not thread-safe, recommend one batch per thread. */
@ -128,8 +129,7 @@ WELLSPRINGAPI void Wellspring_StartTextBatch(
WELLSPRINGAPI uint8_t Wellspring_TextBounds(
Wellspring_Font *font,
float x,
float y,
int pixelSize,
Wellspring_HorizontalAlignment horizontalAlignment,
Wellspring_VerticalAlignment verticalAlignment,
const uint8_t *strBytes,
@ -141,6 +141,7 @@ WELLSPRINGAPI uint8_t Wellspring_Draw(
Wellspring_TextBatch *textBatch,
float x,
float y,
int pixelSize,
float depth,
Wellspring_Color *color,
Wellspring_HorizontalAlignment horizontalAlignment,

View File

@ -154,8 +154,10 @@ typedef struct Font
float ascender;
float descender;
float lineHeight;
float pixelsPerEm;
float scale;
float geometryScale; // all json values are premultiplied by this value, we need it for kerning
float kerningScale; // kerning values from stb_tt are in a different scale
Packer packer;
} Font;
@ -228,7 +230,6 @@ static uint8_t json_object_has_key(const json_object_t *object, const char* name
{
if (currentElement->next == NULL)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Key %s not found in JSON!", name);
return 0;
}
@ -349,7 +350,8 @@ Wellspring_Font* Wellspring_CreateFont(
const uint8_t* fontBytes,
uint32_t fontBytesLength,
const uint8_t *atlasJsonBytes,
uint32_t atlasJsonBytesLength
uint32_t atlasJsonBytesLength,
float *pPixelsPerEm
) {
Font *font = Wellspring_malloc(sizeof(Font));
@ -396,13 +398,13 @@ Wellspring_Font* Wellspring_CreateFont(
font->packer.width = json_object_get_uint(atlasObject, "width");
font->packer.height = json_object_get_uint(atlasObject, "height");
font->pixelsPerEm = json_object_get_double(atlasObject, "size");
font->ascender = json_object_get_double(metricsObject, "ascender");
font->descender = json_object_get_double(metricsObject, "descender");
font->lineHeight = json_object_get_double(metricsObject, "lineHeight");
font->geometryScale = font->ascender / stbAscender;
font->scale = 1 / (font->ascender - font->descender);
font->scale = font->pixelsPerEm * 4 / 3; // converting from "points" (dpi) to pixels
/* Pack unicode ranges */
@ -459,10 +461,6 @@ Wellspring_Font* Wellspring_CreateFont(
packedChar->atlasTop = json_object_get_double(boundsObject, "top");
packedChar->atlasBottom = json_object_get_double(boundsObject, "bottom");
// flip texture coords because the atlas outputs glyphs in OpenGL texture space (lol)
packedChar->atlasTop = font->packer.height - packedChar->atlasTop;
packedChar->atlasBottom = font->packer.height - packedChar->atlasBottom;
json_object_t *planeObject = json_object_get_object(currentGlyphObject, "planeBounds");
packedChar->planeLeft = json_object_get_double(planeObject, "left");
@ -474,7 +472,14 @@ Wellspring_Font* Wellspring_CreateFont(
currentGlyphElement = currentGlyphElement->next;
}
int advanceWidth, bearing;
stbtt_GetCodepointHMetrics(&font->fontInfo, font->packer.ranges[0].firstCodepoint, &advanceWidth, &bearing);
font->kerningScale = font->packer.ranges[0].data[0].xAdvance / advanceWidth;
Wellspring_free(jsonRoot);
*pPixelsPerEm = font->pixelsPerEm;
return (Wellspring_Font*) font;
}
@ -581,8 +586,7 @@ static void GetPackedQuad(PackedChar *charData, float scale, int packerWidth, in
static uint8_t Wellspring_Internal_TextBounds(
Font* font,
float x,
float y,
int pixelSize,
Wellspring_HorizontalAlignment horizontalAlignment,
Wellspring_VerticalAlignment verticalAlignment,
const uint8_t* strBytes,
@ -597,14 +601,16 @@ static uint8_t Wellspring_Internal_TextBounds(
PackedChar* rangeData;
Quad charQuad;
uint32_t i, j;
float x = 0, y = 0;
float minX = x;
float minY = y;
float maxX = x;
float maxY = y;
float startX = x;
float advance = 0;
float sizeFactor = pixelSize / font->pixelsPerEm;
y += Wellspring_INTERNAL_GetVerticalAlignOffset(font, verticalAlignment, font->scale);
y += Wellspring_INTERNAL_GetVerticalAlignOffset(font, verticalAlignment, sizeFactor * font->scale);
for (i = 0; i < strLengthInBytes; i += 1)
{
@ -645,8 +651,8 @@ static uint8_t Wellspring_Internal_TextBounds(
if (IsWhitespace(codepoint))
{
PackedChar *packedChar = rangeData + rangeIndex;
x += font->scale * packedChar->xAdvance;
maxX += font->scale * packedChar->xAdvance;
x += sizeFactor * font->scale * packedChar->xAdvance;
maxX += sizeFactor * font->scale * packedChar->xAdvance;
previousGlyphIndex = -1;
continue;
}
@ -655,12 +661,12 @@ static uint8_t Wellspring_Internal_TextBounds(
if (previousGlyphIndex != -1)
{
x += font->geometryScale * font->scale * stbtt_GetGlyphKernAdvance(&font->fontInfo, previousGlyphIndex, glyphIndex);
x += sizeFactor * font->kerningScale * font->scale * stbtt_GetGlyphKernAdvance(&font->fontInfo, previousGlyphIndex, glyphIndex);
}
GetPackedQuad(
rangeData,
font->scale,
sizeFactor * font->scale,
packer->width,
packer->height,
rangeIndex,
@ -700,8 +706,7 @@ static uint8_t Wellspring_Internal_TextBounds(
uint8_t Wellspring_TextBounds(
Wellspring_Font *font,
float x,
float y,
int pixelSize,
Wellspring_HorizontalAlignment horizontalAlignment,
Wellspring_VerticalAlignment verticalAlignment,
const uint8_t* strBytes,
@ -710,8 +715,7 @@ uint8_t Wellspring_TextBounds(
) {
return Wellspring_Internal_TextBounds(
(Font*) font,
x,
y,
pixelSize,
horizontalAlignment,
verticalAlignment,
strBytes,
@ -724,6 +728,7 @@ uint8_t Wellspring_Draw(
Wellspring_TextBatch *textBatch,
float x,
float y,
int pixelSize,
float depth,
Wellspring_Color *color,
Wellspring_HorizontalAlignment horizontalAlignment,
@ -745,13 +750,14 @@ uint8_t Wellspring_Draw(
uint32_t indexBufferIndex;
Wellspring_Rectangle bounds;
uint32_t i, j;
float sizeFactor = pixelSize / font->pixelsPerEm;
y += Wellspring_INTERNAL_GetVerticalAlignOffset(font, verticalAlignment, font->scale);
y += Wellspring_INTERNAL_GetVerticalAlignOffset(font, verticalAlignment, sizeFactor * font->scale);
/* FIXME: If we horizontally align, we have to decode and process glyphs twice, very inefficient. */
if (horizontalAlignment == WELLSPRING_HORIZONTALALIGNMENT_RIGHT)
{
if (!Wellspring_Internal_TextBounds(font, x, y, horizontalAlignment, verticalAlignment, strBytes, strLengthInBytes, &bounds))
if (!Wellspring_Internal_TextBounds(font, pixelSize, horizontalAlignment, verticalAlignment, strBytes, strLengthInBytes, &bounds))
{
/* Something went wrong while calculating bounds. */
return 0;
@ -761,7 +767,7 @@ uint8_t Wellspring_Draw(
}
else if (horizontalAlignment == WELLSPRING_HORIZONTALALIGNMENT_CENTER)
{
if (!Wellspring_Internal_TextBounds(font, x, y, horizontalAlignment, verticalAlignment, strBytes, strLengthInBytes, &bounds))
if (!Wellspring_Internal_TextBounds(font, pixelSize, horizontalAlignment, verticalAlignment, strBytes, strLengthInBytes, &bounds))
{
/* Something went wrong while calculating bounds. */
return 0;
@ -807,7 +813,7 @@ uint8_t Wellspring_Draw(
if (IsWhitespace(codepoint))
{
PackedChar *packedChar = rangeData + rangeIndex;
x += font->scale * packedChar->xAdvance;
x += sizeFactor * font->scale * packedChar->xAdvance;
previousGlyphIndex = -1;
continue;
}
@ -816,12 +822,12 @@ uint8_t Wellspring_Draw(
if (previousGlyphIndex != -1)
{
x += font->geometryScale * font->scale * stbtt_GetGlyphKernAdvance(&font->fontInfo, previousGlyphIndex, glyphIndex);
x += sizeFactor * font->kerningScale * font->scale * stbtt_GetGlyphKernAdvance(&font->fontInfo, previousGlyphIndex, glyphIndex);
}
GetPackedQuad(
rangeData,
font->scale,
sizeFactor * font->scale,
myPacker->width,
myPacker->height,
rangeIndex,