]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
remove a no longer applying fixme comment
[divverent/darkplaces.git] / ft2.c
1 /* FreeType 2 and UTF-8 encoding support for
2  * DarkPlaces
3  */
4 #include "quakedef.h"
5
6 #include "ft2.h"
7 #include "ft2_defs.h"
8 #include "ft2_fontdefs.h"
9
10 static int img_fontmap[256] = {
11         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
12         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
13         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
14         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
15         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
16         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
17         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
18         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
20         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
21         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
27 };
28
29 /*
30 ================================================================================
31 CVars introduced with the freetype extension
32 ================================================================================
33 */
34
35 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
36 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
37 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
38 cvar_t r_font_hinting = {CVAR_SAVE, "r_font_hinting", "2", "0 = no hinting, 1 = force autohinting, 2 = full hinting"};
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_hinting);
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 = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
784         if (r_font_hinting.integer == 1)
785                 load_flags = FT_LOAD_FORCE_AUTOHINT;
786         else if (r_font_hinting.integer == 2)
787                 load_flags = 0;
788
789         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
790         //if (status)
791         if (font->image_font && mapstart->intSize < 0)
792                 mapstart->intSize = mapstart->size;
793         if (mapstart->intSize < 0)
794         {
795                 mapstart->intSize = mapstart->size;
796                 while (1)
797                 {
798                         if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
799                         {
800                                 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
801                                 return false;
802                         }
803                         if ((fontface->size->metrics.height>>6) <= mapstart->size)
804                                 break;
805                         if (mapstart->intSize < 2)
806                         {
807                                 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
808                                 return false;
809                         }
810                         --mapstart->intSize;
811                 }
812                 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
813         }
814
815         if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
816         {
817                 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
818                 return false;
819         }
820
821         map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
822         if (!map)
823         {
824                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
825                 return false;
826         }
827
828         // copy over the information
829         map->size = mapstart->size;
830         map->intSize = mapstart->intSize;
831         map->glyphSize = mapstart->glyphSize;
832         map->sfx = mapstart->sfx;
833         map->sfy = mapstart->sfy;
834
835         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
836         data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
837         if (!data)
838         {
839                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
840                 Mem_Free(map);
841                 return false;
842         }
843
844         // initialize as white texture with zero alpha
845         tp = 0;
846         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
847         {
848                 if (bytesPerPixel == 4)
849                 {
850                         data[tp++] = 0xFF;
851                         data[tp++] = 0xFF;
852                         data[tp++] = 0xFF;
853                 }
854                 data[tp++] = 0x00;
855         }
856
857         // insert the map
858         map->start = mapidx * FONT_CHARS_PER_MAP;
859         next = mapstart;
860         while(next->next && next->next->start < map->start)
861                 next = next->next;
862         map->next = next->next;
863         next->next = map;
864
865         gR = 0;
866         gC = -1;
867         for (ch = map->start;
868              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
869              ++ch)
870         {
871                 FT_ULong glyphIndex;
872                 int w, h, x, y;
873                 FT_GlyphSlot glyph;
874                 FT_Bitmap *bmp;
875                 unsigned char *imagedata, *dst, *src;
876                 glyph_slot_t *mapglyph;
877                 FT_Face face;
878
879                 mapch = ch - map->start;
880
881                 if (developer_extra.integer)
882                         Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
883
884                 ++gC;
885                 if (gC >= FONT_CHARS_PER_LINE)
886                 {
887                         gC -= FONT_CHARS_PER_LINE;
888                         ++gR;
889                 }
890
891                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
892                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
893                 // we need the glyphIndex
894                 face = font->face;
895                 usefont = NULL;
896                 if (font->image_font && mapch == ch && img_fontmap[mapch])
897                 {
898                         map->glyphs[mapch].image = true;
899                         continue;
900                 }
901                 glyphIndex = qFT_Get_Char_Index(face, ch);
902                 if (glyphIndex == 0)
903                 {
904                         // by convention, 0 is the "missing-glyph"-glyph
905                         // try to load from a fallback font
906                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
907                         {
908                                 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
909                                         continue;
910                                 // try that glyph
911                                 face = usefont->face;
912                                 glyphIndex = qFT_Get_Char_Index(face, ch);
913                                 if (glyphIndex == 0)
914                                         continue;
915                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
916                                 if (status)
917                                         continue;
918                                 break;
919                         }
920                         if (!usefont)
921                         {
922                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
923                                 // now we let it use the "missing-glyph"-glyph
924                                 face = font->face;
925                                 glyphIndex = 0;
926                         }
927                 }
928
929                 if (!usefont)
930                 {
931                         usefont = font;
932                         face = font->face;
933                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
934                         if (status)
935                         {
936                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
937                                 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
938                                 continue;
939                         }
940                 }
941
942                 glyph = face->glyph;
943                 bmp = &glyph->bitmap;
944
945                 w = bmp->width;
946                 h = bmp->rows;
947
948                 if (w > map->glyphSize || h > map->glyphSize) {
949                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
950                         if (w > map->glyphSize)
951                                 w = map->glyphSize;
952                         if (h > map->glyphSize)
953                                 h = map->glyphSize;
954                 }
955
956                 switch (bmp->pixel_mode)
957                 {
958                 case FT_PIXEL_MODE_MONO:
959                         if (developer_extra.integer)
960                                 Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
961                         break;
962                 case FT_PIXEL_MODE_GRAY2:
963                         if (developer_extra.integer)
964                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
965                         break;
966                 case FT_PIXEL_MODE_GRAY4:
967                         if (developer_extra.integer)
968                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
969                         break;
970                 case FT_PIXEL_MODE_GRAY:
971                         if (developer_extra.integer)
972                                 Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
973                         break;
974                 default:
975                         if (developer_extra.integer)
976                                 Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
977                         Mem_Free(data);
978                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
979                         return false;
980                 }
981                 for (y = 0; y < h; ++y)
982                 {
983                         dst = imagedata + y * pitch;
984                         src = bmp->buffer + y * bmp->pitch;
985
986                         switch (bmp->pixel_mode)
987                         {
988                         case FT_PIXEL_MODE_MONO:
989                                 dst += bytesPerPixel - 1; // shift to alpha byte
990                                 for (x = 0; x < bmp->width; x += 8)
991                                 {
992                                         unsigned char ch = *src++;
993                                         *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
994                                         *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
995                                         *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
996                                         *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
997                                         *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
998                                         *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
999                                         *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
1000                                         *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
1001                                 }
1002                                 break;
1003                         case FT_PIXEL_MODE_GRAY2:
1004                                 dst += bytesPerPixel - 1; // shift to alpha byte
1005                                 for (x = 0; x < bmp->width; x += 4)
1006                                 {
1007                                         unsigned char ch = *src++;
1008                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1009                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1010                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1011                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1012                                 }
1013                                 break;
1014                         case FT_PIXEL_MODE_GRAY4:
1015                                 dst += bytesPerPixel - 1; // shift to alpha byte
1016                                 for (x = 0; x < bmp->width; x += 2)
1017                                 {
1018                                         unsigned char ch = *src++;
1019                                         *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1020                                         *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1021                                 }
1022                                 break;
1023                         case FT_PIXEL_MODE_GRAY:
1024                                 // in this case pitch should equal width
1025                                 for (tp = 0; tp < bmp->pitch; ++tp)
1026                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1027
1028                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
1029                                 //dst += bmp->pitch;
1030                                 break;
1031                         default:
1032                                 break;
1033                         }
1034                 }
1035
1036                 // now fill map->glyphs[ch - map->start]
1037                 mapglyph = &map->glyphs[mapch];
1038
1039                 {
1040                         // old way
1041                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1042
1043                         double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1044                         double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1045                         double advance = (glyph->advance.x >> 6) / map->size;
1046                         double mWidth = (glyph->metrics.width >> 6) / map->size;
1047                         double mHeight = (glyph->metrics.height >> 6) / map->size;
1048
1049                         mapglyph->vxmin = bearingX;
1050                         mapglyph->vxmax = bearingX + mWidth;
1051                         mapglyph->vymin = -bearingY;
1052                         mapglyph->vymax = mHeight - bearingY;
1053                         mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1054                         mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1055                         mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1056                         mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1057                         //mapglyph->advance_x = advance * usefont->size;
1058                         mapglyph->advance_x = advance;
1059                         mapglyph->advance_y = 0;
1060
1061                         if (developer_extra.integer)
1062                         {
1063                                 Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1064                                 Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1065                                 if (ch >= 32 && ch <= 128)
1066                                         Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1067                                 Con_DPrintf("glyphinfo:   Vertex info:\n");
1068                                 Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1069                                 Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1070                                 Con_DPrintf("glyphinfo:   Texture info:\n");
1071                                 Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1072                                 Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1073                                 Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1074                         }
1075                 }
1076                 map->glyphs[mapch].image = false;
1077         }
1078
1079         // create a texture from the data now
1080
1081         if (developer_extra.integer)
1082         {
1083                 // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
1084                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1085                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1086                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1087         }
1088         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1089
1090         // probably use bytesPerPixel here instead?
1091         if (r_font_use_alpha_textures.integer)
1092         {
1093                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1094                                                map->glyphSize * FONT_CHARS_PER_LINE,
1095                                                map->glyphSize * FONT_CHAR_LINES,
1096                                                data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1097         } else {
1098                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1099                                                map->glyphSize * FONT_CHARS_PER_LINE,
1100                                                map->glyphSize * FONT_CHAR_LINES,
1101                                                data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1102         }
1103
1104         Mem_Free(data);
1105         if (!map->texture)
1106         {
1107                 // if the first try isn't successful, keep it with a broken texture
1108                 // otherwise we retry to load it every single frame where ft2 rendering is used
1109                 // this would be bad...
1110                 // only `data' must be freed
1111                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1112                            font->name, mapstart->size, mapidx);
1113                 return false;
1114         }
1115         if (outmap)
1116                 *outmap = map;
1117         return true;
1118 }
1119
1120 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1121 {
1122         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1123                 return false;
1124         // the first map must have been loaded already
1125         if (!font->font_maps[map_index])
1126                 return false;
1127         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1128 }
1129
1130 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1131 {
1132         while (start && start->start + FONT_CHARS_PER_MAP < ch)
1133                 start = start->next;
1134         if (start && start->start > ch)
1135                 return NULL;
1136         return start;
1137 }