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