modify logging to simplify i18n
[voxelands-alt.git] / src / graphics / font_ttf.c
blob3e7a882a9c96a620d9264c2b2e5a284f94148b43
1 /************************************************************************
2 * font.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "path.h"
22 #define _WM_EXPOSE_ALL
23 #include "wm.h"
24 #include "graphics.h"
26 #include <string.h>
27 #include <ft2build.h>
28 #include FT_FREETYPE_H
29 #include FT_GLYPH_H
30 #include FT_OUTLINE_H
31 #include FT_TRIGONOMETRY_H
33 static uint32_t font_ttf_get_page_size(FT_Face face, uint32_t *mw, uint32_t *mh, int32_t *bl, uint32_t i)
35 uint32_t w = 0;
36 uint32_t h = 0;
37 uint32_t ch;
38 FT_Glyph glyph;
39 FT_BitmapGlyph bitmap_glyph;
41 *mh = 0;
42 *mw = 0;
43 *bl = 0;
45 for (ch=0; ch<256; ch++) {
46 if (FT_Load_Glyph(face,FT_Get_Char_Index(face,ch+(i*256)),FT_LOAD_DEFAULT))
47 return 1;
49 if (FT_Get_Glyph(face->glyph,&glyph))
50 return 1;
52 /* make a bitmap of the glyph */
53 FT_Glyph_To_Bitmap(&glyph,ft_render_mode_normal,0,1);
54 bitmap_glyph = (FT_BitmapGlyph)glyph;
56 w = bitmap_glyph->bitmap.width;
57 h = bitmap_glyph->bitmap.rows;
59 if (h > *mh)
60 *mh = h;
61 if (w > *mw)
62 *mw = w;
63 if (bitmap_glyph->top > *bl)
64 *bl = bitmap_glyph->top;
67 if (!(*mw) || !(*mh))
68 return 0;
70 *mw += 6;
71 *mh += 6;
73 w = (*mw)*16;
74 h = (*mh)*16;
76 if (w > h)
77 return math_next_pow2(w);
79 return math_next_pow2(h);
82 static int font_ttf_gen_fontpage(font_t *f, uint32_t i)
84 FT_Face face;
85 FT_Library library;
86 FT_Glyph glyph;
87 FT_BitmapGlyph bitmap_glyph;
88 fontpage_t *p;
89 fontchar_t *character;
90 uint32_t s;
91 uint32_t h = 32<<6;
92 uint32_t ch;
93 uint32_t gw;
94 uint32_t gh;
95 int32_t bl;
96 uint32_t mh = 0;
97 uint32_t mw = 0;
98 uint32_t sx;
99 uint32_t sy;
100 uint32_t ax;
101 uint32_t ay;
102 int b = 0;
103 int t = 0;
104 int m = 0;
105 int j;
106 int k;
107 int l;
109 p = array_get_ptr(&f->pages,i);
110 if (p)
111 return 0;
113 /* connect to freetype */
114 if (FT_Init_FreeType(&library))
115 return 1;
117 if (FT_New_Face(library,f->file,0,&face)) {
118 FT_Done_FreeType(library);
119 return 1;
122 if (FT_Select_Charmap(face, FT_ENCODING_UNICODE)) {
123 FT_Done_Face(face);
124 FT_Done_FreeType(library);
125 return 1;
128 /* something something characters something something */
129 if (FT_Set_Char_Size(face,h,h,96,96)) {
130 FT_Done_Face(face);
131 FT_Done_FreeType(library);
132 return 1;
135 s = font_ttf_get_page_size(face,&mw,&mh,&bl,i);
137 if (!s) {
138 FT_Done_Face(face);
139 FT_Done_FreeType(library);
140 return 1;
143 p = malloc(sizeof(fontpage_t));
144 if (!p) {
145 FT_Done_Face(face);
146 FT_Done_FreeType(library);
147 return 1;
150 gw = 2*s*s;
152 p->pixels = malloc(gw);
153 if (!p->pixels) {
154 free(p);
155 FT_Done_Face(face);
156 FT_Done_FreeType(library);
157 return 1;
160 array_init(&p->sizes,ARRAY_TYPE_PTR);
162 memset(p->pixels,0,gw);
164 sx = 0;
165 sy = 0;
167 for (ch=0; ch<256; ch++) {
168 if (FT_Load_Glyph(face,FT_Get_Char_Index(face,ch+(i*256)),FT_LOAD_DEFAULT))
169 return 1;
171 if (FT_Get_Glyph(face->glyph,&glyph))
172 return 1;
174 /* make a bitmap of the glyph */
175 FT_Glyph_To_Bitmap(&glyph,ft_render_mode_normal,0,1);
176 bitmap_glyph = (FT_BitmapGlyph)glyph;
178 /* TODO: a less shitty way to do this, should calculate for rows/columns */
179 gw = bitmap_glyph->bitmap.width;
180 gh = bitmap_glyph->bitmap.rows;
181 character = malloc(sizeof(fontchar_t));
182 character->x[0] = (float)((float)sx/(float)s);
183 character->y[0] = (float)((float)sy/(float)s);
184 character->x[1] = (float)character->x[0]+(float)((float)mw/(float)s);
185 character->y[1] = (float)character->y[0]+(float)((float)mh/(float)s);
186 character->a = (face->glyph->advance.x >> 6);
187 character->w = mw;
188 character->h = mh;
190 array_push_ptr(&p->sizes,character);
191 for (j=0; j<mh; j++) {
192 for (k=0; k<mw; k++) {
193 ax = 2*((sx+k));
194 ay = 2*((sy+j)+(bl-bitmap_glyph->top));
195 l = (ax+(ay*s));
196 p->pixels[l] = 255;
197 l++;
198 if (k >= bitmap_glyph->bitmap.width || j >= bitmap_glyph->bitmap.rows) {
199 p->pixels[l] = 0;
200 }else{
201 p->pixels[l] = bitmap_glyph->bitmap.buffer[k + bitmap_glyph->bitmap.width*j];
206 sx += mw;
207 if (sx+mw > s) {
208 sx = 0;
209 sy += mh;
211 FT_Done_Glyph(glyph);
214 glGenTextures(1,&p->glid);
215 glBindTexture(GL_TEXTURE_2D, p->glid);
217 b = opengl_has_bilinear();
218 t = opengl_has_trilinear();
219 m = opengl_has_mipmap();
221 /* draw the pixels to the texture */
222 glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,s,s,0,GL_LUMINANCE_ALPHA,GL_UNSIGNED_BYTE,p->pixels);
224 if (m) {
225 /* shouldn't ever need this, but there's an ATI/AMD bug that this fixes */
226 glEnable(GL_TEXTURE_2D);
227 glGenerateMipmap(GL_TEXTURE_2D);
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
232 if (t) {
233 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
234 if (m) {
235 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
236 }else{
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
239 }else if (b) {
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
242 }else{
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
247 if (opengl_has_anisotropic()) {
248 float ma = opengl_max_anisotropic();
249 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ma);
252 /* done! */
253 FT_Done_Face(face);
254 FT_Done_FreeType(library);
256 array_set_ptr(&f->pages,p,i);
258 return 0;
261 /* load a true type font file */
262 int font_load_ttf(font_t *f, char* file)
264 f->file = path_get("font",file,1,NULL,0);
266 if (!f->file)
267 return 1;
269 array_init(&f->pages,ARRAY_TYPE_PTR);
271 /* create the ascii fontpage */
272 if (font_ttf_gen_fontpage(f,0))
273 vlprintf(CN_WARN, "font_load_ttf: failed to generate ASCII fontpage");
275 return 0;
278 /* returns the opengl texture id and texcoords for a character */
279 int font_ttf_get_char(font_t *f, uint32_t ch, fontchar_t **fc, GLuint *glid)
281 uint32_t pid;
282 fontpage_t *p;
283 pid = ch/256;
285 if (font_ttf_gen_fontpage(f,pid))
286 return 1;
288 p = array_get_ptr(&f->pages,pid);
289 if (!p)
290 return 1;
292 *fc = array_get_ptr(&p->sizes,ch%256);
293 if (!(*fc))
294 return 1;
296 *glid = p->glid;
298 return 0;