112 lines
2.7 KiB
C
112 lines
2.7 KiB
C
|
#include "./cache.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include <GL/glew.h>
|
||
|
|
||
|
#include "util/container/array.h"
|
||
|
#include "util/gleasy/atlas.h"
|
||
|
#include "util/memory/memory.h"
|
||
|
|
||
|
#include "./face.h"
|
||
|
|
||
|
struct glyphas_cache_t {
|
||
|
gleasy_atlas_t* atlas;
|
||
|
glyphas_face_t* face;
|
||
|
|
||
|
int32_t char_width;
|
||
|
int32_t char_height;
|
||
|
|
||
|
/* TODO(catfoot): linear search isn't efficient. :( */
|
||
|
CONTAINER_ARRAY glyphas_cache_glyph_t* items;
|
||
|
};
|
||
|
|
||
|
glyphas_cache_t* glyphas_cache_new(
|
||
|
gleasy_atlas_t* atlas,
|
||
|
glyphas_face_t* face,
|
||
|
int32_t char_width,
|
||
|
int32_t char_height) {
|
||
|
assert(atlas != NULL);
|
||
|
assert(face != NULL);
|
||
|
assert(char_width > 0);
|
||
|
assert(char_height > 0);
|
||
|
|
||
|
glyphas_cache_t* cache = memory_new(sizeof(*cache));
|
||
|
*cache = (typeof(*cache)) {
|
||
|
.atlas = atlas,
|
||
|
.face = face,
|
||
|
.char_width = char_width,
|
||
|
.char_height = char_height,
|
||
|
};
|
||
|
return cache;
|
||
|
}
|
||
|
|
||
|
void glyphas_cache_delete(glyphas_cache_t* cache) {
|
||
|
if (cache == NULL) return;
|
||
|
|
||
|
container_array_delete(cache->items);
|
||
|
|
||
|
memory_delete(cache);
|
||
|
}
|
||
|
|
||
|
const glyphas_cache_glyph_t* glyphas_cache_add_glyph(
|
||
|
glyphas_cache_t* cache, uint32_t unicode) {
|
||
|
assert(cache != NULL);
|
||
|
|
||
|
const glyphas_cache_glyph_t* found =
|
||
|
glyphas_cache_lookup_glyph(cache, unicode);
|
||
|
if (found != NULL) return found;
|
||
|
|
||
|
if (!glyphas_face_set_pixel_size(
|
||
|
cache->face, cache->char_width, cache->char_height)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
if (!glyphas_face_render_glyph(cache->face, unicode)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
gleasy_atlas_geometry_t geo = {0};
|
||
|
|
||
|
const glyphas_glyph_t* rendered = &cache->face->glyph;
|
||
|
if (rendered->bitmap.width > 0) {
|
||
|
const gleasy_atlas_bitmap_t bmp = {
|
||
|
.width = rendered->bitmap.width,
|
||
|
.height = rendered->bitmap.height,
|
||
|
.buffer = rendered->bitmap.buffer,
|
||
|
.format = GL_RED,
|
||
|
.type = GL_UNSIGNED_BYTE,
|
||
|
};
|
||
|
if (!gleasy_atlas_add(cache->atlas, &geo, &bmp)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const size_t index = container_array_get_length(cache->items);
|
||
|
container_array_insert(cache->items, index);
|
||
|
|
||
|
glyphas_cache_glyph_t* g = &cache->items[index];
|
||
|
*g = (typeof(*g)) {
|
||
|
.unicode = unicode,
|
||
|
.width = rendered->bitmap.width,
|
||
|
.height = rendered->bitmap.height,
|
||
|
.geometry = geo,
|
||
|
.hmetrics = rendered->hmetrics,
|
||
|
.vmetrics = rendered->vmetrics,
|
||
|
};
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
const glyphas_cache_glyph_t* glyphas_cache_lookup_glyph(
|
||
|
const glyphas_cache_t* cache, uint32_t unicode) {
|
||
|
assert(cache != NULL);
|
||
|
|
||
|
const size_t len = container_array_get_length(cache->items);
|
||
|
for (size_t i = 0; i < len; ++i) {
|
||
|
const glyphas_cache_glyph_t* g = &cache->items[i];
|
||
|
if (g->unicode == unicode) return g;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|