src/atlas.c
 1#include "internal.h"
 2
 3typedef struct
 4{
 5    uint32_t character;
 6    FT_Long glyph_index;
 7    FT_Bitmap bitmap;
 8} Glyph;
 9
10uint64_t hash_glyph(const void* item, const uint64_t seed0, const uint64_t seed1)
11{
12    return hashmap_murmur(&((Glyph*)item)->character, sizeof(FT_Long), seed0, seed1);
13}
14
15int compare_glyph(const void* va, const void* vb, void* udata)
16{
17    const Glyph* a = va;
18    const Glyph* b = vb;
19    return a->character - b->character;
20}
21
22Atlas atlas_new(const uint32_t capacity)
23{
24    Atlas atlas = {0};
25    atlas.glyphs = hashmap_new(sizeof(Glyph), capacity, 0, 0, hash_glyph, compare_glyph, NULL, NULL);
26    if (capacity != 0)
27    {
28        atlas_reserve(&atlas, capacity);
29    }
30    return atlas;
31}
32
33void atlas_reserve(Atlas* atlas, const uint32_t capacity)
34{
35    dynarray_reserve(&atlas->glyph_sizes, capacity * 4);
36}
37
38void atlas_append(Atlas* atlas, const FT_Face face, const uint32_t character)
39{
40    const FT_Long glyph_index = FT_Load_Char(face, character, FT_LOAD_RENDER);
41
42    const Glyph glyph = {
43        .character = character,
44        .glyph_index = glyph_index,
45        .bitmap = face->glyph->bitmap,
46    };
47    const uint32_t hash = hash_glyph(&glyph, 0, 0); // Execute hash only once
48    if (hashmap_get_with_hash(atlas->glyphs, &glyph, hash) == NULL)
49    {
50        hashmap_set_with_hash(atlas->glyphs, &glyph, hash);
51        atlas->dirty = 1;
52    }
53}
54
55void atlas_generate_image(Atlas* atlas)
56{
57    if (atlas->dirty == 0) return;
58
59    size_t iter = 0;
60    Glyph* glyph;
61    DynArray glyphs = dynarray_new(sizeof(Glyph), hashmap_count(atlas->glyphs));
62    while (hashmap_iter(atlas->glyphs, &iter, (void**)&glyph))
63    {
64        dynarray_append(&glyphs, glyph);
65    }
66    dynarray_sort(&glyphs, compare_glyph);
67
68    atlas->width = 1024;
69    atlas->height = 1024;
70    atlas->image = reallocarray(atlas->image, atlas->width * atlas->height * 4, sizeof(uint8_t));
71}
72
73void atlas_release(const Atlas* atlas)
74{
75    hashmap_free(atlas->glyphs);
76    dynarray_release(&atlas->glyph_sizes);
77    if (atlas->image != NULL)
78    {
79        free(atlas->image);
80    }
81}