]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - ft2.c
8648c6415dfcf50b9828e86bdc6440bb971f6e5f
[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_%d_%g_%g_%g_%g_%g_%u",
1215                 font->name,
1216                 (double) mapstart->intSize,
1217                 (int) load_flags,
1218                 (double) font->settings->blur,
1219                 (double) font->settings->outline,
1220                 (double) font->settings->shadowx,
1221                 (double) font->settings->shadowy,
1222                 (double) font->settings->shadowz,
1223                 (unsigned) mapidx);
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         if (developer_font.integer)
1228         {
1229                 if (map->pic->tex == r_texture_notexture)
1230                         Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1231                 else
1232                         Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1233         }
1234
1235         Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1236
1237         // copy over the information
1238         map->size = mapstart->size;
1239         map->intSize = mapstart->intSize;
1240         map->glyphSize = mapstart->glyphSize;
1241         map->sfx = mapstart->sfx;
1242         map->sfy = mapstart->sfy;
1243
1244         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1245         if (map->pic->tex == r_texture_notexture)
1246         {
1247                 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1248                 if (!data)
1249                 {
1250                         Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1251                         Mem_Free(map);
1252                         return false;
1253                 }
1254                 // initialize as white texture with zero alpha
1255                 tp = 0;
1256                 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1257                 {
1258                         if (bytesPerPixel == 4)
1259                         {
1260                                 data[tp++] = 0xFF;
1261                                 data[tp++] = 0xFF;
1262                                 data[tp++] = 0xFF;
1263                         }
1264                         data[tp++] = 0x00;
1265                 }
1266         }
1267
1268         memset(map->width_of, 0, sizeof(map->width_of));
1269
1270         // insert the map
1271         map->start = mapidx * FONT_CHARS_PER_MAP;
1272         next = mapstart;
1273         while(next->next && next->next->start < map->start)
1274                 next = next->next;
1275         map->next = next->next;
1276         next->next = map;
1277
1278         gR = 0;
1279         gC = -1;
1280         for (ch = map->start;
1281              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1282              ++ch)
1283         {
1284                 FT_ULong glyphIndex;
1285                 int w, h, x, y;
1286                 FT_GlyphSlot glyph;
1287                 FT_Bitmap *bmp;
1288                 unsigned char *imagedata = NULL, *dst, *src;
1289                 glyph_slot_t *mapglyph;
1290                 FT_Face face;
1291                 int pad_l, pad_r, pad_t, pad_b;
1292
1293                 mapch = ch - map->start;
1294
1295                 if (developer_font.integer)
1296                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1297
1298                 ++gC;
1299                 if (gC >= FONT_CHARS_PER_LINE)
1300                 {
1301                         gC -= FONT_CHARS_PER_LINE;
1302                         ++gR;
1303                 }
1304
1305                 if (data)
1306                 {
1307                         imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1308                         imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1309                 }
1310                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1311                 // we need the glyphIndex
1312                 face = (FT_Face)font->face;
1313                 usefont = NULL;
1314                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1315                 {
1316                         map->glyphs[mapch].image = true;
1317                         continue;
1318                 }
1319                 glyphIndex = qFT_Get_Char_Index(face, ch);
1320                 if (glyphIndex == 0)
1321                 {
1322                         // by convention, 0 is the "missing-glyph"-glyph
1323                         // try to load from a fallback font
1324                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1325                         {
1326                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1327                                         continue;
1328                                 // try that glyph
1329                                 face = (FT_Face)usefont->face;
1330                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1331                                 if (glyphIndex == 0)
1332                                         continue;
1333                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1334                                 if (status)
1335                                         continue;
1336                                 break;
1337                         }
1338                         if (!usefont)
1339                         {
1340                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1341                                 // now we let it use the "missing-glyph"-glyph
1342                                 face = (FT_Face)font->face;
1343                                 glyphIndex = 0;
1344                         }
1345                 }
1346
1347                 if (!usefont)
1348                 {
1349                         usefont = font;
1350                         face = (FT_Face)font->face;
1351                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1352                         if (status)
1353                         {
1354                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1355                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1356                                 continue;
1357                         }
1358                 }
1359
1360                 glyph = face->glyph;
1361                 bmp = &glyph->bitmap;
1362
1363                 w = bmp->width;
1364                 h = bmp->rows;
1365
1366                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1367                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1368                         if (w > map->glyphSize)
1369                                 w = map->glyphSize - gpad_l - gpad_r;
1370                         if (h > map->glyphSize)
1371                                 h = map->glyphSize;
1372                 }
1373
1374                 if (imagedata)
1375                 {
1376                         switch (bmp->pixel_mode)
1377                         {
1378                         case FT_PIXEL_MODE_MONO:
1379                                 if (developer_font.integer)
1380                                         Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1381                                 break;
1382                         case FT_PIXEL_MODE_GRAY2:
1383                                 if (developer_font.integer)
1384                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1385                                 break;
1386                         case FT_PIXEL_MODE_GRAY4:
1387                                 if (developer_font.integer)
1388                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1389                                 break;
1390                         case FT_PIXEL_MODE_GRAY:
1391                                 if (developer_font.integer)
1392                                         Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1393                                 break;
1394                         default:
1395                                 if (developer_font.integer)
1396                                         Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1397                                 Mem_Free(data);
1398                                 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1399                                 return false;
1400                         }
1401                         for (y = 0; y < h; ++y)
1402                         {
1403                                 dst = imagedata + y * pitch;
1404                                 src = bmp->buffer + y * bmp->pitch;
1405
1406                                 switch (bmp->pixel_mode)
1407                                 {
1408                                 case FT_PIXEL_MODE_MONO:
1409                                         dst += bytesPerPixel - 1; // shift to alpha byte
1410                                         for (x = 0; x < bmp->width; x += 8)
1411                                         {
1412                                                 unsigned char ch = *src++;
1413                                                 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1414                                                 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1415                                                 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1416                                                 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1417                                                 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1418                                                 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1419                                                 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1420                                                 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1421                                         }
1422                                         break;
1423                                 case FT_PIXEL_MODE_GRAY2:
1424                                         dst += bytesPerPixel - 1; // shift to alpha byte
1425                                         for (x = 0; x < bmp->width; x += 4)
1426                                         {
1427                                                 unsigned char ch = *src++;
1428                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1429                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1430                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1431                                                 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1432                                         }
1433                                         break;
1434                                 case FT_PIXEL_MODE_GRAY4:
1435                                         dst += bytesPerPixel - 1; // shift to alpha byte
1436                                         for (x = 0; x < bmp->width; x += 2)
1437                                         {
1438                                                 unsigned char ch = *src++;
1439                                                 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1440                                                 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1441                                         }
1442                                         break;
1443                                 case FT_PIXEL_MODE_GRAY:
1444                                         // in this case pitch should equal width
1445                                         for (tp = 0; tp < bmp->pitch; ++tp)
1446                                                 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1447
1448                                         //memcpy((void*)dst, (void*)src, bmp->pitch);
1449                                         //dst += bmp->pitch;
1450                                         break;
1451                                 default:
1452                                         break;
1453                                 }
1454                         }
1455
1456                         pad_l = gpad_l;
1457                         pad_r = gpad_r;
1458                         pad_t = gpad_t;
1459                         pad_b = gpad_b;
1460                         Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1461                 }
1462                 else
1463                 {
1464                         pad_l = gpad_l;
1465                         pad_r = gpad_r;
1466                         pad_t = gpad_t;
1467                         pad_b = gpad_b;
1468                         Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1469                 }
1470
1471
1472                 // now fill map->glyphs[ch - map->start]
1473                 mapglyph = &map->glyphs[mapch];
1474
1475                 {
1476                         // old way
1477                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1478
1479                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1480                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1481                         double advance = (glyph->advance.x / 64.0) / map->size;
1482                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1483                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1484
1485                         mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1486                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1487                         mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1488                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1489                         //mapglyph->vxmin = bearingX;
1490                         //mapglyph->vxmax = bearingX + mWidth;
1491                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1492                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1493                         //mapglyph->vymin = -bearingY;
1494                         //mapglyph->vymax = mHeight - bearingY;
1495                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1496                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1497                         //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);
1498                         //mapglyph->advance_x = advance * usefont->size;
1499                         //mapglyph->advance_x = advance;
1500                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1501                         mapglyph->advance_y = 0;
1502
1503                         if (developer_font.integer)
1504                         {
1505                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1506                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1507                                 if (ch >= 32 && ch <= 128)
1508                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1509                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1510                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1511                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1512                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1513                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1514                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1515                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1516                         }
1517                 }
1518                 map->glyphs[mapch].image = false;
1519         }
1520
1521         if (map->pic->tex == r_texture_notexture)
1522         {
1523                 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1524                 int h = map->glyphSize * FONT_CHAR_LINES;
1525                 rtexture_t *tex;
1526                 // abuse the Draw_CachePic system to keep track of this texture
1527                 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);
1528                 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1529                 if (tex)
1530                         map->pic->tex = tex;
1531
1532                 if (r_font_diskcache.integer >= 1)
1533                 {
1534                         // swap to BGRA for tga writing...
1535                         int s = w * h;
1536                         int x;
1537                         int b;
1538                         for (x = 0;x < s;x++)
1539                         {
1540                                 b = data[x*4+0];
1541                                 data[x*4+0] = data[x*4+2];
1542                                 data[x*4+2] = b;
1543                         }
1544                         Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
1545                         if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1546                                 R_SaveTextureDDSFile(tex, va("dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1547                 }
1548         }
1549
1550         if(data)
1551                 Mem_Free(data);
1552
1553         if (map->pic->tex == r_texture_notexture)
1554         {
1555                 // if the first try isn't successful, keep it with a broken texture
1556                 // otherwise we retry to load it every single frame where ft2 rendering is used
1557                 // this would be bad...
1558                 // only `data' must be freed
1559                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1560                            font->name, mapstart->size, mapidx);
1561                 return false;
1562         }
1563         if (outmap)
1564                 *outmap = map;
1565         return true;
1566 }
1567
1568 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1569 {
1570         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1571                 return false;
1572         // the first map must have been loaded already
1573         if (!font->font_maps[map_index])
1574                 return false;
1575         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1576 }
1577
1578 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1579 {
1580         while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1581                 start = start->next;
1582         if (start && start->start > ch)
1583                 return NULL;
1584         return start;
1585 }