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