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