]> git.xonotic.org Git - xonotic/darkplaces.git/blob - ft2.c
cvar: r_font_autohinting added
[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_autohinting = {CVAR_SAVE, "r_font_autohinting", "1", "enable autohinting if possible"};
39
40 /*
41 ================================================================================
42 Function definitions. Taken from the freetype2 headers.
43 ================================================================================
44 */
45
46
47 FT_EXPORT( FT_Error )
48 (*qFT_Init_FreeType)( FT_Library  *alibrary );
49 FT_EXPORT( FT_Error )
50 (*qFT_Done_FreeType)( FT_Library  library );
51 /*
52 FT_EXPORT( FT_Error )
53 (*qFT_New_Face)( FT_Library   library,
54                  const char*  filepathname,
55                  FT_Long      face_index,
56                  FT_Face     *aface );
57 */
58 FT_EXPORT( FT_Error )
59 (*qFT_New_Memory_Face)( FT_Library      library,
60                         const FT_Byte*  file_base,
61                         FT_Long         file_size,
62                         FT_Long         face_index,
63                         FT_Face        *aface );
64 FT_EXPORT( FT_Error )
65 (*qFT_Done_Face)( FT_Face  face );
66 FT_EXPORT( FT_Error )
67 (*qFT_Select_Size)( FT_Face  face,
68                     FT_Int   strike_index );
69 FT_EXPORT( FT_Error )
70 (*qFT_Request_Size)( FT_Face          face,
71                      FT_Size_Request  req );
72 FT_EXPORT( FT_Error )
73 (*qFT_Set_Char_Size)( FT_Face     face,
74                       FT_F26Dot6  char_width,
75                       FT_F26Dot6  char_height,
76                       FT_UInt     horz_resolution,
77                       FT_UInt     vert_resolution );
78 FT_EXPORT( FT_Error )
79 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
80                         FT_UInt  pixel_width,
81                         FT_UInt  pixel_height );
82 FT_EXPORT( FT_Error )
83 (*qFT_Load_Glyph)( FT_Face   face,
84                    FT_UInt   glyph_index,
85                    FT_Int32  load_flags );
86 FT_EXPORT( FT_Error )
87 (*qFT_Load_Char)( FT_Face   face,
88                   FT_ULong  char_code,
89                   FT_Int32  load_flags );
90 FT_EXPORT( FT_UInt )
91 (*qFT_Get_Char_Index)( FT_Face   face,
92                        FT_ULong  charcode );
93 FT_EXPORT( FT_Error )
94 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
95                      FT_Render_Mode  render_mode );
96 FT_EXPORT( FT_Error )
97 (*qFT_Get_Kerning)( FT_Face     face,
98                     FT_UInt     left_glyph,
99                     FT_UInt     right_glyph,
100                     FT_UInt     kern_mode,
101                     FT_Vector  *akerning );
102 FT_EXPORT( FT_Error )
103 (*qFT_Attach_Stream)( FT_Face        face,
104                       FT_Open_Args*  parameters );
105 /*
106 ================================================================================
107 Support for dynamically loading the FreeType2 library
108 ================================================================================
109 */
110
111 static dllfunction_t ft2funcs[] =
112 {
113         {"FT_Init_FreeType",            (void **) &qFT_Init_FreeType},
114         {"FT_Done_FreeType",            (void **) &qFT_Done_FreeType},
115         //{"FT_New_Face",                       (void **) &qFT_New_Face},
116         {"FT_New_Memory_Face",          (void **) &qFT_New_Memory_Face},
117         {"FT_Done_Face",                (void **) &qFT_Done_Face},
118         {"FT_Select_Size",              (void **) &qFT_Select_Size},
119         {"FT_Request_Size",             (void **) &qFT_Request_Size},
120         {"FT_Set_Char_Size",            (void **) &qFT_Set_Char_Size},
121         {"FT_Set_Pixel_Sizes",          (void **) &qFT_Set_Pixel_Sizes},
122         {"FT_Load_Glyph",               (void **) &qFT_Load_Glyph},
123         {"FT_Load_Char",                (void **) &qFT_Load_Char},
124         {"FT_Get_Char_Index",           (void **) &qFT_Get_Char_Index},
125         {"FT_Render_Glyph",             (void **) &qFT_Render_Glyph},
126         {"FT_Get_Kerning",              (void **) &qFT_Get_Kerning},
127         {"FT_Attach_Stream",            (void **) &qFT_Attach_Stream},
128         {NULL, NULL}
129 };
130
131 /// Handle for FreeType2 DLL
132 static dllhandle_t ft2_dll = NULL;
133
134 /// Memory pool for fonts
135 static mempool_t *font_mempool= NULL;
136 static rtexturepool_t *font_texturepool = NULL;
137
138 /// FreeType library handle
139 static FT_Library font_ft2lib = NULL;
140
141 /*
142 ====================
143 Font_CloseLibrary
144
145 Unload the FreeType2 DLL
146 ====================
147 */
148 void Font_CloseLibrary (void)
149 {
150         if (font_mempool)
151                 Mem_FreePool(&font_mempool);
152         if (font_texturepool)
153                 R_FreeTexturePool(&font_texturepool);
154         if (font_ft2lib && qFT_Done_FreeType)
155         {
156                 qFT_Done_FreeType(font_ft2lib);
157                 font_ft2lib = NULL;
158         }
159         Sys_UnloadLibrary (&ft2_dll);
160 }
161
162 /*
163 ====================
164 Font_OpenLibrary
165
166 Try to load the FreeType2 DLL
167 ====================
168 */
169 qboolean Font_OpenLibrary (void)
170 {
171         const char* dllnames [] =
172         {
173 #if defined(WIN32)
174                 "freetype6.dll",
175 #elif defined(MACOSX)
176                 "libfreetype.dylib",
177 #else
178                 "libfreetype.so.6",
179                 "libfreetype.so",
180 #endif
181                 NULL
182         };
183
184         if (r_font_disable_freetype.integer)
185                 return false;
186
187         // Already loaded?
188         if (ft2_dll)
189                 return true;
190
191         // Load the DLL
192         if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
193                 return false;
194         return true;
195 }
196
197 /*
198 ====================
199 Font_Init
200
201 Initialize the freetype2 font subsystem
202 ====================
203 */
204
205 void font_start(void)
206 {
207         if (!Font_OpenLibrary())
208                 return;
209
210         if (qFT_Init_FreeType(&font_ft2lib))
211         {
212                 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
213                 Font_CloseLibrary();
214                 return;
215         }
216
217         font_mempool = Mem_AllocPool("FONT", 0, NULL);
218         if (!font_mempool)
219         {
220                 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
221                 Font_CloseLibrary();
222                 return;
223         }
224
225         font_texturepool = R_AllocTexturePool();
226         if (!font_texturepool)
227         {
228                 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
229                 Font_CloseLibrary();
230                 return;
231         }
232 }
233
234 void font_shutdown(void)
235 {
236         int i;
237         for (i = 0; i < MAX_FONTS; ++i)
238         {
239                 if (dp_fonts[i].ft2)
240                 {
241                         Font_UnloadFont(dp_fonts[i].ft2);
242                         dp_fonts[i].ft2 = NULL;
243                 }
244         }
245         Font_CloseLibrary();
246 }
247
248 void font_newmap(void)
249 {
250 }
251
252 void Font_Init(void)
253 {
254         Cvar_RegisterVariable(&r_font_disable_freetype);
255         Cvar_RegisterVariable(&r_font_use_alpha_textures);
256         Cvar_RegisterVariable(&r_font_size_snapping);
257         Cvar_RegisterVariable(&r_font_autohinting);
258 }
259
260 /*
261 ================================================================================
262 Implementation of a more or less lazy font loading and rendering code.
263 ================================================================================
264 */
265
266 #include "ft2_fontdefs.h"
267
268 ft2_font_t *Font_Alloc(void)
269 {
270         if (!ft2_dll)
271                 return NULL;
272         return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
273 }
274
275 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
276 {
277         ft2_attachment_t *na;
278
279         font->attachmentcount++;
280         na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
281         if (na == NULL)
282                 return false;
283         if (font->attachments && font->attachmentcount > 1)
284         {
285                 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
286                 Mem_Free(font->attachments);
287         }
288         memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
289         font->attachments = na;
290         return true;
291 }
292
293 static float Font_VirtualToRealSize(float sz)
294 {
295         int vh, vw, si;
296         float sn;
297         if(sz < 0)
298                 return sz;
299         vw = ((vid.width > 0) ? vid.width : vid_width.value);
300         vh = ((vid.height > 0) ? vid.height : vid_height.value);
301         // now try to scale to our actual size:
302         sn = sz * vh / vid_conheight.value;
303         si = (int)sn;
304         if ( sn - (float)si >= 0.5 )
305                 ++si;
306         return si;
307 }
308
309 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
310 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
311 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
312 {
313         int s, count, i;
314         ft2_font_t *ft2, *fbfont, *fb;
315
316         ft2 = Font_Alloc();
317         if (!ft2)
318         {
319                 dpfnt->ft2 = NULL;
320                 return false;
321         }
322
323         // check if a fallback font has been specified, if it has been, and the
324         // font fails to load, use the image font as main font
325         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
326         {
327                 if (dpfnt->fallbacks[i][0])
328                         break;
329         }
330
331         if (!Font_LoadFile(name, dpfnt->req_face, ft2))
332         {
333                 if (i >= MAX_FONT_FALLBACKS)
334                 {
335                         dpfnt->ft2 = NULL;
336                         Mem_Free(ft2);
337                         return false;
338                 }
339                 strlcpy(ft2->name, name, sizeof(ft2->name));
340                 ft2->image_font = true;
341                 ft2->has_kerning = false;
342         }
343         else
344         {
345                 ft2->image_font = false;
346         }
347
348         // attempt to load fallback fonts:
349         fbfont = ft2;
350         for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
351         {
352                 if (!dpfnt->fallbacks[i][0])
353                         break;
354                 if (! (fb = Font_Alloc()) )
355                 {
356                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
357                         break;
358                 }
359                 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
360                 {
361                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
362                         Mem_Free(fb);
363                         break;
364                 }
365                 count = 0;
366                 for (s = 0; s < MAX_FONT_SIZES; ++s)
367                 {
368                         if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
369                                 ++count;
370                 }
371                 if (!count)
372                 {
373                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
374                         Font_UnloadFont(fb);
375                         Mem_Free(fb);
376                         break;
377                 }
378                 // at least one size of the fallback font loaded successfully
379                 // link it:
380                 fbfont->next = fb;
381                 fbfont = fb;
382         }
383
384         if (fbfont == ft2 && ft2->image_font)
385         {
386                 // no fallbacks were loaded successfully:
387                 dpfnt->ft2 = NULL;
388                 Mem_Free(ft2);
389                 return false;
390         }
391
392         count = 0;
393         for (s = 0; s < MAX_FONT_SIZES; ++s)
394         {
395                 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
396                         ++count;
397         }
398         if (!count)
399         {
400                 // loading failed for every requested size
401                 Font_UnloadFont(ft2);
402                 Mem_Free(ft2);
403                 dpfnt->ft2 = NULL;
404                 return false;
405         }
406
407         //Con_Printf("%i sizes loaded\n", count);
408         dpfnt->ft2 = ft2;
409         return true;
410 }
411
412 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
413 {
414         size_t namelen;
415         char filename[MAX_QPATH];
416         int status;
417         size_t i;
418         unsigned char *data;
419         fs_offset_t datasize;
420
421         memset(font, 0, sizeof(*font));
422
423         if (!Font_OpenLibrary())
424         {
425                 if (!r_font_disable_freetype.integer)
426                 {
427                         Con_Printf("WARNING: can't open load font %s\n"
428                                    "You need the FreeType2 DLL to load font files\n",
429                                    name);
430                 }
431                 return false;
432         }
433
434         namelen = strlen(name);
435
436         memcpy(filename, name, namelen);
437         memcpy(filename + namelen, ".ttf", 5);
438         data = FS_LoadFile(filename, font_mempool, false, &datasize);
439         if (!data)
440         {
441                 memcpy(filename + namelen, ".otf", 5);
442                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
443         }
444         if (!data)
445         {
446                 ft2_attachment_t afm;
447
448                 memcpy(filename + namelen, ".pfb", 5);
449                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
450
451                 if (data)
452                 {
453                         memcpy(filename + namelen, ".afm", 5);
454                         afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
455
456                         if (afm.data)
457                                 Font_Attach(font, &afm);
458                 }
459         }
460
461         if (!data)
462         {
463                 // FS_LoadFile being not-quiet should print an error :)
464                 return false;
465         }
466         Con_Printf("Loading font %s face %i...\n", filename, _face);
467
468         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
469         if (status && _face != 0)
470         {
471                 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
472                 _face = 0;
473                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
474         }
475         if (status)
476         {
477                 Con_Printf("ERROR: can't create face for %s\n"
478                            "Error %i\n", // TODO: error strings
479                            name, status);
480                 Font_UnloadFont(font);
481                 return false;
482         }
483
484         // add the attachments
485         for (i = 0; i < font->attachmentcount; ++i)
486         {
487                 FT_Open_Args args;
488                 memset(&args, 0, sizeof(args));
489                 args.flags = FT_OPEN_MEMORY;
490                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
491                 args.memory_size = font->attachments[i].size;
492                 if (qFT_Attach_Stream(font->face, &args))
493                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
494         }
495
496         memcpy(font->name, name, namelen+1);
497         font->image_font = false;
498         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
499         return true;
500 }
501
502 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
503 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
504 {
505         int map_index;
506         ft2_font_map_t *fmap, temp;
507
508         if (!(size > 0.001f && size < 1000.0f))
509                 size = 0;
510
511         if (!size)
512                 size = 16;
513         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
514                 return false;
515
516         if (!no_texture)
517         {
518                 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
519                 {
520                         if (!font->font_maps[map_index])
521                                 break;
522                         // if a similar size has already been loaded, ignore this one
523                         //abs(font->font_maps[map_index]->size - size) < 4
524                         if (font->font_maps[map_index]->size == size)
525                                 return true;
526                 }
527
528                 if (map_index >= MAX_FONT_SIZES)
529                         return false;
530
531                 memset(&temp, 0, sizeof(temp));
532                 temp.size = size;
533                 temp.glyphSize = CeilPowerOf2(size*2);
534                 temp.sfx = (1.0/64.0)/(double)size;
535                 temp.sfy = (1.0/64.0)/(double)size;
536                 temp.intSize = -1; // negative value: LoadMap must search now :)
537                 if (!Font_LoadMap(font, &temp, 0, &fmap))
538                 {
539                         Con_Printf("ERROR: can't load the first character map for %s\n"
540                                    "This is fatal\n",
541                                    font->name);
542                         Font_UnloadFont(font);
543                         return false;
544                 }
545                 font->font_maps[map_index] = temp.next;
546
547                 fmap->sfx = temp.sfx;
548                 fmap->sfy = temp.sfy;
549         }
550         if (!no_kerning)
551         {
552                 // load the default kerning vector:
553                 if (font->has_kerning)
554                 {
555                         Uchar l, r;
556                         FT_Vector kernvec;
557                         for (l = 0; l < 256; ++l)
558                         {
559                                 for (r = 0; r < 256; ++r)
560                                 {
561                                         FT_ULong ul, ur;
562                                         ul = qFT_Get_Char_Index(font->face, l);
563                                         ur = qFT_Get_Char_Index(font->face, r);
564                                         if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
565                                         {
566                                                 fmap->kerning.kerning[l][r][0] = 0;
567                                                 fmap->kerning.kerning[l][r][1] = 0;
568                                         }
569                                         else
570                                         {
571                                                 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
572                                                 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
573                                         }
574                                 }
575                         }
576                 }
577         }
578
579         return true;
580 }
581
582 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
583 {
584         int match = -1;
585         int value = 1000000;
586         int nval;
587         int matchsize = -10000;
588         int m;
589         int size;
590         float fsize;
591         ft2_font_map_t **maps = font->font_maps;
592
593         fsize = _fsize * vid.height / vid_conheight.value;
594
595         if (fsize < 0)
596                 size = 16;
597         else
598         {
599                 // round up
600                 size = (int)fsize;
601                 if (fsize - (float)size >= 0.49)
602                         ++size;
603         }
604
605         for (m = 0; m < MAX_FONT_SIZES; ++m)
606         {
607                 if (!maps[m])
608                         continue;
609                 // "round up" to the bigger size if two equally-valued matches exist
610                 nval = abs(maps[m]->size - size);
611                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
612                 {
613                         value = nval;
614                         match = m;
615                         matchsize = maps[m]->size;
616                         if (value == 0) // there is no better match
617                                 break;
618                 }
619         }
620         if (value <= r_font_size_snapping.value)
621         {
622                 if (outw && outh)
623                 {
624                         if (!*outh) *outh = *outw;
625                         if (!*outw) *outw = *outh;
626                 }
627                 // keep the aspect
628                 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
629                 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
630         }
631         return match;
632 }
633
634 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
635 {
636         if (index < 0 || index >= MAX_FONT_SIZES)
637                 return NULL;
638         return font->font_maps[index];
639 }
640
641 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
642 {
643         if (font->currenth == h &&
644             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
645              font->currentw == w)) // same size has been requested
646         {
647                 return true;
648         }
649         // sorry, but freetype doesn't seem to care about other sizes
650         w = (int)w;
651         h = (int)h;
652         if (font->image_font)
653         {
654                 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
655                         return false;
656         }
657         else
658         {
659                 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
660                         return false;
661         }
662         font->currentw = w;
663         font->currenth = h;
664         return true;
665 }
666
667 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
668 {
669         ft2_font_map_t *fmap;
670         if (!font->has_kerning)
671                 return false;
672         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
673                 return false;
674         fmap = font->font_maps[map_index];
675         if (!fmap)
676                 return false;
677         if (left < 256 && right < 256)
678         {
679                 // quick-kerning, be aware of the size: scale it
680                 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
681                 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
682                 return true;
683         }
684         else
685         {
686                 FT_Vector kernvec;
687                 FT_ULong ul, ur;
688
689                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
690                 if (!Font_SetSize(font, w, h))
691                 {
692                         // this deserves an error message
693                         Con_Printf("Failed to get kerning for %s\n", font->name);
694                         return false;
695                 }
696                 ul = qFT_Get_Char_Index(font->face, left);
697                 ur = qFT_Get_Char_Index(font->face, right);
698                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
699                 {
700                         if (outx) *outx = kernvec.x * fmap->sfx;
701                         if (outy) *outy = kernvec.y * fmap->sfy;
702                         return true;
703                 }
704                 return false;
705         }
706 }
707
708 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
709 {
710         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
711 }
712
713 static void UnloadMapRec(ft2_font_map_t *map)
714 {
715         if (map->texture)
716         {
717                 R_FreeTexture(map->texture);
718                 map->texture = NULL;
719         }
720         if (map->next)
721                 UnloadMapRec(map->next);
722         Mem_Free(map);
723 }
724
725 void Font_UnloadFont(ft2_font_t *font)
726 {
727         int i;
728         if (font->attachments && font->attachmentcount)
729         {
730                 Mem_Free(font->attachments);
731                 font->attachmentcount = 0;
732                 font->attachments = NULL;
733         }
734         for (i = 0; i < MAX_FONT_SIZES; ++i)
735         {
736                 if (font->font_maps[i])
737                 {
738                         UnloadMapRec(font->font_maps[i]);
739                         font->font_maps[i] = NULL;
740                 }
741         }
742         if (ft2_dll)
743         {
744                 if (font->face)
745                 {
746                         qFT_Done_Face((FT_Face)font->face);
747                         font->face = NULL;
748                 }
749         }
750 }
751
752 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
753 {
754         char map_identifier[MAX_QPATH];
755         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
756         unsigned char *data;
757         FT_ULong ch, mapch;
758         int status;
759         int tp;
760         FT_Int32 load_flags;
761
762         int pitch;
763         int gR, gC; // glyph position: row and column
764
765         ft2_font_map_t *map, *next;
766         ft2_font_t *usefont;
767
768         FT_Face fontface;
769
770         int bytesPerPixel = 4; // change the conversion loop too if you change this!
771
772         if (outmap)
773                 *outmap = NULL;
774
775         if (r_font_use_alpha_textures.integer)
776                 bytesPerPixel = 1;
777
778         if (font->image_font)
779                 fontface = (FT_Face)font->next->face;
780         else
781                 fontface = (FT_Face)font->face;
782
783         load_flags = 0;
784         if (r_font_autohinting.integer == 0)
785                 load_flags = FT_LOAD_NO_AUTOHINT;
786         if (r_font_autohinting.integer <= -1)
787                 load_flags |= FT_LOAD_NO_HINTING;
788         if (r_font_autohinting.integer <= -2)
789                 load_flags |= FT_LOAD_NO_AUTOHINT;
790
791         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
792         //if (status)
793         if (font->image_font && mapstart->intSize < 0)
794                 mapstart->intSize = mapstart->size;
795         if (mapstart->intSize < 0)
796         {
797                 mapstart->intSize = mapstart->size;
798                 while (1)
799                 {
800                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
801                         {
802                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
803                                 return false;
804                         }
805                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
806                                 break;
807                         if (mapstart->intSize < 2)
808                         {
809                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
810                                 return false;
811                         }
812                         --mapstart->intSize;
813                 }
814                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
815         }
816
817         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
818         {
819                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
820                 return false;
821         }
822
823         map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
824         if (!map)
825         {
826                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
827                 return false;
828         }
829
830         // copy over the information
831         map->size = mapstart->size;
832         map->intSize = mapstart->intSize;
833         map->glyphSize = mapstart->glyphSize;
834         map->sfx = mapstart->sfx;
835         map->sfy = mapstart->sfy;
836
837         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
838         data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
839         if (!data)
840         {
841                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
842                 Mem_Free(map);
843                 return false;
844         }
845
846         // initialize as white texture with zero alpha
847         tp = 0;
848         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
849         {
850                 if (bytesPerPixel == 4)
851                 {
852                         data[tp++] = 0xFF;
853                         data[tp++] = 0xFF;
854                         data[tp++] = 0xFF;
855                 }
856                 data[tp++] = 0x00;
857         }
858
859         // insert the map
860         map->start = mapidx * FONT_CHARS_PER_MAP;
861         next = mapstart;
862         while(next->next && next->next->start < map->start)
863                 next = next->next;
864         map->next = next->next;
865         next->next = map;
866
867         gR = 0;
868         gC = -1;
869         for (ch = map->start;
870              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
871              ++ch)
872         {
873                 FT_ULong glyphIndex;
874                 int w, h, x, y;
875                 FT_GlyphSlot glyph;
876                 FT_Bitmap *bmp;
877                 unsigned char *imagedata, *dst, *src;
878                 glyph_slot_t *mapglyph;
879                 FT_Face face;
880
881                 mapch = ch - map->start;
882
883                 if (developer_extra.integer)
884                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
885
886                 ++gC;
887                 if (gC >= FONT_CHARS_PER_LINE)
888                 {
889                         gC -= FONT_CHARS_PER_LINE;
890                         ++gR;
891                 }
892
893                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
894                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
895                 // we need the glyphIndex
896                 face = font->face;
897                 usefont = NULL;
898                 if (font->image_font && mapch == ch && img_fontmap[mapch])
899                 {
900                         map->glyphs[mapch].image = true;
901                         continue;
902                 }
903                 glyphIndex = qFT_Get_Char_Index(face, ch);
904                 if (glyphIndex == 0)
905                 {
906                         // by convention, 0 is the "missing-glyph"-glyph
907                         // try to load from a fallback font
908                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
909                         {
910                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
911                                         continue;
912                                 // try that glyph
913                                 face = usefont->face;
914                                 glyphIndex = qFT_Get_Char_Index(face, ch);
915                                 if (glyphIndex == 0)
916                                         continue;
917                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
918                                 if (status)
919                                         continue;
920                                 break;
921                         }
922                         if (!usefont)
923                         {
924                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
925                                 // now we let it use the "missing-glyph"-glyph
926                                 face = font->face;
927                                 glyphIndex = 0;
928                         }
929                 }
930
931                 if (!usefont)
932                 {
933                         usefont = font;
934                         face = font->face;
935                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
936                         if (status)
937                         {
938                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
939                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
940                                 continue;
941                         }
942                 }
943
944                 glyph = face->glyph;
945                 bmp = &glyph->bitmap;
946
947                 w = bmp->width;
948                 h = bmp->rows;
949
950                 if (w > map->glyphSize || h > map->glyphSize) {
951                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
952                         if (w > map->glyphSize)
953                                 w = map->glyphSize;
954                         if (h > map->glyphSize)
955                                 h = map->glyphSize;
956                 }
957
958                 switch (bmp->pixel_mode)
959                 {
960                 case FT_PIXEL_MODE_MONO:
961                         if (developer_extra.integer)
962                                 Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
963                         break;
964                 case FT_PIXEL_MODE_GRAY2:
965                         if (developer_extra.integer)
966                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
967                         break;
968                 case FT_PIXEL_MODE_GRAY4:
969                         if (developer_extra.integer)
970                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
971                         break;
972                 case FT_PIXEL_MODE_GRAY:
973                         if (developer_extra.integer)
974                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
975                         break;
976                 default:
977                         if (developer_extra.integer)
978                                 Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
979                         Mem_Free(data);
980                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
981                         return false;
982                 }
983                 for (y = 0; y < h; ++y)
984                 {
985                         dst = imagedata + y * pitch;
986                         src = bmp->buffer + y * bmp->pitch;
987
988                         switch (bmp->pixel_mode)
989                         {
990                         case FT_PIXEL_MODE_MONO:
991                                 dst += bytesPerPixel - 1; // shift to alpha byte
992                                 for (x = 0; x < bmp->width; x += 8)
993                                 {
994                                         unsigned char ch = *src++;
995                                         *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
996                                         *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
997                                         *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
998                                         *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
999                                         *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
1000                                         *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
1001                                         *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
1002                                         *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
1003                                 }
1004                                 break;
1005                         case FT_PIXEL_MODE_GRAY2:
1006                                 dst += bytesPerPixel - 1; // shift to alpha byte
1007                                 for (x = 0; x < bmp->width; x += 4)
1008                                 {
1009                                         unsigned char ch = *src++;
1010                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1011                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1012                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1013                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1014                                 }
1015                                 break;
1016                         case FT_PIXEL_MODE_GRAY4:
1017                                 dst += bytesPerPixel - 1; // shift to alpha byte
1018                                 for (x = 0; x < bmp->width; x += 2)
1019                                 {
1020                                         unsigned char ch = *src++;
1021                                         *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1022                                         *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1023                                 }
1024                                 break;
1025                         case FT_PIXEL_MODE_GRAY:
1026                                 // in this case pitch should equal width
1027                                 for (tp = 0; tp < bmp->pitch; ++tp)
1028                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1029
1030                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1031                                 //dst += bmp->pitch;
1032                                 break;
1033                         default:
1034                                 break;
1035                         }
1036                 }
1037
1038                 // now fill map->glyphs[ch - map->start]
1039                 mapglyph = &map->glyphs[mapch];
1040
1041                 {
1042                         // old way
1043                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1044
1045                         double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1046                         double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1047                         double advance = (glyph->advance.x >> 6) / map->size;
1048                         double mWidth = (glyph->metrics.width >> 6) / map->size;
1049                         double mHeight = (glyph->metrics.height >> 6) / map->size;
1050
1051                         mapglyph->vxmin = bearingX;
1052                         mapglyph->vxmax = bearingX + mWidth;
1053                         mapglyph->vymin = -bearingY;
1054                         mapglyph->vymax = mHeight - bearingY;
1055                         mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1056                         mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1057                         mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1058                         mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1059                         //mapglyph->advance_x = advance * usefont->size;
1060                         mapglyph->advance_x = advance;
1061                         mapglyph->advance_y = 0;
1062
1063                         if (developer_extra.integer)
1064                         {
1065                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1066                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1067                                 if (ch >= 32 && ch <= 128)
1068                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1069                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1070                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1071                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1072                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1073                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1074                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1075                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1076                         }
1077                 }
1078                 map->glyphs[mapch].image = false;
1079         }
1080
1081         // create a texture from the data now
1082
1083         if (developer_extra.integer)
1084         {
1085                 // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
1086                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1087                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1088                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1089         }
1090         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1091
1092         // probably use bytesPerPixel here instead?
1093         if (r_font_use_alpha_textures.integer)
1094         {
1095                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1096                                                map->glyphSize * FONT_CHARS_PER_LINE,
1097                                                map->glyphSize * FONT_CHAR_LINES,
1098                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1099         } else {
1100                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1101                                                map->glyphSize * FONT_CHARS_PER_LINE,
1102                                                map->glyphSize * FONT_CHAR_LINES,
1103                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1104         }
1105
1106         Mem_Free(data);
1107         if (!map->texture)
1108         {
1109                 // if the first try isn't successful, keep it with a broken texture
1110                 // otherwise we retry to load it every single frame where ft2 rendering is used
1111                 // this would be bad...
1112                 // only `data' must be freed
1113                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1114                            font->name, mapstart->size, mapidx);
1115                 return false;
1116         }
1117         if (outmap)
1118                 *outmap = map;
1119         return true;
1120 }
1121
1122 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1123 {
1124         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1125                 return false;
1126         // the first map must have been loaded already
1127         if (!font->font_maps[map_index])
1128                 return false;
1129         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1130 }
1131
1132 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1133 {
1134         while (start && start->start + FONT_CHARS_PER_MAP < ch)
1135                 start = start->next;
1136         if (start && start->start > ch)
1137                 return NULL;
1138         return start;
1139 }