/** * 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); } float fontGetScale(float fontSize) { return fontSize / FONT_SIZE_DEFAULT; } 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); } void fontTextClamp(font_t *font, fonttextinfo_t *info, char *text, float maxWidth, float fontSize ) { int32_t i, j, wordIndex; char c; float x, y, wordX, scale; stbtt_aligned_quad *quad; // Get the font scale scale = fontGetScale(fontSize); // Adjust the max width to match the scale, and allow "no max width". maxWidth = maxWidth == -1 ? 999999 : maxWidth * (1 / scale); /** Which index in the original text var is the current word from */ int32_t wordStart = 0; // Setup Scales info->length = 0; info->realLength = 0; info->lineCount = 0; // Prepare the line counters info->lines[0].start = 0; info->lines[0].length = 0; // Reset Dimensions info->width = 0, info->height = 0; // Setup the initial loop state, and X/Y coords for the quad. 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 * scale; // Did this space cause a newline? if(x > maxWidth) { info->lineCount++; info->lines[info->lineCount].start = info->realLength; info->lines[info->lineCount].length = 0; y += FONT_LINE_HEIGHT * scale; x = 0; } wordX = x; wordStart = info->realLength; continue; } // New line. if(c == FONT_NEWLINE) { info->lineCount++; info->lines[info->lineCount].start = info->realLength; info->lines[info->lineCount].length = 0; wordStart = info->realLength; y += FONT_LINE_HEIGHT * scale; x = 0; continue; } // 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; } // Go back to the previous (still current) line and remove the chars info->lines[info->lineCount].length -= info->realLength - wordStart; // Next line begins with this word info->lineCount++; info->lines[info->lineCount].start = wordStart; info->lines[info->lineCount].length = info->realLength - wordStart; y += FONT_LINE_HEIGHT; wordX = 0; } info->lines[info->lineCount].length++; info->realLength++; } info->lineCount++; for(j = 0; j < info->realLength; j++) { quad = info->quads + j; // Scale the Quad if(scale != 1.0) { quad->x0 *= scale; quad->x1 *= scale; quad->y0 *= scale; quad->y1 *= scale; } // Update the dimensions. info->width = mathMax(info->width, quad->x1); info->height = mathMax(info->height, quad->y1); } } int32_t fontGetLineCharCount(fonttextinfo_t *info,int32_t start,int32_t count) { int32_t charCount, i, m; m = mathMin(start+count, info->lineCount); charCount = 0; for(i = start; i < m; i++) { charCount += info->lines[i].length; } return charCount; }