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