diff --git a/include/Wellspring.h b/include/Wellspring.h index 0565c8a..2cf60e3 100644 --- a/include/Wellspring.h +++ b/include/Wellspring.h @@ -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, diff --git a/src/Wellspring.c b/src/Wellspring.c index b3c9f38..efffc71 100644 --- a/src/Wellspring.c +++ b/src/Wellspring.c @@ -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,