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