]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
Merge branch 'master' into cmd_unset
[divverent/darkplaces.git] / ft2.c
1 /* FreeType 2 and UTF-8 encoding support for
2  * DarkPlaces
3  */
4 #include "quakedef.h"
5
6 #include "ft2.h"
7 #include "ft2_defs.h"
8 #include "ft2_fontdefs.h"
9
10 static int img_fontmap[256] = {
11         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
12         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
13         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
14         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
15         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
16         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
17         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
18         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
20         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
21         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
27 };
28
29 /*
30 ================================================================================
31 CVars introduced with the freetype extension
32 ================================================================================
33 */
34
35 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
36 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
37 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
38
39 /*
40 ================================================================================
41 Function definitions. Taken from the freetype2 headers.
42 ================================================================================
43 */
44
45
46 FT_EXPORT( FT_Error )
47 (*qFT_Init_FreeType)( FT_Library  *alibrary );
48 FT_EXPORT( FT_Error )
49 (*qFT_Done_FreeType)( FT_Library  library );
50 /*
51 FT_EXPORT( FT_Error )
52 (*qFT_New_Face)( FT_Library   library,
53                  const char*  filepathname,
54                  FT_Long      face_index,
55                  FT_Face     *aface );
56 */
57 FT_EXPORT( FT_Error )
58 (*qFT_New_Memory_Face)( FT_Library      library,
59                         const FT_Byte*  file_base,
60                         FT_Long         file_size,
61                         FT_Long         face_index,
62                         FT_Face        *aface );
63 FT_EXPORT( FT_Error )
64 (*qFT_Done_Face)( FT_Face  face );
65 FT_EXPORT( FT_Error )
66 (*qFT_Select_Size)( FT_Face  face,
67                     FT_Int   strike_index );
68 FT_EXPORT( FT_Error )
69 (*qFT_Request_Size)( FT_Face          face,
70                      FT_Size_Request  req );
71 FT_EXPORT( FT_Error )
72 (*qFT_Set_Char_Size)( FT_Face     face,
73                       FT_F26Dot6  char_width,
74                       FT_F26Dot6  char_height,
75                       FT_UInt     horz_resolution,
76                       FT_UInt     vert_resolution );
77 FT_EXPORT( FT_Error )
78 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
79                         FT_UInt  pixel_width,
80                         FT_UInt  pixel_height );
81 FT_EXPORT( FT_Error )
82 (*qFT_Load_Glyph)( FT_Face   face,
83                    FT_UInt   glyph_index,
84                    FT_Int32  load_flags );
85 FT_EXPORT( FT_Error )
86 (*qFT_Load_Char)( FT_Face   face,
87                   FT_ULong  char_code,
88                   FT_Int32  load_flags );
89 FT_EXPORT( FT_UInt )
90 (*qFT_Get_Char_Index)( FT_Face   face,
91                        FT_ULong  charcode );
92 FT_EXPORT( FT_Error )
93 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
94                      FT_Render_Mode  render_mode );
95 FT_EXPORT( FT_Error )
96 (*qFT_Get_Kerning)( FT_Face     face,
97                     FT_UInt     left_glyph,
98                     FT_UInt     right_glyph,
99                     FT_UInt     kern_mode,
100                     FT_Vector  *akerning );
101 FT_EXPORT( FT_Error )
102 (*qFT_Attach_Stream)( FT_Face        face,
103                       FT_Open_Args*  parameters );
104 /*
105 ================================================================================
106 Support for dynamically loading the FreeType2 library
107 ================================================================================
108 */
109
110 static dllfunction_t ft2funcs[] =
111 {
112         {"FT_Init_FreeType",            (void **) &qFT_Init_FreeType},
113         {"FT_Done_FreeType",            (void **) &qFT_Done_FreeType},
114         //{"FT_New_Face",                       (void **) &qFT_New_Face},
115         {"FT_New_Memory_Face",          (void **) &qFT_New_Memory_Face},
116         {"FT_Done_Face",                (void **) &qFT_Done_Face},
117         {"FT_Select_Size",              (void **) &qFT_Select_Size},
118         {"FT_Request_Size",             (void **) &qFT_Request_Size},
119         {"FT_Set_Char_Size",            (void **) &qFT_Set_Char_Size},
120         {"FT_Set_Pixel_Sizes",          (void **) &qFT_Set_Pixel_Sizes},
121         {"FT_Load_Glyph",               (void **) &qFT_Load_Glyph},
122         {"FT_Load_Char",                (void **) &qFT_Load_Char},
123         {"FT_Get_Char_Index",           (void **) &qFT_Get_Char_Index},
124         {"FT_Render_Glyph",             (void **) &qFT_Render_Glyph},
125         {"FT_Get_Kerning",              (void **) &qFT_Get_Kerning},
126         {"FT_Attach_Stream",            (void **) &qFT_Attach_Stream},
127         {NULL, NULL}
128 };
129
130 /// Handle for FreeType2 DLL
131 static dllhandle_t ft2_dll = NULL;
132
133 /// Memory pool for fonts
134 static mempool_t *font_mempool= NULL;
135 static rtexturepool_t *font_texturepool = NULL;
136
137 /// FreeType library handle
138 static FT_Library font_ft2lib = NULL;
139
140 /*
141 ====================
142 Font_CloseLibrary
143
144 Unload the FreeType2 DLL
145 ====================
146 */
147 void Font_CloseLibrary (void)
148 {
149         if (font_mempool)
150                 Mem_FreePool(&font_mempool);
151         if (font_texturepool)
152                 R_FreeTexturePool(&font_texturepool);
153         if (font_ft2lib && qFT_Done_FreeType)
154         {
155                 qFT_Done_FreeType(font_ft2lib);
156                 font_ft2lib = NULL;
157         }
158         Sys_UnloadLibrary (&ft2_dll);
159 }
160
161 /*
162 ====================
163 Font_OpenLibrary
164
165 Try to load the FreeType2 DLL
166 ====================
167 */
168 qboolean Font_OpenLibrary (void)
169 {
170         const char* dllnames [] =
171         {
172 #if defined(WIN32)
173                 "freetype6.dll",
174 #elif defined(MACOSX)
175                 "libfreetype.dylib",
176 #else
177                 "libfreetype.so.6",
178                 "libfreetype.so",
179 #endif
180                 NULL
181         };
182
183         if (r_font_disable_freetype.integer)
184                 return false;
185
186         // Already loaded?
187         if (ft2_dll)
188                 return true;
189
190         // Load the DLL
191         if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
192                 return false;
193         return true;
194 }
195
196 /*
197 ====================
198 Font_Init
199
200 Initialize the freetype2 font subsystem
201 ====================
202 */
203
204 void font_start(void)
205 {
206         if (!Font_OpenLibrary())
207                 return;
208
209         if (qFT_Init_FreeType(&font_ft2lib))
210         {
211                 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
212                 Font_CloseLibrary();
213                 return;
214         }
215
216         font_mempool = Mem_AllocPool("FONT", 0, NULL);
217         if (!font_mempool)
218         {
219                 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
220                 Font_CloseLibrary();
221                 return;
222         }
223
224         font_texturepool = R_AllocTexturePool();
225         if (!font_texturepool)
226         {
227                 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
228                 Font_CloseLibrary();
229                 return;
230         }
231 }
232
233 void font_shutdown(void)
234 {
235         int i;
236         for (i = 0; i < MAX_FONTS; ++i)
237         {
238                 if (dp_fonts[i].ft2)
239                 {
240                         Font_UnloadFont(dp_fonts[i].ft2);
241                         dp_fonts[i].ft2 = NULL;
242                 }
243         }
244         Font_CloseLibrary();
245 }
246
247 void font_newmap(void)
248 {
249 }
250
251 void Font_Init(void)
252 {
253         Cvar_RegisterVariable(&r_font_disable_freetype);
254         Cvar_RegisterVariable(&r_font_use_alpha_textures);
255         Cvar_RegisterVariable(&r_font_size_snapping);
256 }
257
258 /*
259 ================================================================================
260 Implementation of a more or less lazy font loading and rendering code.
261 ================================================================================
262 */
263
264 #include "ft2_fontdefs.h"
265
266 ft2_font_t *Font_Alloc(void)
267 {
268         if (!ft2_dll)
269                 return NULL;
270         return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
271 }
272
273 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
274 {
275         ft2_attachment_t *na;
276
277         font->attachmentcount++;
278         na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
279         if (na == NULL)
280                 return false;
281         if (font->attachments && font->attachmentcount > 1)
282         {
283                 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
284                 Mem_Free(font->attachments);
285         }
286         memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
287         font->attachments = na;
288         return true;
289 }
290
291 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
292 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
293 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
294 {
295         int s, count, i;
296         ft2_font_t *ft2, *fbfont, *fb;
297
298         ft2 = Font_Alloc();
299         if (!ft2)
300         {
301                 dpfnt->ft2 = NULL;
302                 return false;
303         }
304
305         // check if a fallback font has been specified, if it has been, and the
306         // font fails to load, use the image font as main font
307         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
308         {
309                 if (dpfnt->fallbacks[i][0])
310                         break;
311         }
312
313         if (!Font_LoadFile(name, dpfnt->req_face, ft2))
314         {
315                 if (i >= MAX_FONT_FALLBACKS)
316                 {
317                         dpfnt->ft2 = NULL;
318                         Mem_Free(ft2);
319                         return false;
320                 }
321                 strlcpy(ft2->name, name, sizeof(ft2->name));
322                 ft2->image_font = true;
323                 ft2->has_kerning = false;
324         }
325         else
326         {
327                 ft2->image_font = false;
328         }
329
330         // attempt to load fallback fonts:
331         fbfont = ft2;
332         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
333         {
334                 if (!dpfnt->fallbacks[i][0])
335                         break;
336                 if (! (fb = Font_Alloc()) )
337                 {
338                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
339                         break;
340                 }
341                 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
342                 {
343                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
344                         Mem_Free(fb);
345                         break;
346                 }
347                 count = 0;
348                 for (s = 0; s < MAX_FONT_SIZES; ++s)
349                 {
350                         if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
351                                 ++count;
352                 }
353                 if (!count)
354                 {
355                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
356                         Font_UnloadFont(fb);
357                         Mem_Free(fb);
358                         break;
359                 }
360                 // at least one size of the fallback font loaded successfully
361                 // link it:
362                 fbfont->next = fb;
363                 fbfont = fb;
364         }
365
366         if (fbfont == ft2 && ft2->image_font)
367         {
368                 // no fallbacks were loaded successfully:
369                 dpfnt->ft2 = NULL;
370                 Mem_Free(ft2);
371                 return false;
372         }
373
374         count = 0;
375         for (s = 0; s < MAX_FONT_SIZES; ++s)
376         {
377                 if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
378                         ++count;
379         }
380         if (!count)
381         {
382                 // loading failed for every requested size
383                 Font_UnloadFont(ft2);
384                 Mem_Free(ft2);
385                 dpfnt->ft2 = NULL;
386                 return false;
387         }
388
389         //Con_Printf("%i sizes loaded\n", count);
390         dpfnt->ft2 = ft2;
391         return true;
392 }
393
394 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
395 {
396         size_t namelen;
397         char filename[MAX_QPATH];
398         int status;
399         size_t i;
400         unsigned char *data;
401         fs_offset_t datasize;
402
403         memset(font, 0, sizeof(*font));
404
405         if (!Font_OpenLibrary())
406         {
407                 if (!r_font_disable_freetype.integer)
408                 {
409                         Con_Printf("WARNING: can't open load font %s\n"
410                                    "You need the FreeType2 DLL to load font files\n",
411                                    name);
412                 }
413                 return false;
414         }
415
416         namelen = strlen(name);
417
418         memcpy(filename, name, namelen);
419         memcpy(filename + namelen, ".ttf", 5);
420         data = FS_LoadFile(filename, font_mempool, false, &datasize);
421         if (!data)
422         {
423                 memcpy(filename + namelen, ".otf", 5);
424                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
425         }
426         if (!data)
427         {
428                 ft2_attachment_t afm;
429
430                 memcpy(filename + namelen, ".pfb", 5);
431                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
432
433                 if (data)
434                 {
435                         memcpy(filename + namelen, ".afm", 5);
436                         afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
437
438                         if (afm.data)
439                                 Font_Attach(font, &afm);
440                 }
441         }
442
443         if (!data)
444         {
445                 // FS_LoadFile being not-quiet should print an error :)
446                 return false;
447         }
448         Con_Printf("Loading font %s face %i...\n", filename, _face);
449
450         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
451         if (status && _face != 0)
452         {
453                 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
454                 _face = 0;
455                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
456         }
457         if (status)
458         {
459                 Con_Printf("ERROR: can't create face for %s\n"
460                            "Error %i\n", // TODO: error strings
461                            name, status);
462                 Font_UnloadFont(font);
463                 return false;
464         }
465
466         // add the attachments
467         for (i = 0; i < font->attachmentcount; ++i)
468         {
469                 FT_Open_Args args;
470                 memset(&args, 0, sizeof(args));
471                 args.flags = FT_OPEN_MEMORY;
472                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
473                 args.memory_size = font->attachments[i].size;
474                 if (qFT_Attach_Stream(font->face, &args))
475                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
476         }
477
478         memcpy(font->name, name, namelen+1);
479         font->image_font = false;
480         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
481         return true;
482 }
483
484 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
485 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
486 {
487         int map_index;
488         ft2_font_map_t *fmap, temp;
489
490         if (IS_NAN(size))
491                 size = 0;
492
493         if (!size)
494                 size = 16;
495         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
496                 return false;
497
498         if (!no_texture)
499         {
500                 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
501                 {
502                         if (!font->font_maps[map_index])
503                                 break;
504                         // if a similar size has already been loaded, ignore this one
505                         //abs(font->font_maps[map_index]->size - size) < 4
506                         if (font->font_maps[map_index]->size == size)
507                                 return true;
508                 }
509
510                 if (map_index >= MAX_FONT_SIZES)
511                         return false;
512
513                 memset(&temp, 0, sizeof(temp));
514                 temp.size = size;
515                 temp.glyphSize = CeilPowerOf2(size*2);
516                 temp.sfx = (1.0/64.0)/(double)size;
517                 temp.sfy = (1.0/64.0)/(double)size;
518                 temp.intSize = -1; // negative value: LoadMap must search now :)
519                 if (!Font_LoadMap(font, &temp, 0, &fmap))
520                 {
521                         Con_Printf("ERROR: can't load the first character map for %s\n"
522                                    "This is fatal\n",
523                                    font->name);
524                         Font_UnloadFont(font);
525                         return false;
526                 }
527                 font->font_maps[map_index] = temp.next;
528
529                 fmap->sfx = temp.sfx;
530                 fmap->sfy = temp.sfy;
531         }
532         if (!no_kerning)
533         {
534                 // load the default kerning vector:
535                 if (font->has_kerning)
536                 {
537                         Uchar l, r;
538                         FT_Vector kernvec;
539                         for (l = 0; l < 256; ++l)
540                         {
541                                 for (r = 0; r < 256; ++r)
542                                 {
543                                         FT_ULong ul, ur;
544                                         ul = qFT_Get_Char_Index(font->face, l);
545                                         ur = qFT_Get_Char_Index(font->face, r);
546                                         if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
547                                         {
548                                                 fmap->kerning.kerning[l][r][0] = 0;
549                                                 fmap->kerning.kerning[l][r][1] = 0;
550                                         }
551                                         else
552                                         {
553                                                 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
554                                                 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
555                                         }
556                                 }
557                         }
558                 }
559         }
560
561         return true;
562 }
563
564 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
565 {
566         int match = -1;
567         int value = 1000000;
568         int nval;
569         int matchsize = -10000;
570         int m;
571         int size;
572         float fsize;
573         ft2_font_map_t **maps = font->font_maps;
574
575         fsize = _fsize * vid.height / vid_conheight.value;
576
577         if (fsize < 0)
578                 size = 16;
579         else
580         {
581                 // round up
582                 size = (int)fsize;
583                 if (fsize - (float)size >= 0.49)
584                         ++size;
585         }
586
587         for (m = 0; m < MAX_FONT_SIZES; ++m)
588         {
589                 if (!maps[m])
590                         continue;
591                 // "round up" to the bigger size if two equally-valued matches exist
592                 nval = abs(maps[m]->size - size);
593                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
594                 {
595                         value = nval;
596                         match = m;
597                         matchsize = maps[m]->size;
598                         if (value == 0) // there is no better match
599                                 break;
600                 }
601         }
602         if (value <= r_font_size_snapping.value)
603         {
604                 if (outw && outh)
605                 {
606                         if (!*outh) *outh = *outw;
607                         if (!*outw) *outw = *outh;
608                 }
609                 // keep the aspect
610                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
611                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
612         }
613         return match;
614 }
615
616 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
617 {
618         if (index < 0 || index >= MAX_FONT_SIZES)
619                 return NULL;
620         return font->font_maps[index];
621 }
622
623 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
624 {
625         if (font->currenth == h &&
626             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
627              font->currentw == w)) // same size has been requested
628         {
629                 return true;
630         }
631         // sorry, but freetype doesn't seem to care about other sizes
632         w = (int)w;
633         h = (int)h;
634         if (font->image_font)
635         {
636                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
637                         return false;
638         }
639         else
640         {
641                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
642                         return false;
643         }
644         font->currentw = w;
645         font->currenth = h;
646         return true;
647 }
648
649 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
650 {
651         ft2_font_map_t *fmap;
652         if (!font->has_kerning)
653                 return false;
654         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
655                 return false;
656         fmap = font->font_maps[map_index];
657         if (!fmap)
658                 return false;
659         if (left < 256 && right < 256)
660         {
661                 // quick-kerning, be aware of the size: scale it
662                 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
663                 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
664                 return true;
665         }
666         else
667         {
668                 FT_Vector kernvec;
669                 FT_ULong ul, ur;
670
671                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
672                 if (!Font_SetSize(font, w, h))
673                 {
674                         // this deserves an error message
675                         Con_Printf("Failed to get kerning for %s\n", font->name);
676                         return false;
677                 }
678                 ul = qFT_Get_Char_Index(font->face, left);
679                 ur = qFT_Get_Char_Index(font->face, right);
680                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
681                 {
682                         if (outx) *outx = kernvec.x * fmap->sfx;
683                         if (outy) *outy = kernvec.y * fmap->sfy;
684                         return true;
685                 }
686                 return false;
687         }
688 }
689
690 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
691 {
692         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
693 }
694
695 static void UnloadMapRec(ft2_font_map_t *map)
696 {
697         if (map->texture)
698         {
699                 R_FreeTexture(map->texture);
700                 map->texture = NULL;
701         }
702         if (map->next)
703                 UnloadMapRec(map->next);
704         Mem_Free(map);
705 }
706
707 void Font_UnloadFont(ft2_font_t *font)
708 {
709         int i;
710         if (font->attachments && font->attachmentcount)
711         {
712                 Mem_Free(font->attachments);
713                 font->attachmentcount = 0;
714                 font->attachments = NULL;
715         }
716         for (i = 0; i < MAX_FONT_SIZES; ++i)
717         {
718                 if (font->font_maps[i])
719                 {
720                         UnloadMapRec(font->font_maps[i]);
721                         font->font_maps[i] = NULL;
722                 }
723         }
724         if (ft2_dll)
725         {
726                 if (font->face)
727                 {
728                         qFT_Done_Face((FT_Face)font->face);
729                         font->face = NULL;
730                 }
731         }
732 }
733
734 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
735 {
736         char map_identifier[MAX_QPATH];
737         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
738         unsigned char *data;
739         FT_ULong ch, mapch;
740         int status;
741         int tp;
742
743         int pitch;
744         int gR, gC; // glyph position: row and column
745
746         ft2_font_map_t *map, *next;
747         ft2_font_t *usefont;
748
749         FT_Face fontface;
750
751         int bytesPerPixel = 4; // change the conversion loop too if you change this!
752
753         if (outmap)
754                 *outmap = NULL;
755
756         if (r_font_use_alpha_textures.integer)
757                 bytesPerPixel = 1;
758
759         if (font->image_font)
760                 fontface = (FT_Face)font->next->face;
761         else
762                 fontface = (FT_Face)font->face;
763
764         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
765         //if (status)
766         if (font->image_font && mapstart->intSize < 0)
767                 mapstart->intSize = mapstart->size;
768         if (mapstart->intSize < 0)
769         {
770                 mapstart->intSize = mapstart->size;
771                 while (1)
772                 {
773                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
774                         {
775                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
776                                 return false;
777                         }
778                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
779                                 break;
780                         if (mapstart->intSize < 2)
781                         {
782                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
783                                 return false;
784                         }
785                         --mapstart->intSize;
786                 }
787                 if (developer.integer)
788                         Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
789         }
790
791         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
792         {
793                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
794                 return false;
795         }
796
797         map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
798         if (!map)
799         {
800                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
801                 return false;
802         }
803
804         // copy over the information
805         map->size = mapstart->size;
806         map->intSize = mapstart->intSize;
807         map->glyphSize = mapstart->glyphSize;
808         map->sfx = mapstart->sfx;
809         map->sfy = mapstart->sfy;
810
811         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
812         data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
813         if (!data)
814         {
815                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
816                 Mem_Free(map);
817                 return false;
818         }
819
820         // initialize as white texture with zero alpha
821         tp = 0;
822         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
823         {
824                 if (bytesPerPixel == 4)
825                 {
826                         data[tp++] = 0xFF;
827                         data[tp++] = 0xFF;
828                         data[tp++] = 0xFF;
829                 }
830                 data[tp++] = 0x00;
831         }
832
833         // insert the map
834         map->start = mapidx * FONT_CHARS_PER_MAP;
835         next = mapstart;
836         while(next->next && next->next->start < map->start)
837                 next = next->next;
838         map->next = next->next;
839         next->next = map;
840
841         gR = 0;
842         gC = -1;
843         for (ch = map->start;
844              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
845              ++ch)
846         {
847                 FT_ULong glyphIndex;
848                 int w, h, x, y;
849                 FT_GlyphSlot glyph;
850                 FT_Bitmap *bmp;
851                 unsigned char *imagedata, *dst, *src;
852                 glyph_slot_t *mapglyph;
853                 FT_Face face;
854
855                 mapch = ch - map->start;
856
857                 if (developer.integer)
858                         Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
859
860                 ++gC;
861                 if (gC >= FONT_CHARS_PER_LINE)
862                 {
863                         gC -= FONT_CHARS_PER_LINE;
864                         ++gR;
865                 }
866
867                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
868                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
869                 // we need the glyphIndex
870                 face = font->face;
871                 usefont = NULL;
872                 if (font->image_font && mapch == ch && img_fontmap[mapch])
873                 {
874                         map->glyphs[mapch].image = true;
875                         continue;
876                 }
877                 glyphIndex = qFT_Get_Char_Index(face, ch);
878                 if (glyphIndex == 0)
879                 {
880                         // by convention, 0 is the "missing-glyph"-glyph
881                         // try to load from a fallback font
882                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
883                         {
884                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
885                                         continue;
886                                 // try that glyph
887                                 face = usefont->face;
888                                 glyphIndex = qFT_Get_Char_Index(face, ch);
889                                 if (glyphIndex == 0)
890                                         continue;
891                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
892                                 if (status)
893                                         continue;
894                                 break;
895                         }
896                         if (!usefont)
897                         {
898                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
899                                 // now we let it use the "missing-glyph"-glyph
900                                 face = font->face;
901                                 glyphIndex = 0;
902                         }
903                 }
904
905                 if (!usefont)
906                 {
907                         usefont = font;
908                         face = font->face;
909                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
910                         if (status)
911                         {
912                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
913                                 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
914                                 continue;
915                         }
916                 }
917
918                 glyph = face->glyph;
919                 bmp = &glyph->bitmap;
920
921                 w = bmp->width;
922                 h = bmp->rows;
923
924                 if (w > map->glyphSize || h > map->glyphSize) {
925                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
926                         if (w > map->glyphSize)
927                                 w = map->glyphSize;
928                         if (h > map->glyphSize)
929                                 h = map->glyphSize;
930                 }
931
932                 switch (bmp->pixel_mode)
933                 {
934                 case FT_PIXEL_MODE_MONO:
935                         if (developer.integer)
936                                 Con_Print("glyphinfo:   Pixel Mode: MONO\n");
937                         break;
938                 case FT_PIXEL_MODE_GRAY2:
939                         if (developer.integer)
940                                 Con_Print("glyphinfo:   Pixel Mode: GRAY2\n");
941                         break;
942                 case FT_PIXEL_MODE_GRAY4:
943                         if (developer.integer)
944                                 Con_Print("glyphinfo:   Pixel Mode: GRAY4\n");
945                         break;
946                 case FT_PIXEL_MODE_GRAY:
947                         if (developer.integer)
948                                 Con_Print("glyphinfo:   Pixel Mode: GRAY\n");
949                         break;
950                 default:
951                         if (developer.integer)
952                                 Con_Printf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
953                         Mem_Free(data);
954                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
955                         return false;
956                 }
957                 for (y = 0; y < h; ++y)
958                 {
959                         dst = imagedata + y * pitch;
960                         src = bmp->buffer + y * bmp->pitch;
961
962                         switch (bmp->pixel_mode)
963                         {
964                         case FT_PIXEL_MODE_MONO:
965                                 dst += bytesPerPixel - 1; // shift to alpha byte
966                                 for (x = 0; x < bmp->width; x += 8)
967                                 {
968                                         unsigned char ch = *src++;
969                                         *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
970                                         *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
971                                         *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
972                                         *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
973                                         *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
974                                         *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
975                                         *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
976                                         *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
977                                 }
978                                 break;
979                         case FT_PIXEL_MODE_GRAY2:
980                                 dst += bytesPerPixel - 1; // shift to alpha byte
981                                 for (x = 0; x < bmp->width; x += 4)
982                                 {
983                                         unsigned char ch = *src++;
984                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
985                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
986                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
987                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
988                                 }
989                                 break;
990                         case FT_PIXEL_MODE_GRAY4:
991                                 dst += bytesPerPixel - 1; // shift to alpha byte
992                                 for (x = 0; x < bmp->width; x += 2)
993                                 {
994                                         unsigned char ch = *src++;
995                                         *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
996                                         *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
997                                 }
998                                 break;
999                         case FT_PIXEL_MODE_GRAY:
1000                                 // in this case pitch should equal width
1001                                 for (tp = 0; tp < bmp->pitch; ++tp)
1002                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1003
1004                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1005                                 //dst += bmp->pitch;
1006                                 break;
1007                         default:
1008                                 break;
1009                         }
1010                 }
1011
1012                 // now fill map->glyphs[ch - map->start]
1013                 mapglyph = &map->glyphs[mapch];
1014
1015                 {
1016                         // old way
1017                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1018
1019                         double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1020                         double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1021                         double advance = (glyph->advance.x >> 6) / map->size;
1022                         double mWidth = (glyph->metrics.width >> 6) / map->size;
1023                         double mHeight = (glyph->metrics.height >> 6) / map->size;
1024
1025                         mapglyph->vxmin = bearingX;
1026                         mapglyph->vxmax = bearingX + mWidth;
1027                         mapglyph->vymin = -bearingY;
1028                         mapglyph->vymax = mHeight - bearingY;
1029                         mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1030                         mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1031                         mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1032                         mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1033                         //mapglyph->advance_x = advance * usefont->size;
1034                         mapglyph->advance_x = advance;
1035                         mapglyph->advance_y = 0;
1036
1037                         if (developer.integer)
1038                         {
1039                                 Con_Printf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1040                                 Con_Printf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1041                                 if (ch >= 32 && ch <= 128)
1042                                         Con_Printf("glyphinfo:   Character: %c\n", (int)ch);
1043                                 Con_Printf("glyphinfo:   Vertex info:\n");
1044                                 Con_Printf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1045                                 Con_Printf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1046                                 Con_Printf("glyphinfo:   Texture info:\n");
1047                                 Con_Printf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1048                                 Con_Printf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1049                                 Con_Printf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1050                         }
1051                 }
1052                 map->glyphs[mapch].image = false;
1053         }
1054
1055         // create a texture from the data now
1056
1057         if (developer.integer)
1058         {
1059                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1060                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1061                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1062         }
1063         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1064
1065         // probably use bytesPerPixel here instead?
1066         if (r_font_use_alpha_textures.integer)
1067         {
1068                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1069                                                map->glyphSize * FONT_CHARS_PER_LINE,
1070                                                map->glyphSize * FONT_CHAR_LINES,
1071                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1072         } else {
1073                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1074                                                map->glyphSize * FONT_CHARS_PER_LINE,
1075                                                map->glyphSize * FONT_CHAR_LINES,
1076                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1077         }
1078
1079         Mem_Free(data);
1080         if (!map->texture)
1081         {
1082                 // if the first try isn't successful, keep it with a broken texture
1083                 // otherwise we retry to load it every single frame where ft2 rendering is used
1084                 // this would be bad...
1085                 // only `data' must be freed
1086                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1087                            font->name, mapstart->size, mapidx);
1088                 return false;
1089         }
1090         if (outmap)
1091                 *outmap = map;
1092         return true;
1093 }
1094
1095 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1096 {
1097         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1098                 return false;
1099         // the first map must have been loaded already
1100         if (!font->font_maps[map_index])
1101                 return false;
1102         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1103 }
1104
1105 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1106 {
1107         while (start && start->start + FONT_CHARS_PER_MAP < ch)
1108                 start = start->next;
1109         if (start && start->start > ch)
1110                 return NULL;
1111         return start;
1112 }