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