]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - ft2.c
if the two mtimes are identical, also use the max interval as it's better to have...
[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 ================================================================================
32 CVars introduced with the freetype extension
33 ================================================================================
34 */
35
36 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
37 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
38 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
39 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
40 cvar_t r_font_diskcache = {CVAR_SAVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"};
41 cvar_t r_font_compress = {CVAR_SAVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
42 cvar_t r_font_nonpoweroftwo = {CVAR_SAVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
43 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
44
45 /*
46 ================================================================================
47 Function definitions. Taken from the freetype2 headers.
48 ================================================================================
49 */
50
51
52 FT_EXPORT( FT_Error )
53 (*qFT_Init_FreeType)( FT_Library  *alibrary );
54 FT_EXPORT( FT_Error )
55 (*qFT_Done_FreeType)( FT_Library  library );
56 /*
57 FT_EXPORT( FT_Error )
58 (*qFT_New_Face)( FT_Library   library,
59                  const char*  filepathname,
60                  FT_Long      face_index,
61                  FT_Face     *aface );
62 */
63 FT_EXPORT( FT_Error )
64 (*qFT_New_Memory_Face)( FT_Library      library,
65                         const FT_Byte*  file_base,
66                         FT_Long         file_size,
67                         FT_Long         face_index,
68                         FT_Face        *aface );
69 FT_EXPORT( FT_Error )
70 (*qFT_Done_Face)( FT_Face  face );
71 FT_EXPORT( FT_Error )
72 (*qFT_Select_Size)( FT_Face  face,
73                     FT_Int   strike_index );
74 FT_EXPORT( FT_Error )
75 (*qFT_Request_Size)( FT_Face          face,
76                      FT_Size_Request  req );
77 FT_EXPORT( FT_Error )
78 (*qFT_Set_Char_Size)( FT_Face     face,
79                       FT_F26Dot6  char_width,
80                       FT_F26Dot6  char_height,
81                       FT_UInt     horz_resolution,
82                       FT_UInt     vert_resolution );
83 FT_EXPORT( FT_Error )
84 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
85                         FT_UInt  pixel_width,
86                         FT_UInt  pixel_height );
87 FT_EXPORT( FT_Error )
88 (*qFT_Load_Glyph)( FT_Face   face,
89                    FT_UInt   glyph_index,
90                    FT_Int32  load_flags );
91 FT_EXPORT( FT_Error )
92 (*qFT_Load_Char)( FT_Face   face,
93                   FT_ULong  char_code,
94                   FT_Int32  load_flags );
95 FT_EXPORT( FT_UInt )
96 (*qFT_Get_Char_Index)( FT_Face   face,
97                        FT_ULong  charcode );
98 FT_EXPORT( FT_Error )
99 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
100                      FT_Render_Mode  render_mode );
101 FT_EXPORT( FT_Error )
102 (*qFT_Get_Kerning)( FT_Face     face,
103                     FT_UInt     left_glyph,
104                     FT_UInt     right_glyph,
105                     FT_UInt     kern_mode,
106                     FT_Vector  *akerning );
107 FT_EXPORT( FT_Error )
108 (*qFT_Attach_Stream)( FT_Face        face,
109                       FT_Open_Args*  parameters );
110 /*
111 ================================================================================
112 Support for dynamically loading the FreeType2 library
113 ================================================================================
114 */
115
116 static dllfunction_t ft2funcs[] =
117 {
118         {"FT_Init_FreeType",            (void **) &qFT_Init_FreeType},
119         {"FT_Done_FreeType",            (void **) &qFT_Done_FreeType},
120         //{"FT_New_Face",                       (void **) &qFT_New_Face},
121         {"FT_New_Memory_Face",          (void **) &qFT_New_Memory_Face},
122         {"FT_Done_Face",                (void **) &qFT_Done_Face},
123         {"FT_Select_Size",              (void **) &qFT_Select_Size},
124         {"FT_Request_Size",             (void **) &qFT_Request_Size},
125         {"FT_Set_Char_Size",            (void **) &qFT_Set_Char_Size},
126         {"FT_Set_Pixel_Sizes",          (void **) &qFT_Set_Pixel_Sizes},
127         {"FT_Load_Glyph",               (void **) &qFT_Load_Glyph},
128         {"FT_Load_Char",                (void **) &qFT_Load_Char},
129         {"FT_Get_Char_Index",           (void **) &qFT_Get_Char_Index},
130         {"FT_Render_Glyph",             (void **) &qFT_Render_Glyph},
131         {"FT_Get_Kerning",              (void **) &qFT_Get_Kerning},
132         {"FT_Attach_Stream",            (void **) &qFT_Attach_Stream},
133         {NULL, NULL}
134 };
135
136 /// Handle for FreeType2 DLL
137 static dllhandle_t ft2_dll = NULL;
138
139 /// Memory pool for fonts
140 static mempool_t *font_mempool= NULL;
141
142 /// FreeType library handle
143 static FT_Library font_ft2lib = NULL;
144
145 #define POSTPROCESS_MAXRADIUS 8
146 typedef struct
147 {
148         unsigned char *buf, *buf2;
149         int bufsize, bufwidth, bufheight, bufpitch;
150         float blur, outline, shadowx, shadowy, shadowz;
151         int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
152         unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
153         unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
154 }
155 font_postprocess_t;
156 static font_postprocess_t pp;
157
158 typedef struct fontfilecache_s
159 {
160         unsigned char *buf;
161         fs_offset_t len;
162         int refcount;
163         char path[MAX_QPATH];
164 }
165 fontfilecache_t;
166 #define MAX_FONTFILES 8
167 static fontfilecache_t fontfiles[MAX_FONTFILES];
168 static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer)
169 {
170         int i;
171         unsigned char *buf;
172
173         for(i = 0; i < MAX_FONTFILES; ++i)
174         {
175                 if(fontfiles[i].refcount > 0)
176                         if(!strcmp(path, fontfiles[i].path))
177                         {
178                                 *filesizepointer = fontfiles[i].len;
179                                 ++fontfiles[i].refcount;
180                                 return fontfiles[i].buf;
181                         }
182         }
183
184         buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
185         if(buf)
186         {
187                 for(i = 0; i < MAX_FONTFILES; ++i)
188                         if(fontfiles[i].refcount <= 0)
189                         {
190                                 strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
191                                 fontfiles[i].len = *filesizepointer;
192                                 fontfiles[i].buf = buf;
193                                 fontfiles[i].refcount = 1;
194                                 return buf;
195                         }
196         }
197
198         return buf;
199 }
200 static void fontfilecache_Free(const unsigned char *buf)
201 {
202         int i;
203         for(i = 0; i < MAX_FONTFILES; ++i)
204         {
205                 if(fontfiles[i].refcount > 0)
206                         if(fontfiles[i].buf == buf)
207                         {
208                                 if(--fontfiles[i].refcount <= 0)
209                                 {
210                                         Mem_Free(fontfiles[i].buf);
211                                         fontfiles[i].buf = NULL;
212                                 }
213                                 return;
214                         }
215         }
216         // if we get here, it used regular allocation
217         Mem_Free((void *) buf);
218 }
219 static void fontfilecache_FreeAll(void)
220 {
221         int i;
222         for(i = 0; i < MAX_FONTFILES; ++i)
223         {
224                 if(fontfiles[i].refcount > 0)
225                         Mem_Free(fontfiles[i].buf);
226                 fontfiles[i].buf = NULL;
227                 fontfiles[i].refcount = 0;
228         }
229 }
230
231 /*
232 ====================
233 Font_CloseLibrary
234
235 Unload the FreeType2 DLL
236 ====================
237 */
238 void Font_CloseLibrary (void)
239 {
240         fontfilecache_FreeAll();
241         if (font_mempool)
242                 Mem_FreePool(&font_mempool);
243         if (font_ft2lib && qFT_Done_FreeType)
244         {
245                 qFT_Done_FreeType(font_ft2lib);
246                 font_ft2lib = NULL;
247         }
248         Sys_UnloadLibrary (&ft2_dll);
249         pp.buf = NULL;
250 }
251
252 /*
253 ====================
254 Font_OpenLibrary
255
256 Try to load the FreeType2 DLL
257 ====================
258 */
259 qboolean Font_OpenLibrary (void)
260 {
261         const char* dllnames [] =
262         {
263 #if defined(WIN32)
264                 "libfreetype-6.dll",
265                 "freetype6.dll",
266 #elif defined(MACOSX)
267                 "libfreetype.6.dylib",
268                 "libfreetype.dylib",
269 #else
270                 "libfreetype.so.6",
271                 "libfreetype.so",
272 #endif
273                 NULL
274         };
275
276         if (r_font_disable_freetype.integer)
277                 return false;
278
279         // Already loaded?
280         if (ft2_dll)
281                 return true;
282
283         // Load the DLL
284         if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
285                 return false;
286         return true;
287 }
288
289 /*
290 ====================
291 Font_Init
292
293 Initialize the freetype2 font subsystem
294 ====================
295 */
296
297 void font_start(void)
298 {
299         if (!Font_OpenLibrary())
300                 return;
301
302         if (qFT_Init_FreeType(&font_ft2lib))
303         {
304                 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
305                 Font_CloseLibrary();
306                 return;
307         }
308
309         font_mempool = Mem_AllocPool("FONT", 0, NULL);
310         if (!font_mempool)
311         {
312                 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
313                 Font_CloseLibrary();
314                 return;
315         }
316 }
317
318 void font_shutdown(void)
319 {
320         int i;
321         for (i = 0; i < dp_fonts.maxsize; ++i)
322         {
323                 if (dp_fonts.f[i].ft2)
324                 {
325                         Font_UnloadFont(dp_fonts.f[i].ft2);
326                         dp_fonts.f[i].ft2 = NULL;
327                 }
328         }
329         Font_CloseLibrary();
330 }
331
332 void font_newmap(void)
333 {
334 }
335
336 void Font_Init(void)
337 {
338         Cvar_RegisterVariable(&r_font_nonpoweroftwo);
339         Cvar_RegisterVariable(&r_font_disable_freetype);
340         Cvar_RegisterVariable(&r_font_use_alpha_textures);
341         Cvar_RegisterVariable(&r_font_size_snapping);
342         Cvar_RegisterVariable(&r_font_kerning);
343         Cvar_RegisterVariable(&r_font_diskcache);
344         Cvar_RegisterVariable(&r_font_compress);
345         Cvar_RegisterVariable(&developer_font);
346
347         // let's open it at startup already
348         Font_OpenLibrary();
349 }
350
351 /*
352 ================================================================================
353 Implementation of a more or less lazy font loading and rendering code.
354 ================================================================================
355 */
356
357 #include "ft2_fontdefs.h"
358
359 ft2_font_t *Font_Alloc(void)
360 {
361         if (!ft2_dll)
362                 return NULL;
363         return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
364 }
365
366 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
367 {
368         ft2_attachment_t *na;
369
370         font->attachmentcount++;
371         na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
372         if (na == NULL)
373                 return false;
374         if (font->attachments && font->attachmentcount > 1)
375         {
376                 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
377                 Mem_Free(font->attachments);
378         }
379         memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
380         font->attachments = na;
381         return true;
382 }
383
384 float Font_VirtualToRealSize(float sz)
385 {
386         int vh;
387         //int vw;
388         int si;
389         float sn;
390         if(sz < 0)
391                 return sz;
392         //vw = ((vid.width > 0) ? vid.width : vid_width.value);
393         vh = ((vid.height > 0) ? vid.height : vid_height.value);
394         // now try to scale to our actual size:
395         sn = sz * vh / vid_conheight.value;
396         si = (int)sn;
397         if ( sn - (float)si >= 0.5 )
398                 ++si;
399         return si;
400 }
401
402 float Font_SnapTo(float val, float snapwidth)
403 {
404         return floor(val / snapwidth + 0.5f) * snapwidth;
405 }
406
407 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
408 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
409 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
410 {
411         int s, count, i;
412         ft2_font_t *ft2, *fbfont, *fb;
413
414         ft2 = Font_Alloc();
415         if (!ft2)
416         {
417                 dpfnt->ft2 = NULL;
418                 return false;
419         }
420
421         // check if a fallback font has been specified, if it has been, and the
422         // font fails to load, use the image font as main font
423         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
424         {
425                 if (dpfnt->fallbacks[i][0])
426                         break;
427         }
428
429         if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
430         {
431                 if (i >= MAX_FONT_FALLBACKS)
432                 {
433                         dpfnt->ft2 = NULL;
434                         Mem_Free(ft2);
435                         return false;
436                 }
437                 strlcpy(ft2->name, name, sizeof(ft2->name));
438                 ft2->image_font = true;
439                 ft2->has_kerning = false;
440         }
441         else
442         {
443                 ft2->image_font = false;
444         }
445
446         // attempt to load fallback fonts:
447         fbfont = ft2;
448         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
449         {
450                 if (!dpfnt->fallbacks[i][0])
451                         break;
452                 if (! (fb = Font_Alloc()) )
453                 {
454                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
455                         break;
456                 }
457
458                 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
459                 {
460                         if(!FS_FileExists(va("%s.tga", dpfnt->fallbacks[i])))
461                         if(!FS_FileExists(va("%s.png", dpfnt->fallbacks[i])))
462                         if(!FS_FileExists(va("%s.jpg", dpfnt->fallbacks[i])))
463                         if(!FS_FileExists(va("%s.pcx", dpfnt->fallbacks[i])))
464                                 Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
465                         Mem_Free(fb);
466                         continue;
467                 }
468                 count = 0;
469                 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
470                 {
471                         if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
472                                 ++count;
473                 }
474                 if (!count)
475                 {
476                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
477                         Font_UnloadFont(fb);
478                         Mem_Free(fb);
479                         break;
480                 }
481                 // at least one size of the fallback font loaded successfully
482                 // link it:
483                 fbfont->next = fb;
484                 fbfont = fb;
485         }
486
487         if (fbfont == ft2 && ft2->image_font)
488         {
489                 // no fallbacks were loaded successfully:
490                 dpfnt->ft2 = NULL;
491                 Mem_Free(ft2);
492                 return false;
493         }
494
495         count = 0;
496         for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
497         {
498                 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
499                         ++count;
500         }
501         if (!count)
502         {
503                 // loading failed for every requested size
504                 Font_UnloadFont(ft2);
505                 Mem_Free(ft2);
506                 dpfnt->ft2 = NULL;
507                 return false;
508         }
509
510         //Con_Printf("%i sizes loaded\n", count);
511         dpfnt->ft2 = ft2;
512         return true;
513 }
514
515 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
516 {
517         size_t namelen;
518         char filename[MAX_QPATH];
519         int status;
520         size_t i;
521         const unsigned char *data;
522         fs_offset_t datasize;
523
524         memset(font, 0, sizeof(*font));
525
526         if (!Font_OpenLibrary())
527         {
528                 if (!r_font_disable_freetype.integer)
529                 {
530                         Con_Printf("WARNING: can't open load font %s\n"
531                                    "You need the FreeType2 DLL to load font files\n",
532                                    name);
533                 }
534                 return false;
535         }
536
537         font->settings = settings;
538
539         namelen = strlen(name);
540
541         // try load direct file
542         memcpy(filename, name, namelen+1);
543         data = fontfilecache_LoadFile(filename, false, &datasize);
544         // try load .ttf
545         if (!data)
546         {
547                 memcpy(filename + namelen, ".ttf", 5);
548                 data = fontfilecache_LoadFile(filename, false, &datasize);
549         }
550         // try load .otf
551         if (!data)
552         {
553                 memcpy(filename + namelen, ".otf", 5);
554                 data = fontfilecache_LoadFile(filename, false, &datasize);
555         }
556         // try load .pfb/afm
557         if (!data)
558         {
559                 ft2_attachment_t afm;
560
561                 memcpy(filename + namelen, ".pfb", 5);
562                 data = fontfilecache_LoadFile(filename, false, &datasize);
563
564                 if (data)
565                 {
566                         memcpy(filename + namelen, ".afm", 5);
567                         afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
568
569                         if (afm.data)
570                                 Font_Attach(font, &afm);
571                 }
572         }
573         if (!data)
574         {
575                 // FS_LoadFile being not-quiet should print an error :)
576                 return false;
577         }
578         Con_DPrintf("Loading font %s face %i...\n", filename, _face);
579
580         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
581         if (status && _face != 0)
582         {
583                 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
584                 _face = 0;
585                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
586         }
587         font->data = data;
588         if (status)
589         {
590                 Con_Printf("ERROR: can't create face for %s\n"
591                            "Error %i\n", // TODO: error strings
592                            name, status);
593                 Font_UnloadFont(font);
594                 return false;
595         }
596
597         // add the attachments
598         for (i = 0; i < font->attachmentcount; ++i)
599         {
600                 FT_Open_Args args;
601                 memset(&args, 0, sizeof(args));
602                 args.flags = FT_OPEN_MEMORY;
603                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
604                 args.memory_size = font->attachments[i].size;
605                 if (qFT_Attach_Stream((FT_Face)font->face, &args))
606                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
607         }
608
609         memcpy(font->name, name, namelen+1);
610         font->image_font = false;
611         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
612         return true;
613 }
614
615 void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
616 {
617         int needed, x, y;
618         float gausstable[2*POSTPROCESS_MAXRADIUS+1];
619         qboolean need_gauss  = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
620         qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
621         pp.blur = fnt->settings->blur;
622         pp.outline = fnt->settings->outline;
623         pp.shadowx = fnt->settings->shadowx;
624         pp.shadowy = fnt->settings->shadowy;
625         pp.shadowz = fnt->settings->shadowz;
626         pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
627         pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
628         pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
629         pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
630         pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
631         pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
632         pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
633         pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
634         pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
635         pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
636         if(need_gauss)
637         {
638                 float sum = 0;
639                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
640                         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));
641                 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
642                         sum += gausstable[POSTPROCESS_MAXRADIUS+x];
643                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
644                         pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
645         }
646         if(need_circle)
647         {
648                 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
649                         for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
650                         {
651                                 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
652                                 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
653                         }
654         }
655         pp.bufwidth = w + pp.padding_l + pp.padding_r;
656         pp.bufheight = h + pp.padding_t + pp.padding_b;
657         pp.bufpitch = pp.bufwidth;
658         needed = pp.bufwidth * pp.bufheight;
659         if(!pp.buf || pp.bufsize < needed * 2)
660         {
661                 if(pp.buf)
662                         Mem_Free(pp.buf);
663                 pp.bufsize = needed * 4;
664                 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
665                 pp.buf2 = pp.buf + needed;
666         }
667 }
668
669 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)
670 {
671         int x, y;
672
673         // calculate gauss table
674         Font_Postprocess_Update(fnt, bpp, w, h);
675
676         if(imagedata)
677         {
678                 // enlarge buffer
679                 // perform operation, not exceeding the passed padding values,
680                 // but possibly reducing them
681                 *pad_l = min(*pad_l, pp.padding_l);
682                 *pad_r = min(*pad_r, pp.padding_r);
683                 *pad_t = min(*pad_t, pp.padding_t);
684                 *pad_b = min(*pad_b, pp.padding_b);
685
686                 // outline the font (RGBA only)
687                 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
688                 {
689                         // this is like mplayer subtitle rendering
690                         // bbuffer, bitmap buffer: this is our font
691                         // abuffer, alpha buffer: this is pp.buf
692                         // tmp: this is pp.buf2
693
694                         // create outline buffer
695                         memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
696                         for(y = -*pad_t; y < h + *pad_b; ++y)
697                                 for(x = -*pad_l; x < w + *pad_r; ++x)
698                                 {
699                                         int x1 = max(-x, -pp.outlinepadding_r);
700                                         int y1 = max(-y, -pp.outlinepadding_b);
701                                         int x2 = min(pp.outlinepadding_l, w-1-x);
702                                         int y2 = min(pp.outlinepadding_t, h-1-y);
703                                         int mx, my;
704                                         int cur = 0;
705                                         int highest = 0;
706                                         for(my = y1; my <= y2; ++my)
707                                                 for(mx = x1; mx <= x2; ++mx)
708                                                 {
709                                                         cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
710                                                         if(cur > highest)
711                                                                 highest = cur;
712                                                 }
713                                         pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
714                                 }
715
716                         // blur the outline buffer
717                         if(pp.blur > 0 || pp.shadowz != 0)
718                         {
719                                 // horizontal blur
720                                 for(y = 0; y < pp.bufheight; ++y)
721                                         for(x = 0; x < pp.bufwidth; ++x)
722                                         {
723                                                 int x1 = max(-x, -pp.blurpadding_rb);
724                                                 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
725                                                 int mx;
726                                                 int blurred = 0;
727                                                 for(mx = x1; mx <= x2; ++mx)
728                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
729                                                 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
730                                         }
731
732                                 // vertical blur
733                                 for(y = 0; y < pp.bufheight; ++y)
734                                         for(x = 0; x < pp.bufwidth; ++x)
735                                         {
736                                                 int y1 = max(-y, -pp.blurpadding_rb);
737                                                 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
738                                                 int my;
739                                                 int blurred = 0;
740                                                 for(my = y1; my <= y2; ++my)
741                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
742                                                 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
743                                         }
744                         }
745
746                         // paste the outline below the font
747                         for(y = -*pad_t; y < h + *pad_b; ++y)
748                                 for(x = -*pad_l; x < w + *pad_r; ++x)
749                                 {
750                                         unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
751                                         if(outlinealpha > 0)
752                                         {
753                                                 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
754                                                 // a' = 1 - (1 - a1) (1 - a2)
755                                                 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
756                                                 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
757                                                 unsigned char oldfactor     = (255 * (int)oldalpha) / newalpha;
758                                                 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
759                                                 int i;
760                                                 for(i = 0; i < bpp-1; ++i)
761                                                 {
762                                                         unsigned char c = imagedata[x * bpp + pitch * y + i];
763                                                         c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
764                                                         imagedata[x * bpp + pitch * y + i] = c;
765                                                 }
766                                                 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
767                                         }
768                                         //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
769                                 }
770                 }
771         }
772         else if(pitch)
773         {
774                 // perform operation, not exceeding the passed padding values,
775                 // but possibly reducing them
776                 *pad_l = min(*pad_l, pp.padding_l);
777                 *pad_r = min(*pad_r, pp.padding_r);
778                 *pad_t = min(*pad_t, pp.padding_t);
779                 *pad_b = min(*pad_b, pp.padding_b);
780         }
781         else
782         {
783                 // just calculate parameters
784                 *pad_l = pp.padding_l;
785                 *pad_r = pp.padding_r;
786                 *pad_t = pp.padding_t;
787                 *pad_b = pp.padding_b;
788         }
789 }
790
791 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
792 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
793 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
794 {
795         int map_index;
796         ft2_font_map_t *fmap, temp;
797         int gpad_l, gpad_r, gpad_t, gpad_b;
798
799         if (!(size > 0.001f && size < 1000.0f))
800                 size = 0;
801
802         if (!size)
803                 size = 16;
804         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
805                 return false;
806
807         for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
808         {
809                 if (!font->font_maps[map_index])
810                         break;
811                 // if a similar size has already been loaded, ignore this one
812                 //abs(font->font_maps[map_index]->size - size) < 4
813                 if (font->font_maps[map_index]->size == size)
814                         return true;
815         }
816
817         if (map_index >= MAX_FONT_SIZES)
818                 return false;
819
820         if (check_only) {
821                 FT_Face fontface;
822                 if (font->image_font)
823                         fontface = (FT_Face)font->next->face;
824                 else
825                         fontface = (FT_Face)font->face;
826                 return (Font_SearchSize(font, fontface, size) > 0);
827         }
828
829         Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
830
831         memset(&temp, 0, sizeof(temp));
832         temp.size = size;
833         temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
834         if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
835                 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
836         temp.sfx = (1.0/64.0)/(double)size;
837         temp.sfy = (1.0/64.0)/(double)size;
838         temp.intSize = -1; // negative value: LoadMap must search now :)
839         if (!Font_LoadMap(font, &temp, 0, &fmap))
840         {
841                 Con_Printf("ERROR: can't load the first character map for %s\n"
842                            "This is fatal\n",
843                            font->name);
844                 Font_UnloadFont(font);
845                 return false;
846         }
847         font->font_maps[map_index] = temp.next;
848
849         fmap->sfx = temp.sfx;
850         fmap->sfy = temp.sfy;
851
852         // load the default kerning vector:
853         if (font->has_kerning)
854         {
855                 Uchar l, r;
856                 FT_Vector kernvec;
857                 for (l = 0; l < 256; ++l)
858                 {
859                         for (r = 0; r < 256; ++r)
860                         {
861                                 FT_ULong ul, ur;
862                                 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
863                                 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
864                                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
865                                 {
866                                         fmap->kerning.kerning[l][r][0] = 0;
867                                         fmap->kerning.kerning[l][r][1] = 0;
868                                 }
869                                 else
870                                 {
871                                         fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
872                                         fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
873                                 }
874                         }
875                 }
876         }
877         return true;
878 }
879
880 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
881 {
882         int match = -1;
883         float value = 1000000;
884         float nval;
885         int matchsize = -10000;
886         int m;
887         float fsize_x, fsize_y;
888         ft2_font_map_t **maps = font->font_maps;
889
890         fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
891         if(outw && *outw)
892                 fsize_x = *outw * vid.width / vid_conwidth.value;
893         if(outh && *outh)
894                 fsize_y = *outh * vid.height / vid_conheight.value;
895
896         if (fsize_x < 0)
897         {
898                 if(fsize_y < 0)
899                         fsize_x = fsize_y = 16;
900                 else
901                         fsize_x = fsize_y;
902         }
903         else
904         {
905                 if(fsize_y < 0)
906                         fsize_y = fsize_x;
907         }
908
909         for (m = 0; m < MAX_FONT_SIZES; ++m)
910         {
911                 if (!maps[m])
912                         continue;
913                 // "round up" to the bigger size if two equally-valued matches exist
914                 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
915                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
916                 {
917                         value = nval;
918                         match = m;
919                         matchsize = maps[m]->size;
920                         if (value == 0) // there is no better match
921                                 break;
922                 }
923         }
924         if (value <= r_font_size_snapping.value)
925         {
926                 // do NOT keep the aspect for perfect rendering
927                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
928                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
929         }
930         return match;
931 }
932
933 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
934 {
935         if (index < 0 || index >= MAX_FONT_SIZES)
936                 return NULL;
937         return font->font_maps[index];
938 }
939
940 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
941 {
942         if (font->currenth == h &&
943             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
944              font->currentw == w)) // same size has been requested
945         {
946                 return true;
947         }
948         // sorry, but freetype doesn't seem to care about other sizes
949         w = (int)w;
950         h = (int)h;
951         if (font->image_font)
952         {
953                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
954                         return false;
955         }
956         else
957         {
958                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
959                         return false;
960         }
961         font->currentw = w;
962         font->currenth = h;
963         return true;
964 }
965
966 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
967 {
968         ft2_font_map_t *fmap;
969         if (!font->has_kerning || !r_font_kerning.integer)
970                 return false;
971         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
972                 return false;
973         fmap = font->font_maps[map_index];
974         if (!fmap)
975                 return false;
976         if (left < 256 && right < 256)
977         {
978                 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
979                 // quick-kerning, be aware of the size: scale it
980                 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
981                 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
982                 return true;
983         }
984         else
985         {
986                 FT_Vector kernvec;
987                 FT_ULong ul, ur;
988
989                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
990 #if 0
991                 if (!Font_SetSize(font, w, h))
992                 {
993                         // this deserves an error message
994                         Con_Printf("Failed to get kerning for %s\n", font->name);
995                         return false;
996                 }
997                 ul = qFT_Get_Char_Index(font->face, left);
998                 ur = qFT_Get_Char_Index(font->face, right);
999                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1000                 {
1001                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1002                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1003                         return true;
1004                 }
1005 #endif
1006                 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1007                 {
1008                         // this deserves an error message
1009                         Con_Printf("Failed to get kerning for %s\n", font->name);
1010                         return false;
1011                 }
1012                 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1013                 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1014                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1015                 {
1016                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1017                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1018                         return true;
1019                 }
1020                 return false;
1021         }
1022 }
1023
1024 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1025 {
1026         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1027 }
1028
1029 static void UnloadMapRec(ft2_font_map_t *map)
1030 {
1031         if (map->pic)
1032         {
1033                 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1034                 map->pic = NULL;
1035         }
1036         if (map->next)
1037                 UnloadMapRec(map->next);
1038         Mem_Free(map);
1039 }
1040
1041 void Font_UnloadFont(ft2_font_t *font)
1042 {
1043         int i;
1044
1045         // unload fallbacks
1046         if(font->next)
1047                 Font_UnloadFont(font->next);
1048
1049         if (font->attachments && font->attachmentcount)
1050         {
1051                 for (i = 0; i < (int)font->attachmentcount; ++i) {
1052                         if (font->attachments[i].data)
1053                                 fontfilecache_Free(font->attachments[i].data);
1054                 }
1055                 Mem_Free(font->attachments);
1056                 font->attachmentcount = 0;
1057                 font->attachments = NULL;
1058         }
1059         for (i = 0; i < MAX_FONT_SIZES; ++i)
1060         {
1061                 if (font->font_maps[i])
1062                 {
1063                         UnloadMapRec(font->font_maps[i]);
1064                         font->font_maps[i] = NULL;
1065                 }
1066         }
1067         if (ft2_dll)
1068         {
1069                 if (font->face)
1070                 {
1071                         qFT_Done_Face((FT_Face)font->face);
1072                         font->face = NULL;
1073                 }
1074         }
1075         if (font->data) {
1076             fontfilecache_Free(font->data);
1077             font->data = NULL;
1078         }
1079 }
1080
1081 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1082 {
1083         float intSize = size;
1084         while (1)
1085         {
1086                 if (!Font_SetSize(font, intSize, intSize))
1087                 {
1088                         Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1089                         return -1;
1090                 }
1091                 if ((fontface->size->metrics.height>>6) <= size)
1092                         return intSize;
1093                 if (intSize < 2)
1094                 {
1095                         Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1096                         return -1;
1097                 }
1098                 --intSize;
1099         }
1100 }
1101
1102 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1103 {
1104         char map_identifier[MAX_QPATH];
1105         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1106         unsigned char *data = NULL;
1107         FT_ULong ch, mapch;
1108         int status;
1109         int tp;
1110         FT_Int32 load_flags;
1111         int gpad_l, gpad_r, gpad_t, gpad_b;
1112
1113         int pitch;
1114         int gR, gC; // glyph position: row and column
1115
1116         ft2_font_map_t *map, *next;
1117         ft2_font_t *usefont;
1118
1119         FT_Face fontface;
1120
1121         int bytesPerPixel = 4; // change the conversion loop too if you change this!
1122
1123         if (outmap)
1124                 *outmap = NULL;
1125
1126         if (r_font_use_alpha_textures.integer)
1127                 bytesPerPixel = 1;
1128
1129         if (font->image_font)
1130                 fontface = (FT_Face)font->next->face;
1131         else
1132                 fontface = (FT_Face)font->face;
1133
1134         switch(font->settings->antialias)
1135         {
1136                 case 0:
1137                         switch(font->settings->hinting)
1138                         {
1139                                 case 0:
1140                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1141                                         break;
1142                                 case 1:
1143                                 case 2:
1144                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1145                                         break;
1146                                 default:
1147                                 case 3:
1148                                         load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1149                                         break;
1150                         }
1151                         break;
1152                 default:
1153                 case 1:
1154                         switch(font->settings->hinting)
1155                         {
1156                                 case 0:
1157                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1158                                         break;
1159                                 case 1:
1160                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1161                                         break;
1162                                 case 2:
1163                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1164                                         break;
1165                                 default:
1166                                 case 3:
1167                                         load_flags = FT_LOAD_TARGET_NORMAL;
1168                                         break;
1169                         }
1170                         break;
1171         }
1172
1173         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1174         //if (status)
1175         if (font->image_font && mapstart->intSize < 0)
1176                 mapstart->intSize = mapstart->size;
1177         if (mapstart->intSize < 0)
1178         {
1179                 /*
1180                 mapstart->intSize = mapstart->size;
1181                 while (1)
1182                 {
1183                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1184                         {
1185                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1186                                 return false;
1187                         }
1188                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
1189                                 break;
1190                         if (mapstart->intSize < 2)
1191                         {
1192                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1193                                 return false;
1194                         }
1195                         --mapstart->intSize;
1196                 }
1197                 */
1198                 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1199                         return false;
1200                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1201         }
1202
1203         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1204         {
1205                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1206                 return false;
1207         }
1208
1209         map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1210         if (!map)
1211         {
1212                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1213                 return false;
1214         }
1215
1216         // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1217         dpsnprintf(map_identifier, sizeof(map_identifier),
1218                 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1219                 font->name,
1220                 (double) mapstart->intSize,
1221                 (int) load_flags,
1222                 (double) font->settings->blur,
1223                 (double) font->settings->outline,
1224                 (double) font->settings->shadowx,
1225                 (double) font->settings->shadowy,
1226                 (double) font->settings->shadowz,
1227                 (unsigned) mapidx);
1228
1229         // create a cachepic_t from the data now, or reuse an existing one
1230         map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1231         if (developer_font.integer)
1232         {
1233                 if (map->pic->tex == r_texture_notexture)
1234                         Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1235                 else
1236                         Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1237         }
1238
1239         Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1240
1241         // copy over the information
1242         map->size = mapstart->size;
1243         map->intSize = mapstart->intSize;
1244         map->glyphSize = mapstart->glyphSize;
1245         map->sfx = mapstart->sfx;
1246         map->sfy = mapstart->sfy;
1247
1248         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1249         if (map->pic->tex == r_texture_notexture)
1250         {
1251                 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1252                 if (!data)
1253                 {
1254                         Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1255                         Mem_Free(map);
1256                         return false;
1257                 }
1258                 // initialize as white texture with zero alpha
1259                 tp = 0;
1260                 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1261                 {
1262                         if (bytesPerPixel == 4)
1263                         {
1264                                 data[tp++] = 0xFF;
1265                                 data[tp++] = 0xFF;
1266                                 data[tp++] = 0xFF;
1267                         }
1268                         data[tp++] = 0x00;
1269                 }
1270         }
1271
1272         memset(map->width_of, 0, sizeof(map->width_of));
1273
1274         // insert the map
1275         map->start = mapidx * FONT_CHARS_PER_MAP;
1276         next = mapstart;
1277         while(next->next && next->next->start < map->start)
1278                 next = next->next;
1279         map->next = next->next;
1280         next->next = map;
1281
1282         gR = 0;
1283         gC = -1;
1284         for (ch = map->start;
1285              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1286              ++ch)
1287         {
1288                 FT_ULong glyphIndex;
1289                 int w, h, x, y;
1290                 FT_GlyphSlot glyph;
1291                 FT_Bitmap *bmp;
1292                 unsigned char *imagedata = NULL, *dst, *src;
1293                 glyph_slot_t *mapglyph;
1294                 FT_Face face;
1295                 int pad_l, pad_r, pad_t, pad_b;
1296
1297                 mapch = ch - map->start;
1298
1299                 if (developer_font.integer)
1300                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1301
1302                 ++gC;
1303                 if (gC >= FONT_CHARS_PER_LINE)
1304                 {
1305                         gC -= FONT_CHARS_PER_LINE;
1306                         ++gR;
1307                 }
1308
1309                 if (data)
1310                 {
1311                         imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1312                         imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1313                 }
1314                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1315                 // we need the glyphIndex
1316                 face = (FT_Face)font->face;
1317                 usefont = NULL;
1318                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1319                 {
1320                         map->glyphs[mapch].image = true;
1321                         continue;
1322                 }
1323                 glyphIndex = qFT_Get_Char_Index(face, ch);
1324                 if (glyphIndex == 0)
1325                 {
1326                         // by convention, 0 is the "missing-glyph"-glyph
1327                         // try to load from a fallback font
1328                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1329                         {
1330                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1331                                         continue;
1332                                 // try that glyph
1333                                 face = (FT_Face)usefont->face;
1334                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1335                                 if (glyphIndex == 0)
1336                                         continue;
1337                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1338                                 if (status)
1339                                         continue;
1340                                 break;
1341                         }
1342                         if (!usefont)
1343                         {
1344                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1345                                 // now we let it use the "missing-glyph"-glyph
1346                                 face = (FT_Face)font->face;
1347                                 glyphIndex = 0;
1348                         }
1349                 }
1350
1351                 if (!usefont)
1352                 {
1353                         usefont = font;
1354                         face = (FT_Face)font->face;
1355                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1356                         if (status)
1357                         {
1358                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1359                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1360                                 continue;
1361                         }
1362                 }
1363
1364                 glyph = face->glyph;
1365                 bmp = &glyph->bitmap;
1366
1367                 w = bmp->width;
1368                 h = bmp->rows;
1369
1370                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1371                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1372                         if (w > map->glyphSize)
1373                                 w = map->glyphSize - gpad_l - gpad_r;
1374                         if (h > map->glyphSize)
1375                                 h = map->glyphSize;
1376                 }
1377
1378                 if (imagedata)
1379                 {
1380                         switch (bmp->pixel_mode)
1381                         {
1382                         case FT_PIXEL_MODE_MONO:
1383                                 if (developer_font.integer)
1384                                         Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1385                                 break;
1386                         case FT_PIXEL_MODE_GRAY2:
1387                                 if (developer_font.integer)
1388                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1389                                 break;
1390                         case FT_PIXEL_MODE_GRAY4:
1391                                 if (developer_font.integer)
1392                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1393                                 break;
1394                         case FT_PIXEL_MODE_GRAY:
1395                                 if (developer_font.integer)
1396                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1397                                 break;
1398                         default:
1399                                 if (developer_font.integer)
1400                                         Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1401                                 Mem_Free(data);
1402                                 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1403                                 return false;
1404                         }
1405                         for (y = 0; y < h; ++y)
1406                         {
1407                                 dst = imagedata + y * pitch;
1408                                 src = bmp->buffer + y * bmp->pitch;
1409
1410                                 switch (bmp->pixel_mode)
1411                                 {
1412                                 case FT_PIXEL_MODE_MONO:
1413                                         dst += bytesPerPixel - 1; // shift to alpha byte
1414                                         for (x = 0; x < bmp->width; x += 8)
1415                                         {
1416                                                 unsigned char ch = *src++;
1417                                                 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1418                                                 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1419                                                 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1420                                                 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1421                                                 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1422                                                 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1423                                                 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1424                                                 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1425                                         }
1426                                         break;
1427                                 case FT_PIXEL_MODE_GRAY2:
1428                                         dst += bytesPerPixel - 1; // shift to alpha byte
1429                                         for (x = 0; x < bmp->width; x += 4)
1430                                         {
1431                                                 unsigned char ch = *src++;
1432                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1433                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1434                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1435                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1436                                         }
1437                                         break;
1438                                 case FT_PIXEL_MODE_GRAY4:
1439                                         dst += bytesPerPixel - 1; // shift to alpha byte
1440                                         for (x = 0; x < bmp->width; x += 2)
1441                                         {
1442                                                 unsigned char ch = *src++;
1443                                                 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1444                                                 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1445                                         }
1446                                         break;
1447                                 case FT_PIXEL_MODE_GRAY:
1448                                         // in this case pitch should equal width
1449                                         for (tp = 0; tp < bmp->pitch; ++tp)
1450                                                 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1451
1452                                         //memcpy((void*)dst, (void*)src, bmp->pitch);
1453                                         //dst += bmp->pitch;
1454                                         break;
1455                                 default:
1456                                         break;
1457                                 }
1458                         }
1459
1460                         pad_l = gpad_l;
1461                         pad_r = gpad_r;
1462                         pad_t = gpad_t;
1463                         pad_b = gpad_b;
1464                         Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1465                 }
1466                 else
1467                 {
1468                         pad_l = gpad_l;
1469                         pad_r = gpad_r;
1470                         pad_t = gpad_t;
1471                         pad_b = gpad_b;
1472                         Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1473                 }
1474
1475
1476                 // now fill map->glyphs[ch - map->start]
1477                 mapglyph = &map->glyphs[mapch];
1478
1479                 {
1480                         // old way
1481                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1482
1483                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1484                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1485                         double advance = (glyph->advance.x / 64.0) / map->size;
1486                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1487                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1488
1489                         mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1490                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1491                         mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1492                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1493                         //mapglyph->vxmin = bearingX;
1494                         //mapglyph->vxmax = bearingX + mWidth;
1495                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1496                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1497                         //mapglyph->vymin = -bearingY;
1498                         //mapglyph->vymax = mHeight - bearingY;
1499                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1500                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1501                         //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);
1502                         //mapglyph->advance_x = advance * usefont->size;
1503                         //mapglyph->advance_x = advance;
1504                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1505                         mapglyph->advance_y = 0;
1506
1507                         if (developer_font.integer)
1508                         {
1509                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1510                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1511                                 if (ch >= 32 && ch <= 128)
1512                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1513                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1514                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1515                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1516                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1517                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1518                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1519                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1520                         }
1521                 }
1522                 map->glyphs[mapch].image = false;
1523         }
1524
1525         if (map->pic->tex == r_texture_notexture)
1526         {
1527                 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1528                 int h = map->glyphSize * FONT_CHAR_LINES;
1529                 rtexture_t *tex;
1530                 // abuse the Draw_CachePic system to keep track of this texture
1531                 tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL);
1532                 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1533                 if (tex)
1534                         map->pic->tex = tex;
1535
1536                 if (r_font_diskcache.integer >= 1)
1537                 {
1538                         // swap to BGRA for tga writing...
1539                         int s = w * h;
1540                         int x;
1541                         int b;
1542                         for (x = 0;x < s;x++)
1543                         {
1544                                 b = data[x*4+0];
1545                                 data[x*4+0] = data[x*4+2];
1546                                 data[x*4+2] = b;
1547                         }
1548                         Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
1549 #ifndef USE_GLES2
1550                         if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1551                                 R_SaveTextureDDSFile(tex, va("dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1552 #endif
1553                 }
1554         }
1555
1556         if(data)
1557                 Mem_Free(data);
1558
1559         if (map->pic->tex == r_texture_notexture)
1560         {
1561                 // if the first try isn't successful, keep it with a broken texture
1562                 // otherwise we retry to load it every single frame where ft2 rendering is used
1563                 // this would be bad...
1564                 // only `data' must be freed
1565                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1566                            font->name, mapstart->size, mapidx);
1567                 return false;
1568         }
1569         if (outmap)
1570                 *outmap = map;
1571         return true;
1572 }
1573
1574 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1575 {
1576         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1577                 return false;
1578         // the first map must have been loaded already
1579         if (!font->font_maps[map_index])
1580                 return false;
1581         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1582 }
1583
1584 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1585 {
1586         while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1587                 start = start->next;
1588         if (start && start->start > ch)
1589                 return NULL;
1590         return start;
1591 }