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