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