168 lines
4.3 KiB
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;
|
|
} |