]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
better font sizes loaded now
[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, qboolean no_texture, qboolean no_kerning);
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                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
316                         Mem_Free(fb);
317                         break;
318                 }
319                 count = 0;
320                 for (s = 0; s < MAX_FONT_SIZES; ++s)
321                 {
322                         if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
323                                 ++count;
324                 }
325                 if (!count)
326                 {
327                         Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
328                         Font_UnloadFont(fb);
329                         Mem_Free(fb);
330                         break;
331                 }
332                 // at least one size of the fallback font loaded successfully
333                 // link it:
334                 fbfont->next = fb;
335                 fbfont = fb;
336         }
337
338         count = 0;
339         for (s = 0; s < MAX_FONT_SIZES; ++s)
340         {
341                 if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
342                         ++count;
343         }
344         if (!count)
345         {
346                 // loading failed for every requested size
347                 Font_UnloadFont(ft2);
348                 Mem_Free(ft2);
349                 dpfnt->ft2 = NULL;
350                 return false;
351         }
352
353         //Con_Printf("%i sizes loaded\n", count);
354         dpfnt->ft2 = ft2;
355         return true;
356 }
357
358 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
359 {
360         size_t namelen;
361         char filename[PATH_MAX];
362         int status;
363         size_t i;
364         unsigned char *data;
365         fs_offset_t datasize;
366
367         memset(font, 0, sizeof(*font));
368
369         if (!Font_OpenLibrary())
370         {
371                 if (!r_font_disable_freetype.integer)
372                 {
373                         Con_Printf("WARNING: can't open load font %s\n"
374                                    "You need the FreeType2 DLL to load font files\n",
375                                    name);
376                 }
377                 return false;
378         }
379
380         namelen = strlen(name);
381
382         memcpy(filename, name, namelen);
383         memcpy(filename + namelen, ".ttf", 5);
384         data = FS_LoadFile(filename, font_mempool, false, &datasize);
385         if (!data)
386         {
387                 memcpy(filename + namelen, ".otf", 5);
388                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
389         }
390         if (!data)
391         {
392                 ft2_attachment_t afm;
393
394                 memcpy(filename + namelen, ".pfb", 5);
395                 data = FS_LoadFile(filename, font_mempool, false, &datasize);
396
397                 if (data)
398                 {
399                         memcpy(filename + namelen, ".afm", 5);
400                         afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
401
402                         if (afm.data)
403                                 Font_Attach(font, &afm);
404                 }
405         }
406
407         if (!data)
408         {
409                 // FS_LoadFile being not-quiet should print an error :)
410                 return false;
411         }
412         Con_Printf("Loading font %s face %i...\n", filename, _face);
413
414         status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
415         if (status && _face != 0)
416         {
417                 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
418                 _face = 0;
419                 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
420         }
421         if (status)
422         {
423                 Con_Printf("ERROR: can't create face for %s\n"
424                            "Error %i\n", // TODO: error strings
425                            name, status);
426                 Font_UnloadFont(font);
427                 return false;
428         }
429
430         // add the attachments
431         for (i = 0; i < font->attachmentcount; ++i)
432         {
433                 FT_Open_Args args;
434                 memset(&args, 0, sizeof(args));
435                 args.flags = FT_OPEN_MEMORY;
436                 args.memory_base = (const FT_Byte*)font->attachments[i].data;
437                 args.memory_size = font->attachments[i].size;
438                 if (qFT_Attach_Stream(font->face, &args))
439                         Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
440         }
441
442         memcpy(font->name, name, namelen+1);
443         font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
444         return true;
445 }
446
447 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
448 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
449 {
450         int map_index;
451         ft2_font_map_t *fmap, temp;
452
453         if (IS_NAN(size))
454                 size = 0;
455
456         if (!size)
457                 size = 16;
458         if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
459                 return false;
460
461         if (!no_texture)
462         {
463                 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
464                 {
465                         if (!font->font_maps[map_index])
466                                 break;
467                         // if a similar size has already been loaded, ignore this one
468                         //abs(font->font_maps[map_index]->size - size) < 4
469                         if (font->font_maps[map_index]->size == size)
470                                 return true;
471                 }
472
473                 if (map_index >= MAX_FONT_SIZES)
474                         return false;
475
476                 memset(&temp, 0, sizeof(temp));
477                 temp.size = size;
478                 temp.glyphSize = CeilPowerOf2(size*2);
479                 temp.sfx = (1.0/64.0)/(double)size;
480                 temp.sfy = (1.0/64.0)/(double)size;
481                 if (!Font_LoadMap(font, &temp, 0, &fmap))
482                 {
483                         Con_Printf("ERROR: can't load the first character map for %s\n"
484                                    "This is fatal\n",
485                                    font->name);
486                         Font_UnloadFont(font);
487                         return false;
488                 }
489                 font->font_maps[map_index] = temp.next;
490
491                 fmap->sfx = temp.sfx;
492                 fmap->sfy = temp.sfy;
493         }
494         if (!no_kerning)
495         {
496                 // load the default kerning vector:
497                 if (font->has_kerning)
498                 {
499                         Uchar l, r;
500                         FT_Vector kernvec;
501                         for (l = 0; l < 256; ++l)
502                         {
503                                 for (r = 0; r < 256; ++r)
504                                 {
505                                         FT_ULong ul, ur;
506                                         ul = qFT_Get_Char_Index(font->face, l);
507                                         ur = qFT_Get_Char_Index(font->face, r);
508                                         if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
509                                         {
510                                                 fmap->kerning.kerning[l][r][0] = 0;
511                                                 fmap->kerning.kerning[l][r][1] = 0;
512                                         }
513                                         else
514                                         {
515                                                 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
516                                                 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
517                                         }
518                                 }
519                         }
520                 }
521         }
522
523         return true;
524 }
525
526 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
527 {
528         int match = -1;
529         int value = 1000000;
530         int nval;
531         int matchsize = -10000;
532         int m;
533         int size;
534         float fsize;
535         ft2_font_map_t **maps = font->font_maps;
536
537         fsize = _fsize * vid.height / vid_conheight.value;
538
539         if (fsize < 0)
540                 size = 16;
541         else
542         {
543                 // round up
544                 size = (int)fsize;
545                 if (fsize - (float)size >= 0.49)
546                         ++size;
547         }
548
549         for (m = 0; m < MAX_FONT_SIZES; ++m)
550         {
551                 if (!maps[m])
552                         continue;
553                 // "round up" to the bigger size if two equally-valued matches exist
554                 nval = abs(maps[m]->size - size);
555                 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
556                 {
557                         value = nval;
558                         match = m;
559                         matchsize = maps[m]->size;
560                         if (value == 0) // there is no better match
561                                 break;
562                 }
563         }
564         /*
565         // keep the aspect
566         if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
567         if (outw) *outw = maps[match]->size * vid_conheight.value / vid.height * *outw / _fsize;
568         */
569         return match;
570 }
571
572 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
573 {
574         if (index < 0 || index >= MAX_FONT_SIZES)
575                 return NULL;
576         return font->font_maps[index];
577 }
578
579 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
580 {
581         if (font->currenth == h &&
582             ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
583              font->currentw == w)) // same size has been requested
584         {
585                 return true;
586         }
587         // sorry, but freetype doesn't seem to care about other sizes
588         w = (int)w;
589         h = (int)h;
590         if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
591                 return false;
592         font->currentw = w;
593         font->currenth = h;
594         return true;
595 }
596
597 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
598 {
599         ft2_font_map_t *fmap;
600         if (!font->has_kerning)
601                 return false;
602         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
603                 return false;
604         fmap = font->font_maps[map_index];
605         if (!fmap)
606                 return false;
607         if (left < 256 && right < 256)
608         {
609                 // quick-kerning, be aware of the size: scale it
610                 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
611                 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
612                 return true;
613         }
614         else
615         {
616                 FT_Vector kernvec;
617                 FT_ULong ul, ur;
618
619                 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
620                 if (!Font_SetSize(font, w, h))
621                 {
622                         // this deserves an error message
623                         Con_Printf("Failed to get kerning for %s\n", font->name);
624                         return false;
625                 }
626                 ul = qFT_Get_Char_Index(font->face, left);
627                 ur = qFT_Get_Char_Index(font->face, right);
628                 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
629                 {
630                         if (outx) *outx = kernvec.x * fmap->sfx;
631                         if (outy) *outy = kernvec.y * fmap->sfy;
632                         return true;
633                 }
634                 return false;
635         }
636 }
637
638 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
639 {
640         return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
641 }
642
643 static void UnloadMapRec(ft2_font_map_t *map)
644 {
645         if (map->texture)
646         {
647                 R_FreeTexture(map->texture);
648                 map->texture = NULL;
649         }
650         if (map->next)
651                 UnloadMapRec(map->next);
652         Mem_Free(map);
653 }
654
655 void Font_UnloadFont(ft2_font_t *font)
656 {
657         int i;
658         /*
659         if (font->data)
660                 Mem_Free(font->data);
661         */
662         if (font->attachments && font->attachmentcount)
663         {
664                 Mem_Free(font->attachments);
665                 font->attachmentcount = 0;
666                 font->attachments = NULL;
667         }
668         for (i = 0; i < MAX_FONT_SIZES; ++i)
669         {
670                 if (font->font_maps[i])
671                 {
672                         UnloadMapRec(font->font_maps[i]);
673                         font->font_maps[i] = NULL;
674                 }
675         }
676         if (ft2_dll)
677         {
678                 if (font->face)
679                 {
680                         qFT_Done_Face((FT_Face)font->face);
681                         font->face = NULL;
682                 }
683         }
684 }
685
686 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
687 {
688         char map_identifier[PATH_MAX];
689         unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
690         unsigned char *data;
691         FT_ULong ch, mapch;
692         int status;
693         int tp;
694
695         int pitch;
696         int gR, gC; // glyph position: row and column
697
698         ft2_font_map_t *map, *next;
699         ft2_font_t *usefont;
700
701         int bytesPerPixel = 4; // change the conversion loop too if you change this!
702
703         if (outmap)
704                 *outmap = NULL;
705
706         if (r_font_use_alpha_textures.integer)
707                 bytesPerPixel = 1;
708
709         //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
710         //if (status)
711         if (!Font_SetSize(font, mapstart->size, mapstart->size))
712         {
713                 Con_Printf("ERROR: can't set pixel sizes for font %s: %f\n", font->name, mapstart->size);
714                 return false;
715         }
716
717         map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
718         if (!map)
719         {
720                 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
721                 return false;
722         }
723
724         // copy over the information
725         map->size = mapstart->size;
726         map->glyphSize = mapstart->glyphSize;
727         map->sfx = mapstart->sfx;
728         map->sfy = mapstart->sfy;
729
730         pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
731         data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
732         if (!data)
733         {
734                 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
735                 Mem_Free(map);
736                 return false;
737         }
738
739         // initialize as white texture with zero alpha
740         tp = 0;
741         while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
742         {
743                 if (bytesPerPixel == 4)
744                 {
745                         data[tp++] = 0xFF;
746                         data[tp++] = 0xFF;
747                         data[tp++] = 0xFF;
748                 }
749                 data[tp++] = 0x00;
750         }
751
752         // insert the map
753         map->start = mapidx * FONT_CHARS_PER_MAP;
754         next = mapstart;
755         while(next->next && next->next->start < map->start)
756                 next = next->next;
757         map->next = next->next;
758         next->next = map;
759
760         gR = 0;
761         gC = -1;
762         for (ch = map->start;
763              ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
764              ++ch)
765         {
766                 FT_ULong glyphIndex;
767                 int w, h, x, y;
768                 FT_GlyphSlot glyph;
769                 FT_Bitmap *bmp;
770                 unsigned char *imagedata, *dst, *src;
771                 glyph_slot_t *mapglyph;
772                 FT_Face face;
773
774                 if (developer.integer)
775                         Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
776
777                 ++gC;
778                 if (gC >= FONT_CHARS_PER_LINE)
779                 {
780                         gC -= FONT_CHARS_PER_LINE;
781                         ++gR;
782                 }
783
784                 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
785                 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
786                 // we need the glyphIndex
787                 face = font->face;
788                 usefont = NULL;
789                 glyphIndex = qFT_Get_Char_Index(face, ch);
790                 if (glyphIndex == 0)
791                 {
792                         // by convention, 0 is the "missing-glyph"-glyph
793                         // try to load from a fallback font
794                         for(usefont = font->next; usefont != NULL; usefont = usefont->next)
795                         {
796                                 if (!Font_SetSize(usefont, mapstart->size, mapstart->size))
797                                         continue;
798                                 // try that glyph
799                                 face = usefont->face;
800                                 glyphIndex = qFT_Get_Char_Index(face, ch);
801                                 if (glyphIndex == 0)
802                                         continue;
803                                 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
804                                 if (status)
805                                         continue;
806                                 break;
807                         }
808                         if (!usefont)
809                         {
810                                 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
811                                 // now we let it use the "missing-glyph"-glyph
812                                 face = font->face;
813                                 glyphIndex = 0;
814                         }
815                 }
816
817                 if (!usefont)
818                 {
819                         usefont = font;
820                         face = font->face;
821                         status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
822                         if (status)
823                         {
824                                 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
825                                 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
826                                 continue;
827                         }
828                 }
829
830                 /* obsolete when using FT_LOAD_RENDER
831                 if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
832                 {
833                         status = qFT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
834                         if (status)
835                         {
836                                 Con_Printf("failed to render glyph %lu for %s\n", glyphIndex, font->name);
837                                 continue;
838                         }
839                 }
840                 */
841
842                 glyph = face->glyph;
843                 bmp = &glyph->bitmap;
844
845                 w = bmp->width;
846                 h = bmp->rows;
847
848                 if (w > map->glyphSize || h > map->glyphSize) {
849                         Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
850                         if (w > map->glyphSize)
851                                 w = map->glyphSize;
852                         if (h > map->glyphSize)
853                                 h = map->glyphSize;
854                 }
855
856                 switch (bmp->pixel_mode)
857                 {
858                 case FT_PIXEL_MODE_MONO:
859                         if (developer.integer)
860                                 Con_Print("glyphinfo:   Pixel Mode: MONO\n");
861                         break;
862                 case FT_PIXEL_MODE_GRAY2:
863                         if (developer.integer)
864                                 Con_Print("glyphinfo:   Pixel Mode: GRAY2\n");
865                         break;
866                 case FT_PIXEL_MODE_GRAY4:
867                         if (developer.integer)
868                                 Con_Print("glyphinfo:   Pixel Mode: GRAY4\n");
869                         break;
870                 case FT_PIXEL_MODE_GRAY:
871                         if (developer.integer)
872                                 Con_Print("glyphinfo:   Pixel Mode: GRAY\n");
873                         break;
874                 default:
875                         if (developer.integer)
876                                 Con_Printf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
877                         Mem_Free(data);
878                         Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
879                         return false;
880                 }
881                 for (y = 0; y < h; ++y)
882                 {
883                         dst = imagedata + y * pitch;
884                         src = bmp->buffer + y * bmp->pitch;
885
886                         switch (bmp->pixel_mode)
887                         {
888                         case FT_PIXEL_MODE_MONO:
889                                 dst += bytesPerPixel - 1; // shift to alpha byte
890                                 for (x = 0; x < bmp->width; x += 8)
891                                 {
892                                         unsigned char ch = *src++;
893                                         *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
894                                         *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
895                                         *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
896                                         *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
897                                         *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
898                                         *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
899                                         *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
900                                         *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
901                                 }
902                                 break;
903                         case FT_PIXEL_MODE_GRAY2:
904                                 dst += bytesPerPixel - 1; // shift to alpha byte
905                                 for (x = 0; x < bmp->width; x += 4)
906                                 {
907                                         unsigned char ch = *src++;
908                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
909                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
910                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
911                                         *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
912                                 }
913                                 break;
914                         case FT_PIXEL_MODE_GRAY4:
915                                 dst += bytesPerPixel - 1; // shift to alpha byte
916                                 for (x = 0; x < bmp->width; x += 2)
917                                 {
918                                         unsigned char ch = *src++;
919                                         *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
920                                         *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
921                                 }
922                                 break;
923                         case FT_PIXEL_MODE_GRAY:
924                                 // in this case pitch should equal width
925                                 for (tp = 0; tp < bmp->pitch; ++tp)
926                                         dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
927
928                                 //memcpy((void*)dst, (void*)src, bmp->pitch);
929                                 //dst += bmp->pitch;
930                                 break;
931                         default:
932                                 break;
933                         }
934                 }
935
936                 // now fill map->glyphs[ch - map->start]
937                 mapch = ch - map->start;
938                 mapglyph = &map->glyphs[mapch];
939
940                 {
941                         // old way
942                         // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
943
944                         double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
945                         double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
946                         double advance = (glyph->advance.x >> 6) / map->size;
947                         double mWidth = (glyph->metrics.width >> 6) / map->size;
948                         double mHeight = (glyph->metrics.height >> 6) / map->size;
949
950                         mapglyph->vxmin = bearingX;
951                         mapglyph->vxmax = bearingX + mWidth;
952                         mapglyph->vymin = -bearingY;
953                         mapglyph->vymax = mHeight - bearingY;
954                         mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
955                         mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
956                         mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
957                         mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
958                         //mapglyph->advance_x = advance * usefont->size;
959                         mapglyph->advance_x = advance;
960                         mapglyph->advance_y = 0;
961
962                         if (developer.integer)
963                         {
964                                 Con_Printf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
965                                 Con_Printf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
966                                 if (ch >= 32 && ch <= 128)
967                                         Con_Printf("glyphinfo:   Character: %c\n", (int)ch);
968                                 Con_Printf("glyphinfo:   Vertex info:\n");
969                                 Con_Printf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
970                                 Con_Printf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
971                                 Con_Printf("glyphinfo:   Texture info:\n");
972                                 Con_Printf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
973                                 Con_Printf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
974                                 Con_Printf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
975                         }
976                 }
977         }
978
979         // create a texture from the data now
980
981         if (developer.integer)
982         {
983                 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
984                 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
985                 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
986         }
987         dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
988
989         // probably use bytesPerPixel here instead?
990         if (r_font_use_alpha_textures.integer)
991         {
992                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
993                                                map->glyphSize * FONT_CHARS_PER_LINE,
994                                                map->glyphSize * FONT_CHAR_LINES,
995                                                data, TEXTYPE_ALPHA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
996         } else {
997                 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
998                                                map->glyphSize * FONT_CHARS_PER_LINE,
999                                                map->glyphSize * FONT_CHAR_LINES,
1000                                                data, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
1001         }
1002
1003         Mem_Free(data);
1004         if (!map->texture)
1005         {
1006                 // if the first try isn't successful, keep it with a broken texture
1007                 // otherwise we retry to load it every single frame where ft2 rendering is used
1008                 // this would be bad...
1009                 // only `data' must be freed
1010                 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1011                            font->name, mapstart->size, mapidx);
1012                 return false;
1013         }
1014         if (outmap)
1015                 *outmap = map;
1016         return true;
1017 }
1018
1019 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1020 {
1021         if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1022                 return false;
1023         // the first map must have been loaded already
1024         if (!font->font_maps[map_index])
1025                 return false;
1026         return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1027 }
1028
1029 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1030 {
1031         while (start && start->start + FONT_CHARS_PER_MAP < ch)
1032                 start = start->next;
1033         if (start && start->start > ch)
1034                 return NULL;
1035         return start;
1036 }