]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/font.c
15e432a7ffe99ec925c48689ed5efe629bae64f7
[dragonblocks_alpha.git] / src / client / font.c
1 #include <string.h>
2 #include <ft2build.h>
3 #include FT_FREETYPE_H
4 #include "client/client.h"
5 #include "client/font.h"
6 #include "client/texture.h"
7
8 #define NUM_CHARS 128
9
10 typedef struct {
11         Texture texture;
12         v2s32 bearing;
13         u32 advance;
14 } Character;
15
16 static FT_Library font_library;
17 static FT_Face font_face;
18 static Character font_chars[NUM_CHARS];
19 static GLfloat font_height;
20
21 typedef struct {
22         v2f32 position;
23         v2f32 textureCoordinates;
24 } __attribute__((packed)) FontVertex;
25 static VertexLayout font_vertex_layout = {
26         .attributes = (VertexAttribute[]) {
27                 {GL_FLOAT, 2, sizeof(v2f32)}, // position
28                 {GL_FLOAT, 2, sizeof(v2f32)}, // textureCoordinates
29         },
30         .count = 2,
31         .size = sizeof(FontVertex),
32 };
33
34 bool font_init()
35 {
36         if (FT_Init_FreeType(&font_library)) {
37                 fprintf(stderr, "[error] failed to initialize Freetype\n");
38                 return false;
39         }
40
41         if (FT_New_Face(font_library, RESSOURCE_PATH "fonts/Minecraftia.ttf", 0, &font_face)) {
42                 fprintf(stderr, "[error] failed to load Minecraftia.ttf\n");
43                 return false;
44         }
45
46         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
47         FT_Set_Pixel_Sizes(font_face, 0, 16);
48
49         for (unsigned char c = 0; c < NUM_CHARS; c++) {
50                 if (FT_Load_Char(font_face, c, FT_LOAD_RENDER)) {
51                         fprintf(stderr, "[warning] failed to load glyph %c\n", c);
52                         font_chars[c].texture.txo = 0;
53                         continue;
54                 }
55
56                 font_chars[c].texture.width = font_face->glyph->bitmap.width;
57                 font_chars[c].texture.height = font_face->glyph->bitmap.rows;
58                 texture_upload(&font_chars[c].texture, font_face->glyph->bitmap.buffer, GL_RED, false);
59
60                 font_chars[c].bearing = (v2s32) {font_face->glyph->bitmap_left, font_face->glyph->bitmap_top};
61                 font_chars[c].advance = font_face->glyph->advance.x;
62         }
63
64         font_height = font_chars['|'].texture.height;
65
66         FT_Done_Face(font_face);
67         FT_Done_FreeType(font_library);
68
69         return true;
70 }
71
72 void font_deinit()
73 {
74         for (unsigned char c = 0; c < NUM_CHARS; c++)
75                 texture_destroy(&font_chars[c].texture);
76 }
77
78 Font *font_create(const char *text)
79 {
80         Font *font = malloc(sizeof *font);
81
82         font->count = strlen(text);
83         font->meshes = malloc(font->count * sizeof *font->meshes);
84         font->textures = malloc(font->count * sizeof *font->textures);
85
86         GLfloat offset = 0.0f;
87
88         for (size_t i = 0; i < font->count; i++) {
89                 unsigned char c = text[i];
90
91                 if (c >= NUM_CHARS || !font_chars[c].texture.txo)
92                         c = '?';
93
94                 Character *ch = &font_chars[c];
95
96                 GLfloat width = ch->texture.width;
97                 GLfloat height = ch->texture.height;
98
99                 GLfloat x = ch->bearing.x + offset;
100                 GLfloat y = font_height - ch->bearing.y;
101
102                 // this is art
103                 // selling this as NFT starting price is 10 BTC
104                 font->meshes[i].data = (FontVertex[]) {
105                         {{x,         y         }, {0.0f, 0.0f}},
106                         {{x,         y + height}, {0.0f, 1.0f}},
107                         {{x + width, y + height}, {1.0f, 1.0f}},
108                         {{x,         y         }, {0.0f, 0.0f}},
109                         {{x + width, y + height}, {1.0f, 1.0f}},
110                         {{x + width, y         }, {1.0f, 0.0f}},
111                 };
112                 font->meshes[i].count = 6;
113                 font->meshes[i].layout = &font_vertex_layout;
114                 font->meshes[i].vao = font->meshes[i].vbo = 0;
115                 font->meshes[i].free_data = false;
116                 mesh_upload(&font->meshes[i]);
117
118                 font->textures[i] = ch->texture.txo;
119
120                 offset += ch->advance >> 6;
121         }
122
123         font->size = (v2f32) {offset, font_height};
124
125         return font;
126 }
127
128 void font_delete(Font *font)
129 {
130         for (size_t i = 0; i < font->count; i++)
131                 mesh_destroy(&font->meshes[i]);
132
133         free(font->meshes);
134         free(font->textures);
135         free(font);
136 }
137
138 void font_render(Font *font)
139 {
140         for (size_t i = 0; i < font->count; i++) {
141                 glBindTextureUnit(0, font->textures[i]);
142                 mesh_render(&font->meshes[i]);
143         }
144 }