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