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