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