]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/font.c
3fa6002dcbcef2997e5f8aa60f53f84e22f9dfc8
[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
7 #define NUM_CHARS 128
8
9
10 typedef struct
11 {
12         Texture *texture;
13         v2s32 bearing;
14         u32 advance;
15 } Character;
16
17 static struct
18 {
19         FT_Library library;
20         FT_Face face;
21         Character chars[NUM_CHARS];
22         GLfloat height;
23 } font;
24
25 typedef struct
26 {
27         GLfloat x, y;
28 } __attribute__((packed)) VertexFontPosition;
29
30 typedef struct
31 {
32         GLfloat s, t;
33 } __attribute__((packed)) VertexFontTextureCoordinates;
34
35 typedef struct
36 {
37         VertexFontPosition position;
38         VertexFontTextureCoordinates textureCoordinates;
39 } __attribute__((packed)) VertexFont;
40
41 static VertexAttribute vertex_attributes[2] = {
42         // position
43         {
44                 .type = GL_FLOAT,
45                 .length = 2,
46                 .size = sizeof(VertexFontPosition),
47         },
48         // textureCoordinates
49         {
50                 .type = GL_FLOAT,
51                 .length = 2,
52                 .size = sizeof(VertexFontTextureCoordinates),
53         },
54 };
55
56 static VertexLayout vertex_layout = {
57         .attributes = vertex_attributes,
58         .count = 2,
59         .size = sizeof(VertexFont),
60 };
61
62 bool font_init()
63 {
64         if (FT_Init_FreeType(&font.library)) {
65                 fprintf(stderr, "Failed to initialize Freetype\n");
66                 return false;
67         }
68
69         if (FT_New_Face(font.library, RESSOURCEPATH "fonts/Minecraftia.ttf", 0, &font.face)) {
70                 fprintf(stderr, "Failed to load Minecraftia.ttf\n");
71                 return false;
72         }
73
74         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
75         FT_Set_Pixel_Sizes(font.face, 0, 16);
76
77         for (unsigned char c = 0; c < NUM_CHARS; c++) {
78                 if (FT_Load_Char(font.face, c, FT_LOAD_RENDER)) {
79                         fprintf(stderr, "Failed to load glyph %c\n", c);
80
81                         font.chars[c] = (Character) {
82                                 .texture = NULL,
83                                 .bearing = {0, 0},
84                                 .advance = 0,
85                         };
86                 } else {
87                         font.chars[c] = (Character) {
88                                 .texture = texture_create(font.face->glyph->bitmap.buffer, font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows, GL_RED),
89                                 .bearing = {font.face->glyph->bitmap_left, font.face->glyph->bitmap_top},
90                                 .advance = font.face->glyph->advance.x,
91                         };
92                 }
93         }
94
95         font.height = font.chars['|'].texture->height;
96
97         FT_Done_Face(font.face);
98         FT_Done_FreeType(font.library);
99
100         return true;
101 }
102
103 void font_deinit()
104 {
105         for (unsigned char c = 0; c < NUM_CHARS; c++) {
106                 if (font.chars[c].texture)
107                         texture_delete(font.chars[c].texture);
108         }
109 }
110
111 Font *font_create(const char *text)
112 {
113         Font *fnt = malloc(sizeof(fnt));
114
115         size_t len = strlen(text);
116
117         fnt->meshes = malloc(sizeof(Mesh *) * len);
118         fnt->meshes_count = len;
119
120         GLfloat offset = 0.0f;
121
122         for (size_t i = 0; i < len; i++) {
123                 unsigned char c = text[i];
124
125                 if (c >= NUM_CHARS || ! font.chars[c].texture)
126                         c = '?';
127
128                 Character *ch = &font.chars[c];
129
130                 GLfloat width = ch->texture->width;
131         GLfloat height = ch->texture->height;
132
133                 GLfloat x = ch->bearing.x + offset;
134         GLfloat y = font.height - ch->bearing.y;
135
136         VertexFont vertices[6] = {
137             {{x,         y         }, {0.0f, 0.0f}},
138             {{x,         y + height}, {0.0f, 1.0f}},
139             {{x + width, y + height}, {1.0f, 1.0f}},
140             {{x,         y         }, {0.0f, 0.0f}},
141             {{x + width, y + height}, {1.0f, 1.0f}},
142             {{x + width, y         }, {1.0f, 0.0f}},
143         };
144
145                 Mesh *mesh = fnt->meshes[i] = mesh_create();
146                 mesh->textures = &ch->texture->id;
147                 mesh->textures_count = 1;
148                 mesh->free_textures = false;
149                 mesh->vertices = vertices;
150                 mesh->vertices_count = 6;
151                 mesh->free_vertices = false;
152                 mesh->layout = &vertex_layout;
153                 mesh_configure(mesh);
154
155                 offset += ch->advance >> 6;
156         }
157
158         fnt->size = (v2f32) {offset, font.height};
159
160         return fnt;
161 }
162
163 void font_delete(Font *fnt)
164 {
165         for (size_t i = 0; i < fnt->meshes_count; i++)
166                 mesh_delete(fnt->meshes[i]);
167
168         free(fnt);
169 }
170
171 void font_render(Font *fnt)
172 {
173         for (size_t i = 0; i < fnt->meshes_count; i++)
174                 mesh_render(fnt->meshes[i]);
175 }