/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "font.h" // Due to some compiler bullshit, this is here. #ifndef STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION #include #endif void fontInit(font_t *font, char *data) { int32_t i, s; s = FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT; uint8_t *bitmapData = malloc(sizeof(uint8_t) * s); pixel_t *pixels = malloc(sizeof(pixel_t) * s); // STBTT Loads fonts as single channel values only. stbtt_BakeFontBitmap( data, 0, FONT_TEXTURE_SIZE, bitmapData, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, FONT_FIRST_CHAR, FONT_NUM_CHARS, font->characterData ); for(i = 0; i < FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT; i++) { pixels[i].r = 0xFF; pixels[i].g = 0xFF; pixels[i].b = 0xFF; pixels[i].a = bitmapData[i]; } textureInit(&font->texture, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, pixels); free(bitmapData); free(pixels); } void fontDispose(font_t *font) { textureDispose(&font->texture); } fonttextinfo_t * fontGetTextInfo(font_t *font, char *text) { return fontTextClamp(font, text, 999999); } void fontTextInfoDispose(fonttextinfo_t *info) { free(info->quads); free(info); } void fontTextBuffer(font_t *font,primitive_t *primitive,fonttextinfo_t *info) { stbtt_aligned_quad *quad; int32_t i; for(i = 0; i < info->realLength; i++) { quad = info->quads + i; quadBuffer(primitive, 0, quad->x0, quad->y0, quad->s0, quad->t0, quad->x1, quad->y1, quad->s1, quad->t1, i*QUAD_VERTICE_COUNT, i*QUAD_INDICE_COUNT ); } } void fontTextInit(font_t *font, primitive_t *primitive, fonttextinfo_t *info) { primitiveInit(primitive, QUAD_VERTICE_COUNT * info->realLength, QUAD_INDICE_COUNT * info->realLength ); fontTextBuffer(font, primitive, info); } fonttextinfo_t * fontTextClamp(font_t *font, char *text, float maxWidth) { // This method is similar to fontGetTextInfo, but will modify the text. int32_t i, j, wordIndex; char c; float x, y, wordX; stbtt_aligned_quad *quad; fonttextinfo_t *info = malloc(sizeof(fonttextinfo_t)); /** Which index in the original text var is the current word from */ int32_t wordStart = 0; /** Buffer of the quads for the word (currently) */ int32_t bufferTextSize = 64; info->quads = malloc(sizeof(stbtt_aligned_quad) * bufferTextSize); // Setup Scales info->length = 0; info->realLength = 0; info->lines = 1; // Unlike GetTextInfo we can actually calculate the quads at the same time // that we determine the string length. i = 0; x = 0; y = FONT_INITIAL_LINE; wordX = 0; while(c = text[i++]) { info->length++; // When space, start of new word about to begin if(c == FONT_SPACE) { x += FONT_SPACE_SIZE; // Did this space cause a newline? if(x > maxWidth) { info->lines++; y += FONT_LINE_HEIGHT; x = 0; } // info->width = mathMax(info->width, x); // info->height = mathMax(info->height, y); wordX = x; wordStart = info->realLength; continue; } // New line. if(c == FONT_NEWLINE) { info->lines++; wordStart = info->realLength; y += FONT_LINE_HEIGHT; x = 0; continue; } // Actual letter. We need to start by resizing the buffer if(info->realLength+1 >= bufferTextSize) { info->quads = memBufferResize(info->quads, bufferTextSize, bufferTextSize * 2, sizeof(stbtt_aligned_quad) ); bufferTextSize *= 2; } // Generate the quad. quad = info->quads + info->realLength; stbtt_GetBakedQuad(font->characterData, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, ((int32_t)c)-FONT_FIRST_CHAR, &x, &y, quad, FONT_FILL_MODE ); // Now measure the width of the line (take the right side of that quad) if(x > maxWidth) { // We've exceeded the edge, go back to the start of the word and newline. x = quad->x1 - wordX; for(j = wordStart; j <= info->realLength; j++) { quad = info->quads + j; quad->x0 -= wordX, quad->x1 -= wordX; quad->y0 += FONT_LINE_HEIGHT, quad->y1 += FONT_LINE_HEIGHT; } y += FONT_LINE_HEIGHT; info->lines++; wordX = 0; } info->realLength++; } return info; }