]> git.xonotic.org Git - xonotic/darkplaces.git/blob - ft2.c
physics: fix and refactor unsticking
[xonotic/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 #include "image.h"
10
11 static int img_fontmap[256] = {
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,
14         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
15         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
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, // caps
18         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
20         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
21         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
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         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
28 };
29
30 /*
31  * Some big blocks of Unicode characters, according to
32  *     http://www.unicode.org/Public/UNIDATA/Blocks.txt
33  *
34  * Let's call these "bigblocks".
35  * These characters are "spreaded", and ordinary maps will 
36  *     waste huge amount of resources rendering/caching unused glyphs.
37  *
38  * So, a new design is introduced to solve the problem:
39  *     incremental maps, in which only used glyphs are stored.
40  */
41 static const Uchar unicode_bigblocks[] = {
42         0x3400, 0x4DBF,         //   6592  CJK Unified Ideographs Extension A
43         0x4E00, 0x9FFF,         //  20992  CJK Unified Ideographs
44         0xAC00, 0xD7AF,         //  11184  Hangul Syllables
45         0xE000, 0xF8FF,         //   6400  Private Use Area
46         0x10000, 0x10FFFF   //         Everything above
47 };
48
49 /*
50 ================================================================================
51 CVars introduced with the freetype extension
52 ================================================================================
53 */
54
55 cvar_t r_font_disable_freetype = {CF_CLIENT | CF_ARCHIVE, "r_font_disable_freetype", "0", "disable freetype support for fonts entirely"};
56 cvar_t r_font_size_snapping = {CF_CLIENT | CF_ARCHIVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
57 cvar_t r_font_kerning = {CF_CLIENT | CF_ARCHIVE, "r_font_kerning", "1", "Use kerning if available"};
58 cvar_t r_font_diskcache = {CF_CLIENT | CF_ARCHIVE, "r_font_diskcache", "0", "[deprecated, not effective] save font textures to disk for future loading rather than generating them every time"};
59 cvar_t r_font_compress = {CF_CLIENT | CF_ARCHIVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
60 cvar_t r_font_nonpoweroftwo = {CF_CLIENT | CF_ARCHIVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
61 cvar_t developer_font = {CF_CLIENT | CF_ARCHIVE, "developer_font", "0", "prints debug messages about fonts"};
62
63 cvar_t r_font_disable_incmaps = {CF_CLIENT | CF_ARCHIVE, "r_font_disable_incmaps", "0", "always to load a full glyph map for individual unmapped character, even when it will mean extreme resources waste"};
64
65 #ifndef DP_FREETYPE_STATIC
66
67 /*
68 ================================================================================
69 Function definitions. Taken from the freetype2 headers.
70 ================================================================================
71 */
72
73
74 FT_EXPORT( FT_Error )
75 (*qFT_Init_FreeType)( FT_Library  *alibrary );
76 FT_EXPORT( FT_Error )
77 (*qFT_Done_FreeType)( FT_Library  library );
78 /*
79 FT_EXPORT( FT_Error )
80 (*qFT_New_Face)( FT_Library   library,
81                  const char*  filepathname,
82                  FT_Long      face_index,
83                  FT_Face     *aface );
84 */
85 FT_EXPORT( FT_Error )
86 (*qFT_New_Memory_Face)( FT_Library      library,
87                         const FT_Byte*  file_base,
88                         FT_Long         file_size,
89                         FT_Long         face_index,
90                         FT_Face        *aface );
91 FT_EXPORT( FT_Error )
92 (*qFT_Done_Face)( FT_Face  face );
93 FT_EXPORT( FT_Error )
94 (*qFT_Select_Size)( FT_Face  face,
95                     FT_Int   strike_index );
96 FT_EXPORT( FT_Error )
97 (*qFT_Request_Size)( FT_Face          face,
98                      FT_Size_Request  req );
99 FT_EXPORT( FT_Error )
100 (*qFT_Set_Char_Size)( FT_Face     face,
101                       FT_F26Dot6  char_width,
102                       FT_F26Dot6  char_height,
103                       FT_UInt     horz_resolution,
104                       FT_UInt     vert_resolution );
105 FT_EXPORT( FT_Error )
106 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
107                         FT_UInt  pixel_width,
108                         FT_UInt  pixel_height );
109 FT_EXPORT( FT_Error )
110 (*qFT_Load_Glyph)( FT_Face   face,
111                    FT_UInt   glyph_index,
112                    FT_Int32  load_flags );
113 FT_EXPORT( FT_Error )
114 (*qFT_Load_Char)( FT_Face   face,
115                   FT_ULong  char_code,
116                   FT_Int32  load_flags );
117 FT_EXPORT( FT_UInt )
118 (*qFT_Get_Char_Index)( FT_Face   face,
119                        FT_ULong  charcode );
120 FT_EXPORT( FT_Error )
121 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
122                      FT_Render_Mode  render_mode );
123 FT_EXPORT( FT_Error )
124 (*qFT_Get_Kerning)( FT_Face     face,
125                     FT_UInt     left_glyph,
126                     FT_UInt     right_glyph,
127                     FT_UInt     kern_mode,
128                     FT_Vector  *akerning );
129 FT_EXPORT( FT_Error )
130 (*qFT_Attach_Stream)( FT_Face        face,
131                       FT_Open_Args*  parameters );
132 /*
133 ================================================================================
134 Support for dynamically loading the FreeType2 library
135 ================================================================================
136 */
137
138 static dllfunction_t ft2funcs[] =
139 {
140         {"FT_Init_FreeType",            (void **) &qFT_Init_FreeType},
141         {"FT_Done_FreeType",            (void **) &qFT_Done_FreeType},
142         //{"FT_New_Face",                       (void **) &qFT_New_Face},
143         {"FT_New_Memory_Face",          (void **) &qFT_New_Memory_Face},
144         {"FT_Done_Face",                (void **) &qFT_Done_Face},
145         {"FT_Select_Size",              (void **) &qFT_Select_Size},
146         {"FT_Request_Size",             (void **) &qFT_Request_Size},
147         {"FT_Set_Char_Size",            (void **) &qFT_Set_Char_Size},
148         {"FT_Set_Pixel_Sizes",          (void **) &qFT_Set_Pixel_Sizes},
149         {"FT_Load_Glyph",               (void **) &qFT_Load_Glyph},
150         {"FT_Load_Char",                (void **) &qFT_Load_Char},
151         {"FT_Get_Char_Index",           (void **) &qFT_Get_Char_Index},
152         {"FT_Render_Glyph",             (void **) &qFT_Render_Glyph},
153         {"FT_Get_Kerning",              (void **) &qFT_Get_Kerning},
154         {"FT_Attach_Stream",            (void **) &qFT_Attach_Stream},
155         {NULL, NULL}
156 };
157
158 /// Handle for FreeType2 DLL
159 static dllhandle_t ft2_dll = NULL;
160
161 #else
162
163 FT_EXPORT( FT_Error )
164 (FT_Init_FreeType)( FT_Library  *alibrary );
165 FT_EXPORT( FT_Error )
166 (FT_Done_FreeType)( FT_Library  library );
167 /*
168 FT_EXPORT( FT_Error )
169 (FT_New_Face)( FT_Library   library,
170                  const char*  filepathname,
171                  FT_Long      face_index,
172                  FT_Face     *aface );
173 */
174 FT_EXPORT( FT_Error )
175 (FT_New_Memory_Face)( FT_Library      library,
176                         const FT_Byte*  file_base,
177                         FT_Long         file_size,
178                         FT_Long         face_index,
179                         FT_Face        *aface );
180 FT_EXPORT( FT_Error )
181 (FT_Done_Face)( FT_Face  face );
182 FT_EXPORT( FT_Error )
183 (FT_Select_Size)( FT_Face  face,
184                     FT_Int   strike_index );
185 FT_EXPORT( FT_Error )
186 (FT_Request_Size)( FT_Face          face,
187                      FT_Size_Request  req );
188 FT_EXPORT( FT_Error )
189 (FT_Set_Char_Size)( FT_Face     face,
190                       FT_F26Dot6  char_width,
191                       FT_F26Dot6  char_height,
192                       FT_UInt     horz_resolution,
193                       FT_UInt     vert_resolution );
194 FT_EXPORT( FT_Error )
195 (FT_Set_Pixel_Sizes)( FT_Face  face,
196                         FT_UInt  pixel_width,
197                         FT_UInt  pixel_height );
198 FT_EXPORT( FT_Error )
199 (FT_Load_Glyph)( FT_Face   face,
200                    FT_UInt   glyph_index,
201                    FT_Int32  load_flags );
202 FT_EXPORT( FT_Error )
203 (FT_Load_Char)( FT_Face   face,
204                   FT_ULong  char_code,
205                   FT_Int32  load_flags );
206 FT_EXPORT( FT_UInt )
207 (FT_Get_Char_Index)( FT_Face   face,
208                        FT_ULong  charcode );
209 FT_EXPORT( FT_Error )
210 (FT_Render_Glyph)( FT_GlyphSlot    slot,
211                      FT_Render_Mode  render_mode );
212 FT_EXPORT( FT_Error )
213 (FT_Get_Kerning)( FT_Face     face,
214                     FT_UInt     left_glyph,
215                     FT_UInt     right_glyph,
216                     FT_UInt     kern_mode,
217                     FT_Vector  *akerning );
218 FT_EXPORT( FT_Error )
219 (FT_Attach_Stream)( FT_Face        face,
220                       FT_Open_Args*  parameters );
221
222 #define qFT_Init_FreeType               FT_Init_FreeType
223 #define qFT_Done_FreeType               FT_Done_FreeType
224 //#define qFT_New_Face                  FT_New_Face
225 #define qFT_New_Memory_Face             FT_New_Memory_Face
226 #define qFT_Done_Face                   FT_Done_Face
227 #define qFT_Select_Size                 FT_Select_Size
228 #define qFT_Request_Size                FT_Request_Size
229 #define qFT_Set_Char_Size               FT_Set_Char_Size
230 #define qFT_Set_Pixel_Sizes             FT_Set_Pixel_Sizes
231 #define qFT_Load_Glyph                  FT_Load_Glyph
232 #define qFT_Load_Char                   FT_Load_Char
233 #define qFT_Get_Char_Index              FT_Get_Char_Index
234 #define qFT_Render_Glyph                FT_Render_Glyph
235 #define qFT_Get_Kerning                 FT_Get_Kerning
236 #define qFT_Attach_Stream               FT_Attach_Stream
237
238 #endif
239
240 /// Memory pool for fonts
241 static mempool_t *font_mempool= NULL;
242
243 /// FreeType library handle
244 static FT_Library font_ft2lib = NULL;
245
246 #define POSTPROCESS_MAXRADIUS 8
247 typedef struct
248 {
249         unsigned char *buf, *buf2;
250         int bufsize, bufwidth, bufheight, bufpitch;
251         float blur, outline, shadowx, shadowy, shadowz;
252         int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
253         unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
254         unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
255 }
256 font_postprocess_t;
257 static font_postprocess_t pp;
258
259 typedef struct fontfilecache_s
260 {
261         unsigned char *buf;
262         fs_offset_t len;
263         int refcount;
264         char path[MAX_QPATH];
265 }
266 fontfilecache_t;
267 #define MAX_FONTFILES 8
268 static fontfilecache_t fontfiles[MAX_FONTFILES];
269 static const unsigned char *fontfilecache_LoadFile(const char *path, qbool quiet, fs_offset_t *filesizepointer)
270 {
271         int i;
272         unsigned char *buf;
273
274         for(i = 0; i < MAX_FONTFILES; ++i)
275         {
276                 if(fontfiles[i].refcount > 0)
277                         if(!strcmp(path, fontfiles[i].path))
278                         {
279                                 *filesizepointer = fontfiles[i].len;
280                                 ++fontfiles[i].refcount;
281                                 return fontfiles[i].buf;
282                         }
283         }
284
285         buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
286         if(buf)
287         {
288                 for(i = 0; i < MAX_FONTFILES; ++i)
289                         if(fontfiles[i].refcount <= 0)
290                         {
291                                 dp_strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
292                                 fontfiles[i].len = *filesizepointer;
293                                 fontfiles[i].buf = buf;
294                                 fontfiles[i].refcount = 1;
295                                 return buf;
296                         }
297         }
298
299         return buf;
300 }
301 static void fontfilecache_Free(const unsigned char *buf)
302 {
303         int i;
304         for(i = 0; i < MAX_FONTFILES; ++i)
305         {
306                 if(fontfiles[i].refcount > 0)
307                         if(fontfiles[i].buf == buf)
308                         {
309                                 if(--fontfiles[i].refcount <= 0)
310                                 {
311                                         Mem_Free(fontfiles[i].buf);
312                                         fontfiles[i].buf = NULL;
313                                 }
314                                 return;
315                         }
316         }
317         // if we get here, it used regular allocation
318         Mem_Free((void *) buf);
319 }
320 static void fontfilecache_FreeAll(void)
321 {
322         int i;
323         for(i = 0; i < MAX_FONTFILES; ++i)
324         {
325                 if(fontfiles[i].refcount > 0)
326                         Mem_Free(fontfiles[i].buf);
327                 fontfiles[i].buf = NULL;
328                 fontfiles[i].refcount = 0;
329         }
330 }
331
332 /*
333 ====================
334 Font_CloseLibrary
335
336 Unload the FreeType2 DLL
337 ====================
338 */
339 void Font_CloseLibrary (void)
340 {
341         fontfilecache_FreeAll();
342         if (font_mempool)
343                 Mem_FreePool(&font_mempool);
344         if (font_ft2lib && qFT_Done_FreeType)
345         {
346                 qFT_Done_FreeType(font_ft2lib);
347                 font_ft2lib = NULL;
348         }
349 #ifndef DP_FREETYPE_STATIC
350         Sys_FreeLibrary (&ft2_dll);
351 #endif
352         pp.buf = NULL;
353 }
354
355 /*
356 ====================
357 Font_OpenLibrary
358
359 Try to load the FreeType2 DLL
360 ====================
361 */
362 qbool Font_OpenLibrary (void)
363 {
364 #ifndef DP_FREETYPE_STATIC
365         const char* dllnames [] =
366         {
367 #if defined(WIN32)
368                 "libfreetype-6.dll",
369                 "freetype6.dll",
370 #elif defined(MACOSX)
371                 "libfreetype.6.dylib",
372                 "libfreetype.dylib",
373 #else
374                 "libfreetype.so.6",
375                 "libfreetype.so",
376 #endif
377                 NULL
378         };
379 #endif
380
381         if (r_font_disable_freetype.integer)
382                 return false;
383
384 #ifndef DP_FREETYPE_STATIC
385         // Already loaded?
386         if (ft2_dll)
387                 return true;
388
389         // Load the DLL
390         if (!Sys_LoadDependency (dllnames, &ft2_dll, ft2funcs))
391                 return false;
392 #endif
393         return true;
394 }
395
396 /*
397 ====================
398 Font_Init
399
400 Initialize the freetype2 font subsystem
401 ====================
402 */
403
404 void font_start(void)
405 {
406         if (!Font_OpenLibrary())
407                 return;
408
409         if (qFT_Init_FreeType(&font_ft2lib))
410         {
411                 Con_Print(CON_ERROR "ERROR: Failed to initialize the FreeType2 library!\n");
412                 Font_CloseLibrary();
413                 return;
414         }
415
416         font_mempool = Mem_AllocPool("FONT", 0, NULL);
417         if (!font_mempool)
418         {
419                 Con_Print(CON_ERROR "ERROR: Failed to allocate FONT memory pool!\n");
420                 Font_CloseLibrary();
421                 return;
422         }
423 }
424
425 void font_shutdown(void)
426 {
427         int i;
428         for (i = 0; i < dp_fonts.maxsize; ++i)
429         {
430                 if (dp_fonts.f[i].ft2)
431                 {
432                         Font_UnloadFont(dp_fonts.f[i].ft2);
433                         dp_fonts.f[i].ft2 = NULL;
434                 }
435         }
436         Font_CloseLibrary();
437 }
438
439 void font_newmap(void)
440 {
441 }
442
443 void Font_Init(void)
444 {
445         Cvar_RegisterVariable(&r_font_nonpoweroftwo);
446         Cvar_RegisterVariable(&r_font_disable_freetype);
447         Cvar_RegisterVariable(&r_font_size_snapping);
448         Cvar_RegisterVariable(&r_font_kerning);
449         Cvar_RegisterVariable(&r_font_diskcache);
450         Cvar_RegisterVariable(&r_font_compress);
451         Cvar_RegisterVariable(&developer_font);
452
453         Cvar_RegisterVariable(&r_font_disable_incmaps);
454
455         // let's open it at startup already
456         Font_OpenLibrary();
457 }
458
459 /*
460 ================================================================================
461 Implementation of a more or less lazy font loading and rendering code.
462 ================================================================================
463 */
464
465 #include "ft2_fontdefs.h"
466
467 ft2_font_t *Font_Alloc(void)
468 {
469 #ifndef DP_FREETYPE_STATIC
470         if (!ft2_dll)
471 #else
472         if (r_font_disable_freetype.integer)
473 #endif
474                 return NULL;
475         return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
476 }
477
478 static qbool Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
479 {
480         ft2_attachment_t *na;
481
482         font->attachmentcount++;
483         na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
484         if (na == NULL)
485                 return false;
486         if (font->attachments && font->attachmentcount > 1)
487         {
488                 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
489                 Mem_Free(font->attachments);
490         }
491         memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
492         font->attachments = na;
493         return true;
494 }
495
496 float Font_VirtualToRealSize(float sz)
497 {
498         int vh;
499         //int vw;
500         int si;
501         float sn;
502         if(sz < 0)
503                 return sz;
504         //vw = ((vid.width > 0) ? vid.width : vid_width.value);
505         vh = ((vid.mode.height > 0) ? vid.mode.height : vid_height.value);
506         // now try to scale to our actual size:
507         sn = sz * vh / vid_conheight.value;
508         si = (int)sn;
509         if ( sn - (float)si >= 0.5 )
510                 ++si;
511         return si;
512 }
513
514 float Font_SnapTo(float val, float snapwidth)
515 {
516         return floor(val / snapwidth + 0.5f) * snapwidth;
517 }
518
519 static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
520 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only);
521 qbool Font_LoadFont(const char *name, dp_font_t *dpfnt)
522 {
523         int s, count, i;
524         ft2_font_t *ft2, *fbfont, *fb;
525         char vabuf[1024];
526
527         ft2 = Font_Alloc();
528         if (!ft2)
529         {
530                 dpfnt->ft2 = NULL;
531                 return false;
532         }
533
534         // check if a fallback font has been specified, if it has been, and the
535         // font fails to load, use the image font as main font
536         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
537         {
538                 if (dpfnt->fallbacks[i][0])
539                         break;
540         }
541
542         if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
543         {
544                 if (i >= MAX_FONT_FALLBACKS)
545                 {
546                         dpfnt->ft2 = NULL;
547                         Mem_Free(ft2);
548                         return false;
549                 }
550                 dp_strlcpy(ft2->name, name, sizeof(ft2->name));
551                 ft2->image_font = true;
552                 ft2->has_kerning = false;
553         }
554         else
555         {
556                 ft2->image_font = false;
557         }
558
559         // attempt to load fallback fonts:
560         fbfont = ft2;
561         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
562         {
563                 if (!dpfnt->fallbacks[i][0])
564                         break;
565                 if (! (fb = Font_Alloc()) )
566                 {
567                         Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
568                         break;
569                 }
570
571                 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
572                 {
573                         if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i])))
574                         if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i])))
575                         if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i])))
576                         if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i])))
577                                 Con_Printf(CON_ERROR "Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
578                         Mem_Free(fb);
579                         continue;
580                 }
581                 count = 0;
582                 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
583                 {
584                         if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
585                                 ++count;
586                 }
587                 if (!count)
588                 {
589                         Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
590                         Font_UnloadFont(fb);
591                         Mem_Free(fb);
592                         break;
593                 }
594                 // at least one size of the fallback font loaded successfully
595                 // link it:
596                 fbfont->next = fb;
597                 fbfont = fb;
598         }
599
600         if (fbfont == ft2 && ft2->image_font)
601         {
602                 // no fallbacks were loaded successfully:
603                 dpfnt->ft2 = NULL;
604                 Mem_Free(ft2);
605                 return false;
606         }
607
608         count = 0;
609         for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
610         {
611                 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
612                         ++count;
613         }
614         if (!count)
615         {
616                 // loading failed for every requested size
617                 Font_UnloadFont(ft2);
618                 Mem_Free(ft2);
619                 dpfnt->ft2 = NULL;
620                 return false;
621         }
622
623         //Con_Printf("%i sizes loaded\n", count);
624         dpfnt->ft2 = ft2;
625         return true;
626 }
627
628 static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
629 {
630         size_t namelen;
631         char filename[MAX_QPATH];
632         int status;
633         size_t i;
634         const unsigned char *data;
635         fs_offset_t datasize;
636
637         memset(font, 0, sizeof(*font));
638
639         if (!Font_OpenLibrary())
640         {
641                 if (!r_font_disable_freetype.integer)
642                 {
643                         Con_Printf(CON_WARN "WARNING: can't open load font %s\n"
644                                    "You need the FreeType2 DLL to load font files\n",
645                                    name);
646                 }
647                 return false;
648         }
649
650         font->settings = settings;
651
652         namelen = strlen(name);
653         if (namelen + 5 > sizeof(filename))
654         {
655                 Con_Printf(CON_WARN "WARNING: too long font name. Cannot load this.\n");
656                 return false;
657         }
658
659         // try load direct file
660         memcpy(filename, name, namelen+1);
661         data = fontfilecache_LoadFile(filename, false, &datasize);
662         // try load .ttf
663         if (!data)
664         {
665                 memcpy(filename + namelen, ".ttf", 5);
666                 data = fontfilecache_LoadFile(filename, false, &datasize);
667         }
668         // try load .otf
669         if (!data)
670         {
671                 memcpy(filename + namelen, ".otf", 5);
672                 data = fontfilecache_LoadFile(filename, false, &datasize);
673         }
674         // try load .pfb/afm
675         if (!data)
676         {
677                 ft2_attachment_t afm;
678
679                 memcpy(filename + namelen, ".pfb", 5);
680                 data = fontfilecache_LoadFile(filename, false, &datasize);
681
682                 if (data)
683                 {
684                         memcpy(filename + namelen, ".afm", 5);
685                         afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
686
687                         if (afm.data)
688                                 Font_Attach(font, &afm);
689                 }
690         }
691         if (!data)
692         {
693                 // FS_LoadFile being not-quiet should print an error :)
694                 return false;
695         }
696         Con_DPrintf("Loading font %s face %i...\n", filename, _face);
697
698         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
699         if (status && _face != 0)
700         {
701                 Con_Printf(CON_ERROR "Failed to load face %i of %s. Falling back to face 0\n", _face, name);
702                 _face = 0;
703                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
704         }
705         font->data = data;
706         if (status)
707         {
708                 Con_Printf(CON_ERROR "ERROR: can't create face for %s\n"
709                            "Error %i\n", // TODO: error strings
710                            name, status);
711                 Font_UnloadFont(font);
712                 return false;
713         }
714
715         // add the attachments
716         for (i = 0; i < font->attachmentcount; ++i)
717         {
718                 FT_Open_Args args;
719                 memset(&args, 0, sizeof(args));
720                 args.flags = FT_OPEN_MEMORY;
721                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
722                 args.memory_size = font->attachments[i].size;
723                 if (qFT_Attach_Stream((FT_Face)font->face, &args))
724                         Con_Printf(CON_ERROR "Failed to add attachment %u to %s\n", (unsigned)i, font->name);
725         }
726
727         dp_strlcpy(font->name, name, sizeof(font->name));
728         font->image_font = false;
729         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
730         return true;
731 }
732
733 static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
734 {
735         int needed, x, y;
736         float gausstable[2*POSTPROCESS_MAXRADIUS+1];
737         qbool need_gauss  = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
738         qbool need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
739         pp.blur = fnt->settings->blur;
740         pp.outline = fnt->settings->outline;
741         pp.shadowx = fnt->settings->shadowx;
742         pp.shadowy = fnt->settings->shadowy;
743         pp.shadowz = fnt->settings->shadowz;
744         pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
745         pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
746         pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
747         pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
748         pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
749         pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
750         pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
751         pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
752         pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
753         pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
754         if(need_gauss)
755         {
756                 float sum = 0;
757                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
758                         gausstable[POSTPROCESS_MAXRADIUS+x] = (pp.blur > 0 ? exp(-(pow(x + pp.shadowz, 2))/(pp.blur*pp.blur * 2)) : (floor(x + pp.shadowz + 0.5) == 0));
759                 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
760                         sum += gausstable[POSTPROCESS_MAXRADIUS+x];
761                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
762                         pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
763         }
764         if(need_circle)
765         {
766                 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
767                         for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
768                         {
769                                 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
770                                 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
771                         }
772         }
773         pp.bufwidth = w + pp.padding_l + pp.padding_r;
774         pp.bufheight = h + pp.padding_t + pp.padding_b;
775         pp.bufpitch = pp.bufwidth;
776         needed = pp.bufwidth * pp.bufheight;
777         if(!pp.buf || pp.bufsize < needed * 2)
778         {
779                 if(pp.buf)
780                         Mem_Free(pp.buf);
781                 pp.bufsize = needed * 4;
782                 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
783                 pp.buf2 = pp.buf + needed;
784         }
785 }
786
787 static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b)
788 {
789         int x, y;
790
791         // calculate gauss table
792         Font_Postprocess_Update(fnt, bpp, w, h);
793
794         if(imagedata)
795         {
796                 // enlarge buffer
797                 // perform operation, not exceeding the passed padding values,
798                 // but possibly reducing them
799                 *pad_l = min(*pad_l, pp.padding_l);
800                 *pad_r = min(*pad_r, pp.padding_r);
801                 *pad_t = min(*pad_t, pp.padding_t);
802                 *pad_b = min(*pad_b, pp.padding_b);
803
804                 // outline the font (RGBA only)
805                 if(bpp == 4 && (pp.outline > 0 || pp.blur > 0 || pp.shadowx != 0 || pp.shadowy != 0 || pp.shadowz != 0)) // we can only do this in BGRA
806                 {
807                         // this is like mplayer subtitle rendering
808                         // bbuffer, bitmap buffer: this is our font
809                         // abuffer, alpha buffer: this is pp.buf
810                         // tmp: this is pp.buf2
811
812                         // create outline buffer
813                         memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
814                         for(y = -*pad_t; y < h + *pad_b; ++y)
815                                 for(x = -*pad_l; x < w + *pad_r; ++x)
816                                 {
817                                         int x1 = max(-x, -pp.outlinepadding_r);
818                                         int y1 = max(-y, -pp.outlinepadding_b);
819                                         int x2 = min(pp.outlinepadding_l, w-1-x);
820                                         int y2 = min(pp.outlinepadding_t, h-1-y);
821                                         int mx, my;
822                                         int cur = 0;
823                                         int highest = 0;
824                                         for(my = y1; my <= y2; ++my)
825                                                 for(mx = x1; mx <= x2; ++mx)
826                                                 {
827                                                         cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
828                                                         if(cur > highest)
829                                                                 highest = cur;
830                                                 }
831                                         pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
832                                 }
833
834                         // blur the outline buffer
835                         if(pp.blur > 0 || pp.shadowz != 0)
836                         {
837                                 // horizontal blur
838                                 for(y = 0; y < pp.bufheight; ++y)
839                                         for(x = 0; x < pp.bufwidth; ++x)
840                                         {
841                                                 int x1 = max(-x, -pp.blurpadding_rb);
842                                                 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
843                                                 int mx;
844                                                 int blurred = 0;
845                                                 for(mx = x1; mx <= x2; ++mx)
846                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
847                                                 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
848                                         }
849
850                                 // vertical blur
851                                 for(y = 0; y < pp.bufheight; ++y)
852                                         for(x = 0; x < pp.bufwidth; ++x)
853                                         {
854                                                 int y1 = max(-y, -pp.blurpadding_rb);
855                                                 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
856                                                 int my;
857                                                 int blurred = 0;
858                                                 for(my = y1; my <= y2; ++my)
859                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
860                                                 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
861                                         }
862                         }
863
864                         // paste the outline below the font
865                         for(y = -*pad_t; y < h + *pad_b; ++y)
866                                 for(x = -*pad_l; x < w + *pad_r; ++x)
867                                 {
868                                         unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
869                                         if(outlinealpha > 0)
870                                         {
871                                                 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
872                                                 // a' = 1 - (1 - a1) (1 - a2)
873                                                 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
874                                                 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
875                                                 unsigned char oldfactor     = (255 * (int)oldalpha) / newalpha;
876                                                 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
877                                                 int i;
878                                                 for(i = 0; i < bpp-1; ++i)
879                                                 {
880                                                         unsigned char c = imagedata[x * bpp + pitch * y + i];
881                                                         c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
882                                                         imagedata[x * bpp + pitch * y + i] = c;
883                                                 }
884                                                 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
885                                         }
886                                         //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
887                                 }
888                 }
889         }
890         else if(pitch)
891         {
892                 // perform operation, not exceeding the passed padding values,
893                 // but possibly reducing them
894                 *pad_l = min(*pad_l, pp.padding_l);
895                 *pad_r = min(*pad_r, pp.padding_r);
896                 *pad_t = min(*pad_t, pp.padding_t);
897                 *pad_b = min(*pad_b, pp.padding_b);
898         }
899         else
900         {
901                 // just calculate parameters
902                 *pad_l = pp.padding_l;
903                 *pad_r = pp.padding_r;
904                 *pad_t = pp.padding_t;
905                 *pad_b = pp.padding_b;
906         }
907 }
908
909 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
910 static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap, int *outmapch, qbool incmap_ok);
911 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only)
912 {
913         int map_index;
914         ft2_font_map_t *fmap, temp;
915         int gpad_l, gpad_r, gpad_t, gpad_b;
916
917         if (!(size > 0.001f && size < 1000.0f))
918                 size = 0;
919
920         if (!size)
921                 size = 16;
922         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
923                 return false;
924
925         for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
926         {
927                 if (!font->font_maps[map_index])
928                         break;
929                 // if a similar size has already been loaded, ignore this one
930                 //abs(font->font_maps[map_index]->size - size) < 4
931                 if (font->font_maps[map_index]->size == size)
932                         return true;
933         }
934
935         if (map_index >= MAX_FONT_SIZES)
936                 return false;
937
938         if (check_only) {
939                 FT_Face fontface;
940                 if (font->image_font)
941                         fontface = (FT_Face)font->next->face;
942                 else
943                         fontface = (FT_Face)font->face;
944                 return (Font_SearchSize(font, fontface, size) > 0);
945         }
946
947         Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
948
949         memset(&temp, 0, sizeof(temp));
950         temp.size = size;
951         temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
952         if (!r_font_nonpoweroftwo.integer)
953                 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
954         temp.sfx = (1.0/64.0)/(double)size;
955         temp.sfy = (1.0/64.0)/(double)size;
956         temp.intSize = -1; // negative value: LoadMap must search now :)
957         if (!Font_LoadMap(font, &temp, 0, &fmap, NULL, false))
958         {
959                 Con_Printf(CON_ERROR "ERROR: can't load the first character map for %s\n"
960                            "This is fatal\n",
961                            font->name);
962                 Font_UnloadFont(font);
963                 return false;
964         }
965         font->font_maps[map_index] = temp.next;
966
967         fmap->sfx = temp.sfx;
968         fmap->sfy = temp.sfy;
969
970         // load the default kerning vector:
971         if (font->has_kerning)
972         {
973                 Uchar l, r;
974                 FT_Vector kernvec;
975                 fmap->kerning = (ft2_kerning_t *)Mem_Alloc(font_mempool, sizeof(ft2_kerning_t));
976                 for (l = 0; l < 256; ++l)
977                 {
978                         for (r = 0; r < 256; ++r)
979                         {
980                                 FT_ULong ul, ur;
981                                 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
982                                 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
983                                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
984                                 {
985                                         fmap->kerning->kerning[l][r][0] = 0;
986                                         fmap->kerning->kerning[l][r][1] = 0;
987                                 }
988                                 else
989                                 {
990                                         fmap->kerning->kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
991                                         fmap->kerning->kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
992                                 }
993                         }
994                 }
995         }
996         return true;
997 }
998
999 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
1000 {
1001         int match = -1;
1002         float value = 1000000;
1003         float nval;
1004         int matchsize = -10000;
1005         int m;
1006         float fsize_x, fsize_y;
1007         ft2_font_map_t **maps = font->font_maps;
1008
1009         fsize_x = fsize_y = _fsize * vid.mode.height / vid_conheight.value;
1010         if(outw && *outw)
1011                 fsize_x = *outw * vid.mode.width / vid_conwidth.value;
1012         if(outh && *outh)
1013                 fsize_y = *outh * vid.mode.height / vid_conheight.value;
1014
1015         if (fsize_x < 0)
1016         {
1017                 if(fsize_y < 0)
1018                         fsize_x = fsize_y = 16;
1019                 else
1020                         fsize_x = fsize_y;
1021         }
1022         else
1023         {
1024                 if(fsize_y < 0)
1025                         fsize_y = fsize_x;
1026         }
1027
1028         for (m = 0; m < MAX_FONT_SIZES; ++m)
1029         {
1030                 if (!maps[m])
1031                         continue;
1032                 // "round up" to the bigger size if two equally-valued matches exist
1033                 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1034                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1035                 {
1036                         value = nval;
1037                         match = m;
1038                         matchsize = maps[m]->size;
1039                         if (value == 0) // there is no better match
1040                                 break;
1041                 }
1042         }
1043         if (value <= r_font_size_snapping.value)
1044         {
1045                 // do NOT keep the aspect for perfect rendering
1046                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.mode.height;
1047                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.mode.width;
1048         }
1049         return match;
1050 }
1051
1052 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1053 {
1054         if (index < 0 || index >= MAX_FONT_SIZES)
1055                 return NULL;
1056         return font->font_maps[index];
1057 }
1058
1059 static qbool Font_SetSize(ft2_font_t *font, float w, float h)
1060 {
1061         if (font->currenth == h &&
1062             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1063              font->currentw == w)) // same size has been requested
1064         {
1065                 return true;
1066         }
1067         // sorry, but freetype doesn't seem to care about other sizes
1068         w = (int)w;
1069         h = (int)h;
1070         if (font->image_font)
1071         {
1072                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1073                         return false;
1074         }
1075         else
1076         {
1077                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1078                         return false;
1079         }
1080         font->currentw = w;
1081         font->currenth = h;
1082         return true;
1083 }
1084
1085 qbool Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1086 {
1087         ft2_font_map_t *fmap;
1088         if (!font->has_kerning || !r_font_kerning.integer)
1089                 return false;
1090         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1091                 return false;
1092         fmap = font->font_maps[map_index];
1093         if (!fmap)
1094                 return false;
1095         if (left < 256 && right < 256)
1096         {
1097                 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1098                 // quick-kerning, be aware of the size: scale it
1099                 if (outx) *outx = fmap->kerning->kerning[left][right][0];// * (w / (float)fmap->size);
1100                 if (outy) *outy = fmap->kerning->kerning[left][right][1];// * (h / (float)fmap->size);
1101                 return true;
1102         }
1103         else
1104         {
1105                 FT_Vector kernvec;
1106                 FT_ULong ul, ur;
1107
1108                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1109 #if 0
1110                 if (!Font_SetSize(font, w, h))
1111                 {
1112                         // this deserves an error message
1113                         Con_Printf("Failed to get kerning for %s\n", font->name);
1114                         return false;
1115                 }
1116                 ul = qFT_Get_Char_Index(font->face, left);
1117                 ur = qFT_Get_Char_Index(font->face, right);
1118                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1119                 {
1120                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1121                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1122                         return true;
1123                 }
1124 #endif
1125                 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1126                 {
1127                         // this deserves an error message
1128                         Con_Printf(CON_ERROR "Failed to get kerning for %s\n", font->name);
1129                         return false;
1130                 }
1131                 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1132                 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1133                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1134                 {
1135                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1136                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1137                         return true;
1138                 }
1139                 return false;
1140         }
1141 }
1142
1143 qbool Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1144 {
1145         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1146 }
1147
1148 // this is used to gracefully unload a map chain; the passed map
1149 // needs not necessarily be a startmap, so maps ahead of it can be kept
1150 static void UnloadMapChain(ft2_font_map_t *map)
1151 {
1152         int i;
1153         ft2_font_map_t *nextmap;
1154         // these may only be in a startmap
1155         if (map->kerning != NULL)
1156                 Mem_Free(map->kerning);
1157         if (map->incmap != NULL)
1158         {
1159                 for (i = 0; i < FONT_CHARS_PER_LINE; ++i)
1160                         if (map->incmap->data_tier1[i] != NULL)
1161                                 Mem_Free(map->incmap->data_tier1[i]);
1162                         else
1163                                 break;
1164                 for (i = 0; i < FONT_CHAR_LINES; ++i)
1165                         if (map->incmap->data_tier2[i] != NULL)
1166                                 Mem_Free(map->incmap->data_tier2[i]);
1167                         else
1168                                 break;
1169                 Mem_Free(map->incmap);
1170         }
1171         while (map != NULL)
1172         {
1173                 if (map->pic)
1174                 {
1175                         //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1176                         map->pic = NULL;
1177                 }
1178                 nextmap = map->next;
1179                 Mem_Free(map);
1180                 map = nextmap;
1181         }
1182 }
1183
1184 void Font_UnloadFont(ft2_font_t *font)
1185 {
1186         int i;
1187
1188         // unload fallbacks
1189         if(font->next)
1190                 Font_UnloadFont(font->next);
1191
1192         if (font->attachments && font->attachmentcount)
1193         {
1194                 for (i = 0; i < (int)font->attachmentcount; ++i) {
1195                         if (font->attachments[i].data)
1196                                 fontfilecache_Free(font->attachments[i].data);
1197                 }
1198                 Mem_Free(font->attachments);
1199                 font->attachmentcount = 0;
1200                 font->attachments = NULL;
1201         }
1202         for (i = 0; i < MAX_FONT_SIZES; ++i)
1203         {
1204                 if (font->font_maps[i])
1205                 {
1206                         UnloadMapChain(font->font_maps[i]);
1207                         font->font_maps[i] = NULL;
1208                 }
1209         }
1210 #ifndef DP_FREETYPE_STATIC
1211         if (ft2_dll)
1212 #else
1213         if (!r_font_disable_freetype.integer)
1214 #endif
1215         {
1216                 if (font->face)
1217                 {
1218                         qFT_Done_Face((FT_Face)font->face);
1219                         font->face = NULL;
1220                 }
1221         }
1222         if (font->data) {
1223             fontfilecache_Free(font->data);
1224             font->data = NULL;
1225         }
1226 }
1227
1228 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1229 {
1230         float intSize = size;
1231         while (1)
1232         {
1233                 if (!Font_SetSize(font, intSize, intSize))
1234                 {
1235                         Con_Printf(CON_ERROR "ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1236                         return -1;
1237                 }
1238                 if ((fontface->size->metrics.height>>6) <= size)
1239                         return intSize;
1240                 if (intSize < 2)
1241                 {
1242                         Con_Printf(CON_ERROR "ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1243                         return -1;
1244                 }
1245                 --intSize;
1246         }
1247 }
1248
1249 // helper inline functions for incmap_post_process:
1250
1251 static inline void update_pic_for_fontmap(ft2_font_map_t *fontmap, const char *identifier,
1252                 int width, int height, unsigned char *data)
1253 {
1254         fontmap->pic = Draw_NewPic(identifier, width, height, data, TEXTYPE_RGBA,
1255                 TEXF_ALPHA | TEXF_CLAMP | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0));
1256 }
1257
1258 // glyphs' texture coords needs to be fixed when merging to bigger texture
1259 static inline void transform_glyph_coords(glyph_slot_t *glyph, float shiftx, float shifty, float scalex, float scaley)
1260 {
1261         glyph->txmin = glyph->txmin * scalex + shiftx;
1262         glyph->txmax = glyph->txmax * scalex + shiftx;
1263         glyph->tymin = glyph->tymin * scaley + shifty;
1264         glyph->tymax = glyph->tymax * scaley + shifty;
1265 }
1266 #define fix_glyph_coords_tier1(glyph, order) transform_glyph_coords(glyph, order / (float)FONT_CHARS_PER_LINE, 0.0f, 1.0f / (float)FONT_CHARS_PER_LINE, 1.0f)
1267 #define fix_glyph_coords_tier2(glyph, order) transform_glyph_coords(glyph, 0.0f, order / (float)FONT_CHARS_PER_LINE, 1.0f, 1.0f / (float)FONT_CHARS_PER_LINE)
1268
1269 // pull glyph things from sourcemap to targetmap
1270 static inline void merge_single_map(ft2_font_map_t *targetmap, int targetindex, ft2_font_map_t *sourcemap, int sourceindex)
1271 {
1272         targetmap->glyphs[targetindex] = sourcemap->glyphs[sourceindex];
1273         targetmap->glyphchars[targetindex] = sourcemap->glyphchars[sourceindex];
1274 }
1275
1276 #define calc_data_arguments(w, h)                       \
1277                 width = startmap->glyphSize * w;        \
1278                 height = startmap->glyphSize * h;       \
1279                 pitch = width * bytes_per_pixel;        \
1280                 datasize = height * pitch;
1281
1282 // do incremental map process
1283 static inline void incmap_post_process(font_incmap_t *incmap, Uchar ch,
1284                 unsigned char *data, ft2_font_map_t **outmap, int *outmapch)
1285 {
1286         #define bytes_per_pixel 4
1287
1288         int index, targetmap_at;
1289         // where will the next `data` be placed
1290         int tier1_data_index, tier2_data_index;
1291         // metrics of data to manipulate
1292         int width, height, pitch, datasize;
1293         int i, j, x, y;
1294         unsigned char *newdata, *chunk;
1295         ft2_font_map_t *startmap, *targetmap, *currentmap;
1296         #define M FONT_CHARS_PER_LINE
1297         #define N FONT_CHAR_LINES
1298
1299         startmap = incmap->fontmap;
1300         index = incmap->charcount;
1301         tier1_data_index = index % M;
1302         tier2_data_index = incmap->tier1_merged;
1303
1304         incmap->data_tier1[tier1_data_index] = data;
1305
1306         if (index % M == M - 1)
1307         {
1308                 // tier 1 reduction, pieces to line
1309                 calc_data_arguments(1, 1);
1310                 targetmap_at = incmap->tier2_merged + incmap->tier1_merged;
1311                 targetmap = startmap;
1312                 for (i = 0; i < targetmap_at; ++i)
1313                         targetmap = targetmap->next;
1314                 currentmap = targetmap;
1315                 newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * M);
1316                 for (i = 0; i < M; ++i)
1317                 {
1318                         chunk = incmap->data_tier1[i];
1319                         if (chunk == NULL)
1320                                 continue;
1321                         for (y = 0; y < datasize; y += pitch)
1322                                 for (x = 0; x < pitch; ++x)
1323                                         newdata[y * M + i * pitch + x] = chunk[y + x];
1324                         Mem_Free(chunk);
1325                         incmap->data_tier1[i] = NULL;
1326                         merge_single_map(targetmap, i, currentmap, 0);
1327                         fix_glyph_coords_tier1(&targetmap->glyphs[i], (float)i);
1328                         currentmap = currentmap->next;
1329                 }
1330                 update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width * M, height, newdata);
1331                 UnloadMapChain(targetmap->next);
1332                 targetmap->next = NULL;
1333                 incmap->data_tier2[tier2_data_index] = newdata;
1334                 ++incmap->tier1_merged;
1335                 incmap->tier1_merged %= M;
1336                 incmap->newmap_start = INCMAP_START + targetmap_at + 1;
1337                 // then give this merged map
1338                 *outmap = targetmap;
1339                 *outmapch = FONT_CHARS_PER_LINE - 1;
1340         }
1341         if (index % (M * N) == M * N - 1)
1342         {
1343                 // tier 2 reduction, lines to full map
1344                 calc_data_arguments(M, 1);
1345                 targetmap_at = incmap->tier2_merged;
1346                 targetmap = startmap;
1347                 for (i = 0; i < targetmap_at; ++i)
1348                         targetmap = targetmap->next;
1349                 currentmap = targetmap;
1350                 newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * N);
1351                 for (i = 0; i < N; ++i)
1352                 {
1353                         chunk = incmap->data_tier2[i];
1354                         if (chunk == NULL)
1355                                 continue;
1356                         for (x = 0; x < datasize; ++x)
1357                                 newdata[i * datasize + x] = chunk[x];
1358                         Mem_Free(chunk);
1359                         incmap->data_tier2[i] = NULL;
1360                         for (j = 0; j < M; ++j)
1361                         {
1362                                 merge_single_map(targetmap, i * M + j, currentmap, j);
1363                                 fix_glyph_coords_tier2(&targetmap->glyphs[i * M + j], (float)i);
1364                         }
1365                         currentmap = currentmap->next;
1366                 }
1367                 update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width, height * N, newdata);
1368                 UnloadMapChain(targetmap->next);
1369                 targetmap->next = NULL;
1370                 Mem_Free(newdata);
1371                 ++incmap->tier2_merged;
1372                 incmap->newmap_start = INCMAP_START + targetmap_at + 1;
1373                 // then give this merged map
1374                 *outmap = targetmap;
1375                 *outmapch = FONT_CHARS_PER_MAP - 1;
1376         }
1377
1378         ++incmap->charcount;
1379         ++incmap->newmap_start;
1380
1381         #undef M
1382         #undef N
1383 }
1384
1385 static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch,
1386                 ft2_font_map_t **outmap, int *outmapch, qbool use_incmap)
1387 {
1388         #define bytes_per_pixel 4
1389
1390         char map_identifier[MAX_QPATH];
1391         unsigned long map_startglyph = _ch / FONT_CHARS_PER_MAP * FONT_CHARS_PER_MAP;
1392         unsigned char *data = NULL;
1393         FT_ULong ch = 0, mapch = 0;
1394         int status;
1395         int tp;
1396         FT_Int32 load_flags;
1397         int gpad_l, gpad_r, gpad_t, gpad_b;
1398
1399         int pitch;
1400         int width, height, datasize;
1401         int glyph_row, glyph_column;
1402
1403         int chars_per_line = FONT_CHARS_PER_LINE;
1404         int char_lines = FONT_CHAR_LINES;
1405         int chars_per_map = FONT_CHARS_PER_MAP;
1406
1407         ft2_font_t *usefont;
1408         ft2_font_map_t *map, *next;
1409         font_incmap_t *incmap;
1410
1411         FT_Face fontface;
1412
1413         incmap = mapstart->incmap;
1414         if (use_incmap)
1415         {
1416                 // only render one character in this map;
1417                 // such small maps will be merged together later in `incmap_post_process`
1418                 chars_per_line = char_lines = chars_per_map = 1;
1419                 // and the index is incremental
1420                 map_startglyph = incmap ? incmap->newmap_start : INCMAP_START;
1421         }
1422
1423         if (font->image_font)
1424                 fontface = (FT_Face)font->next->face;
1425         else
1426                 fontface = (FT_Face)font->face;
1427
1428         switch(font->settings->antialias)
1429         {
1430                 case 0:
1431                         switch(font->settings->hinting)
1432                         {
1433                                 case 0:
1434                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1435                                         break;
1436                                 case 1:
1437                                 case 2:
1438                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1439                                         break;
1440                                 default:
1441                                 case 3:
1442                                         load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1443                                         break;
1444                         }
1445                         break;
1446                 default:
1447                 case 1:
1448                         switch(font->settings->hinting)
1449                         {
1450                                 case 0:
1451                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1452                                         break;
1453                                 case 1:
1454                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1455                                         break;
1456                                 case 2:
1457                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1458                                         break;
1459                                 default:
1460                                 case 3:
1461                                         load_flags = FT_LOAD_TARGET_NORMAL;
1462                                         break;
1463                         }
1464                         break;
1465         }
1466
1467         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1468         //if (status)
1469         if (font->image_font && mapstart->intSize < 0)
1470                 mapstart->intSize = mapstart->size;
1471         if (mapstart->intSize < 0)
1472         {
1473                 /*
1474                 mapstart->intSize = mapstart->size;
1475                 while (1)
1476                 {
1477                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1478                         {
1479                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1480                                 return false;
1481                         }
1482                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
1483                                 break;
1484                         if (mapstart->intSize < 2)
1485                         {
1486                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1487                                 return false;
1488                         }
1489                         --mapstart->intSize;
1490                 }
1491                 */
1492                 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1493                         return false;
1494                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1495         }
1496
1497         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1498         {
1499                 Con_Printf(CON_ERROR "ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1500                 return false;
1501         }
1502
1503         map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1504         if (!map)
1505         {
1506                 Con_Printf(CON_ERROR "ERROR: Out of memory when allocating fontmap for %s\n", font->name);
1507                 return false;
1508         }
1509
1510         map->start = map_startglyph;
1511
1512         // create a unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1513         /*
1514         dpsnprintf(map_identifier, sizeof(map_identifier),
1515                 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u_%lx",
1516                 font->name,
1517                 (double) mapstart->intSize,
1518                 (int) load_flags,
1519                 (double) font->settings->blur,
1520                 (double) font->settings->outline,
1521                 (double) font->settings->shadowx,
1522                 (double) font->settings->shadowy,
1523                 (double) font->settings->shadowz,
1524                 (unsigned) map_startglyph,
1525                 // add pointer as a unique part to avoid earlier incmaps' state being trashed
1526                 use_incmap ? (unsigned long)mapstart : 0x0);
1527         */
1528         /*
1529          * note 1: it appears that different font instances may have the same metrics, causing this pic being overwritten
1530          *         will use startmap's pointer as a unique part to avoid earlier incmaps' dynamic pics being trashed
1531          * note 2: if this identifier is made too long, significient performance drop will take place
1532          * note 3: blur/outline/shadow are per-font settings, so a pointer to startmap & map size
1533          *         already made these unique, hence they are omitted
1534          * note 4: font_diskcache is removed, this name can be less meaningful
1535          */
1536         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%g_%p_%u",
1537                         font->name, mapstart->intSize, mapstart, (unsigned) map_startglyph);
1538
1539         // create a cachepic_t from the data now, or reuse an existing one
1540         if (developer_font.integer)
1541                 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1542
1543         Font_Postprocess(font, NULL, 0, bytes_per_pixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1544
1545         // copy over the information
1546         map->size = mapstart->size;
1547         map->intSize = mapstart->intSize;
1548         map->glyphSize = mapstart->glyphSize;
1549         map->sfx = mapstart->sfx;
1550         map->sfy = mapstart->sfy;
1551
1552         width = map->glyphSize * chars_per_line;
1553         height = map->glyphSize * char_lines;
1554         pitch = width * bytes_per_pixel;
1555         datasize = height * pitch;
1556         data = (unsigned char *)Mem_Alloc(font_mempool, datasize);
1557         if (!data)
1558         {
1559                 Con_Printf(CON_ERROR "ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1560                 Mem_Free(map);
1561                 return false;
1562         }
1563
1564         if (use_incmap)
1565         {
1566                 if (mapstart->incmap == NULL)
1567                 {
1568                         // initial incmap
1569                         incmap = mapstart->incmap = (font_incmap_t *)Mem_Alloc(font_mempool, sizeof(font_incmap_t));
1570                         if (!incmap)
1571                         {
1572                                 Con_Printf(CON_ERROR "ERROR: Out of memory when allocating incremental fontmap for %s\n", font->name);
1573                                 return false;
1574                         }
1575                         // this will be the startmap of incmap
1576                         incmap->fontmap = map;
1577                         incmap->newmap_start = INCMAP_START;
1578                 }
1579                 else
1580                 {
1581                         // new maps for incmap shall always be the last one
1582                         next = incmap->fontmap;
1583                         while (next->next != NULL)
1584                                 next = next->next;
1585                         next->next = map;
1586                 }
1587         }
1588         else
1589         {
1590                 // insert this normal map
1591                 next = use_incmap ? incmap->fontmap : mapstart;
1592                 while(next->next && next->next->start < map->start)
1593                         next = next->next;
1594                 map->next = next->next;
1595                 next->next = map;
1596         }
1597
1598         // initialize as white texture with zero alpha
1599         tp = 0;
1600         while (tp < datasize)
1601         {
1602                 if (bytes_per_pixel == 4)
1603                 {
1604                         data[tp++] = 0xFF;
1605                         data[tp++] = 0xFF;
1606                         data[tp++] = 0xFF;
1607                 }
1608                 data[tp++] = 0x00;
1609         }
1610
1611         glyph_row = 0;
1612         glyph_column = 0;
1613         ch = (FT_ULong)(use_incmap ? _ch : map->start);
1614         mapch = 0;
1615         while (true)
1616         {
1617                 FT_ULong glyphIndex;
1618                 int w, h, x, y;
1619                 FT_GlyphSlot glyph;
1620                 FT_Bitmap *bmp;
1621                 unsigned char *imagedata = NULL, *dst, *src;
1622                 glyph_slot_t *mapglyph;
1623                 FT_Face face;
1624                 int pad_l, pad_r, pad_t, pad_b;
1625
1626                 if (developer_font.integer)
1627                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1628
1629                 map->glyphchars[mapch] = (Uchar)ch;
1630
1631                 if (data)
1632                 {
1633                         imagedata = data + glyph_row * pitch * map->glyphSize + glyph_column * map->glyphSize * bytes_per_pixel;
1634                         imagedata += gpad_t * pitch + gpad_l * bytes_per_pixel;
1635                 }
1636                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1637                 // we need the glyphIndex
1638                 face = (FT_Face)font->face;
1639                 usefont = NULL;
1640                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1641                 {
1642                         map->glyphs[mapch].image = true;
1643                         continue;
1644                 }
1645                 glyphIndex = qFT_Get_Char_Index(face, ch);
1646                 if (glyphIndex == 0)
1647                 {
1648                         // by convention, 0 is the "missing-glyph"-glyph
1649                         // try to load from a fallback font
1650                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1651                         {
1652                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1653                                         continue;
1654                                 // try that glyph
1655                                 face = (FT_Face)usefont->face;
1656                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1657                                 if (glyphIndex == 0)
1658                                         continue;
1659                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1660                                 if (status)
1661                                         continue;
1662                                 break;
1663                         }
1664                         if (!usefont)
1665                         {
1666                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1667                                 // now we let it use the "missing-glyph"-glyph
1668                                 face = (FT_Face)font->face;
1669                                 glyphIndex = 0;
1670                         }
1671                 }
1672
1673                 if (!usefont)
1674                 {
1675                         usefont = font;
1676                         face = (FT_Face)font->face;
1677                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1678                         if (status)
1679                         {
1680                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1681                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1682                                 continue;
1683                         }
1684                 }
1685
1686                 glyph = face->glyph;
1687                 bmp = &glyph->bitmap;
1688
1689                 w = bmp->width;
1690                 h = bmp->rows;
1691
1692                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1693                         Con_Printf(CON_WARN "WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1694                         if (w > map->glyphSize)
1695                                 w = map->glyphSize - gpad_l - gpad_r;
1696                         if (h > map->glyphSize)
1697                                 h = map->glyphSize;
1698                 }
1699
1700                 if (imagedata)
1701                 {
1702                         switch (bmp->pixel_mode)
1703                         {
1704                         case FT_PIXEL_MODE_MONO:
1705                                 if (developer_font.integer)
1706                                         Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1707                                 break;
1708                         case FT_PIXEL_MODE_GRAY2:
1709                                 if (developer_font.integer)
1710                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1711                                 break;
1712                         case FT_PIXEL_MODE_GRAY4:
1713                                 if (developer_font.integer)
1714                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1715                                 break;
1716                         case FT_PIXEL_MODE_GRAY:
1717                                 if (developer_font.integer)
1718                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1719                                 break;
1720                         default:
1721                                 if (developer_font.integer)
1722                                         Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1723                                 Mem_Free(data);
1724                                 Con_Printf(CON_ERROR "ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1725                                 return false;
1726                         }
1727                         for (y = 0; y < h; ++y)
1728                         {
1729                                 dst = imagedata + y * pitch;
1730                                 src = bmp->buffer + y * bmp->pitch;
1731
1732                                 switch (bmp->pixel_mode)
1733                                 {
1734                                 case FT_PIXEL_MODE_MONO:
1735                                         dst += bytes_per_pixel - 1; // shift to alpha byte
1736                                         for (x = 0; x < bmp->width; x += 8)
1737                                         {
1738                                                 unsigned char c = *src++;
1739                                                 *dst = 255 * !!((c & 0x80) >> 7); dst += bytes_per_pixel;
1740                                                 *dst = 255 * !!((c & 0x40) >> 6); dst += bytes_per_pixel;
1741                                                 *dst = 255 * !!((c & 0x20) >> 5); dst += bytes_per_pixel;
1742                                                 *dst = 255 * !!((c & 0x10) >> 4); dst += bytes_per_pixel;
1743                                                 *dst = 255 * !!((c & 0x08) >> 3); dst += bytes_per_pixel;
1744                                                 *dst = 255 * !!((c & 0x04) >> 2); dst += bytes_per_pixel;
1745                                                 *dst = 255 * !!((c & 0x02) >> 1); dst += bytes_per_pixel;
1746                                                 *dst = 255 * !!((c & 0x01) >> 0); dst += bytes_per_pixel;
1747                                         }
1748                                         break;
1749                                 case FT_PIXEL_MODE_GRAY2:
1750                                         dst += bytes_per_pixel - 1; // shift to alpha byte
1751                                         for (x = 0; x < bmp->width; x += 4)
1752                                         {
1753                                                 unsigned char c = *src++;
1754                                                 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1755                                                 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1756                                                 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1757                                                 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1758                                         }
1759                                         break;
1760                                 case FT_PIXEL_MODE_GRAY4:
1761                                         dst += bytes_per_pixel - 1; // shift to alpha byte
1762                                         for (x = 0; x < bmp->width; x += 2)
1763                                         {
1764                                                 unsigned char c = *src++;
1765                                                 *dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytes_per_pixel;
1766                                                 *dst = ( ((c & 0x0F) ) * 0x11); dst += bytes_per_pixel;
1767                                         }
1768                                         break;
1769                                 case FT_PIXEL_MODE_GRAY:
1770                                         // in this case pitch should equal width
1771                                         for (tp = 0; tp < bmp->pitch; ++tp)
1772                                                 dst[(bytes_per_pixel - 1) + tp*bytes_per_pixel] = src[tp]; // copy the grey value into the alpha bytes
1773
1774                                         //memcpy((void*)dst, (void*)src, bmp->pitch);
1775                                         //dst += bmp->pitch;
1776                                         break;
1777                                 default:
1778                                         break;
1779                                 }
1780                         }
1781
1782                         pad_l = gpad_l;
1783                         pad_r = gpad_r;
1784                         pad_t = gpad_t;
1785                         pad_b = gpad_b;
1786                         Font_Postprocess(font, imagedata, pitch, bytes_per_pixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1787                 }
1788                 else
1789                 {
1790                         pad_l = gpad_l;
1791                         pad_r = gpad_r;
1792                         pad_t = gpad_t;
1793                         pad_b = gpad_b;
1794                         Font_Postprocess(font, NULL, pitch, bytes_per_pixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1795                 }
1796
1797
1798                 // now fill map->glyphs[ch - map->start]
1799                 mapglyph = &map->glyphs[mapch];
1800
1801                 {
1802                         // old way
1803                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1804
1805                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1806                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1807                         double advance = (glyph->advance.x / 64.0) / map->size;
1808                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1809                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1810
1811                         mapglyph->txmin = ( (double)(glyph_column * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * chars_per_line) );
1812                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * chars_per_line) );
1813                         mapglyph->tymin = ( (double)(glyph_row * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * char_lines) );
1814                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * char_lines) );
1815                         //mapglyph->vxmin = bearingX;
1816                         //mapglyph->vxmax = bearingX + mWidth;
1817                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1818                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1819                         //mapglyph->vymin = -bearingY;
1820                         //mapglyph->vymax = mHeight - bearingY;
1821                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1822                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1823                         //Con_Printf("dpi = %f %f (%f %d) %d %d\n", bmp->width / (mapglyph->vxmax - mapglyph->vxmin), bmp->rows / (mapglyph->vymax - mapglyph->vymin), map->size, map->glyphSize, (int)fontface->size->metrics.x_ppem, (int)fontface->size->metrics.y_ppem);
1824                         //mapglyph->advance_x = advance * usefont->size;
1825                         //mapglyph->advance_x = advance;
1826                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1827                         mapglyph->advance_y = 0;
1828
1829                         if (developer_font.integer)
1830                         {
1831                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, glyph_column, glyph_row);
1832                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1833                                 if (ch >= 32 && ch <= 128)
1834                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1835                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1836                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1837                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1838                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1839                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1840                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1841                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1842                         }
1843                 }
1844                 map->glyphs[mapch].image = false;
1845
1846                 ++mapch; ++ch;
1847                 if ((int)mapch == chars_per_map)
1848                         break;
1849                 if (++glyph_column % chars_per_line == 0)
1850                 {
1851                         glyph_column = 0;
1852                         ++glyph_row;
1853                 }
1854         }
1855
1856         // update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1857         update_pic_for_fontmap(map, map_identifier, width, height, data);
1858
1859         if (!Draw_IsPicLoaded(map->pic))
1860         {
1861                 // if the first try isn't successful, keep it with a broken texture
1862                 // otherwise we retry to load it every single frame where ft2 rendering is used
1863                 // this would be bad...
1864                 // only `data' must be freed
1865                 Con_Printf(CON_ERROR "ERROR: Failed to generate texture for font %s size %f map %lu\n",
1866                            font->name, mapstart->size, map_startglyph);
1867                 return false;
1868         }
1869
1870         if (use_incmap)
1871         {
1872                 *outmap = map;
1873                 *outmapch = 0;
1874                 // data will be kept in incmap for being merged later, freed afterward
1875                 incmap_post_process(incmap, _ch, data, outmap, outmapch);
1876         }
1877         else if (data)
1878         {
1879                 Mem_Free(data);
1880                 *outmap = map;
1881                 if (outmapch != NULL)
1882                         *outmapch = _ch - map->start;
1883         }
1884
1885         return true;
1886 }
1887
1888 static qbool legacy_font_loading_api_alerted = false;
1889 static inline void alert_legacy_font_api(const char *name)
1890 {
1891         if (!legacy_font_loading_api_alerted)
1892         {
1893                 Con_DPrintf(CON_WARN "Warning: You are using an legacy API '%s', which have certain limitations; please use 'Font_GetMapForChar' instead\n", name);
1894                 legacy_font_loading_api_alerted = true;
1895         }
1896 }
1897
1898 // legacy font API, please use `Font_GetMapForChar` instead
1899 qbool Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap)
1900 {
1901         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1902                 return false;
1903         // the first map must have been loaded already
1904         if (!font->font_maps[map_index])
1905                 return false;
1906         alert_legacy_font_api("Font_LoadMapForIndex");
1907         return Font_LoadMap(font, font->font_maps[map_index], ch, outmap, NULL, false);
1908 }
1909
1910 // legacy font API. please use `Font_GetMapForChar` instead
1911 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1912 {
1913         ft2_font_map_t *map = start;
1914         while (map && map->start + FONT_CHARS_PER_MAP <= ch)
1915                 map = map->next;
1916         if (map && map->start > ch)
1917                 return NULL;
1918         alert_legacy_font_api("FontMap_FindForChar");
1919         return map;
1920 }
1921
1922 static inline qbool should_use_incmap(Uchar ch)
1923 {
1924         int i;
1925         // optimize: a simple check logic for usual conditions
1926         if (ch < unicode_bigblocks[0])
1927                 return false;
1928         if (r_font_disable_incmaps.integer == 1)
1929                 return false;
1930         for (i = 0; i < (int)(sizeof(unicode_bigblocks) / sizeof(Uchar)); i += 2)
1931                 if (unicode_bigblocks[i] <= ch && ch <= unicode_bigblocks[i + 1])
1932                         return true;
1933         return false;
1934 }
1935
1936 static inline qbool get_char_from_incmap(ft2_font_map_t *map, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
1937 {
1938         int i;
1939         font_incmap_t *incmap;
1940
1941         incmap = map->incmap;
1942         *outmapch = 0;
1943
1944         if (incmap != NULL)
1945         {
1946                 map = incmap->fontmap;
1947                 while (map != NULL)
1948                 {
1949                         for (i = 0; i < FONT_CHARS_PER_MAP; ++i)
1950                         {
1951                                 if (map->glyphchars[i] == ch)
1952                                 {
1953                                         *outmap = map;
1954                                         *outmapch = i;
1955                                         return true;
1956                                 }
1957                                 else if (map->glyphchars[i] == 0)
1958                                         // this tier0/tier1 map ends here
1959                                         break;
1960                         }
1961                         map = map->next;
1962                 }
1963         }
1964         return false;
1965 }
1966
1967 /**
1968  * Query for or load a font map for a character, with the character's place on it.
1969  * Supports the incremental map mechanism; returning if the operation is done successfully
1970  */
1971 qbool Font_GetMapForChar(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
1972 {
1973         qbool use_incmap;
1974         ft2_font_map_t *map;
1975
1976         // startmap
1977         map = Font_MapForIndex(font, map_index);
1978
1979         // optimize: the first map must have been loaded already
1980         if (ch < FONT_CHARS_PER_MAP)
1981         {
1982                 *outmapch = ch;
1983                 *outmap = map;
1984                 return true;
1985         }
1986
1987         // search for the character
1988
1989         use_incmap = should_use_incmap(ch);
1990
1991         if (!use_incmap)
1992         {
1993                 // normal way
1994                 *outmapch = ch % FONT_CHARS_PER_MAP;
1995                 while (map && map->start + FONT_CHARS_PER_MAP <= ch)
1996                         map = map->next;
1997                 if (map && map->start <= ch)
1998                 {
1999                         *outmap = map;
2000                         return true;
2001                 }
2002         }
2003         else if (get_char_from_incmap(map, ch, outmap, outmapch))
2004                 // got it
2005                 return true;
2006
2007         // so no appropriate map was found, load one
2008
2009         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
2010                 return false;
2011         return Font_LoadMap(font, font->font_maps[map_index], ch, outmap, outmapch, use_incmap);
2012 }