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