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