2017-02-03 23:16:30 +00:00
|
|
|
#include "graphics/font.h"
|
2022-03-15 23:02:35 +00:00
|
|
|
#include "graphics/graphics.h"
|
2017-02-03 23:16:30 +00:00
|
|
|
#include "graphics/texture.h"
|
2019-09-07 22:07:07 +00:00
|
|
|
#include "data/rasterizer.h"
|
2021-02-09 03:17:47 +00:00
|
|
|
#include "data/image.h"
|
2019-09-07 22:07:07 +00:00
|
|
|
#include "core/map.h"
|
2017-02-03 23:16:30 +00:00
|
|
|
#include <string.h>
|
2017-02-06 09:54:11 +00:00
|
|
|
#include <stdlib.h>
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
typedef struct {
|
|
|
|
uint32_t x;
|
|
|
|
uint32_t y;
|
|
|
|
uint32_t width;
|
|
|
|
uint32_t height;
|
|
|
|
uint32_t rowHeight;
|
|
|
|
uint32_t padding;
|
|
|
|
arr_t(Glyph) glyphs;
|
|
|
|
map_t glyphMap;
|
|
|
|
} FontAtlas;
|
|
|
|
|
|
|
|
struct Font {
|
2021-02-11 23:37:55 +00:00
|
|
|
uint32_t ref;
|
2019-09-07 22:07:07 +00:00
|
|
|
Rasterizer* rasterizer;
|
|
|
|
Texture* texture;
|
|
|
|
FontAtlas atlas;
|
|
|
|
map_t kerning;
|
2021-02-10 14:08:29 +00:00
|
|
|
double spread;
|
|
|
|
uint32_t padding;
|
2019-09-07 22:07:07 +00:00
|
|
|
float lineHeight;
|
|
|
|
float pixelDensity;
|
2022-03-15 23:02:35 +00:00
|
|
|
TextureFilter filter;
|
2019-09-07 22:07:07 +00:00
|
|
|
bool flip;
|
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
static float* lovrFontAlignLine(float* x, float* lineEnd, float width, HorizontalAlign halign) {
|
2019-05-20 11:15:24 +00:00
|
|
|
while (x < lineEnd) {
|
2017-03-16 03:12:56 +00:00
|
|
|
if (halign == ALIGN_CENTER) {
|
2018-03-22 05:03:03 +00:00
|
|
|
*x -= width / 2.f;
|
2017-03-16 03:12:56 +00:00
|
|
|
} else if (halign == ALIGN_RIGHT) {
|
2018-03-22 05:03:03 +00:00
|
|
|
*x -= width;
|
2017-03-16 03:12:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
x += 8;
|
2017-03-16 03:12:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
return x;
|
2017-03-16 03:12:56 +00:00
|
|
|
}
|
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
static Glyph* lovrFontGetGlyph(Font* font, uint32_t codepoint);
|
|
|
|
static void lovrFontAddGlyph(Font* font, Glyph* glyph);
|
|
|
|
static void lovrFontExpandTexture(Font* font);
|
|
|
|
static void lovrFontCreateTexture(Font* font);
|
|
|
|
|
2022-03-15 23:02:35 +00:00
|
|
|
Font* lovrFontCreate(Rasterizer* rasterizer, uint32_t padding, double spread) {
|
2021-02-09 00:23:18 +00:00
|
|
|
Font* font = calloc(1, sizeof(Font));
|
|
|
|
lovrAssert(font, "Out of memory");
|
|
|
|
font->ref = 1;
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRetain(rasterizer);
|
2018-01-22 16:28:33 +00:00
|
|
|
font->rasterizer = rasterizer;
|
2021-02-10 14:08:29 +00:00
|
|
|
font->padding = padding;
|
|
|
|
font->spread = spread;
|
2017-02-12 11:14:10 +00:00
|
|
|
font->lineHeight = 1.f;
|
2021-02-08 17:58:39 +00:00
|
|
|
font->pixelDensity = (float) lovrRasterizerGetHeight(rasterizer);
|
2022-03-15 23:02:35 +00:00
|
|
|
font->filter = lovrGraphicsGetDefaultFilter();
|
2019-09-07 22:07:07 +00:00
|
|
|
map_init(&font->kerning, 0);
|
2017-02-06 04:30:17 +00:00
|
|
|
|
|
|
|
// Atlas
|
2021-02-10 14:08:29 +00:00
|
|
|
// The atlas padding affects the padding of the edges of the atlas and the space between rows.
|
|
|
|
// It is different from the main font->padding, which is the padding on each individual glyph.
|
|
|
|
uint32_t atlasPadding = 1;
|
|
|
|
font->atlas.x = atlasPadding;
|
|
|
|
font->atlas.y = atlasPadding;
|
|
|
|
font->atlas.width = 256;
|
|
|
|
font->atlas.height = 256;
|
|
|
|
font->atlas.padding = atlasPadding;
|
2022-03-14 19:27:58 +00:00
|
|
|
arr_init(&font->atlas.glyphs, arr_alloc);
|
2019-09-07 22:07:07 +00:00
|
|
|
map_init(&font->atlas.glyphMap, 0);
|
2017-02-05 06:21:41 +00:00
|
|
|
|
2017-02-12 11:14:10 +00:00
|
|
|
// Set initial atlas size
|
2021-02-08 17:58:39 +00:00
|
|
|
while (font->atlas.height < 4 * lovrRasterizerGetSize(rasterizer)) {
|
2017-02-12 11:14:10 +00:00
|
|
|
lovrFontExpandTexture(font);
|
2017-02-09 02:57:47 +00:00
|
|
|
}
|
|
|
|
|
2017-11-24 22:13:07 +00:00
|
|
|
// Create the texture
|
|
|
|
lovrFontCreateTexture(font);
|
2017-04-16 23:56:49 +00:00
|
|
|
|
2017-02-03 23:16:30 +00:00
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
void lovrFontDestroy(void* ref) {
|
|
|
|
Font* font = ref;
|
2021-02-09 00:52:26 +00:00
|
|
|
lovrRelease(font->rasterizer, lovrRasterizerDestroy);
|
|
|
|
lovrRelease(font->texture, lovrTextureDestroy);
|
2019-09-07 22:07:07 +00:00
|
|
|
for (size_t i = 0; i < font->atlas.glyphs.length; i++) {
|
2021-02-09 03:17:47 +00:00
|
|
|
lovrRelease(font->atlas.glyphs.data[i].data, lovrImageDestroy);
|
2018-08-02 10:22:27 +00:00
|
|
|
}
|
2020-05-23 19:03:16 +00:00
|
|
|
arr_free(&font->atlas.glyphs);
|
2019-09-07 22:07:07 +00:00
|
|
|
map_free(&font->atlas.glyphMap);
|
|
|
|
map_free(&font->kerning);
|
2021-02-09 00:52:26 +00:00
|
|
|
free(font);
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 01:29:41 +00:00
|
|
|
Rasterizer* lovrFontGetRasterizer(Font* font) {
|
|
|
|
return font->rasterizer;
|
|
|
|
}
|
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
Texture* lovrFontGetTexture(Font* font) {
|
|
|
|
return font->texture;
|
|
|
|
}
|
|
|
|
|
2022-03-15 23:02:35 +00:00
|
|
|
TextureFilter lovrFontGetFilter(Font* font) {
|
|
|
|
return font->filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFontSetFilter(Font* font, TextureFilter filter) {
|
|
|
|
if (font->filter.mode != filter.mode || font->filter.anisotropy != filter.anisotropy) {
|
|
|
|
font->filter = filter;
|
|
|
|
lovrTextureSetFilter(font->texture, filter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-27 21:50:42 +00:00
|
|
|
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex) {
|
2017-02-05 06:21:41 +00:00
|
|
|
FontAtlas* atlas = &font->atlas;
|
2019-01-30 05:49:49 +00:00
|
|
|
bool flip = font->flip;
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2021-02-08 17:58:39 +00:00
|
|
|
int height = lovrRasterizerGetHeight(font->rasterizer);
|
|
|
|
|
2019-04-21 00:02:48 +00:00
|
|
|
float cx = 0.f;
|
2021-02-08 17:58:39 +00:00
|
|
|
float cy = -height * .8f * (flip ? -1.f : 1.f);
|
2017-02-06 04:30:17 +00:00
|
|
|
float u = atlas->width;
|
|
|
|
float v = atlas->height;
|
2019-04-21 00:02:48 +00:00
|
|
|
float scale = 1.f / font->pixelDensity;
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2017-02-12 11:14:10 +00:00
|
|
|
const char* start = str;
|
2018-12-25 08:28:56 +00:00
|
|
|
const char* end = str + length;
|
2017-02-08 06:11:20 +00:00
|
|
|
unsigned int previous = '\0';
|
2017-02-06 09:54:11 +00:00
|
|
|
unsigned int codepoint;
|
2017-02-16 23:42:33 +00:00
|
|
|
size_t bytes;
|
2017-02-06 09:54:11 +00:00
|
|
|
|
2018-12-27 21:50:42 +00:00
|
|
|
float* vertexCursor = vertices;
|
|
|
|
uint16_t* indexCursor = indices;
|
2018-12-05 18:23:26 +00:00
|
|
|
float* lineStart = vertices;
|
2018-12-27 21:50:42 +00:00
|
|
|
uint16_t I = baseVertex;
|
2017-02-06 09:54:11 +00:00
|
|
|
|
|
|
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
2017-02-08 06:11:20 +00:00
|
|
|
|
|
|
|
// Newlines
|
2021-02-09 15:06:37 +00:00
|
|
|
if (codepoint == '\n' || (wrap && cx * scale > wrap && (codepoint == ' ' || previous == ' '))) {
|
2018-12-27 21:50:42 +00:00
|
|
|
lineStart = lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
2019-04-21 00:02:48 +00:00
|
|
|
cx = 0.f;
|
2021-02-08 17:58:39 +00:00
|
|
|
cy -= height * font->lineHeight * (flip ? -1.f : 1.f);
|
2017-02-08 06:11:20 +00:00
|
|
|
previous = '\0';
|
2021-02-09 15:06:37 +00:00
|
|
|
if (codepoint == ' ' || codepoint == '\n') {
|
|
|
|
str += bytes;
|
|
|
|
continue;
|
|
|
|
}
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:28:34 +00:00
|
|
|
// Tabs
|
|
|
|
if (codepoint == '\t') {
|
|
|
|
Glyph* space = lovrFontGetGlyph(font, ' ');
|
2019-04-21 00:02:48 +00:00
|
|
|
cx += space->advance * 4.f;
|
2018-11-12 02:28:34 +00:00
|
|
|
str += bytes;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-08 06:11:20 +00:00
|
|
|
// Kerning
|
2017-02-17 00:23:52 +00:00
|
|
|
cx += lovrFontGetKerning(font, previous, codepoint);
|
2017-02-08 06:11:20 +00:00
|
|
|
previous = codepoint;
|
2017-02-05 06:21:41 +00:00
|
|
|
|
2017-02-12 11:14:10 +00:00
|
|
|
// Get glyph
|
2017-02-08 06:11:20 +00:00
|
|
|
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
|
2017-02-12 11:14:10 +00:00
|
|
|
|
|
|
|
// Start over if texture was repacked
|
|
|
|
if (u != atlas->width || v != atlas->height) {
|
2018-12-27 21:50:42 +00:00
|
|
|
lovrFontRender(font, start, length, wrap, halign, vertices, indices, baseVertex);
|
2017-02-16 23:42:33 +00:00
|
|
|
return;
|
2017-02-12 11:14:10 +00:00
|
|
|
}
|
|
|
|
|
2017-02-08 06:11:20 +00:00
|
|
|
// Triangles
|
2017-02-17 00:23:52 +00:00
|
|
|
if (glyph->w > 0 && glyph->h > 0) {
|
2021-03-25 18:18:48 +00:00
|
|
|
int32_t padding = font->padding;
|
|
|
|
float x1 = cx + glyph->dx - padding;
|
|
|
|
float y1 = cy + (glyph->dy + padding) * (flip ? -1.f : 1.f);
|
2017-07-14 16:53:05 +00:00
|
|
|
float x2 = x1 + glyph->tw;
|
2019-04-21 00:02:48 +00:00
|
|
|
float y2 = y1 - glyph->th * (flip ? -1.f : 1.f);
|
2017-02-17 00:23:52 +00:00
|
|
|
float s1 = glyph->x / u;
|
2017-07-14 16:53:05 +00:00
|
|
|
float t1 = (glyph->y + glyph->th) / v;
|
|
|
|
float s2 = (glyph->x + glyph->tw) / u;
|
2017-07-14 15:18:25 +00:00
|
|
|
float t2 = glyph->y / v;
|
2017-02-17 00:23:52 +00:00
|
|
|
|
2018-12-27 21:50:42 +00:00
|
|
|
memcpy(vertexCursor, (float[32]) {
|
2019-04-21 00:02:48 +00:00
|
|
|
x1, y1, 0.f, 0.f, 0.f, 0.f, s1, t1,
|
|
|
|
x1, y2, 0.f, 0.f, 0.f, 0.f, s1, t2,
|
|
|
|
x2, y1, 0.f, 0.f, 0.f, 0.f, s2, t1,
|
|
|
|
x2, y2, 0.f, 0.f, 0.f, 0.f, s2, t2
|
2018-12-27 21:50:42 +00:00
|
|
|
}, 32 * sizeof(float));
|
|
|
|
|
|
|
|
memcpy(indexCursor, (uint16_t[6]) { I + 0, I + 1, I + 2, I + 2, I + 1, I + 3 }, 6 * sizeof(uint16_t));
|
2017-02-05 06:21:41 +00:00
|
|
|
|
2018-12-27 21:50:42 +00:00
|
|
|
vertexCursor += 32;
|
|
|
|
indexCursor += 6;
|
|
|
|
I += 4;
|
2017-02-05 06:21:41 +00:00
|
|
|
}
|
|
|
|
|
2017-02-08 06:11:20 +00:00
|
|
|
// Advance cursor
|
2017-02-17 00:23:52 +00:00
|
|
|
cx += glyph->advance;
|
2017-02-06 09:54:11 +00:00
|
|
|
str += bytes;
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2017-03-16 03:12:56 +00:00
|
|
|
// Align the last line
|
2018-12-27 21:50:42 +00:00
|
|
|
lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 23:14:47 +00:00
|
|
|
void lovrFontMeasure(Font* font, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
|
2021-10-11 22:31:43 +00:00
|
|
|
wrap *= font->pixelDensity;
|
2021-12-20 15:12:39 +00:00
|
|
|
lovrRasterizerMeasure(font->rasterizer, str, length, wrap, width, lastLineWidth, height, lineCount, glyphCount);
|
2021-10-11 22:31:43 +00:00
|
|
|
*width /= font->pixelDensity;
|
2021-12-20 15:12:39 +00:00
|
|
|
*lastLineWidth /= font->pixelDensity;
|
2021-10-11 22:31:43 +00:00
|
|
|
*height *= font->lineHeight * (font->flip ? -1 : 1);
|
2017-03-16 08:12:32 +00:00
|
|
|
}
|
|
|
|
|
2021-02-10 14:08:29 +00:00
|
|
|
uint32_t lovrFontGetPadding(Font* font) {
|
|
|
|
return font->padding;
|
|
|
|
}
|
|
|
|
|
|
|
|
double lovrFontGetSpread(Font* font) {
|
|
|
|
return font->spread;
|
|
|
|
}
|
|
|
|
|
2017-03-16 08:12:32 +00:00
|
|
|
float lovrFontGetHeight(Font* font) {
|
2021-02-08 17:58:39 +00:00
|
|
|
return lovrRasterizerGetHeight(font->rasterizer) / font->pixelDensity;
|
2017-03-16 08:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float lovrFontGetAscent(Font* font) {
|
2021-02-08 17:58:39 +00:00
|
|
|
return lovrRasterizerGetAscent(font->rasterizer) / font->pixelDensity;
|
2017-03-16 08:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float lovrFontGetDescent(Font* font) {
|
2021-02-08 17:58:39 +00:00
|
|
|
return lovrRasterizerGetDescent(font->rasterizer) / font->pixelDensity;
|
2017-03-16 08:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float lovrFontGetBaseline(Font* font) {
|
2021-02-08 17:58:39 +00:00
|
|
|
return lovrRasterizerGetHeight(font->rasterizer) * .8f / font->pixelDensity;
|
2017-03-16 08:12:32 +00:00
|
|
|
}
|
|
|
|
|
2017-02-12 11:14:10 +00:00
|
|
|
float lovrFontGetLineHeight(Font* font) {
|
|
|
|
return font->lineHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFontSetLineHeight(Font* font, float lineHeight) {
|
|
|
|
font->lineHeight = lineHeight;
|
|
|
|
}
|
|
|
|
|
2019-01-30 05:49:49 +00:00
|
|
|
bool lovrFontIsFlipEnabled(Font* font) {
|
|
|
|
return font->flip;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFontSetFlipEnabled(Font* font, bool flip) {
|
|
|
|
font->flip = flip;
|
|
|
|
}
|
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
int32_t lovrFontGetKerning(Font* font, uint32_t left, uint32_t right) {
|
|
|
|
uint64_t key = ((uint64_t) left << 32) + right;
|
|
|
|
uint64_t hash = hash64(&key, sizeof(key)); // TODO improve number hashing
|
|
|
|
uint64_t kerning = map_get(&font->kerning, hash);
|
2017-02-08 06:11:20 +00:00
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
if (kerning == MAP_NIL) {
|
|
|
|
kerning = lovrRasterizerGetKerning(font->rasterizer, left, right);
|
|
|
|
map_set(&font->kerning, hash, kerning);
|
2017-02-08 06:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return kerning;
|
|
|
|
}
|
|
|
|
|
2017-03-16 03:51:16 +00:00
|
|
|
float lovrFontGetPixelDensity(Font* font) {
|
|
|
|
return font->pixelDensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrFontSetPixelDensity(Font* font, float pixelDensity) {
|
|
|
|
if (pixelDensity <= 0) {
|
2021-02-08 17:58:39 +00:00
|
|
|
pixelDensity = lovrRasterizerGetHeight(font->rasterizer);
|
2017-03-16 03:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
font->pixelDensity = pixelDensity;
|
|
|
|
}
|
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
static Glyph* lovrFontGetGlyph(Font* font, uint32_t codepoint) {
|
2017-02-05 06:21:41 +00:00
|
|
|
FontAtlas* atlas = &font->atlas;
|
2019-09-07 22:07:07 +00:00
|
|
|
uint64_t hash = hash64(&codepoint, sizeof(codepoint));
|
|
|
|
uint64_t index = map_get(&atlas->glyphMap, hash);
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2017-02-06 04:30:17 +00:00
|
|
|
// Add the glyph to the atlas if it isn't there
|
2019-09-07 22:07:07 +00:00
|
|
|
if (index == MAP_NIL) {
|
|
|
|
index = atlas->glyphs.length;
|
|
|
|
arr_reserve(&atlas->glyphs, atlas->glyphs.length + 1);
|
2021-02-10 14:08:29 +00:00
|
|
|
lovrRasterizerLoadGlyph(font->rasterizer, codepoint, font->padding, font->spread, &atlas->glyphs.data[atlas->glyphs.length++]);
|
2019-09-07 22:07:07 +00:00
|
|
|
map_set(&atlas->glyphMap, hash, index);
|
|
|
|
lovrFontAddGlyph(font, &atlas->glyphs.data[index]);
|
2017-02-05 06:21:41 +00:00
|
|
|
}
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
return &atlas->glyphs.data[index];
|
2017-02-05 06:21:41 +00:00
|
|
|
}
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
static void lovrFontAddGlyph(Font* font, Glyph* glyph) {
|
2017-02-06 04:30:17 +00:00
|
|
|
FontAtlas* atlas = &font->atlas;
|
|
|
|
|
|
|
|
// Don't waste space on empty glyphs
|
|
|
|
if (glyph->w == 0 && glyph->h == 0) {
|
|
|
|
return;
|
2017-02-05 06:21:41 +00:00
|
|
|
}
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2017-02-06 04:30:17 +00:00
|
|
|
// If the glyph does not fit, you must acquit (new row)
|
2017-07-14 16:53:05 +00:00
|
|
|
if (atlas->x + glyph->tw > atlas->width - 2 * atlas->padding) {
|
2017-02-06 04:30:17 +00:00
|
|
|
atlas->x = atlas->padding;
|
|
|
|
atlas->y += atlas->rowHeight + atlas->padding;
|
|
|
|
atlas->rowHeight = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expand the texture if needed. Expanding the texture re-adds all the glyphs, so we can return.
|
2017-07-14 16:53:05 +00:00
|
|
|
if (atlas->y + glyph->th > atlas->height - 2 * atlas->padding) {
|
2017-02-06 04:30:17 +00:00
|
|
|
lovrFontExpandTexture(font);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep track of glyph's position in the atlas
|
|
|
|
glyph->x = atlas->x;
|
|
|
|
glyph->y = atlas->y;
|
|
|
|
|
|
|
|
// Paste glyph into texture
|
2018-07-23 02:42:39 +00:00
|
|
|
lovrTextureReplacePixels(font->texture, glyph->data, atlas->x, atlas->y, 0, 0);
|
2017-02-06 04:30:17 +00:00
|
|
|
|
|
|
|
// Advance atlas cursor
|
2017-07-14 16:53:05 +00:00
|
|
|
atlas->x += glyph->tw + atlas->padding;
|
|
|
|
atlas->rowHeight = MAX(atlas->rowHeight, glyph->th);
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
2019-09-07 22:07:07 +00:00
|
|
|
static void lovrFontExpandTexture(Font* font) {
|
2017-02-05 06:21:41 +00:00
|
|
|
FontAtlas* atlas = &font->atlas;
|
2017-02-06 04:30:17 +00:00
|
|
|
|
2017-02-12 11:14:10 +00:00
|
|
|
if (atlas->width == atlas->height) {
|
|
|
|
atlas->width *= 2;
|
|
|
|
} else {
|
|
|
|
atlas->height *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!font->texture) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-24 22:13:07 +00:00
|
|
|
// Recreate the texture
|
|
|
|
lovrFontCreateTexture(font);
|
2017-02-06 04:30:17 +00:00
|
|
|
|
|
|
|
// Reset the cursor
|
|
|
|
atlas->x = atlas->padding;
|
|
|
|
atlas->y = atlas->padding;
|
|
|
|
atlas->rowHeight = 0;
|
|
|
|
|
|
|
|
// Re-pack all the glyphs
|
2019-09-07 22:07:07 +00:00
|
|
|
for (size_t i = 0; i < atlas->glyphs.length; i++) {
|
|
|
|
lovrFontAddGlyph(font, &atlas->glyphs.data[i]);
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
2017-11-24 22:13:07 +00:00
|
|
|
|
2021-02-09 03:17:47 +00:00
|
|
|
// TODO we only need the Image here to clear the texture, but it's a big waste of memory.
|
2018-08-09 23:12:57 +00:00
|
|
|
// Could look into using glClearTexImage when supported to make this more efficient.
|
2019-09-07 22:07:07 +00:00
|
|
|
static void lovrFontCreateTexture(Font* font) {
|
2021-02-09 00:52:26 +00:00
|
|
|
lovrRelease(font->texture, lovrTextureDestroy);
|
2021-02-10 22:22:30 +00:00
|
|
|
Image* image = lovrImageCreate(font->atlas.width, font->atlas.height, NULL, 0x0, FORMAT_RGBA16F);
|
2021-02-09 03:17:47 +00:00
|
|
|
font->texture = lovrTextureCreate(TEXTURE_2D, &image, 1, false, false, 0);
|
2022-03-15 23:02:35 +00:00
|
|
|
lovrTextureSetFilter(font->texture, font->filter);
|
2017-11-24 22:13:07 +00:00
|
|
|
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
|
2021-02-09 03:17:47 +00:00
|
|
|
lovrRelease(image, lovrImageDestroy);
|
2017-11-24 22:13:07 +00:00
|
|
|
}
|