1 /* FreeType 2 and UTF-8 encoding support for
8 #include "ft2_fontdefs.h"
11 static int img_fontmap[256] = {
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,
14 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
15 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
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, // caps
18 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
31 ================================================================================
32 CVars introduced with the freetype extension
33 ================================================================================
36 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
37 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"};
38 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!"};
39 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
40 cvar_t r_font_diskcache = {CVAR_SAVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"};
41 cvar_t r_font_compress = {CVAR_SAVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
42 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
45 ================================================================================
46 Function definitions. Taken from the freetype2 headers.
47 ================================================================================
52 (*qFT_Init_FreeType)( FT_Library *alibrary );
54 (*qFT_Done_FreeType)( FT_Library library );
57 (*qFT_New_Face)( FT_Library library,
58 const char* filepathname,
63 (*qFT_New_Memory_Face)( FT_Library library,
64 const FT_Byte* file_base,
69 (*qFT_Done_Face)( FT_Face face );
71 (*qFT_Select_Size)( FT_Face face,
72 FT_Int strike_index );
74 (*qFT_Request_Size)( FT_Face face,
75 FT_Size_Request req );
77 (*qFT_Set_Char_Size)( FT_Face face,
78 FT_F26Dot6 char_width,
79 FT_F26Dot6 char_height,
80 FT_UInt horz_resolution,
81 FT_UInt vert_resolution );
83 (*qFT_Set_Pixel_Sizes)( FT_Face face,
85 FT_UInt pixel_height );
87 (*qFT_Load_Glyph)( FT_Face face,
89 FT_Int32 load_flags );
91 (*qFT_Load_Char)( FT_Face face,
93 FT_Int32 load_flags );
95 (*qFT_Get_Char_Index)( FT_Face face,
98 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
99 FT_Render_Mode render_mode );
100 FT_EXPORT( FT_Error )
101 (*qFT_Get_Kerning)( FT_Face face,
105 FT_Vector *akerning );
106 FT_EXPORT( FT_Error )
107 (*qFT_Attach_Stream)( FT_Face face,
108 FT_Open_Args* parameters );
110 ================================================================================
111 Support for dynamically loading the FreeType2 library
112 ================================================================================
115 static dllfunction_t ft2funcs[] =
117 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
118 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
119 //{"FT_New_Face", (void **) &qFT_New_Face},
120 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
121 {"FT_Done_Face", (void **) &qFT_Done_Face},
122 {"FT_Select_Size", (void **) &qFT_Select_Size},
123 {"FT_Request_Size", (void **) &qFT_Request_Size},
124 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
125 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
126 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
127 {"FT_Load_Char", (void **) &qFT_Load_Char},
128 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
129 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
130 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
131 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
135 /// Handle for FreeType2 DLL
136 static dllhandle_t ft2_dll = NULL;
138 /// Memory pool for fonts
139 static mempool_t *font_mempool= NULL;
141 /// FreeType library handle
142 static FT_Library font_ft2lib = NULL;
144 #define POSTPROCESS_MAXRADIUS 8
147 unsigned char *buf, *buf2;
148 int bufsize, bufwidth, bufheight, bufpitch;
149 float blur, outline, shadowx, shadowy, shadowz;
150 int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
151 unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
152 unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
155 static font_postprocess_t pp;
157 typedef struct fontfilecache_s
162 char path[MAX_QPATH];
165 #define MAX_FONTFILES 8
166 static fontfilecache_t fontfiles[MAX_FONTFILES];
167 static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer)
172 for(i = 0; i < MAX_FONTFILES; ++i)
174 if(fontfiles[i].refcount > 0)
175 if(!strcmp(path, fontfiles[i].path))
177 *filesizepointer = fontfiles[i].len;
178 ++fontfiles[i].refcount;
179 return fontfiles[i].buf;
183 buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
186 for(i = 0; i < MAX_FONTFILES; ++i)
187 if(fontfiles[i].refcount <= 0)
189 strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
190 fontfiles[i].len = *filesizepointer;
191 fontfiles[i].buf = buf;
192 fontfiles[i].refcount = 1;
199 static void fontfilecache_Free(const unsigned char *buf)
202 for(i = 0; i < MAX_FONTFILES; ++i)
204 if(fontfiles[i].refcount > 0)
205 if(fontfiles[i].buf == buf)
207 if(--fontfiles[i].refcount <= 0)
209 Mem_Free(fontfiles[i].buf);
210 fontfiles[i].buf = NULL;
215 // if we get here, it used regular allocation
216 Mem_Free((void *) buf);
218 static void fontfilecache_FreeAll(void)
221 for(i = 0; i < MAX_FONTFILES; ++i)
223 if(fontfiles[i].refcount > 0)
224 Mem_Free(fontfiles[i].buf);
225 fontfiles[i].buf = NULL;
226 fontfiles[i].refcount = 0;
234 Unload the FreeType2 DLL
237 void Font_CloseLibrary (void)
239 fontfilecache_FreeAll();
241 Mem_FreePool(&font_mempool);
242 if (font_ft2lib && qFT_Done_FreeType)
244 qFT_Done_FreeType(font_ft2lib);
247 Sys_UnloadLibrary (&ft2_dll);
255 Try to load the FreeType2 DLL
258 qboolean Font_OpenLibrary (void)
260 const char* dllnames [] =
265 #elif defined(MACOSX)
266 "libfreetype.6.dylib",
275 if (r_font_disable_freetype.integer)
283 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
292 Initialize the freetype2 font subsystem
296 void font_start(void)
298 if (!Font_OpenLibrary())
301 if (qFT_Init_FreeType(&font_ft2lib))
303 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
308 font_mempool = Mem_AllocPool("FONT", 0, NULL);
311 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
317 void font_shutdown(void)
320 for (i = 0; i < dp_fonts.maxsize; ++i)
322 if (dp_fonts.f[i].ft2)
324 Font_UnloadFont(dp_fonts.f[i].ft2);
325 dp_fonts.f[i].ft2 = NULL;
331 void font_newmap(void)
337 Cvar_RegisterVariable(&r_font_disable_freetype);
338 Cvar_RegisterVariable(&r_font_use_alpha_textures);
339 Cvar_RegisterVariable(&r_font_size_snapping);
340 Cvar_RegisterVariable(&r_font_kerning);
341 Cvar_RegisterVariable(&r_font_diskcache);
342 Cvar_RegisterVariable(&r_font_compress);
343 Cvar_RegisterVariable(&developer_font);
345 // let's open it at startup already
350 ================================================================================
351 Implementation of a more or less lazy font loading and rendering code.
352 ================================================================================
355 #include "ft2_fontdefs.h"
357 ft2_font_t *Font_Alloc(void)
361 return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
364 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
366 ft2_attachment_t *na;
368 font->attachmentcount++;
369 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
372 if (font->attachments && font->attachmentcount > 1)
374 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
375 Mem_Free(font->attachments);
377 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
378 font->attachments = na;
382 float Font_VirtualToRealSize(float sz)
390 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
391 vh = ((vid.height > 0) ? vid.height : vid_height.value);
392 // now try to scale to our actual size:
393 sn = sz * vh / vid_conheight.value;
395 if ( sn - (float)si >= 0.5 )
400 float Font_SnapTo(float val, float snapwidth)
402 return floor(val / snapwidth + 0.5f) * snapwidth;
405 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
406 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
407 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
410 ft2_font_t *ft2, *fbfont, *fb;
419 // check if a fallback font has been specified, if it has been, and the
420 // font fails to load, use the image font as main font
421 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
423 if (dpfnt->fallbacks[i][0])
427 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
429 if (i >= MAX_FONT_FALLBACKS)
435 strlcpy(ft2->name, name, sizeof(ft2->name));
436 ft2->image_font = true;
437 ft2->has_kerning = false;
441 ft2->image_font = false;
444 // attempt to load fallback fonts:
446 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
448 if (!dpfnt->fallbacks[i][0])
450 if (! (fb = Font_Alloc()) )
452 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
456 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
458 if(!FS_FileExists(va("%s.tga", dpfnt->fallbacks[i])))
459 if(!FS_FileExists(va("%s.png", dpfnt->fallbacks[i])))
460 if(!FS_FileExists(va("%s.jpg", dpfnt->fallbacks[i])))
461 if(!FS_FileExists(va("%s.pcx", dpfnt->fallbacks[i])))
462 Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
467 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
469 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
474 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
479 // at least one size of the fallback font loaded successfully
485 if (fbfont == ft2 && ft2->image_font)
487 // no fallbacks were loaded successfully:
494 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
496 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
501 // loading failed for every requested size
502 Font_UnloadFont(ft2);
508 //Con_Printf("%i sizes loaded\n", count);
513 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
516 char filename[MAX_QPATH];
519 const unsigned char *data;
520 fs_offset_t datasize;
522 memset(font, 0, sizeof(*font));
524 if (!Font_OpenLibrary())
526 if (!r_font_disable_freetype.integer)
528 Con_Printf("WARNING: can't open load font %s\n"
529 "You need the FreeType2 DLL to load font files\n",
535 font->settings = settings;
537 namelen = strlen(name);
539 // try load direct file
540 memcpy(filename, name, namelen+1);
541 data = fontfilecache_LoadFile(filename, false, &datasize);
545 memcpy(filename + namelen, ".ttf", 5);
546 data = fontfilecache_LoadFile(filename, false, &datasize);
551 memcpy(filename + namelen, ".otf", 5);
552 data = fontfilecache_LoadFile(filename, false, &datasize);
557 ft2_attachment_t afm;
559 memcpy(filename + namelen, ".pfb", 5);
560 data = fontfilecache_LoadFile(filename, false, &datasize);
564 memcpy(filename + namelen, ".afm", 5);
565 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
568 Font_Attach(font, &afm);
573 // FS_LoadFile being not-quiet should print an error :)
576 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
578 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
579 if (status && _face != 0)
581 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
583 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
588 Con_Printf("ERROR: can't create face for %s\n"
589 "Error %i\n", // TODO: error strings
591 Font_UnloadFont(font);
595 // add the attachments
596 for (i = 0; i < font->attachmentcount; ++i)
599 memset(&args, 0, sizeof(args));
600 args.flags = FT_OPEN_MEMORY;
601 args.memory_base = (const FT_Byte*)font->attachments[i].data;
602 args.memory_size = font->attachments[i].size;
603 if (qFT_Attach_Stream((FT_Face)font->face, &args))
604 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
607 memcpy(font->name, name, namelen+1);
608 font->image_font = false;
609 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
613 void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
616 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
617 qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
618 qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
619 pp.blur = fnt->settings->blur;
620 pp.outline = fnt->settings->outline;
621 pp.shadowx = fnt->settings->shadowx;
622 pp.shadowy = fnt->settings->shadowy;
623 pp.shadowz = fnt->settings->shadowz;
624 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
625 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
626 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
627 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
628 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
629 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
630 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
631 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
632 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
633 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
637 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
638 gausstable[POSTPROCESS_MAXRADIUS+x] = (pp.blur > 0 ? exp(-(pow(x + pp.shadowz, 2))/(pp.blur*pp.blur * 2)) : (floor(x + pp.shadowz + 0.5) == 0));
639 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
640 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
641 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
642 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
646 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
647 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
649 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
650 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
653 pp.bufwidth = w + pp.padding_l + pp.padding_r;
654 pp.bufheight = h + pp.padding_t + pp.padding_b;
655 pp.bufpitch = pp.bufwidth;
656 needed = pp.bufwidth * pp.bufheight;
657 if(!pp.buf || pp.bufsize < needed * 2)
661 pp.bufsize = needed * 4;
662 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
663 pp.buf2 = pp.buf + needed;
667 void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b)
670 Font_Postprocess_Update(fnt, bpp, w, h);
675 // perform operation, not exceeding the passed padding values,
676 // but possibly reducing them
677 *pad_l = min(*pad_l, pp.padding_l);
678 *pad_r = min(*pad_r, pp.padding_r);
679 *pad_t = min(*pad_t, pp.padding_t);
680 *pad_b = min(*pad_b, pp.padding_b);
682 // calculate gauss table
684 // outline the font (RGBA only)
685 if(bpp == 4 && (pp.outline > 0 || pp.blur > 0 || pp.shadowx != 0 || pp.shadowy != 0 || pp.shadowz != 0)) // we can only do this in BGRA
687 // this is like mplayer subtitle rendering
688 // bbuffer, bitmap buffer: this is our font
689 // abuffer, alpha buffer: this is pp.buf
690 // tmp: this is pp.buf2
692 // create outline buffer
693 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
694 for(y = -*pad_t; y < h + *pad_b; ++y)
695 for(x = -*pad_l; x < w + *pad_r; ++x)
697 int x1 = max(-x, -pp.outlinepadding_r);
698 int y1 = max(-y, -pp.outlinepadding_b);
699 int x2 = min(pp.outlinepadding_l, w-1-x);
700 int y2 = min(pp.outlinepadding_t, h-1-y);
704 for(my = y1; my <= y2; ++my)
705 for(mx = x1; mx <= x2; ++mx)
707 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
711 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
714 // blur the outline buffer
715 if(pp.blur > 0 || pp.shadowz != 0)
718 for(y = 0; y < pp.bufheight; ++y)
719 for(x = 0; x < pp.bufwidth; ++x)
721 int x1 = max(-x, -pp.blurpadding_rb);
722 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
725 for(mx = x1; mx <= x2; ++mx)
726 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
727 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
731 for(y = 0; y < pp.bufheight; ++y)
732 for(x = 0; x < pp.bufwidth; ++x)
734 int y1 = max(-y, -pp.blurpadding_rb);
735 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
738 for(my = y1; my <= y2; ++my)
739 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
740 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
744 // paste the outline below the font
745 for(y = -*pad_t; y < h + *pad_b; ++y)
746 for(x = -*pad_l; x < w + *pad_r; ++x)
748 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
751 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
752 // a' = 1 - (1 - a1) (1 - a2)
753 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
754 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
755 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
756 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
758 for(i = 0; i < bpp-1; ++i)
760 unsigned char c = imagedata[x * bpp + pitch * y + i];
761 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
762 imagedata[x * bpp + pitch * y + i] = c;
764 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
766 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
772 // just calculate parameters
773 *pad_l = pp.padding_l;
774 *pad_r = pp.padding_r;
775 *pad_t = pp.padding_t;
776 *pad_b = pp.padding_b;
780 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
781 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
782 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
785 ft2_font_map_t *fmap, temp;
786 int gpad_l, gpad_r, gpad_t, gpad_b;
788 if (!(size > 0.001f && size < 1000.0f))
793 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
796 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
798 if (!font->font_maps[map_index])
800 // if a similar size has already been loaded, ignore this one
801 //abs(font->font_maps[map_index]->size - size) < 4
802 if (font->font_maps[map_index]->size == size)
806 if (map_index >= MAX_FONT_SIZES)
811 if (font->image_font)
812 fontface = (FT_Face)font->next->face;
814 fontface = (FT_Face)font->face;
815 return (Font_SearchSize(font, fontface, size) > 0);
818 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
820 memset(&temp, 0, sizeof(temp));
822 temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
823 temp.sfx = (1.0/64.0)/(double)size;
824 temp.sfy = (1.0/64.0)/(double)size;
825 temp.intSize = -1; // negative value: LoadMap must search now :)
826 if (!Font_LoadMap(font, &temp, 0, &fmap))
828 Con_Printf("ERROR: can't load the first character map for %s\n"
831 Font_UnloadFont(font);
834 font->font_maps[map_index] = temp.next;
836 fmap->sfx = temp.sfx;
837 fmap->sfy = temp.sfy;
839 // load the default kerning vector:
840 if (font->has_kerning)
844 for (l = 0; l < 256; ++l)
846 for (r = 0; r < 256; ++r)
849 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
850 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
851 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
853 fmap->kerning.kerning[l][r][0] = 0;
854 fmap->kerning.kerning[l][r][1] = 0;
858 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
859 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
867 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
870 float value = 1000000;
872 int matchsize = -10000;
874 float fsize_x, fsize_y;
875 ft2_font_map_t **maps = font->font_maps;
877 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
879 fsize_x = *outw * vid.width / vid_conwidth.value;
881 fsize_y = *outh * vid.height / vid_conheight.value;
886 fsize_x = fsize_y = 16;
896 for (m = 0; m < MAX_FONT_SIZES; ++m)
900 // "round up" to the bigger size if two equally-valued matches exist
901 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
902 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
906 matchsize = maps[m]->size;
907 if (value == 0) // there is no better match
911 if (value <= r_font_size_snapping.value)
913 // do NOT keep the aspect for perfect rendering
914 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
915 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
920 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
922 if (index < 0 || index >= MAX_FONT_SIZES)
924 return font->font_maps[index];
927 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
929 if (font->currenth == h &&
930 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
931 font->currentw == w)) // same size has been requested
935 // sorry, but freetype doesn't seem to care about other sizes
938 if (font->image_font)
940 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
945 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
953 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
955 ft2_font_map_t *fmap;
956 if (!font->has_kerning || !r_font_kerning.integer)
958 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
960 fmap = font->font_maps[map_index];
963 if (left < 256 && right < 256)
965 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
966 // quick-kerning, be aware of the size: scale it
967 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
968 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
976 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
978 if (!Font_SetSize(font, w, h))
980 // this deserves an error message
981 Con_Printf("Failed to get kerning for %s\n", font->name);
984 ul = qFT_Get_Char_Index(font->face, left);
985 ur = qFT_Get_Char_Index(font->face, right);
986 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
988 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
989 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
993 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
995 // this deserves an error message
996 Con_Printf("Failed to get kerning for %s\n", font->name);
999 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1000 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1001 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1003 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1004 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1011 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1013 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1016 static void UnloadMapRec(ft2_font_map_t *map)
1020 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1024 UnloadMapRec(map->next);
1028 void Font_UnloadFont(ft2_font_t *font)
1034 Font_UnloadFont(font->next);
1036 if (font->attachments && font->attachmentcount)
1038 for (i = 0; i < (int)font->attachmentcount; ++i) {
1039 if (font->attachments[i].data)
1040 fontfilecache_Free(font->attachments[i].data);
1042 Mem_Free(font->attachments);
1043 font->attachmentcount = 0;
1044 font->attachments = NULL;
1046 for (i = 0; i < MAX_FONT_SIZES; ++i)
1048 if (font->font_maps[i])
1050 UnloadMapRec(font->font_maps[i]);
1051 font->font_maps[i] = NULL;
1058 qFT_Done_Face((FT_Face)font->face);
1063 fontfilecache_Free(font->data);
1068 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1070 float intSize = size;
1073 if (!Font_SetSize(font, intSize, intSize))
1075 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1078 if ((fontface->size->metrics.height>>6) <= size)
1082 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1089 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1091 char map_identifier[MAX_QPATH];
1092 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1093 unsigned char *data = NULL;
1097 FT_Int32 load_flags;
1098 int gpad_l, gpad_r, gpad_t, gpad_b;
1101 int gR, gC; // glyph position: row and column
1103 ft2_font_map_t *map, *next;
1104 ft2_font_t *usefont;
1108 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1113 if (r_font_use_alpha_textures.integer)
1116 if (font->image_font)
1117 fontface = (FT_Face)font->next->face;
1119 fontface = (FT_Face)font->face;
1121 switch(font->settings->antialias)
1124 switch(font->settings->hinting)
1127 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1131 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1135 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1141 switch(font->settings->hinting)
1144 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1147 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1150 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1154 load_flags = FT_LOAD_TARGET_NORMAL;
1160 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1162 if (font->image_font && mapstart->intSize < 0)
1163 mapstart->intSize = mapstart->size;
1164 if (mapstart->intSize < 0)
1167 mapstart->intSize = mapstart->size;
1170 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1172 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1175 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1177 if (mapstart->intSize < 2)
1179 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1182 --mapstart->intSize;
1185 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1187 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1190 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1192 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1196 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1199 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1203 // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1204 dpsnprintf(map_identifier, sizeof(map_identifier),
1205 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1209 font->settings->blur,
1210 font->settings->outline,
1211 font->settings->shadowx,
1212 font->settings->shadowy,
1213 font->settings->shadowz,
1214 (unsigned)map->start/FONT_CHARS_PER_MAP);
1216 // create a cachepic_t from the data now, or reuse an existing one
1217 map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1219 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1221 // copy over the information
1222 map->size = mapstart->size;
1223 map->intSize = mapstart->intSize;
1224 map->glyphSize = mapstart->glyphSize;
1225 map->sfx = mapstart->sfx;
1226 map->sfy = mapstart->sfy;
1228 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1229 if (map->pic->tex == r_texture_notexture)
1231 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1234 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1238 // initialize as white texture with zero alpha
1240 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1242 if (bytesPerPixel == 4)
1252 memset(map->width_of, 0, sizeof(map->width_of));
1255 map->start = mapidx * FONT_CHARS_PER_MAP;
1257 while(next->next && next->next->start < map->start)
1259 map->next = next->next;
1264 for (ch = map->start;
1265 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1268 FT_ULong glyphIndex;
1272 unsigned char *imagedata = NULL, *dst, *src;
1273 glyph_slot_t *mapglyph;
1275 int pad_l, pad_r, pad_t, pad_b;
1277 mapch = ch - map->start;
1279 if (developer_font.integer)
1280 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1283 if (gC >= FONT_CHARS_PER_LINE)
1285 gC -= FONT_CHARS_PER_LINE;
1291 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1292 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1294 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1295 // we need the glyphIndex
1296 face = (FT_Face)font->face;
1298 if (font->image_font && mapch == ch && img_fontmap[mapch])
1300 map->glyphs[mapch].image = true;
1303 glyphIndex = qFT_Get_Char_Index(face, ch);
1304 if (glyphIndex == 0)
1306 // by convention, 0 is the "missing-glyph"-glyph
1307 // try to load from a fallback font
1308 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1310 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1313 face = (FT_Face)usefont->face;
1314 glyphIndex = qFT_Get_Char_Index(face, ch);
1315 if (glyphIndex == 0)
1317 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1324 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1325 // now we let it use the "missing-glyph"-glyph
1326 face = (FT_Face)font->face;
1334 face = (FT_Face)font->face;
1335 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1338 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1339 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1344 glyph = face->glyph;
1345 bmp = &glyph->bitmap;
1350 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1351 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1352 if (w > map->glyphSize)
1353 w = map->glyphSize - gpad_l - gpad_r;
1354 if (h > map->glyphSize)
1360 switch (bmp->pixel_mode)
1362 case FT_PIXEL_MODE_MONO:
1363 if (developer_font.integer)
1364 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1366 case FT_PIXEL_MODE_GRAY2:
1367 if (developer_font.integer)
1368 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1370 case FT_PIXEL_MODE_GRAY4:
1371 if (developer_font.integer)
1372 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1374 case FT_PIXEL_MODE_GRAY:
1375 if (developer_font.integer)
1376 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1379 if (developer_font.integer)
1380 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1382 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1385 for (y = 0; y < h; ++y)
1387 dst = imagedata + y * pitch;
1388 src = bmp->buffer + y * bmp->pitch;
1390 switch (bmp->pixel_mode)
1392 case FT_PIXEL_MODE_MONO:
1393 dst += bytesPerPixel - 1; // shift to alpha byte
1394 for (x = 0; x < bmp->width; x += 8)
1396 unsigned char ch = *src++;
1397 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1398 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1399 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1400 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1401 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1402 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1403 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1404 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1407 case FT_PIXEL_MODE_GRAY2:
1408 dst += bytesPerPixel - 1; // shift to alpha byte
1409 for (x = 0; x < bmp->width; x += 4)
1411 unsigned char ch = *src++;
1412 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1413 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1414 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1415 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1418 case FT_PIXEL_MODE_GRAY4:
1419 dst += bytesPerPixel - 1; // shift to alpha byte
1420 for (x = 0; x < bmp->width; x += 2)
1422 unsigned char ch = *src++;
1423 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1424 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1427 case FT_PIXEL_MODE_GRAY:
1428 // in this case pitch should equal width
1429 for (tp = 0; tp < bmp->pitch; ++tp)
1430 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1432 //memcpy((void*)dst, (void*)src, bmp->pitch);
1433 //dst += bmp->pitch;
1444 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1447 // now fill map->glyphs[ch - map->start]
1448 mapglyph = &map->glyphs[mapch];
1452 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1454 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1455 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1456 double advance = (glyph->advance.x / 64.0) / map->size;
1457 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1458 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1460 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1461 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1462 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1463 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1464 //mapglyph->vxmin = bearingX;
1465 //mapglyph->vxmax = bearingX + mWidth;
1466 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1467 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1468 //mapglyph->vymin = -bearingY;
1469 //mapglyph->vymax = mHeight - bearingY;
1470 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1471 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1472 //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);
1473 //mapglyph->advance_x = advance * usefont->size;
1474 //mapglyph->advance_x = advance;
1475 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1476 mapglyph->advance_y = 0;
1478 if (developer_font.integer)
1480 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1481 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1482 if (ch >= 32 && ch <= 128)
1483 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1484 Con_DPrintf("glyphinfo: Vertex info:\n");
1485 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1486 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1487 Con_DPrintf("glyphinfo: Texture info:\n");
1488 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1489 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1490 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1493 map->glyphs[mapch].image = false;
1498 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1499 int h = map->glyphSize * FONT_CHAR_LINES;
1501 // abuse the Draw_CachePic system to keep track of this texture
1502 tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL);
1503 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1505 map->pic->tex = tex;
1507 if (r_font_diskcache.integer >= 1)
1509 // swap to BGRA for tga writing...
1513 for (x = 0;x < s;x++)
1516 data[x*4+0] = data[x*4+2];
1519 Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
1520 if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1521 R_SaveTextureDDSFile(tex, va("dds/%s.dds", map_identifier), true, true);
1526 if (map->pic->tex == r_texture_notexture)
1528 // if the first try isn't successful, keep it with a broken texture
1529 // otherwise we retry to load it every single frame where ft2 rendering is used
1530 // this would be bad...
1531 // only `data' must be freed
1532 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1533 font->name, mapstart->size, mapidx);
1541 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1543 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1545 // the first map must have been loaded already
1546 if (!font->font_maps[map_index])
1548 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1551 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1553 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1554 start = start->next;
1555 if (start && start->start > ch)