diff --git a/src/AssetManager.c b/src/AssetManager.c index 370d00d..512446a 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -120,13 +120,12 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) stbtt_InitFont(&fontInfo, fontFileRead.buffer, stbtt_GetFontOffsetForIndex(fontFileRead.buffer, 0)); + /* Initialise Assetmanager Font */ Font *font = &assetManager->font; font->codepointRange = V2i(32, 127); - v2i codepointRange = font->codepointRange; const i32 numGlyphs = codepointRange.y - codepointRange.x; - i32 glyphIndex = 0; GlyphBitmap *glyphBitmaps = CAST(GlyphBitmap *) calloc(numGlyphs, sizeof(GlyphBitmap)); v2i largestGlyphDimension = V2i(0, 0); @@ -134,7 +133,20 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) const f32 targetFontHeight = 64.0f; f32 scaleY = stbtt_ScaleForPixelHeight(&fontInfo, targetFontHeight); + i32 ascent, descent, lineGap; + stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); + + ascent = CAST(i32)(ascent * scaleY); + descent = CAST(i32)(descent * scaleY); + lineGap = CAST(i32)(lineGap * scaleY); + + font->metrics = CAST(FontMetrics){ascent, descent, lineGap}; + + font->charMetrics = + CAST(CharMetrics *) calloc(numGlyphs, sizeof(CharMetrics)); + /* Use STB_TrueType to generate a series of bitmap characters */ + i32 glyphIndex = 0; for (i32 codepoint = codepointRange.x; codepoint < codepointRange.y; codepoint++) { @@ -161,7 +173,22 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) } } + /* Get individual character metrics */ + i32 advance, leftSideBearing; + stbtt_GetCodepointHMetrics(&fontInfo, codepoint, &advance, + &leftSideBearing); + + advance = CAST(i32)(advance * scaleY); + leftSideBearing = CAST(i32)(leftSideBearing * scaleY); + + font->charMetrics[glyphIndex] = + CAST(CharMetrics){advance, leftSideBearing, NULL, + V2i(xOffset, yOffset), V2i(width, height)}; + + /* Store bitmap into intermediate storage */ stbtt_FreeBitmap(monoBitmap, NULL); + + // TODO(doyle): Dimensions is used twice in font->trueSize and this glyphBitmaps[glyphIndex].dimensions = V2i(width, height); glyphBitmaps[glyphIndex].codepoint = codepoint; glyphBitmaps[glyphIndex++].pixels = colorBitmap; @@ -180,7 +207,6 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) "unoptimal\n"); } #endif - } /* @@ -199,12 +225,12 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) if ((largestGlyphDimension.h & 1) == 1) largestGlyphDimension.h += 1; - font->charSize = largestGlyphDimension; + font->maxSize= largestGlyphDimension; - i32 glyphsPerRow = (MAX_TEXTURE_SIZE / font->charSize.w) + 1; + i32 glyphsPerRow = (MAX_TEXTURE_SIZE / font->maxSize.w) + 1; #ifdef WT_DEBUG - i32 glyphsPerCol = MAX_TEXTURE_SIZE / font->charSize.h; + i32 glyphsPerCol = MAX_TEXTURE_SIZE / font->maxSize.h; if ((glyphsPerRow * glyphsPerCol) <= numGlyphs) { printf( @@ -244,15 +270,22 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) ASSERT(activeGlyph.codepoint < ARRAY_COUNT(fontAtlas->texRect)); #endif - v2 origin = V2(CAST(f32)(glyphIndex * font->charSize.w), - CAST(f32) row); + v2 origin = + V2(CAST(f32)(glyphIndex * font->maxSize.w), CAST(f32) row); +#if 1 fontAtlas->texRect[atlasIndex++] = - getRect(origin, V2(CAST(f32) font->charSize.w, - CAST(f32) font->charSize.h)); + getRect(origin, V2(CAST(f32) font->maxSize.w, + CAST(f32) font->maxSize.h)); +#else + v2i fontSize = + font->charMetrics[activeGlyph.codepoint - 32].trueSize; + fontAtlas->texRect[atlasIndex++] = + getRect(origin, V2(CAST(f32)fontSize.x, CAST(f32)fontSize.y)); +#endif } /* Copy over exactly one row of pixels */ - i32 numPixelsToPad = font->charSize.w; + i32 numPixelsToPad = font->maxSize.w; if (verticalPixelsBlitted < activeGlyph.dimensions.h) { const i32 srcPitch = @@ -270,14 +303,13 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) * (NULL/mixes up rows), instead just advance the final bitmap * pointer by the remaining distance */ - numPixelsToPad = - font->charSize.w - activeGlyph.dimensions.w; + numPixelsToPad = font->maxSize.w - activeGlyph.dimensions.w; } destRow += numPixelsToPad; } /* A row of glyphs has been fully formed on the atlas */ - if (verticalPixelsBlitted++ >= font->charSize.h) + if (verticalPixelsBlitted++ >= font->maxSize.h) { verticalPixelsBlitted = 0; startingGlyphIndex += glyphsPerRow; diff --git a/src/Renderer.c b/src/Renderer.c index 4d1e50c..51d6676 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -28,6 +28,12 @@ void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v3 color, // TODO(doyle): Unimplemented // this->shader->uniformSetVec3f("spriteColor", color); +#if 1 + glBindVertexArray(renderer->vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, renderer->numVertexesInVbo); + glBindVertexArray(0); +#endif + glActiveTexture(GL_TEXTURE0); if (tex) @@ -40,6 +46,7 @@ void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v3 color, glDrawArrays(GL_TRIANGLE_STRIP, 0, renderer->numVertexesInVbo); glBindVertexArray(0); + glBindTexture(GL_TEXTURE_2D, 0); glCheckError(); } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index d90dfc3..7fc1cbc 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -343,26 +343,42 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) V3(0, 0, 0), worldTex); Font *font = &assetManager->font; - char *string = "hello world"; - i32 strLen = 11; + char *string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + i32 strLen = 52; quadIndex = 0; RenderQuad *stringQuads = CAST(RenderQuad *)calloc(strLen, sizeof(RenderQuad)); + f32 baseline = 100.0f; f32 xPosOnScreen = 20.0f; + f32 yPosOnScreen = baseline; for (i32 i = 0; i < strLen; i++) { // NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint to // its actual atlas index, i.e. we skip the first 31 glyphs - i32 atlasIndex = string[i] - font->codepointRange.x; + i32 codepoint = string[i]; + i32 relativeIndex = codepoint - font->codepointRange.x; + CharMetrics charMetric = font->charMetrics[relativeIndex]; - v4 charTexRect = font->atlas->texRect[atlasIndex]; + i32 charBaseline = (font->maxSize.h - charMetric.trueSize.h); + if (codepoint == 'a') + { + yPosOnScreen = baseline - charBaseline; + } + else + { + yPosOnScreen = baseline; + } + + const v4 charRectOnScreen = getRect( + V2(xPosOnScreen, yPosOnScreen), + V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h)); + + xPosOnScreen += charMetric.advance; + + /* Get texture out */ + v4 charTexRect = font->atlas->texRect[relativeIndex]; renderer_flipTexCoord(&charTexRect, FALSE, TRUE); - const v4 charRectOnScreen = - getRect(V2(xPosOnScreen, 100.0f), - V2(CAST(f32) font->charSize.w, CAST(f32) font->charSize.w)); - xPosOnScreen += font->charSize.w; - RenderQuad charQuad = renderer_createQuad( &state->renderer, charRectOnScreen, charTexRect, font->tex); stringQuads[quadIndex++] = charQuad; diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index ebdca30..7741689 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -32,12 +32,33 @@ typedef struct TexAtlas v4 texRect[128]; } TexAtlas; +typedef struct FontMetrics +{ + i32 ascent; + i32 descent; + i32 lineGap; +} FontMetrics; + +typedef struct CharMetrics +{ + i32 advance; + i32 leftSideBearing; + i32 *kerning; + v2i offset; + v2i trueSize; +} CharMetrics; + typedef struct Font { TexAtlas *atlas; Texture *tex; + + FontMetrics metrics; + CharMetrics *charMetrics; + v2i codepointRange; - v2i charSize; + v2i maxSize; + } Font; // TODO(doyle): Switch to hash based lookup