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