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}