]> git.xonotic.org Git - xonotic/darkplaces.git/blob - ft2.c
Free the data of each font attachment in Font_UnloadFont
[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                 "libfreetype-6.dll",
190                 "freetype6.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 (ft2_font_t *)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((FT_Face)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 = (unsigned char *)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((FT_Face)font->face, l);
777                                 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
778                                 if (qFT_Get_Kerning((FT_Face)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((FT_Face)font->face, left);
927                 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
928                 if (qFT_Get_Kerning((FT_Face)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                 for (i = 0; i < font->attachmentcount; ++i) {
961                         if (font->attachments[i].data)
962                                 Mem_Free(font->attachments[i].data);
963                 }
964                 Mem_Free(font->attachments);
965                 font->attachmentcount = 0;
966                 font->attachments = NULL;
967         }
968         for (i = 0; i < MAX_FONT_SIZES; ++i)
969         {
970                 if (font->font_maps[i])
971                 {
972                         UnloadMapRec(font->font_maps[i]);
973                         font->font_maps[i] = NULL;
974                 }
975         }
976         if (ft2_dll)
977         {
978                 if (font->face)
979                 {
980                         qFT_Done_Face((FT_Face)font->face);
981                         font->face = NULL;
982                 }
983         }
984 }
985
986 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
987 {
988         float intSize = size;
989         while (1)
990         {
991                 if (!Font_SetSize(font, intSize, intSize))
992                 {
993                         Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
994                         return -1;
995                 }
996                 if ((fontface->size->metrics.height>>6) <= size)
997                         return intSize;
998                 if (intSize < 2)
999                 {
1000                         Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1001                         return -1;
1002                 }
1003                 --intSize;
1004         }
1005 }
1006
1007 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1008 {
1009         char map_identifier[MAX_QPATH];
1010         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1011         unsigned char *data;
1012         FT_ULong ch, mapch;
1013         int status;
1014         int tp;
1015         FT_Int32 load_flags;
1016         int gpad_l, gpad_r, gpad_t, gpad_b;
1017
1018         int pitch;
1019         int gR, gC; // glyph position: row and column
1020
1021         ft2_font_map_t *map, *next;
1022         ft2_font_t *usefont;
1023
1024         FT_Face fontface;
1025
1026         int bytesPerPixel = 4; // change the conversion loop too if you change this!
1027
1028         if (outmap)
1029                 *outmap = NULL;
1030
1031         if (r_font_use_alpha_textures.integer)
1032                 bytesPerPixel = 1;
1033
1034         if (font->image_font)
1035                 fontface = (FT_Face)font->next->face;
1036         else
1037                 fontface = (FT_Face)font->face;
1038
1039         switch(font->settings->antialias)
1040         {
1041                 case 0:
1042                         switch(font->settings->hinting)
1043                         {
1044                                 case 0:
1045                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1046                                         break;
1047                                 case 1:
1048                                 case 2:
1049                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1050                                         break;
1051                                 default:
1052                                 case 3:
1053                                         load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1054                                         break;
1055                         }
1056                         break;
1057                 default:
1058                 case 1:
1059                         switch(font->settings->hinting)
1060                         {
1061                                 case 0:
1062                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1063                                         break;
1064                                 case 1:
1065                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1066                                         break;
1067                                 case 2:
1068                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1069                                         break;
1070                                 default:
1071                                 case 3:
1072                                         load_flags = FT_LOAD_TARGET_NORMAL;
1073                                         break;
1074                         }
1075                         break;
1076         }
1077
1078         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1079         //if (status)
1080         if (font->image_font && mapstart->intSize < 0)
1081                 mapstart->intSize = mapstart->size;
1082         if (mapstart->intSize < 0)
1083         {
1084                 /*
1085                 mapstart->intSize = mapstart->size;
1086                 while (1)
1087                 {
1088                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1089                         {
1090                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1091                                 return false;
1092                         }
1093                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
1094                                 break;
1095                         if (mapstart->intSize < 2)
1096                         {
1097                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1098                                 return false;
1099                         }
1100                         --mapstart->intSize;
1101                 }
1102                 */
1103                 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1104                         return false;
1105                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1106         }
1107
1108         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1109         {
1110                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1111                 return false;
1112         }
1113
1114         map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1115         if (!map)
1116         {
1117                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1118                 return false;
1119         }
1120
1121         Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1122
1123         // copy over the information
1124         map->size = mapstart->size;
1125         map->intSize = mapstart->intSize;
1126         map->glyphSize = mapstart->glyphSize;
1127         map->sfx = mapstart->sfx;
1128         map->sfy = mapstart->sfy;
1129
1130         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1131         data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1132         if (!data)
1133         {
1134                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1135                 Mem_Free(map);
1136                 return false;
1137         }
1138         memset(map->width_of, 0, sizeof(map->width_of));
1139
1140         // initialize as white texture with zero alpha
1141         tp = 0;
1142         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1143         {
1144                 if (bytesPerPixel == 4)
1145                 {
1146                         data[tp++] = 0xFF;
1147                         data[tp++] = 0xFF;
1148                         data[tp++] = 0xFF;
1149                 }
1150                 data[tp++] = 0x00;
1151         }
1152
1153         // insert the map
1154         map->start = mapidx * FONT_CHARS_PER_MAP;
1155         next = mapstart;
1156         while(next->next && next->next->start < map->start)
1157                 next = next->next;
1158         map->next = next->next;
1159         next->next = map;
1160
1161         gR = 0;
1162         gC = -1;
1163         for (ch = map->start;
1164              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1165              ++ch)
1166         {
1167                 FT_ULong glyphIndex;
1168                 int w, h, x, y;
1169                 FT_GlyphSlot glyph;
1170                 FT_Bitmap *bmp;
1171                 unsigned char *imagedata, *dst, *src;
1172                 glyph_slot_t *mapglyph;
1173                 FT_Face face;
1174                 int pad_l, pad_r, pad_t, pad_b;
1175
1176                 mapch = ch - map->start;
1177
1178                 if (developer_font.integer)
1179                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1180
1181                 ++gC;
1182                 if (gC >= FONT_CHARS_PER_LINE)
1183                 {
1184                         gC -= FONT_CHARS_PER_LINE;
1185                         ++gR;
1186                 }
1187
1188                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1189                 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1190                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1191                 // we need the glyphIndex
1192                 face = (FT_Face)font->face;
1193                 usefont = NULL;
1194                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1195                 {
1196                         map->glyphs[mapch].image = true;
1197                         continue;
1198                 }
1199                 glyphIndex = qFT_Get_Char_Index(face, ch);
1200                 if (glyphIndex == 0)
1201                 {
1202                         // by convention, 0 is the "missing-glyph"-glyph
1203                         // try to load from a fallback font
1204                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1205                         {
1206                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1207                                         continue;
1208                                 // try that glyph
1209                                 face = (FT_Face)usefont->face;
1210                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1211                                 if (glyphIndex == 0)
1212                                         continue;
1213                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1214                                 if (status)
1215                                         continue;
1216                                 break;
1217                         }
1218                         if (!usefont)
1219                         {
1220                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1221                                 // now we let it use the "missing-glyph"-glyph
1222                                 face = (FT_Face)font->face;
1223                                 glyphIndex = 0;
1224                         }
1225                 }
1226
1227                 if (!usefont)
1228                 {
1229                         usefont = font;
1230                         face = (FT_Face)font->face;
1231                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1232                         if (status)
1233                         {
1234                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1235                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1236                                 continue;
1237                         }
1238                 }
1239
1240                 glyph = face->glyph;
1241                 bmp = &glyph->bitmap;
1242
1243                 w = bmp->width;
1244                 h = bmp->rows;
1245
1246                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1247                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1248                         if (w > map->glyphSize)
1249                                 w = map->glyphSize - gpad_l - gpad_r;
1250                         if (h > map->glyphSize)
1251                                 h = map->glyphSize;
1252                 }
1253
1254                 switch (bmp->pixel_mode)
1255                 {
1256                 case FT_PIXEL_MODE_MONO:
1257                         if (developer_font.integer)
1258                                 Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1259                         break;
1260                 case FT_PIXEL_MODE_GRAY2:
1261                         if (developer_font.integer)
1262                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1263                         break;
1264                 case FT_PIXEL_MODE_GRAY4:
1265                         if (developer_font.integer)
1266                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1267                         break;
1268                 case FT_PIXEL_MODE_GRAY:
1269                         if (developer_font.integer)
1270                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1271                         break;
1272                 default:
1273                         if (developer_font.integer)
1274                                 Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1275                         Mem_Free(data);
1276                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1277                         return false;
1278                 }
1279                 for (y = 0; y < h; ++y)
1280                 {
1281                         dst = imagedata + y * pitch;
1282                         src = bmp->buffer + y * bmp->pitch;
1283
1284                         switch (bmp->pixel_mode)
1285                         {
1286                         case FT_PIXEL_MODE_MONO:
1287                                 dst += bytesPerPixel - 1; // shift to alpha byte
1288                                 for (x = 0; x < bmp->width; x += 8)
1289                                 {
1290                                         unsigned char ch = *src++;
1291                                         *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1292                                         *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1293                                         *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1294                                         *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1295                                         *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1296                                         *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1297                                         *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1298                                         *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1299                                 }
1300                                 break;
1301                         case FT_PIXEL_MODE_GRAY2:
1302                                 dst += bytesPerPixel - 1; // shift to alpha byte
1303                                 for (x = 0; x < bmp->width; x += 4)
1304                                 {
1305                                         unsigned char ch = *src++;
1306                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1307                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1308                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1309                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1310                                 }
1311                                 break;
1312                         case FT_PIXEL_MODE_GRAY4:
1313                                 dst += bytesPerPixel - 1; // shift to alpha byte
1314                                 for (x = 0; x < bmp->width; x += 2)
1315                                 {
1316                                         unsigned char ch = *src++;
1317                                         *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1318                                         *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1319                                 }
1320                                 break;
1321                         case FT_PIXEL_MODE_GRAY:
1322                                 // in this case pitch should equal width
1323                                 for (tp = 0; tp < bmp->pitch; ++tp)
1324                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1325
1326                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1327                                 //dst += bmp->pitch;
1328                                 break;
1329                         default:
1330                                 break;
1331                         }
1332                 }
1333
1334                 pad_l = gpad_l;
1335                 pad_r = gpad_r;
1336                 pad_t = gpad_t;
1337                 pad_b = gpad_b;
1338                 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1339
1340                 // now fill map->glyphs[ch - map->start]
1341                 mapglyph = &map->glyphs[mapch];
1342
1343                 {
1344                         // old way
1345                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1346
1347                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1348                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1349                         double advance = (glyph->advance.x / 64.0) / map->size;
1350                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1351                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1352
1353                         mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1354                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1355                         mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1356                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1357                         //mapglyph->vxmin = bearingX;
1358                         //mapglyph->vxmax = bearingX + mWidth;
1359                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1360                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1361                         //mapglyph->vymin = -bearingY;
1362                         //mapglyph->vymax = mHeight - bearingY;
1363                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1364                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1365                         //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);
1366                         //mapglyph->advance_x = advance * usefont->size;
1367                         //mapglyph->advance_x = advance;
1368                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1369                         mapglyph->advance_y = 0;
1370
1371                         if (developer_font.integer)
1372                         {
1373                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1374                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1375                                 if (ch >= 32 && ch <= 128)
1376                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1377                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1378                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1379                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1380                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1381                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1382                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1383                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1384                         }
1385                 }
1386                 map->glyphs[mapch].image = false;
1387         }
1388
1389         // create a texture from the data now
1390
1391         if (developer_font.integer > 100)
1392         {
1393                 // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
1394                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1395                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1396                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1397         }
1398         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1399
1400         // probably use bytesPerPixel here instead?
1401         if (r_font_use_alpha_textures.integer)
1402         {
1403                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1404                                                map->glyphSize * FONT_CHARS_PER_LINE,
1405                                                map->glyphSize * FONT_CHAR_LINES,
1406                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1407         } else {
1408                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1409                                                map->glyphSize * FONT_CHARS_PER_LINE,
1410                                                map->glyphSize * FONT_CHAR_LINES,
1411                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1412         }
1413
1414         Mem_Free(data);
1415         if (!map->texture)
1416         {
1417                 // if the first try isn't successful, keep it with a broken texture
1418                 // otherwise we retry to load it every single frame where ft2 rendering is used
1419                 // this would be bad...
1420                 // only `data' must be freed
1421                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1422                            font->name, mapstart->size, mapidx);
1423                 return false;
1424         }
1425         if (outmap)
1426                 *outmap = map;
1427         return true;
1428 }
1429
1430 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1431 {
1432         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1433                 return false;
1434         // the first map must have been loaded already
1435         if (!font->font_maps[map_index])
1436                 return false;
1437         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1438 }
1439
1440 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1441 {
1442         while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1443                 start = start->next;
1444         if (start && start->start > ch)
1445                 return NULL;
1446         return start;
1447 }