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