avoid bugs introduced by the attempt to skip image processing - a closer
[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         Font_Postprocess_Update(fnt, bpp, w, h);
671         if(imagedata)
672         {
673                 // enlarge buffer
674
675                 // perform operation, not exceeding the passed padding values,
676                 // but possibly reducing them
677                 *pad_l = min(*pad_l, pp.padding_l);
678                 *pad_r = min(*pad_r, pp.padding_r);
679                 *pad_t = min(*pad_t, pp.padding_t);
680                 *pad_b = min(*pad_b, pp.padding_b);
681
682                 // calculate gauss table
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
771         {
772                 // just calculate parameters
773                 *pad_l = pp.padding_l;
774                 *pad_r = pp.padding_r;
775                 *pad_t = pp.padding_t;
776                 *pad_b = pp.padding_b;
777         }
778 }
779
780 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
781 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
782 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
783 {
784         int map_index;
785         ft2_font_map_t *fmap, temp;
786         int gpad_l, gpad_r, gpad_t, gpad_b;
787
788         if (!(size > 0.001f && size < 1000.0f))
789                 size = 0;
790
791         if (!size)
792                 size = 16;
793         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
794                 return false;
795
796         for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
797         {
798                 if (!font->font_maps[map_index])
799                         break;
800                 // if a similar size has already been loaded, ignore this one
801                 //abs(font->font_maps[map_index]->size - size) < 4
802                 if (font->font_maps[map_index]->size == size)
803                         return true;
804         }
805
806         if (map_index >= MAX_FONT_SIZES)
807                 return false;
808
809         if (check_only) {
810                 FT_Face fontface;
811                 if (font->image_font)
812                         fontface = (FT_Face)font->next->face;
813                 else
814                         fontface = (FT_Face)font->face;
815                 return (Font_SearchSize(font, fontface, size) > 0);
816         }
817
818         Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
819
820         memset(&temp, 0, sizeof(temp));
821         temp.size = size;
822         temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
823         temp.sfx = (1.0/64.0)/(double)size;
824         temp.sfy = (1.0/64.0)/(double)size;
825         temp.intSize = -1; // negative value: LoadMap must search now :)
826         if (!Font_LoadMap(font, &temp, 0, &fmap))
827         {
828                 Con_Printf("ERROR: can't load the first character map for %s\n"
829                            "This is fatal\n",
830                            font->name);
831                 Font_UnloadFont(font);
832                 return false;
833         }
834         font->font_maps[map_index] = temp.next;
835
836         fmap->sfx = temp.sfx;
837         fmap->sfy = temp.sfy;
838
839         // load the default kerning vector:
840         if (font->has_kerning)
841         {
842                 Uchar l, r;
843                 FT_Vector kernvec;
844                 for (l = 0; l < 256; ++l)
845                 {
846                         for (r = 0; r < 256; ++r)
847                         {
848                                 FT_ULong ul, ur;
849                                 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
850                                 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
851                                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
852                                 {
853                                         fmap->kerning.kerning[l][r][0] = 0;
854                                         fmap->kerning.kerning[l][r][1] = 0;
855                                 }
856                                 else
857                                 {
858                                         fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
859                                         fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
860                                 }
861                         }
862                 }
863         }
864         return true;
865 }
866
867 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
868 {
869         int match = -1;
870         float value = 1000000;
871         float nval;
872         int matchsize = -10000;
873         int m;
874         float fsize_x, fsize_y;
875         ft2_font_map_t **maps = font->font_maps;
876
877         fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
878         if(outw && *outw)
879                 fsize_x = *outw * vid.width / vid_conwidth.value;
880         if(outh && *outh)
881                 fsize_y = *outh * vid.height / vid_conheight.value;
882
883         if (fsize_x < 0)
884         {
885                 if(fsize_y < 0)
886                         fsize_x = fsize_y = 16;
887                 else
888                         fsize_x = fsize_y;
889         }
890         else
891         {
892                 if(fsize_y < 0)
893                         fsize_y = fsize_x;
894         }
895
896         for (m = 0; m < MAX_FONT_SIZES; ++m)
897         {
898                 if (!maps[m])
899                         continue;
900                 // "round up" to the bigger size if two equally-valued matches exist
901                 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
902                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
903                 {
904                         value = nval;
905                         match = m;
906                         matchsize = maps[m]->size;
907                         if (value == 0) // there is no better match
908                                 break;
909                 }
910         }
911         if (value <= r_font_size_snapping.value)
912         {
913                 // do NOT keep the aspect for perfect rendering
914                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
915                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
916         }
917         return match;
918 }
919
920 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
921 {
922         if (index < 0 || index >= MAX_FONT_SIZES)
923                 return NULL;
924         return font->font_maps[index];
925 }
926
927 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
928 {
929         if (font->currenth == h &&
930             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
931              font->currentw == w)) // same size has been requested
932         {
933                 return true;
934         }
935         // sorry, but freetype doesn't seem to care about other sizes
936         w = (int)w;
937         h = (int)h;
938         if (font->image_font)
939         {
940                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
941                         return false;
942         }
943         else
944         {
945                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
946                         return false;
947         }
948         font->currentw = w;
949         font->currenth = h;
950         return true;
951 }
952
953 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
954 {
955         ft2_font_map_t *fmap;
956         if (!font->has_kerning || !r_font_kerning.integer)
957                 return false;
958         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
959                 return false;
960         fmap = font->font_maps[map_index];
961         if (!fmap)
962                 return false;
963         if (left < 256 && right < 256)
964         {
965                 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
966                 // quick-kerning, be aware of the size: scale it
967                 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
968                 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
969                 return true;
970         }
971         else
972         {
973                 FT_Vector kernvec;
974                 FT_ULong ul, ur;
975
976                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
977 #if 0
978                 if (!Font_SetSize(font, w, h))
979                 {
980                         // this deserves an error message
981                         Con_Printf("Failed to get kerning for %s\n", font->name);
982                         return false;
983                 }
984                 ul = qFT_Get_Char_Index(font->face, left);
985                 ur = qFT_Get_Char_Index(font->face, right);
986                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
987                 {
988                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
989                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
990                         return true;
991                 }
992 #endif
993                 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
994                 {
995                         // this deserves an error message
996                         Con_Printf("Failed to get kerning for %s\n", font->name);
997                         return false;
998                 }
999                 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1000                 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1001                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1002                 {
1003                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1004                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1005                         return true;
1006                 }
1007                 return false;
1008         }
1009 }
1010
1011 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1012 {
1013         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1014 }
1015
1016 static void UnloadMapRec(ft2_font_map_t *map)
1017 {
1018         if (map->pic)
1019         {
1020                 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1021                 map->pic = NULL;
1022         }
1023         if (map->next)
1024                 UnloadMapRec(map->next);
1025         Mem_Free(map);
1026 }
1027
1028 void Font_UnloadFont(ft2_font_t *font)
1029 {
1030         int i;
1031
1032         // unload fallbacks
1033         if(font->next)
1034                 Font_UnloadFont(font->next);
1035
1036         if (font->attachments && font->attachmentcount)
1037         {
1038                 for (i = 0; i < (int)font->attachmentcount; ++i) {
1039                         if (font->attachments[i].data)
1040                                 fontfilecache_Free(font->attachments[i].data);
1041                 }
1042                 Mem_Free(font->attachments);
1043                 font->attachmentcount = 0;
1044                 font->attachments = NULL;
1045         }
1046         for (i = 0; i < MAX_FONT_SIZES; ++i)
1047         {
1048                 if (font->font_maps[i])
1049                 {
1050                         UnloadMapRec(font->font_maps[i]);
1051                         font->font_maps[i] = NULL;
1052                 }
1053         }
1054         if (ft2_dll)
1055         {
1056                 if (font->face)
1057                 {
1058                         qFT_Done_Face((FT_Face)font->face);
1059                         font->face = NULL;
1060                 }
1061         }
1062         if (font->data) {
1063             fontfilecache_Free(font->data);
1064             font->data = NULL;
1065         }
1066 }
1067
1068 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1069 {
1070         float intSize = size;
1071         while (1)
1072         {
1073                 if (!Font_SetSize(font, intSize, intSize))
1074                 {
1075                         Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1076                         return -1;
1077                 }
1078                 if ((fontface->size->metrics.height>>6) <= size)
1079                         return intSize;
1080                 if (intSize < 2)
1081                 {
1082                         Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1083                         return -1;
1084                 }
1085                 --intSize;
1086         }
1087 }
1088
1089 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1090 {
1091         char map_identifier[MAX_QPATH];
1092         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1093         unsigned char *data = NULL;
1094         FT_ULong ch, mapch;
1095         int status;
1096         int tp;
1097         FT_Int32 load_flags;
1098         int gpad_l, gpad_r, gpad_t, gpad_b;
1099
1100         int pitch;
1101         int gR, gC; // glyph position: row and column
1102
1103         ft2_font_map_t *map, *next;
1104         ft2_font_t *usefont;
1105
1106         FT_Face fontface;
1107
1108         int bytesPerPixel = 4; // change the conversion loop too if you change this!
1109
1110         if (outmap)
1111                 *outmap = NULL;
1112
1113         if (r_font_use_alpha_textures.integer)
1114                 bytesPerPixel = 1;
1115
1116         if (font->image_font)
1117                 fontface = (FT_Face)font->next->face;
1118         else
1119                 fontface = (FT_Face)font->face;
1120
1121         switch(font->settings->antialias)
1122         {
1123                 case 0:
1124                         switch(font->settings->hinting)
1125                         {
1126                                 case 0:
1127                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1128                                         break;
1129                                 case 1:
1130                                 case 2:
1131                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1132                                         break;
1133                                 default:
1134                                 case 3:
1135                                         load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1136                                         break;
1137                         }
1138                         break;
1139                 default:
1140                 case 1:
1141                         switch(font->settings->hinting)
1142                         {
1143                                 case 0:
1144                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1145                                         break;
1146                                 case 1:
1147                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1148                                         break;
1149                                 case 2:
1150                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1151                                         break;
1152                                 default:
1153                                 case 3:
1154                                         load_flags = FT_LOAD_TARGET_NORMAL;
1155                                         break;
1156                         }
1157                         break;
1158         }
1159
1160         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1161         //if (status)
1162         if (font->image_font && mapstart->intSize < 0)
1163                 mapstart->intSize = mapstart->size;
1164         if (mapstart->intSize < 0)
1165         {
1166                 /*
1167                 mapstart->intSize = mapstart->size;
1168                 while (1)
1169                 {
1170                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1171                         {
1172                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1173                                 return false;
1174                         }
1175                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
1176                                 break;
1177                         if (mapstart->intSize < 2)
1178                         {
1179                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1180                                 return false;
1181                         }
1182                         --mapstart->intSize;
1183                 }
1184                 */
1185                 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1186                         return false;
1187                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1188         }
1189
1190         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1191         {
1192                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1193                 return false;
1194         }
1195
1196         map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1197         if (!map)
1198         {
1199                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1200                 return false;
1201         }
1202
1203         // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1204         dpsnprintf(map_identifier, sizeof(map_identifier),
1205                 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1206                 font->name,
1207                 mapstart->intSize,
1208                 load_flags,
1209                 font->settings->blur,
1210                 font->settings->outline,
1211                 font->settings->shadowx,
1212                 font->settings->shadowy,
1213                 font->settings->shadowz,
1214                 (unsigned)map->start/FONT_CHARS_PER_MAP);
1215
1216         // create a cachepic_t from the data now, or reuse an existing one
1217         map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1218
1219         Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1220
1221         // copy over the information
1222         map->size = mapstart->size;
1223         map->intSize = mapstart->intSize;
1224         map->glyphSize = mapstart->glyphSize;
1225         map->sfx = mapstart->sfx;
1226         map->sfy = mapstart->sfy;
1227
1228         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1229 //      if (map->pic->tex == r_texture_notexture)
1230         {
1231                 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1232                 if (!data)
1233                 {
1234                         Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1235                         Mem_Free(map);
1236                         return false;
1237                 }
1238                 // initialize as white texture with zero alpha
1239                 tp = 0;
1240                 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1241                 {
1242                         if (bytesPerPixel == 4)
1243                         {
1244                                 data[tp++] = 0xFF;
1245                                 data[tp++] = 0xFF;
1246                                 data[tp++] = 0xFF;
1247                         }
1248                         data[tp++] = 0x00;
1249                 }
1250         }
1251
1252         memset(map->width_of, 0, sizeof(map->width_of));
1253
1254         // insert the map
1255         map->start = mapidx * FONT_CHARS_PER_MAP;
1256         next = mapstart;
1257         while(next->next && next->next->start < map->start)
1258                 next = next->next;
1259         map->next = next->next;
1260         next->next = map;
1261
1262         gR = 0;
1263         gC = -1;
1264         for (ch = map->start;
1265              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1266              ++ch)
1267         {
1268                 FT_ULong glyphIndex;
1269                 int w, h, x, y;
1270                 FT_GlyphSlot glyph;
1271                 FT_Bitmap *bmp;
1272                 unsigned char *imagedata = NULL, *dst, *src;
1273                 glyph_slot_t *mapglyph;
1274                 FT_Face face;
1275                 int pad_l, pad_r, pad_t, pad_b;
1276
1277                 mapch = ch - map->start;
1278
1279                 if (developer_font.integer)
1280                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1281
1282                 ++gC;
1283                 if (gC >= FONT_CHARS_PER_LINE)
1284                 {
1285                         gC -= FONT_CHARS_PER_LINE;
1286                         ++gR;
1287                 }
1288
1289                 if (data)
1290                 {
1291                         imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1292                         imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1293                 }
1294                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1295                 // we need the glyphIndex
1296                 face = (FT_Face)font->face;
1297                 usefont = NULL;
1298                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1299                 {
1300                         map->glyphs[mapch].image = true;
1301                         continue;
1302                 }
1303                 glyphIndex = qFT_Get_Char_Index(face, ch);
1304                 if (glyphIndex == 0)
1305                 {
1306                         // by convention, 0 is the "missing-glyph"-glyph
1307                         // try to load from a fallback font
1308                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1309                         {
1310                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1311                                         continue;
1312                                 // try that glyph
1313                                 face = (FT_Face)usefont->face;
1314                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1315                                 if (glyphIndex == 0)
1316                                         continue;
1317                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1318                                 if (status)
1319                                         continue;
1320                                 break;
1321                         }
1322                         if (!usefont)
1323                         {
1324                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1325                                 // now we let it use the "missing-glyph"-glyph
1326                                 face = (FT_Face)font->face;
1327                                 glyphIndex = 0;
1328                         }
1329                 }
1330
1331                 if (!usefont)
1332                 {
1333                         usefont = font;
1334                         face = (FT_Face)font->face;
1335                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1336                         if (status)
1337                         {
1338                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1339                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1340                                 continue;
1341                         }
1342                 }
1343
1344                 glyph = face->glyph;
1345                 bmp = &glyph->bitmap;
1346
1347                 w = bmp->width;
1348                 h = bmp->rows;
1349
1350                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1351                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1352                         if (w > map->glyphSize)
1353                                 w = map->glyphSize - gpad_l - gpad_r;
1354                         if (h > map->glyphSize)
1355                                 h = map->glyphSize;
1356                 }
1357
1358                 if (imagedata)
1359                 {
1360                         switch (bmp->pixel_mode)
1361                         {
1362                         case FT_PIXEL_MODE_MONO:
1363                                 if (developer_font.integer)
1364                                         Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1365                                 break;
1366                         case FT_PIXEL_MODE_GRAY2:
1367                                 if (developer_font.integer)
1368                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1369                                 break;
1370                         case FT_PIXEL_MODE_GRAY4:
1371                                 if (developer_font.integer)
1372                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1373                                 break;
1374                         case FT_PIXEL_MODE_GRAY:
1375                                 if (developer_font.integer)
1376                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1377                                 break;
1378                         default:
1379                                 if (developer_font.integer)
1380                                         Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1381                                 Mem_Free(data);
1382                                 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1383                                 return false;
1384                         }
1385                         for (y = 0; y < h; ++y)
1386                         {
1387                                 dst = imagedata + y * pitch;
1388                                 src = bmp->buffer + y * bmp->pitch;
1389
1390                                 switch (bmp->pixel_mode)
1391                                 {
1392                                 case FT_PIXEL_MODE_MONO:
1393                                         dst += bytesPerPixel - 1; // shift to alpha byte
1394                                         for (x = 0; x < bmp->width; x += 8)
1395                                         {
1396                                                 unsigned char ch = *src++;
1397                                                 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1398                                                 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1399                                                 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1400                                                 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1401                                                 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1402                                                 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1403                                                 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1404                                                 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1405                                         }
1406                                         break;
1407                                 case FT_PIXEL_MODE_GRAY2:
1408                                         dst += bytesPerPixel - 1; // shift to alpha byte
1409                                         for (x = 0; x < bmp->width; x += 4)
1410                                         {
1411                                                 unsigned char ch = *src++;
1412                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1413                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1414                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1415                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1416                                         }
1417                                         break;
1418                                 case FT_PIXEL_MODE_GRAY4:
1419                                         dst += bytesPerPixel - 1; // shift to alpha byte
1420                                         for (x = 0; x < bmp->width; x += 2)
1421                                         {
1422                                                 unsigned char ch = *src++;
1423                                                 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1424                                                 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1425                                         }
1426                                         break;
1427                                 case FT_PIXEL_MODE_GRAY:
1428                                         // in this case pitch should equal width
1429                                         for (tp = 0; tp < bmp->pitch; ++tp)
1430                                                 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1431
1432                                         //memcpy((void*)dst, (void*)src, bmp->pitch);
1433                                         //dst += bmp->pitch;
1434                                         break;
1435                                 default:
1436                                         break;
1437                                 }
1438                         }
1439
1440                         pad_l = gpad_l;
1441                         pad_r = gpad_r;
1442                         pad_t = gpad_t;
1443                         pad_b = gpad_b;
1444                         Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1445                 }
1446
1447                 // now fill map->glyphs[ch - map->start]
1448                 mapglyph = &map->glyphs[mapch];
1449
1450                 {
1451                         // old way
1452                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1453
1454                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1455                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1456                         double advance = (glyph->advance.x / 64.0) / map->size;
1457                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1458                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1459
1460                         mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1461                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1462                         mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1463                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1464                         //mapglyph->vxmin = bearingX;
1465                         //mapglyph->vxmax = bearingX + mWidth;
1466                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1467                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1468                         //mapglyph->vymin = -bearingY;
1469                         //mapglyph->vymax = mHeight - bearingY;
1470                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1471                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1472                         //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);
1473                         //mapglyph->advance_x = advance * usefont->size;
1474                         //mapglyph->advance_x = advance;
1475                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1476                         mapglyph->advance_y = 0;
1477
1478                         if (developer_font.integer)
1479                         {
1480                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1481                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1482                                 if (ch >= 32 && ch <= 128)
1483                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1484                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1485                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1486                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1487                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1488                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1489                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1490                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1491                         }
1492                 }
1493                 map->glyphs[mapch].image = false;
1494         }
1495
1496         if (map->pic->tex == r_texture_notexture)
1497         {
1498                 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1499                 int h = map->glyphSize * FONT_CHAR_LINES;
1500                 rtexture_t *tex;
1501                 // abuse the Draw_CachePic system to keep track of this texture
1502                 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);
1503                 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1504                 if (tex)
1505                         map->pic->tex = tex;
1506
1507                 if (r_font_diskcache.integer >= 1)
1508                 {
1509                         // swap to BGRA for tga writing...
1510                         int s = w * h;
1511                         int x;
1512                         int b;
1513                         for (x = 0;x < s;x++)
1514                         {
1515                                 b = data[x*4+0];
1516                                 data[x*4+0] = data[x*4+2];
1517                                 data[x*4+2] = b;
1518                         }
1519                         Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
1520                         if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1521                                 R_SaveTextureDDSFile(tex, va("dds/%s.dds", map_identifier), true, true);
1522                 }
1523                 Mem_Free(data);
1524         }
1525
1526         if (map->pic->tex == r_texture_notexture)
1527         {
1528                 // if the first try isn't successful, keep it with a broken texture
1529                 // otherwise we retry to load it every single frame where ft2 rendering is used
1530                 // this would be bad...
1531                 // only `data' must be freed
1532                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1533                            font->name, mapstart->size, mapidx);
1534                 return false;
1535         }
1536         if (outmap)
1537                 *outmap = map;
1538         return true;
1539 }
1540
1541 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1542 {
1543         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1544                 return false;
1545         // the first map must have been loaded already
1546         if (!font->font_maps[map_index])
1547                 return false;
1548         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1549 }
1550
1551 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1552 {
1553         while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1554                 start = start->next;
1555         if (start && start->start > ch)
1556                 return NULL;
1557         return start;
1558 }