149 lines
3.5 KiB
C
149 lines
3.5 KiB
C
/**
|
|
* Copyright (c) 2026 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "text.h"
|
|
#include "assert/assert.h"
|
|
#include "util/memory.h"
|
|
#include "display/spritebatch/spritebatch.h"
|
|
#include "asset/asset.h"
|
|
#include "asset/loader/display/assettextureloader.h"
|
|
#include "asset/loader/display/assettilesetloader.h"
|
|
#include "display/shader/shaderunlit.h"
|
|
|
|
font_t FONT_DEFAULT;
|
|
|
|
errorret_t textInit(void) {
|
|
assetloaderinput_t input = { .texture = TEXTURE_FORMAT_RGBA };
|
|
assetentry_t *entryTexture = assetLock(
|
|
"ui/minogram.png", ASSET_LOADER_TYPE_TEXTURE, &input
|
|
);
|
|
assetentry_t *entryTileset = assetLock(
|
|
"ui/minogram.dtf", ASSET_LOADER_TYPE_TILESET, NULL
|
|
);
|
|
errorChain(assetRequireLoaded(entryTexture));
|
|
errorChain(assetRequireLoaded(entryTileset));
|
|
|
|
FONT_DEFAULT.texture = &entryTexture->data.texture;
|
|
FONT_DEFAULT.tileset = &entryTileset->data.tileset;
|
|
errorOk();
|
|
}
|
|
|
|
errorret_t textDispose(void) {
|
|
FONT_DEFAULT.texture = NULL;
|
|
FONT_DEFAULT.tileset = NULL;
|
|
assetUnlock("ui/minogram.png");
|
|
assetUnlock("ui/minogram.dtf");
|
|
errorOk();
|
|
}
|
|
|
|
spritebatchsprite_t textGetSprite(
|
|
const vec2 pos, const char_t c, const font_t *font
|
|
) {
|
|
assertNotNull(font, "Font cannot be NULL");
|
|
|
|
// Change char from ASCII to a tile index.
|
|
int32_t tileIndex = (int32_t)(c) - TEXT_CHAR_START;
|
|
if(tileIndex < 0 || tileIndex >= font->tileset->tileCount) {
|
|
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
|
}
|
|
assertTrue(
|
|
tileIndex >= 0 && tileIndex <= font->tileset->tileCount,
|
|
"Character is out of bounds for font tiles"
|
|
);
|
|
|
|
// Create sprite.
|
|
vec4 uv;
|
|
tilesetTileGetUV(font->tileset, tileIndex, uv);
|
|
|
|
spritebatchsprite_t sprite;
|
|
sprite.min[0] = pos[0];
|
|
sprite.min[1] = pos[1];
|
|
sprite.min[2] = 0.0f;
|
|
sprite.max[0] = pos[0] + font->tileset->tileWidth;
|
|
sprite.max[1] = pos[1] + font->tileset->tileHeight;
|
|
sprite.max[2] = 0.0f;
|
|
sprite.uvMin[0] = uv[0];
|
|
sprite.uvMin[1] = uv[1];
|
|
sprite.uvMax[0] = uv[2];
|
|
sprite.uvMax[1] = uv[3];
|
|
return sprite;
|
|
}
|
|
|
|
errorret_t textDraw(
|
|
const float_t x,
|
|
const float_t y,
|
|
const char_t *text,
|
|
const color_t color,
|
|
font_t *font
|
|
) {
|
|
assertNotNull(text, "Text cannot be NULL");
|
|
|
|
spritebatchsprite_t sprite;
|
|
shadermaterial_t material = {
|
|
.unlit = {
|
|
.color = color,
|
|
.texture = font->texture
|
|
}
|
|
};
|
|
|
|
float_t posX = x;
|
|
float_t posY = y;
|
|
|
|
char_t c;
|
|
int32_t i = 0;
|
|
while((c = text[i++]) != '\0') {
|
|
if(c == '\n') {
|
|
posX = x;
|
|
posY += font->tileset->tileHeight;
|
|
continue;
|
|
}
|
|
|
|
if(c == ' ') {
|
|
posX += font->tileset->tileWidth;
|
|
continue;
|
|
}
|
|
|
|
sprite = textGetSprite((vec2){posX, posY}, c, font);
|
|
errorChain(spriteBatchBuffer(&sprite, 1, &SHADER_UNLIT, material));
|
|
posX += font->tileset->tileWidth;
|
|
}
|
|
errorOk();
|
|
}
|
|
|
|
void textMeasure(
|
|
const char_t *text,
|
|
const font_t *font,
|
|
int32_t *outWidth,
|
|
int32_t *outHeight
|
|
) {
|
|
assertNotNull(text, "Text cannot be NULL");
|
|
assertNotNull(outWidth, "Output width pointer cannot be NULL");
|
|
assertNotNull(outHeight, "Output height pointer cannot be NULL");
|
|
|
|
int32_t width = 0;
|
|
int32_t height = font->tileset->tileHeight;
|
|
int32_t lineWidth = 0;
|
|
|
|
char_t c;
|
|
int32_t i = 0;
|
|
while((c = text[i++]) != '\0') {
|
|
if(c == '\n') {
|
|
if(lineWidth > width) width = lineWidth;
|
|
lineWidth = 0;
|
|
height += font->tileset->tileHeight;
|
|
continue;
|
|
}
|
|
|
|
lineWidth += font->tileset->tileWidth;
|
|
}
|
|
|
|
if(lineWidth > width) width = lineWidth;
|
|
|
|
*outWidth = width;
|
|
*outHeight = height;
|
|
}
|