#include "./cache.h" #include #include #include #include #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; }