]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
allow loading DXT2 and DXT4 dds files
[divverent/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         font->data = data;
514         if (status)
515         {
516                 Con_Printf("ERROR: can't create face for %s\n"
517                            "Error %i\n", // TODO: error strings
518                            name, status);
519                 Font_UnloadFont(font);
520                 return false;
521         }
522
523         // add the attachments
524         for (i = 0; i < font->attachmentcount; ++i)
525         {
526                 FT_Open_Args args;
527                 memset(&args, 0, sizeof(args));
528                 args.flags = FT_OPEN_MEMORY;
529                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
530                 args.memory_size = font->attachments[i].size;
531                 if (qFT_Attach_Stream((FT_Face)font->face, &args))
532                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
533         }
534
535         memcpy(font->name, name, namelen+1);
536         font->image_font = false;
537         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
538         return true;
539 }
540
541 void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
542 {
543         int needed, x, y;
544         float gausstable[2*POSTPROCESS_MAXRADIUS+1];
545         qboolean need_gauss  = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
546         qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
547         pp.blur = fnt->settings->blur;
548         pp.outline = fnt->settings->outline;
549         pp.shadowx = fnt->settings->shadowx;
550         pp.shadowy = fnt->settings->shadowy;
551         pp.shadowz = fnt->settings->shadowz;
552         pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
553         pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
554         pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
555         pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
556         pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
557         pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
558         pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
559         pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
560         pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
561         pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
562         if(need_gauss)
563         {
564                 float sum = 0;
565                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
566                         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));
567                 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
568                         sum += gausstable[POSTPROCESS_MAXRADIUS+x];
569                 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
570                         pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
571         }
572         if(need_circle)
573         {
574                 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
575                         for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
576                         {
577                                 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
578                                 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
579                         }
580         }
581         pp.bufwidth = w + pp.padding_l + pp.padding_r;
582         pp.bufheight = h + pp.padding_t + pp.padding_b;
583         pp.bufpitch = pp.bufwidth;
584         needed = pp.bufwidth * pp.bufheight;
585         if(!pp.buf || pp.bufsize < needed * 2)
586         {
587                 if(pp.buf)
588                         Mem_Free(pp.buf);
589                 pp.bufsize = needed * 4;
590                 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
591                 pp.buf2 = pp.buf + needed;
592         }
593 }
594
595 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)
596 {
597         int x, y;
598         Font_Postprocess_Update(fnt, bpp, w, h);
599         if(imagedata)
600         {
601                 // enlarge buffer
602
603                 // perform operation, not exceeding the passed padding values,
604                 // but possibly reducing them
605                 *pad_l = min(*pad_l, pp.padding_l);
606                 *pad_r = min(*pad_r, pp.padding_r);
607                 *pad_t = min(*pad_t, pp.padding_t);
608                 *pad_b = min(*pad_b, pp.padding_b);
609
610                 // calculate gauss table
611                 
612                 // outline the font (RGBA only)
613                 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
614                 {
615                         // this is like mplayer subtitle rendering
616                         // bbuffer, bitmap buffer: this is our font
617                         // abuffer, alpha buffer: this is pp.buf
618                         // tmp: this is pp.buf2
619
620                         // create outline buffer
621                         memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
622                         for(y = -*pad_t; y < h + *pad_b; ++y)
623                                 for(x = -*pad_l; x < w + *pad_r; ++x)
624                                 {
625                                         int x1 = max(-x, -pp.outlinepadding_r);
626                                         int y1 = max(-y, -pp.outlinepadding_b);
627                                         int x2 = min(pp.outlinepadding_l, w-1-x);
628                                         int y2 = min(pp.outlinepadding_t, h-1-y);
629                                         int mx, my;
630                                         int cur = 0;
631                                         int highest = 0;
632                                         for(my = y1; my <= y2; ++my)
633                                                 for(mx = x1; mx <= x2; ++mx)
634                                                 {
635                                                         cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
636                                                         if(cur > highest)
637                                                                 highest = cur;
638                                                 }
639                                         pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
640                                 }
641
642                         // blur the outline buffer
643                         if(pp.blur > 0 || pp.shadowz != 0)
644                         {
645                                 // horizontal blur
646                                 for(y = 0; y < pp.bufheight; ++y)
647                                         for(x = 0; x < pp.bufwidth; ++x)
648                                         {
649                                                 int x1 = max(-x, -pp.blurpadding_rb);
650                                                 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
651                                                 int mx;
652                                                 int blurred = 0;
653                                                 for(mx = x1; mx <= x2; ++mx)
654                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
655                                                 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
656                                         }
657
658                                 // vertical blur
659                                 for(y = 0; y < pp.bufheight; ++y)
660                                         for(x = 0; x < pp.bufwidth; ++x)
661                                         {
662                                                 int y1 = max(-y, -pp.blurpadding_rb);
663                                                 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
664                                                 int my;
665                                                 int blurred = 0;
666                                                 for(my = y1; my <= y2; ++my)
667                                                         blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
668                                                 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
669                                         }
670                         }
671
672                         // paste the outline below the font
673                         for(y = -*pad_t; y < h + *pad_b; ++y)
674                                 for(x = -*pad_l; x < w + *pad_r; ++x)
675                                 {
676                                         unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
677                                         if(outlinealpha > 0)
678                                         {
679                                                 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
680                                                 // a' = 1 - (1 - a1) (1 - a2)
681                                                 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
682                                                 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
683                                                 unsigned char oldfactor     = (255 * (int)oldalpha) / newalpha;
684                                                 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
685                                                 int i;
686                                                 for(i = 0; i < bpp-1; ++i)
687                                                 {
688                                                         unsigned char c = imagedata[x * bpp + pitch * y + i];
689                                                         c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
690                                                         imagedata[x * bpp + pitch * y + i] = c;
691                                                 }
692                                                 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
693                                         }
694                                         //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
695                                 }
696                 }
697         }
698         else
699         {
700                 // just calculate parameters
701                 *pad_l = pp.padding_l;
702                 *pad_r = pp.padding_r;
703                 *pad_t = pp.padding_t;
704                 *pad_b = pp.padding_b;
705         }
706 }
707
708 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
709 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
710 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
711 {
712         int map_index;
713         ft2_font_map_t *fmap, temp;
714         int gpad_l, gpad_r, gpad_t, gpad_b;
715
716         if (!(size > 0.001f && size < 1000.0f))
717                 size = 0;
718
719         if (!size)
720                 size = 16;
721         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
722                 return false;
723
724         for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
725         {
726                 if (!font->font_maps[map_index])
727                         break;
728                 // if a similar size has already been loaded, ignore this one
729                 //abs(font->font_maps[map_index]->size - size) < 4
730                 if (font->font_maps[map_index]->size == size)
731                         return true;
732         }
733
734         if (map_index >= MAX_FONT_SIZES)
735                 return false;
736
737         if (check_only) {
738                 FT_Face fontface;
739                 if (font->image_font)
740                         fontface = (FT_Face)font->next->face;
741                 else
742                         fontface = (FT_Face)font->face;
743                 return (Font_SearchSize(font, fontface, size) > 0);
744         }
745
746         Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
747
748         memset(&temp, 0, sizeof(temp));
749         temp.size = size;
750         temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
751         temp.sfx = (1.0/64.0)/(double)size;
752         temp.sfy = (1.0/64.0)/(double)size;
753         temp.intSize = -1; // negative value: LoadMap must search now :)
754         if (!Font_LoadMap(font, &temp, 0, &fmap))
755         {
756                 Con_Printf("ERROR: can't load the first character map for %s\n"
757                            "This is fatal\n",
758                            font->name);
759                 Font_UnloadFont(font);
760                 return false;
761         }
762         font->font_maps[map_index] = temp.next;
763
764         fmap->sfx = temp.sfx;
765         fmap->sfy = temp.sfy;
766
767         // load the default kerning vector:
768         if (font->has_kerning)
769         {
770                 Uchar l, r;
771                 FT_Vector kernvec;
772                 for (l = 0; l < 256; ++l)
773                 {
774                         for (r = 0; r < 256; ++r)
775                         {
776                                 FT_ULong ul, ur;
777                                 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
778                                 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
779                                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
780                                 {
781                                         fmap->kerning.kerning[l][r][0] = 0;
782                                         fmap->kerning.kerning[l][r][1] = 0;
783                                 }
784                                 else
785                                 {
786                                         fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
787                                         fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
788                                 }
789                         }
790                 }
791         }
792         return true;
793 }
794
795 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
796 {
797         int match = -1;
798         int value = 1000000;
799         int nval;
800         int matchsize = -10000;
801         int m;
802         float fsize_x, fsize_y;
803         ft2_font_map_t **maps = font->font_maps;
804
805         fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
806         if(outw && *outw)
807                 fsize_x = *outw * vid.width / vid_conwidth.value;
808         if(outh && *outh)
809                 fsize_y = *outh * vid.height / vid_conheight.value;
810
811         if (fsize_x < 0)
812         {
813                 if(fsize_y < 0)
814                         fsize_x = fsize_y = 16;
815                 else
816                         fsize_x = fsize_y;
817         }
818         else
819         {
820                 if(fsize_y < 0)
821                         fsize_y = fsize_x;
822         }
823
824         for (m = 0; m < MAX_FONT_SIZES; ++m)
825         {
826                 if (!maps[m])
827                         continue;
828                 // "round up" to the bigger size if two equally-valued matches exist
829                 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
830                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
831                 {
832                         value = nval;
833                         match = m;
834                         matchsize = maps[m]->size;
835                         if (value == 0) // there is no better match
836                                 break;
837                 }
838         }
839         if (value <= r_font_size_snapping.value)
840         {
841                 // do NOT keep the aspect for perfect rendering
842                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
843                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
844         }
845         return match;
846 }
847
848 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
849 {
850         if (index < 0 || index >= MAX_FONT_SIZES)
851                 return NULL;
852         return font->font_maps[index];
853 }
854
855 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
856 {
857         if (font->currenth == h &&
858             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
859              font->currentw == w)) // same size has been requested
860         {
861                 return true;
862         }
863         // sorry, but freetype doesn't seem to care about other sizes
864         w = (int)w;
865         h = (int)h;
866         if (font->image_font)
867         {
868                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
869                         return false;
870         }
871         else
872         {
873                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
874                         return false;
875         }
876         font->currentw = w;
877         font->currenth = h;
878         return true;
879 }
880
881 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
882 {
883         ft2_font_map_t *fmap;
884         if (!font->has_kerning || !r_font_kerning.integer)
885                 return false;
886         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
887                 return false;
888         fmap = font->font_maps[map_index];
889         if (!fmap)
890                 return false;
891         if (left < 256 && right < 256)
892         {
893                 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
894                 // quick-kerning, be aware of the size: scale it
895                 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
896                 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
897                 return true;
898         }
899         else
900         {
901                 FT_Vector kernvec;
902                 FT_ULong ul, ur;
903
904                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
905 #if 0
906                 if (!Font_SetSize(font, w, h))
907                 {
908                         // this deserves an error message
909                         Con_Printf("Failed to get kerning for %s\n", font->name);
910                         return false;
911                 }
912                 ul = qFT_Get_Char_Index(font->face, left);
913                 ur = qFT_Get_Char_Index(font->face, right);
914                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
915                 {
916                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
917                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
918                         return true;
919                 }
920 #endif
921                 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
922                 {
923                         // this deserves an error message
924                         Con_Printf("Failed to get kerning for %s\n", font->name);
925                         return false;
926                 }
927                 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
928                 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
929                 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
930                 {
931                         if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
932                         if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
933                         return true;
934                 }
935                 return false;
936         }
937 }
938
939 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
940 {
941         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
942 }
943
944 static void UnloadMapRec(ft2_font_map_t *map)
945 {
946         if (map->texture)
947         {
948                 R_FreeTexture(map->texture);
949                 map->texture = NULL;
950         }
951         if (map->next)
952                 UnloadMapRec(map->next);
953         Mem_Free(map);
954 }
955
956 void Font_UnloadFont(ft2_font_t *font)
957 {
958         int i;
959
960         // unload fallbacks
961         if(font->next)
962                 Font_UnloadFont(font->next);
963
964         if (font->attachments && font->attachmentcount)
965         {
966                 for (i = 0; i < (int)font->attachmentcount; ++i) {
967                         if (font->attachments[i].data)
968                                 Mem_Free(font->attachments[i].data);
969                 }
970                 Mem_Free(font->attachments);
971                 font->attachmentcount = 0;
972                 font->attachments = NULL;
973         }
974         for (i = 0; i < MAX_FONT_SIZES; ++i)
975         {
976                 if (font->font_maps[i])
977                 {
978                         UnloadMapRec(font->font_maps[i]);
979                         font->font_maps[i] = NULL;
980                 }
981         }
982         if (ft2_dll)
983         {
984                 if (font->face)
985                 {
986                         qFT_Done_Face((FT_Face)font->face);
987                         font->face = NULL;
988                 }
989         }
990         if (font->data) {
991             Mem_Free(font->data);
992             font->data = NULL;
993         }
994 }
995
996 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
997 {
998         float intSize = size;
999         while (1)
1000         {
1001                 if (!Font_SetSize(font, intSize, intSize))
1002                 {
1003                         Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1004                         return -1;
1005                 }
1006                 if ((fontface->size->metrics.height>>6) <= size)
1007                         return intSize;
1008                 if (intSize < 2)
1009                 {
1010                         Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1011                         return -1;
1012                 }
1013                 --intSize;
1014         }
1015 }
1016
1017 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1018 {
1019         char map_identifier[MAX_QPATH];
1020         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1021         unsigned char *data;
1022         FT_ULong ch, mapch;
1023         int status;
1024         int tp;
1025         FT_Int32 load_flags;
1026         int gpad_l, gpad_r, gpad_t, gpad_b;
1027
1028         int pitch;
1029         int gR, gC; // glyph position: row and column
1030
1031         ft2_font_map_t *map, *next;
1032         ft2_font_t *usefont;
1033
1034         FT_Face fontface;
1035
1036         int bytesPerPixel = 4; // change the conversion loop too if you change this!
1037
1038         if (outmap)
1039                 *outmap = NULL;
1040
1041         if (r_font_use_alpha_textures.integer)
1042                 bytesPerPixel = 1;
1043
1044         if (font->image_font)
1045                 fontface = (FT_Face)font->next->face;
1046         else
1047                 fontface = (FT_Face)font->face;
1048
1049         switch(font->settings->antialias)
1050         {
1051                 case 0:
1052                         switch(font->settings->hinting)
1053                         {
1054                                 case 0:
1055                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1056                                         break;
1057                                 case 1:
1058                                 case 2:
1059                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1060                                         break;
1061                                 default:
1062                                 case 3:
1063                                         load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1064                                         break;
1065                         }
1066                         break;
1067                 default:
1068                 case 1:
1069                         switch(font->settings->hinting)
1070                         {
1071                                 case 0:
1072                                         load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1073                                         break;
1074                                 case 1:
1075                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1076                                         break;
1077                                 case 2:
1078                                         load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1079                                         break;
1080                                 default:
1081                                 case 3:
1082                                         load_flags = FT_LOAD_TARGET_NORMAL;
1083                                         break;
1084                         }
1085                         break;
1086         }
1087
1088         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1089         //if (status)
1090         if (font->image_font && mapstart->intSize < 0)
1091                 mapstart->intSize = mapstart->size;
1092         if (mapstart->intSize < 0)
1093         {
1094                 /*
1095                 mapstart->intSize = mapstart->size;
1096                 while (1)
1097                 {
1098                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1099                         {
1100                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1101                                 return false;
1102                         }
1103                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
1104                                 break;
1105                         if (mapstart->intSize < 2)
1106                         {
1107                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1108                                 return false;
1109                         }
1110                         --mapstart->intSize;
1111                 }
1112                 */
1113                 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1114                         return false;
1115                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1116         }
1117
1118         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1119         {
1120                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1121                 return false;
1122         }
1123
1124         map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1125         if (!map)
1126         {
1127                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1128                 return false;
1129         }
1130
1131         Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1132
1133         // copy over the information
1134         map->size = mapstart->size;
1135         map->intSize = mapstart->intSize;
1136         map->glyphSize = mapstart->glyphSize;
1137         map->sfx = mapstart->sfx;
1138         map->sfy = mapstart->sfy;
1139
1140         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1141         data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1142         if (!data)
1143         {
1144                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1145                 Mem_Free(map);
1146                 return false;
1147         }
1148         memset(map->width_of, 0, sizeof(map->width_of));
1149
1150         // initialize as white texture with zero alpha
1151         tp = 0;
1152         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1153         {
1154                 if (bytesPerPixel == 4)
1155                 {
1156                         data[tp++] = 0xFF;
1157                         data[tp++] = 0xFF;
1158                         data[tp++] = 0xFF;
1159                 }
1160                 data[tp++] = 0x00;
1161         }
1162
1163         // insert the map
1164         map->start = mapidx * FONT_CHARS_PER_MAP;
1165         next = mapstart;
1166         while(next->next && next->next->start < map->start)
1167                 next = next->next;
1168         map->next = next->next;
1169         next->next = map;
1170
1171         gR = 0;
1172         gC = -1;
1173         for (ch = map->start;
1174              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1175              ++ch)
1176         {
1177                 FT_ULong glyphIndex;
1178                 int w, h, x, y;
1179                 FT_GlyphSlot glyph;
1180                 FT_Bitmap *bmp;
1181                 unsigned char *imagedata, *dst, *src;
1182                 glyph_slot_t *mapglyph;
1183                 FT_Face face;
1184                 int pad_l, pad_r, pad_t, pad_b;
1185
1186                 mapch = ch - map->start;
1187
1188                 if (developer_font.integer)
1189                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1190
1191                 ++gC;
1192                 if (gC >= FONT_CHARS_PER_LINE)
1193                 {
1194                         gC -= FONT_CHARS_PER_LINE;
1195                         ++gR;
1196                 }
1197
1198                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1199                 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1200                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1201                 // we need the glyphIndex
1202                 face = (FT_Face)font->face;
1203                 usefont = NULL;
1204                 if (font->image_font && mapch == ch && img_fontmap[mapch])
1205                 {
1206                         map->glyphs[mapch].image = true;
1207                         continue;
1208                 }
1209                 glyphIndex = qFT_Get_Char_Index(face, ch);
1210                 if (glyphIndex == 0)
1211                 {
1212                         // by convention, 0 is the "missing-glyph"-glyph
1213                         // try to load from a fallback font
1214                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1215                         {
1216                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1217                                         continue;
1218                                 // try that glyph
1219                                 face = (FT_Face)usefont->face;
1220                                 glyphIndex = qFT_Get_Char_Index(face, ch);
1221                                 if (glyphIndex == 0)
1222                                         continue;
1223                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1224                                 if (status)
1225                                         continue;
1226                                 break;
1227                         }
1228                         if (!usefont)
1229                         {
1230                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1231                                 // now we let it use the "missing-glyph"-glyph
1232                                 face = (FT_Face)font->face;
1233                                 glyphIndex = 0;
1234                         }
1235                 }
1236
1237                 if (!usefont)
1238                 {
1239                         usefont = font;
1240                         face = (FT_Face)font->face;
1241                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1242                         if (status)
1243                         {
1244                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1245                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1246                                 continue;
1247                         }
1248                 }
1249
1250                 glyph = face->glyph;
1251                 bmp = &glyph->bitmap;
1252
1253                 w = bmp->width;
1254                 h = bmp->rows;
1255
1256                 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1257                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1258                         if (w > map->glyphSize)
1259                                 w = map->glyphSize - gpad_l - gpad_r;
1260                         if (h > map->glyphSize)
1261                                 h = map->glyphSize;
1262                 }
1263
1264                 switch (bmp->pixel_mode)
1265                 {
1266                 case FT_PIXEL_MODE_MONO:
1267                         if (developer_font.integer)
1268                                 Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1269                         break;
1270                 case FT_PIXEL_MODE_GRAY2:
1271                         if (developer_font.integer)
1272                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1273                         break;
1274                 case FT_PIXEL_MODE_GRAY4:
1275                         if (developer_font.integer)
1276                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1277                         break;
1278                 case FT_PIXEL_MODE_GRAY:
1279                         if (developer_font.integer)
1280                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1281                         break;
1282                 default:
1283                         if (developer_font.integer)
1284                                 Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1285                         Mem_Free(data);
1286                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1287                         return false;
1288                 }
1289                 for (y = 0; y < h; ++y)
1290                 {
1291                         dst = imagedata + y * pitch;
1292                         src = bmp->buffer + y * bmp->pitch;
1293
1294                         switch (bmp->pixel_mode)
1295                         {
1296                         case FT_PIXEL_MODE_MONO:
1297                                 dst += bytesPerPixel - 1; // shift to alpha byte
1298                                 for (x = 0; x < bmp->width; x += 8)
1299                                 {
1300                                         unsigned char ch = *src++;
1301                                         *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1302                                         *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1303                                         *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1304                                         *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1305                                         *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1306                                         *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1307                                         *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1308                                         *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1309                                 }
1310                                 break;
1311                         case FT_PIXEL_MODE_GRAY2:
1312                                 dst += bytesPerPixel - 1; // shift to alpha byte
1313                                 for (x = 0; x < bmp->width; x += 4)
1314                                 {
1315                                         unsigned char ch = *src++;
1316                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1317                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1318                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1319                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1320                                 }
1321                                 break;
1322                         case FT_PIXEL_MODE_GRAY4:
1323                                 dst += bytesPerPixel - 1; // shift to alpha byte
1324                                 for (x = 0; x < bmp->width; x += 2)
1325                                 {
1326                                         unsigned char ch = *src++;
1327                                         *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1328                                         *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1329                                 }
1330                                 break;
1331                         case FT_PIXEL_MODE_GRAY:
1332                                 // in this case pitch should equal width
1333                                 for (tp = 0; tp < bmp->pitch; ++tp)
1334                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1335
1336                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1337                                 //dst += bmp->pitch;
1338                                 break;
1339                         default:
1340                                 break;
1341                         }
1342                 }
1343
1344                 pad_l = gpad_l;
1345                 pad_r = gpad_r;
1346                 pad_t = gpad_t;
1347                 pad_b = gpad_b;
1348                 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1349
1350                 // now fill map->glyphs[ch - map->start]
1351                 mapglyph = &map->glyphs[mapch];
1352
1353                 {
1354                         // old way
1355                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1356
1357                         double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1358                         //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1359                         double advance = (glyph->advance.x / 64.0) / map->size;
1360                         //double mWidth = (glyph->metrics.width >> 6) / map->size;
1361                         //double mHeight = (glyph->metrics.height >> 6) / map->size;
1362
1363                         mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1364                         mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1365                         mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1366                         mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1367                         //mapglyph->vxmin = bearingX;
1368                         //mapglyph->vxmax = bearingX + mWidth;
1369                         mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1370                         mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1371                         //mapglyph->vymin = -bearingY;
1372                         //mapglyph->vymax = mHeight - bearingY;
1373                         mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1374                         mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1375                         //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);
1376                         //mapglyph->advance_x = advance * usefont->size;
1377                         //mapglyph->advance_x = advance;
1378                         mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1379                         mapglyph->advance_y = 0;
1380
1381                         if (developer_font.integer)
1382                         {
1383                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1384                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1385                                 if (ch >= 32 && ch <= 128)
1386                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1387                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1388                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1389                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1390                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1391                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1392                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1393                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1394                         }
1395                 }
1396                 map->glyphs[mapch].image = false;
1397         }
1398
1399         // create a texture from the data now
1400
1401         if (developer_font.integer > 100)
1402         {
1403                 // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
1404                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1405                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1406                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1407         }
1408         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1409
1410         // probably use bytesPerPixel here instead?
1411         if (r_font_use_alpha_textures.integer)
1412         {
1413                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1414                                                map->glyphSize * FONT_CHARS_PER_LINE,
1415                                                map->glyphSize * FONT_CHAR_LINES,
1416                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1417         } else {
1418                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1419                                                map->glyphSize * FONT_CHARS_PER_LINE,
1420                                                map->glyphSize * FONT_CHAR_LINES,
1421                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1422         }
1423
1424         Mem_Free(data);
1425         if (!map->texture)
1426         {
1427                 // if the first try isn't successful, keep it with a broken texture
1428                 // otherwise we retry to load it every single frame where ft2 rendering is used
1429                 // this would be bad...
1430                 // only `data' must be freed
1431                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1432                            font->name, mapstart->size, mapidx);
1433                 return false;
1434         }
1435         if (outmap)
1436                 *outmap = map;
1437         return true;
1438 }
1439
1440 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1441 {
1442         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1443                 return false;
1444         // the first map must have been loaded already
1445         if (!font->font_maps[map_index])
1446                 return false;
1447         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1448 }
1449
1450 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1451 {
1452         while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1453                 start = start->next;
1454         if (start && start->start > ch)
1455                 return NULL;
1456         return start;
1457 }