Dawn/src/display/gui/font.c

168 lines
4.3 KiB
C

/**
* 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 <stb_truetype.h>
#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;
}