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

View File

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