]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
reducing error output in font loading (use developer != 0 to re-enable)
[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 float Font_VirtualToRealSize(float sz)
292 {
293         int vh, vw, si;
294         float sn;
295         if(sz < 0)
296                 return sz;
297         vw = ((vid.width > 0) ? vid.width : vid_width.value);
298         vh = ((vid.height > 0) ? vid.height : vid_height.value);
299         // now try to scale to our actual size:
300         sn = sz * vh / vid_conheight.value;
301         si = (int)sn;
302         if ( sn - (float)si >= 0.5 )
303                 ++si;
304         return si;
305 }
306
307 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
308 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
309 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
310 {
311         int s, count, i;
312         ft2_font_t *ft2, *fbfont, *fb;
313
314         ft2 = Font_Alloc();
315         if (!ft2)
316         {
317                 dpfnt->ft2 = NULL;
318                 return false;
319         }
320
321         // check if a fallback font has been specified, if it has been, and the
322         // font fails to load, use the image font as main font
323         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
324         {
325                 if (dpfnt->fallbacks[i][0])
326                         break;
327         }
328
329         if (!Font_LoadFile(name, dpfnt->req_face, ft2))
330         {
331                 if (i >= MAX_FONT_FALLBACKS)
332                 {
333                         dpfnt->ft2 = NULL;
334                         Mem_Free(ft2);
335                         return false;
336                 }
337                 strlcpy(ft2->name, name, sizeof(ft2->name));
338                 ft2->image_font = true;
339                 ft2->has_kerning = false;
340         }
341         else
342         {
343                 ft2->image_font = false;
344         }
345
346         // attempt to load fallback fonts:
347         fbfont = ft2;
348         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
349         {
350                 if (!dpfnt->fallbacks[i][0])
351                         break;
352                 if (! (fb = Font_Alloc()) )
353                 {
354                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
355                         break;
356                 }
357                 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
358                 {
359                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
360                         Mem_Free(fb);
361                         break;
362                 }
363                 count = 0;
364                 for (s = 0; s < MAX_FONT_SIZES; ++s)
365                 {
366                         if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
367                                 ++count;
368                 }
369                 if (!count)
370                 {
371                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
372                         Font_UnloadFont(fb);
373                         Mem_Free(fb);
374                         break;
375                 }
376                 // at least one size of the fallback font loaded successfully
377                 // link it:
378                 fbfont->next = fb;
379                 fbfont = fb;
380         }
381
382         if (fbfont == ft2 && ft2->image_font)
383         {
384                 // no fallbacks were loaded successfully:
385                 dpfnt->ft2 = NULL;
386                 Mem_Free(ft2);
387                 return false;
388         }
389
390         count = 0;
391         for (s = 0; s < MAX_FONT_SIZES; ++s)
392         {
393                 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
394                         ++count;
395         }
396         if (!count)
397         {
398                 // loading failed for every requested size
399                 Font_UnloadFont(ft2);
400                 Mem_Free(ft2);
401                 dpfnt->ft2 = NULL;
402                 return false;
403         }
404
405         //Con_Printf("%i sizes loaded\n", count);
406         dpfnt->ft2 = ft2;
407         return true;
408 }
409
410 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
411 {
412         size_t namelen;
413         char filename[MAX_QPATH];
414         int status;
415         size_t i;
416         unsigned char *data;
417         fs_offset_t datasize;
418
419         memset(font, 0, sizeof(*font));
420
421         if (!Font_OpenLibrary())
422         {
423                 if (!r_font_disable_freetype.integer)
424                 {
425                         Con_Printf("WARNING: can't open load font %s\n"
426                                    "You need the FreeType2 DLL to load font files\n",
427                                    name);
428                 }
429                 return false;
430         }
431
432         namelen = strlen(name);
433
434         memcpy(filename, name, namelen);
435         memcpy(filename + namelen, ".ttf", 5);
436         data = FS_LoadFile(filename, font_mempool, false, &datasize);
437         if (!data)
438         {
439                 memcpy(filename + namelen, ".otf", 5);
440                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
441         }
442         if (!data)
443         {
444                 ft2_attachment_t afm;
445
446                 memcpy(filename + namelen, ".pfb", 5);
447                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
448
449                 if (data)
450                 {
451                         memcpy(filename + namelen, ".afm", 5);
452                         afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
453
454                         if (afm.data)
455                                 Font_Attach(font, &afm);
456                 }
457         }
458
459         if (!data)
460         {
461                 // FS_LoadFile being not-quiet should print an error :)
462                 return false;
463         }
464         Con_Printf("Loading font %s face %i...\n", filename, _face);
465
466         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
467         if (status && _face != 0)
468         {
469                 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
470                 _face = 0;
471                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
472         }
473         if (status)
474         {
475                 Con_Printf("ERROR: can't create face for %s\n"
476                            "Error %i\n", // TODO: error strings
477                            name, status);
478                 Font_UnloadFont(font);
479                 return false;
480         }
481
482         // add the attachments
483         for (i = 0; i < font->attachmentcount; ++i)
484         {
485                 FT_Open_Args args;
486                 memset(&args, 0, sizeof(args));
487                 args.flags = FT_OPEN_MEMORY;
488                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
489                 args.memory_size = font->attachments[i].size;
490                 if (qFT_Attach_Stream(font->face, &args))
491                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
492         }
493
494         memcpy(font->name, name, namelen+1);
495         font->image_font = false;
496         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
497         return true;
498 }
499
500 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
501 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
502 {
503         int map_index;
504         ft2_font_map_t *fmap, temp;
505
506         if (IS_NAN(size))
507                 size = 0;
508
509         if (!size)
510                 size = 16;
511         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
512                 return false;
513
514         if (!no_texture)
515         {
516                 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
517                 {
518                         if (!font->font_maps[map_index])
519                                 break;
520                         // if a similar size has already been loaded, ignore this one
521                         //abs(font->font_maps[map_index]->size - size) < 4
522                         if (font->font_maps[map_index]->size == size)
523                                 return true;
524                 }
525
526                 if (map_index >= MAX_FONT_SIZES)
527                         return false;
528
529                 memset(&temp, 0, sizeof(temp));
530                 temp.size = size;
531                 temp.glyphSize = CeilPowerOf2(size*2);
532                 temp.sfx = (1.0/64.0)/(double)size;
533                 temp.sfy = (1.0/64.0)/(double)size;
534                 temp.intSize = -1; // negative value: LoadMap must search now :)
535                 if (!Font_LoadMap(font, &temp, 0, &fmap))
536                 {
537                         Con_Printf("ERROR: can't load the first character map for %s\n"
538                                    "This is fatal\n",
539                                    font->name);
540                         Font_UnloadFont(font);
541                         return false;
542                 }
543                 font->font_maps[map_index] = temp.next;
544
545                 fmap->sfx = temp.sfx;
546                 fmap->sfy = temp.sfy;
547         }
548         if (!no_kerning)
549         {
550                 // load the default kerning vector:
551                 if (font->has_kerning)
552                 {
553                         Uchar l, r;
554                         FT_Vector kernvec;
555                         for (l = 0; l < 256; ++l)
556                         {
557                                 for (r = 0; r < 256; ++r)
558                                 {
559                                         FT_ULong ul, ur;
560                                         ul = qFT_Get_Char_Index(font->face, l);
561                                         ur = qFT_Get_Char_Index(font->face, r);
562                                         if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
563                                         {
564                                                 fmap->kerning.kerning[l][r][0] = 0;
565                                                 fmap->kerning.kerning[l][r][1] = 0;
566                                         }
567                                         else
568                                         {
569                                                 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
570                                                 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
571                                         }
572                                 }
573                         }
574                 }
575         }
576
577         return true;
578 }
579
580 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
581 {
582         int match = -1;
583         int value = 1000000;
584         int nval;
585         int matchsize = -10000;
586         int m;
587         int size;
588         float fsize;
589         ft2_font_map_t **maps = font->font_maps;
590
591         fsize = _fsize * vid.height / vid_conheight.value;
592
593         if (fsize < 0)
594                 size = 16;
595         else
596         {
597                 // round up
598                 size = (int)fsize;
599                 if (fsize - (float)size >= 0.49)
600                         ++size;
601         }
602
603         for (m = 0; m < MAX_FONT_SIZES; ++m)
604         {
605                 if (!maps[m])
606                         continue;
607                 // "round up" to the bigger size if two equally-valued matches exist
608                 nval = abs(maps[m]->size - size);
609                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
610                 {
611                         value = nval;
612                         match = m;
613                         matchsize = maps[m]->size;
614                         if (value == 0) // there is no better match
615                                 break;
616                 }
617         }
618         if (value <= r_font_size_snapping.value)
619         {
620                 if (outw && outh)
621                 {
622                         if (!*outh) *outh = *outw;
623                         if (!*outw) *outw = *outh;
624                 }
625                 // keep the aspect
626                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
627                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
628         }
629         return match;
630 }
631
632 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
633 {
634         if (index < 0 || index >= MAX_FONT_SIZES)
635                 return NULL;
636         return font->font_maps[index];
637 }
638
639 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
640 {
641         if (font->currenth == h &&
642             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
643              font->currentw == w)) // same size has been requested
644         {
645                 return true;
646         }
647         // sorry, but freetype doesn't seem to care about other sizes
648         w = (int)w;
649         h = (int)h;
650         if (font->image_font)
651         {
652                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
653                         return false;
654         }
655         else
656         {
657                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
658                         return false;
659         }
660         font->currentw = w;
661         font->currenth = h;
662         return true;
663 }
664
665 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
666 {
667         ft2_font_map_t *fmap;
668         if (!font->has_kerning)
669                 return false;
670         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
671                 return false;
672         fmap = font->font_maps[map_index];
673         if (!fmap)
674                 return false;
675         if (left < 256 && right < 256)
676         {
677                 // quick-kerning, be aware of the size: scale it
678                 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
679                 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
680                 return true;
681         }
682         else
683         {
684                 FT_Vector kernvec;
685                 FT_ULong ul, ur;
686
687                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
688                 if (!Font_SetSize(font, w, h))
689                 {
690                         // this deserves an error message
691                         Con_Printf("Failed to get kerning for %s\n", font->name);
692                         return false;
693                 }
694                 ul = qFT_Get_Char_Index(font->face, left);
695                 ur = qFT_Get_Char_Index(font->face, right);
696                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
697                 {
698                         if (outx) *outx = kernvec.x * fmap->sfx;
699                         if (outy) *outy = kernvec.y * fmap->sfy;
700                         return true;
701                 }
702                 return false;
703         }
704 }
705
706 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
707 {
708         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
709 }
710
711 static void UnloadMapRec(ft2_font_map_t *map)
712 {
713         if (map->texture)
714         {
715                 R_FreeTexture(map->texture);
716                 map->texture = NULL;
717         }
718         if (map->next)
719                 UnloadMapRec(map->next);
720         Mem_Free(map);
721 }
722
723 void Font_UnloadFont(ft2_font_t *font)
724 {
725         int i;
726         if (font->attachments && font->attachmentcount)
727         {
728                 Mem_Free(font->attachments);
729                 font->attachmentcount = 0;
730                 font->attachments = NULL;
731         }
732         for (i = 0; i < MAX_FONT_SIZES; ++i)
733         {
734                 if (font->font_maps[i])
735                 {
736                         UnloadMapRec(font->font_maps[i]);
737                         font->font_maps[i] = NULL;
738                 }
739         }
740         if (ft2_dll)
741         {
742                 if (font->face)
743                 {
744                         qFT_Done_Face((FT_Face)font->face);
745                         font->face = NULL;
746                 }
747         }
748 }
749
750 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
751 {
752         char map_identifier[MAX_QPATH];
753         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
754         unsigned char *data;
755         FT_ULong ch, mapch;
756         int status;
757         int tp;
758
759         int pitch;
760         int gR, gC; // glyph position: row and column
761
762         ft2_font_map_t *map, *next;
763         ft2_font_t *usefont;
764
765         FT_Face fontface;
766
767         int bytesPerPixel = 4; // change the conversion loop too if you change this!
768
769         if (outmap)
770                 *outmap = NULL;
771
772         if (r_font_use_alpha_textures.integer)
773                 bytesPerPixel = 1;
774
775         if (font->image_font)
776                 fontface = (FT_Face)font->next->face;
777         else
778                 fontface = (FT_Face)font->face;
779
780         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
781         //if (status)
782         if (font->image_font && mapstart->intSize < 0)
783                 mapstart->intSize = mapstart->size;
784         if (mapstart->intSize < 0)
785         {
786                 mapstart->intSize = mapstart->size;
787                 while (1)
788                 {
789                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
790                         {
791                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
792                                 return false;
793                         }
794                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
795                                 break;
796                         if (mapstart->intSize < 2)
797                         {
798                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
799                                 return false;
800                         }
801                         --mapstart->intSize;
802                 }
803                 if (developer.integer)
804                         Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
805         }
806
807         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
808         {
809                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
810                 return false;
811         }
812
813         map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
814         if (!map)
815         {
816                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
817                 return false;
818         }
819
820         // copy over the information
821         map->size = mapstart->size;
822         map->intSize = mapstart->intSize;
823         map->glyphSize = mapstart->glyphSize;
824         map->sfx = mapstart->sfx;
825         map->sfy = mapstart->sfy;
826
827         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
828         data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
829         if (!data)
830         {
831                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
832                 Mem_Free(map);
833                 return false;
834         }
835
836         // initialize as white texture with zero alpha
837         tp = 0;
838         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
839         {
840                 if (bytesPerPixel == 4)
841                 {
842                         data[tp++] = 0xFF;
843                         data[tp++] = 0xFF;
844                         data[tp++] = 0xFF;
845                 }
846                 data[tp++] = 0x00;
847         }
848
849         // insert the map
850         map->start = mapidx * FONT_CHARS_PER_MAP;
851         next = mapstart;
852         while(next->next && next->next->start < map->start)
853                 next = next->next;
854         map->next = next->next;
855         next->next = map;
856
857         gR = 0;
858         gC = -1;
859         for (ch = map->start;
860              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
861              ++ch)
862         {
863                 FT_ULong glyphIndex;
864                 int w, h, x, y;
865                 FT_GlyphSlot glyph;
866                 FT_Bitmap *bmp;
867                 unsigned char *imagedata, *dst, *src;
868                 glyph_slot_t *mapglyph;
869                 FT_Face face;
870
871                 mapch = ch - map->start;
872
873                 if (developer.integer)
874                         Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
875
876                 ++gC;
877                 if (gC >= FONT_CHARS_PER_LINE)
878                 {
879                         gC -= FONT_CHARS_PER_LINE;
880                         ++gR;
881                 }
882
883                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
884                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
885                 // we need the glyphIndex
886                 face = font->face;
887                 usefont = NULL;
888                 if (font->image_font && mapch == ch && img_fontmap[mapch])
889                 {
890                         map->glyphs[mapch].image = true;
891                         continue;
892                 }
893                 glyphIndex = qFT_Get_Char_Index(face, ch);
894                 if (glyphIndex == 0)
895                 {
896                         // by convention, 0 is the "missing-glyph"-glyph
897                         // try to load from a fallback font
898                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
899                         {
900                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
901                                         continue;
902                                 // try that glyph
903                                 face = usefont->face;
904                                 glyphIndex = qFT_Get_Char_Index(face, ch);
905                                 if (glyphIndex == 0)
906                                         continue;
907                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
908                                 if (status)
909                                         continue;
910                                 break;
911                         }
912                         if (!usefont)
913                         {
914                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
915                                 // now we let it use the "missing-glyph"-glyph
916                                 face = font->face;
917                                 glyphIndex = 0;
918                         }
919                 }
920
921                 if (!usefont)
922                 {
923                         usefont = font;
924                         face = font->face;
925                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
926                         if (status)
927                         {
928                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
929                                 if (developer.integer)
930                                         Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
931                                 continue;
932                         }
933                 }
934
935                 glyph = face->glyph;
936                 bmp = &glyph->bitmap;
937
938                 w = bmp->width;
939                 h = bmp->rows;
940
941                 if (w > map->glyphSize || h > map->glyphSize) {
942                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
943                         if (w > map->glyphSize)
944                                 w = map->glyphSize;
945                         if (h > map->glyphSize)
946                                 h = map->glyphSize;
947                 }
948
949                 switch (bmp->pixel_mode)
950                 {
951                 case FT_PIXEL_MODE_MONO:
952                         if (developer.integer)
953                                 Con_Print("glyphinfo:   Pixel Mode: MONO\n");
954                         break;
955                 case FT_PIXEL_MODE_GRAY2:
956                         if (developer.integer)
957                                 Con_Print("glyphinfo:   Pixel Mode: GRAY2\n");
958                         break;
959                 case FT_PIXEL_MODE_GRAY4:
960                         if (developer.integer)
961                                 Con_Print("glyphinfo:   Pixel Mode: GRAY4\n");
962                         break;
963                 case FT_PIXEL_MODE_GRAY:
964                         if (developer.integer)
965                                 Con_Print("glyphinfo:   Pixel Mode: GRAY\n");
966                         break;
967                 default:
968                         if (developer.integer)
969                                 Con_Printf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
970                         Mem_Free(data);
971                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
972                         return false;
973                 }
974                 for (y = 0; y < h; ++y)
975                 {
976                         dst = imagedata + y * pitch;
977                         src = bmp->buffer + y * bmp->pitch;
978
979                         switch (bmp->pixel_mode)
980                         {
981                         case FT_PIXEL_MODE_MONO:
982                                 dst += bytesPerPixel - 1; // shift to alpha byte
983                                 for (x = 0; x < bmp->width; x += 8)
984                                 {
985                                         unsigned char ch = *src++;
986                                         *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
987                                         *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
988                                         *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
989                                         *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
990                                         *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
991                                         *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
992                                         *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
993                                         *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
994                                 }
995                                 break;
996                         case FT_PIXEL_MODE_GRAY2:
997                                 dst += bytesPerPixel - 1; // shift to alpha byte
998                                 for (x = 0; x < bmp->width; x += 4)
999                                 {
1000                                         unsigned char ch = *src++;
1001                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1002                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1003                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1004                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1005                                 }
1006                                 break;
1007                         case FT_PIXEL_MODE_GRAY4:
1008                                 dst += bytesPerPixel - 1; // shift to alpha byte
1009                                 for (x = 0; x < bmp->width; x += 2)
1010                                 {
1011                                         unsigned char ch = *src++;
1012                                         *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1013                                         *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1014                                 }
1015                                 break;
1016                         case FT_PIXEL_MODE_GRAY:
1017                                 // in this case pitch should equal width
1018                                 for (tp = 0; tp < bmp->pitch; ++tp)
1019                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1020
1021                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1022                                 //dst += bmp->pitch;
1023                                 break;
1024                         default:
1025                                 break;
1026                         }
1027                 }
1028
1029                 // now fill map->glyphs[ch - map->start]
1030                 mapglyph = &map->glyphs[mapch];
1031
1032                 {
1033                         // old way
1034                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1035
1036                         double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1037                         double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1038                         double advance = (glyph->advance.x >> 6) / map->size;
1039                         double mWidth = (glyph->metrics.width >> 6) / map->size;
1040                         double mHeight = (glyph->metrics.height >> 6) / map->size;
1041
1042                         mapglyph->vxmin = bearingX;
1043                         mapglyph->vxmax = bearingX + mWidth;
1044                         mapglyph->vymin = -bearingY;
1045                         mapglyph->vymax = mHeight - bearingY;
1046                         mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1047                         mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1048                         mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1049                         mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1050                         //mapglyph->advance_x = advance * usefont->size;
1051                         mapglyph->advance_x = advance;
1052                         mapglyph->advance_y = 0;
1053
1054                         if (developer.integer)
1055                         {
1056                                 Con_Printf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1057                                 Con_Printf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1058                                 if (ch >= 32 && ch <= 128)
1059                                         Con_Printf("glyphinfo:   Character: %c\n", (int)ch);
1060                                 Con_Printf("glyphinfo:   Vertex info:\n");
1061                                 Con_Printf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1062                                 Con_Printf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1063                                 Con_Printf("glyphinfo:   Texture info:\n");
1064                                 Con_Printf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1065                                 Con_Printf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1066                                 Con_Printf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1067                         }
1068                 }
1069                 map->glyphs[mapch].image = false;
1070         }
1071
1072         // create a texture from the data now
1073
1074         if (developer.integer)
1075         {
1076                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1077                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1078                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1079         }
1080         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1081
1082         // probably use bytesPerPixel here instead?
1083         if (r_font_use_alpha_textures.integer)
1084         {
1085                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1086                                                map->glyphSize * FONT_CHARS_PER_LINE,
1087                                                map->glyphSize * FONT_CHAR_LINES,
1088                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1089         } else {
1090                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1091                                                map->glyphSize * FONT_CHARS_PER_LINE,
1092                                                map->glyphSize * FONT_CHAR_LINES,
1093                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1094         }
1095
1096         Mem_Free(data);
1097         if (!map->texture)
1098         {
1099                 // if the first try isn't successful, keep it with a broken texture
1100                 // otherwise we retry to load it every single frame where ft2 rendering is used
1101                 // this would be bad...
1102                 // only `data' must be freed
1103                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1104                            font->name, mapstart->size, mapidx);
1105                 return false;
1106         }
1107         if (outmap)
1108                 *outmap = map;
1109         return true;
1110 }
1111
1112 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1113 {
1114         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1115                 return false;
1116         // the first map must have been loaded already
1117         if (!font->font_maps[map_index])
1118                 return false;
1119         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1120 }
1121
1122 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1123 {
1124         while (start && start->start + FONT_CHARS_PER_MAP < ch)
1125                 start = start->next;
1126         if (start && start->start > ch)
1127                 return NULL;
1128         return start;
1129 }