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 r_font_nonpoweroftwo = {CVAR_SAVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
43 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
46 ================================================================================
47 Function definitions. Taken from the freetype2 headers.
48 ================================================================================
53 (*qFT_Init_FreeType)( FT_Library *alibrary );
55 (*qFT_Done_FreeType)( FT_Library library );
58 (*qFT_New_Face)( FT_Library library,
59 const char* filepathname,
64 (*qFT_New_Memory_Face)( FT_Library library,
65 const FT_Byte* file_base,
70 (*qFT_Done_Face)( FT_Face face );
72 (*qFT_Select_Size)( FT_Face face,
73 FT_Int strike_index );
75 (*qFT_Request_Size)( FT_Face face,
76 FT_Size_Request req );
78 (*qFT_Set_Char_Size)( FT_Face face,
79 FT_F26Dot6 char_width,
80 FT_F26Dot6 char_height,
81 FT_UInt horz_resolution,
82 FT_UInt vert_resolution );
84 (*qFT_Set_Pixel_Sizes)( FT_Face face,
86 FT_UInt pixel_height );
88 (*qFT_Load_Glyph)( FT_Face face,
90 FT_Int32 load_flags );
92 (*qFT_Load_Char)( FT_Face face,
94 FT_Int32 load_flags );
96 (*qFT_Get_Char_Index)( FT_Face face,
99 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
100 FT_Render_Mode render_mode );
101 FT_EXPORT( FT_Error )
102 (*qFT_Get_Kerning)( FT_Face face,
106 FT_Vector *akerning );
107 FT_EXPORT( FT_Error )
108 (*qFT_Attach_Stream)( FT_Face face,
109 FT_Open_Args* parameters );
111 ================================================================================
112 Support for dynamically loading the FreeType2 library
113 ================================================================================
116 static dllfunction_t ft2funcs[] =
118 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
119 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
120 //{"FT_New_Face", (void **) &qFT_New_Face},
121 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
122 {"FT_Done_Face", (void **) &qFT_Done_Face},
123 {"FT_Select_Size", (void **) &qFT_Select_Size},
124 {"FT_Request_Size", (void **) &qFT_Request_Size},
125 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
126 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
127 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
128 {"FT_Load_Char", (void **) &qFT_Load_Char},
129 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
130 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
131 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
132 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
136 /// Handle for FreeType2 DLL
137 static dllhandle_t ft2_dll = NULL;
139 /// Memory pool for fonts
140 static mempool_t *font_mempool= NULL;
142 /// FreeType library handle
143 static FT_Library font_ft2lib = NULL;
145 #define POSTPROCESS_MAXRADIUS 8
148 unsigned char *buf, *buf2;
149 int bufsize, bufwidth, bufheight, bufpitch;
150 float blur, outline, shadowx, shadowy, shadowz;
151 int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
152 unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
153 unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
156 static font_postprocess_t pp;
158 typedef struct fontfilecache_s
163 char path[MAX_QPATH];
166 #define MAX_FONTFILES 8
167 static fontfilecache_t fontfiles[MAX_FONTFILES];
168 static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer)
173 for(i = 0; i < MAX_FONTFILES; ++i)
175 if(fontfiles[i].refcount > 0)
176 if(!strcmp(path, fontfiles[i].path))
178 *filesizepointer = fontfiles[i].len;
179 ++fontfiles[i].refcount;
180 return fontfiles[i].buf;
184 buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
187 for(i = 0; i < MAX_FONTFILES; ++i)
188 if(fontfiles[i].refcount <= 0)
190 strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
191 fontfiles[i].len = *filesizepointer;
192 fontfiles[i].buf = buf;
193 fontfiles[i].refcount = 1;
200 static void fontfilecache_Free(const unsigned char *buf)
203 for(i = 0; i < MAX_FONTFILES; ++i)
205 if(fontfiles[i].refcount > 0)
206 if(fontfiles[i].buf == buf)
208 if(--fontfiles[i].refcount <= 0)
210 Mem_Free(fontfiles[i].buf);
211 fontfiles[i].buf = NULL;
216 // if we get here, it used regular allocation
217 Mem_Free((void *) buf);
219 static void fontfilecache_FreeAll(void)
222 for(i = 0; i < MAX_FONTFILES; ++i)
224 if(fontfiles[i].refcount > 0)
225 Mem_Free(fontfiles[i].buf);
226 fontfiles[i].buf = NULL;
227 fontfiles[i].refcount = 0;
235 Unload the FreeType2 DLL
238 void Font_CloseLibrary (void)
240 fontfilecache_FreeAll();
242 Mem_FreePool(&font_mempool);
243 if (font_ft2lib && qFT_Done_FreeType)
245 qFT_Done_FreeType(font_ft2lib);
248 Sys_UnloadLibrary (&ft2_dll);
256 Try to load the FreeType2 DLL
259 qboolean Font_OpenLibrary (void)
261 const char* dllnames [] =
266 #elif defined(MACOSX)
267 "libfreetype.6.dylib",
276 if (r_font_disable_freetype.integer)
284 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
293 Initialize the freetype2 font subsystem
297 void font_start(void)
299 if (!Font_OpenLibrary())
302 if (qFT_Init_FreeType(&font_ft2lib))
304 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
309 font_mempool = Mem_AllocPool("FONT", 0, NULL);
312 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
318 void font_shutdown(void)
321 for (i = 0; i < dp_fonts.maxsize; ++i)
323 if (dp_fonts.f[i].ft2)
325 Font_UnloadFont(dp_fonts.f[i].ft2);
326 dp_fonts.f[i].ft2 = NULL;
332 void font_newmap(void)
338 Cvar_RegisterVariable(&r_font_nonpoweroftwo);
339 Cvar_RegisterVariable(&r_font_disable_freetype);
340 Cvar_RegisterVariable(&r_font_use_alpha_textures);
341 Cvar_RegisterVariable(&r_font_size_snapping);
342 Cvar_RegisterVariable(&r_font_kerning);
343 Cvar_RegisterVariable(&r_font_diskcache);
344 Cvar_RegisterVariable(&r_font_compress);
345 Cvar_RegisterVariable(&developer_font);
347 // let's open it at startup already
352 ================================================================================
353 Implementation of a more or less lazy font loading and rendering code.
354 ================================================================================
357 #include "ft2_fontdefs.h"
359 ft2_font_t *Font_Alloc(void)
363 return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
366 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
368 ft2_attachment_t *na;
370 font->attachmentcount++;
371 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
374 if (font->attachments && font->attachmentcount > 1)
376 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
377 Mem_Free(font->attachments);
379 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
380 font->attachments = na;
384 float Font_VirtualToRealSize(float sz)
392 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
393 vh = ((vid.height > 0) ? vid.height : vid_height.value);
394 // now try to scale to our actual size:
395 sn = sz * vh / vid_conheight.value;
397 if ( sn - (float)si >= 0.5 )
402 float Font_SnapTo(float val, float snapwidth)
404 return floor(val / snapwidth + 0.5f) * snapwidth;
407 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
408 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
409 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
412 ft2_font_t *ft2, *fbfont, *fb;
421 // check if a fallback font has been specified, if it has been, and the
422 // font fails to load, use the image font as main font
423 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
425 if (dpfnt->fallbacks[i][0])
429 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
431 if (i >= MAX_FONT_FALLBACKS)
437 strlcpy(ft2->name, name, sizeof(ft2->name));
438 ft2->image_font = true;
439 ft2->has_kerning = false;
443 ft2->image_font = false;
446 // attempt to load fallback fonts:
448 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
450 if (!dpfnt->fallbacks[i][0])
452 if (! (fb = Font_Alloc()) )
454 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
458 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
460 if(!FS_FileExists(va("%s.tga", dpfnt->fallbacks[i])))
461 if(!FS_FileExists(va("%s.png", dpfnt->fallbacks[i])))
462 if(!FS_FileExists(va("%s.jpg", dpfnt->fallbacks[i])))
463 if(!FS_FileExists(va("%s.pcx", dpfnt->fallbacks[i])))
464 Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
469 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
471 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
476 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
481 // at least one size of the fallback font loaded successfully
487 if (fbfont == ft2 && ft2->image_font)
489 // no fallbacks were loaded successfully:
496 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
498 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
503 // loading failed for every requested size
504 Font_UnloadFont(ft2);
510 //Con_Printf("%i sizes loaded\n", count);
515 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
518 char filename[MAX_QPATH];
521 const unsigned char *data;
522 fs_offset_t datasize;
524 memset(font, 0, sizeof(*font));
526 if (!Font_OpenLibrary())
528 if (!r_font_disable_freetype.integer)
530 Con_Printf("WARNING: can't open load font %s\n"
531 "You need the FreeType2 DLL to load font files\n",
537 font->settings = settings;
539 namelen = strlen(name);
541 // try load direct file
542 memcpy(filename, name, namelen+1);
543 data = fontfilecache_LoadFile(filename, false, &datasize);
547 memcpy(filename + namelen, ".ttf", 5);
548 data = fontfilecache_LoadFile(filename, false, &datasize);
553 memcpy(filename + namelen, ".otf", 5);
554 data = fontfilecache_LoadFile(filename, false, &datasize);
559 ft2_attachment_t afm;
561 memcpy(filename + namelen, ".pfb", 5);
562 data = fontfilecache_LoadFile(filename, false, &datasize);
566 memcpy(filename + namelen, ".afm", 5);
567 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
570 Font_Attach(font, &afm);
575 // FS_LoadFile being not-quiet should print an error :)
578 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
580 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
581 if (status && _face != 0)
583 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
585 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
590 Con_Printf("ERROR: can't create face for %s\n"
591 "Error %i\n", // TODO: error strings
593 Font_UnloadFont(font);
597 // add the attachments
598 for (i = 0; i < font->attachmentcount; ++i)
601 memset(&args, 0, sizeof(args));
602 args.flags = FT_OPEN_MEMORY;
603 args.memory_base = (const FT_Byte*)font->attachments[i].data;
604 args.memory_size = font->attachments[i].size;
605 if (qFT_Attach_Stream((FT_Face)font->face, &args))
606 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
609 memcpy(font->name, name, namelen+1);
610 font->image_font = false;
611 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
615 void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
618 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
619 qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
620 qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
621 pp.blur = fnt->settings->blur;
622 pp.outline = fnt->settings->outline;
623 pp.shadowx = fnt->settings->shadowx;
624 pp.shadowy = fnt->settings->shadowy;
625 pp.shadowz = fnt->settings->shadowz;
626 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
627 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
628 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
629 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
630 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
631 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
632 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
633 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
634 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
635 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
639 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
640 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));
641 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
642 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
643 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
644 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
648 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
649 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
651 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
652 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
655 pp.bufwidth = w + pp.padding_l + pp.padding_r;
656 pp.bufheight = h + pp.padding_t + pp.padding_b;
657 pp.bufpitch = pp.bufwidth;
658 needed = pp.bufwidth * pp.bufheight;
659 if(!pp.buf || pp.bufsize < needed * 2)
663 pp.bufsize = needed * 4;
664 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
665 pp.buf2 = pp.buf + needed;
669 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)
673 // calculate gauss table
674 Font_Postprocess_Update(fnt, bpp, w, h);
679 // perform operation, not exceeding the passed padding values,
680 // but possibly reducing them
681 *pad_l = min(*pad_l, pp.padding_l);
682 *pad_r = min(*pad_r, pp.padding_r);
683 *pad_t = min(*pad_t, pp.padding_t);
684 *pad_b = min(*pad_b, pp.padding_b);
686 // outline the font (RGBA only)
687 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
689 // this is like mplayer subtitle rendering
690 // bbuffer, bitmap buffer: this is our font
691 // abuffer, alpha buffer: this is pp.buf
692 // tmp: this is pp.buf2
694 // create outline buffer
695 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
696 for(y = -*pad_t; y < h + *pad_b; ++y)
697 for(x = -*pad_l; x < w + *pad_r; ++x)
699 int x1 = max(-x, -pp.outlinepadding_r);
700 int y1 = max(-y, -pp.outlinepadding_b);
701 int x2 = min(pp.outlinepadding_l, w-1-x);
702 int y2 = min(pp.outlinepadding_t, h-1-y);
706 for(my = y1; my <= y2; ++my)
707 for(mx = x1; mx <= x2; ++mx)
709 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
713 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
716 // blur the outline buffer
717 if(pp.blur > 0 || pp.shadowz != 0)
720 for(y = 0; y < pp.bufheight; ++y)
721 for(x = 0; x < pp.bufwidth; ++x)
723 int x1 = max(-x, -pp.blurpadding_rb);
724 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
727 for(mx = x1; mx <= x2; ++mx)
728 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
729 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
733 for(y = 0; y < pp.bufheight; ++y)
734 for(x = 0; x < pp.bufwidth; ++x)
736 int y1 = max(-y, -pp.blurpadding_rb);
737 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
740 for(my = y1; my <= y2; ++my)
741 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
742 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
746 // paste the outline below the font
747 for(y = -*pad_t; y < h + *pad_b; ++y)
748 for(x = -*pad_l; x < w + *pad_r; ++x)
750 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
753 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
754 // a' = 1 - (1 - a1) (1 - a2)
755 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
756 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
757 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
758 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
760 for(i = 0; i < bpp-1; ++i)
762 unsigned char c = imagedata[x * bpp + pitch * y + i];
763 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
764 imagedata[x * bpp + pitch * y + i] = c;
766 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
768 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
774 // perform operation, not exceeding the passed padding values,
775 // but possibly reducing them
776 *pad_l = min(*pad_l, pp.padding_l);
777 *pad_r = min(*pad_r, pp.padding_r);
778 *pad_t = min(*pad_t, pp.padding_t);
779 *pad_b = min(*pad_b, pp.padding_b);
783 // just calculate parameters
784 *pad_l = pp.padding_l;
785 *pad_r = pp.padding_r;
786 *pad_t = pp.padding_t;
787 *pad_b = pp.padding_b;
791 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
792 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
793 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
796 ft2_font_map_t *fmap, temp;
797 int gpad_l, gpad_r, gpad_t, gpad_b;
799 if (!(size > 0.001f && size < 1000.0f))
804 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
807 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
809 if (!font->font_maps[map_index])
811 // if a similar size has already been loaded, ignore this one
812 //abs(font->font_maps[map_index]->size - size) < 4
813 if (font->font_maps[map_index]->size == size)
817 if (map_index >= MAX_FONT_SIZES)
822 if (font->image_font)
823 fontface = (FT_Face)font->next->face;
825 fontface = (FT_Face)font->face;
826 return (Font_SearchSize(font, fontface, size) > 0);
829 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
831 memset(&temp, 0, sizeof(temp));
833 temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
834 if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
835 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
836 temp.sfx = (1.0/64.0)/(double)size;
837 temp.sfy = (1.0/64.0)/(double)size;
838 temp.intSize = -1; // negative value: LoadMap must search now :)
839 if (!Font_LoadMap(font, &temp, 0, &fmap))
841 Con_Printf("ERROR: can't load the first character map for %s\n"
844 Font_UnloadFont(font);
847 font->font_maps[map_index] = temp.next;
849 fmap->sfx = temp.sfx;
850 fmap->sfy = temp.sfy;
852 // load the default kerning vector:
853 if (font->has_kerning)
857 for (l = 0; l < 256; ++l)
859 for (r = 0; r < 256; ++r)
862 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
863 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
864 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
866 fmap->kerning.kerning[l][r][0] = 0;
867 fmap->kerning.kerning[l][r][1] = 0;
871 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
872 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
880 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
883 float value = 1000000;
885 int matchsize = -10000;
887 float fsize_x, fsize_y;
888 ft2_font_map_t **maps = font->font_maps;
890 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
892 fsize_x = *outw * vid.width / vid_conwidth.value;
894 fsize_y = *outh * vid.height / vid_conheight.value;
899 fsize_x = fsize_y = 16;
909 for (m = 0; m < MAX_FONT_SIZES; ++m)
913 // "round up" to the bigger size if two equally-valued matches exist
914 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
915 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
919 matchsize = maps[m]->size;
920 if (value == 0) // there is no better match
924 if (value <= r_font_size_snapping.value)
926 // do NOT keep the aspect for perfect rendering
927 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
928 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
933 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
935 if (index < 0 || index >= MAX_FONT_SIZES)
937 return font->font_maps[index];
940 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
942 if (font->currenth == h &&
943 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
944 font->currentw == w)) // same size has been requested
948 // sorry, but freetype doesn't seem to care about other sizes
951 if (font->image_font)
953 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
958 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
966 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
968 ft2_font_map_t *fmap;
969 if (!font->has_kerning || !r_font_kerning.integer)
971 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
973 fmap = font->font_maps[map_index];
976 if (left < 256 && right < 256)
978 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
979 // quick-kerning, be aware of the size: scale it
980 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
981 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
989 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
991 if (!Font_SetSize(font, w, h))
993 // this deserves an error message
994 Con_Printf("Failed to get kerning for %s\n", font->name);
997 ul = qFT_Get_Char_Index(font->face, left);
998 ur = qFT_Get_Char_Index(font->face, right);
999 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1001 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1002 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1006 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1008 // this deserves an error message
1009 Con_Printf("Failed to get kerning for %s\n", font->name);
1012 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1013 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1014 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1016 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1017 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1024 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1026 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1029 static void UnloadMapRec(ft2_font_map_t *map)
1033 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1037 UnloadMapRec(map->next);
1041 void Font_UnloadFont(ft2_font_t *font)
1047 Font_UnloadFont(font->next);
1049 if (font->attachments && font->attachmentcount)
1051 for (i = 0; i < (int)font->attachmentcount; ++i) {
1052 if (font->attachments[i].data)
1053 fontfilecache_Free(font->attachments[i].data);
1055 Mem_Free(font->attachments);
1056 font->attachmentcount = 0;
1057 font->attachments = NULL;
1059 for (i = 0; i < MAX_FONT_SIZES; ++i)
1061 if (font->font_maps[i])
1063 UnloadMapRec(font->font_maps[i]);
1064 font->font_maps[i] = NULL;
1071 qFT_Done_Face((FT_Face)font->face);
1076 fontfilecache_Free(font->data);
1081 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1083 float intSize = size;
1086 if (!Font_SetSize(font, intSize, intSize))
1088 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1091 if ((fontface->size->metrics.height>>6) <= size)
1095 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1102 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1104 char map_identifier[MAX_QPATH];
1105 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1106 unsigned char *data = NULL;
1110 FT_Int32 load_flags;
1111 int gpad_l, gpad_r, gpad_t, gpad_b;
1114 int gR, gC; // glyph position: row and column
1116 ft2_font_map_t *map, *next;
1117 ft2_font_t *usefont;
1121 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1126 if (r_font_use_alpha_textures.integer)
1129 if (font->image_font)
1130 fontface = (FT_Face)font->next->face;
1132 fontface = (FT_Face)font->face;
1134 switch(font->settings->antialias)
1137 switch(font->settings->hinting)
1140 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1144 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1148 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1154 switch(font->settings->hinting)
1157 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1160 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1163 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1167 load_flags = FT_LOAD_TARGET_NORMAL;
1173 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1175 if (font->image_font && mapstart->intSize < 0)
1176 mapstart->intSize = mapstart->size;
1177 if (mapstart->intSize < 0)
1180 mapstart->intSize = mapstart->size;
1183 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1185 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1188 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1190 if (mapstart->intSize < 2)
1192 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1195 --mapstart->intSize;
1198 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1200 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1203 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1205 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1209 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1212 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1216 // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1217 dpsnprintf(map_identifier, sizeof(map_identifier),
1218 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1220 (double) mapstart->intSize,
1222 (double) font->settings->blur,
1223 (double) font->settings->outline,
1224 (double) font->settings->shadowx,
1225 (double) font->settings->shadowy,
1226 (double) font->settings->shadowz,
1229 // create a cachepic_t from the data now, or reuse an existing one
1230 map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1231 if (developer_font.integer)
1233 if (map->pic->tex == r_texture_notexture)
1234 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1236 Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1239 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1241 // copy over the information
1242 map->size = mapstart->size;
1243 map->intSize = mapstart->intSize;
1244 map->glyphSize = mapstart->glyphSize;
1245 map->sfx = mapstart->sfx;
1246 map->sfy = mapstart->sfy;
1248 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1249 if (map->pic->tex == r_texture_notexture)
1251 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1254 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1258 // initialize as white texture with zero alpha
1260 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1262 if (bytesPerPixel == 4)
1272 memset(map->width_of, 0, sizeof(map->width_of));
1275 map->start = mapidx * FONT_CHARS_PER_MAP;
1277 while(next->next && next->next->start < map->start)
1279 map->next = next->next;
1284 for (ch = map->start;
1285 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1288 FT_ULong glyphIndex;
1292 unsigned char *imagedata = NULL, *dst, *src;
1293 glyph_slot_t *mapglyph;
1295 int pad_l, pad_r, pad_t, pad_b;
1297 mapch = ch - map->start;
1299 if (developer_font.integer)
1300 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1303 if (gC >= FONT_CHARS_PER_LINE)
1305 gC -= FONT_CHARS_PER_LINE;
1311 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1312 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1314 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1315 // we need the glyphIndex
1316 face = (FT_Face)font->face;
1318 if (font->image_font && mapch == ch && img_fontmap[mapch])
1320 map->glyphs[mapch].image = true;
1323 glyphIndex = qFT_Get_Char_Index(face, ch);
1324 if (glyphIndex == 0)
1326 // by convention, 0 is the "missing-glyph"-glyph
1327 // try to load from a fallback font
1328 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1330 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1333 face = (FT_Face)usefont->face;
1334 glyphIndex = qFT_Get_Char_Index(face, ch);
1335 if (glyphIndex == 0)
1337 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1344 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1345 // now we let it use the "missing-glyph"-glyph
1346 face = (FT_Face)font->face;
1354 face = (FT_Face)font->face;
1355 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1358 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1359 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1364 glyph = face->glyph;
1365 bmp = &glyph->bitmap;
1370 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1371 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1372 if (w > map->glyphSize)
1373 w = map->glyphSize - gpad_l - gpad_r;
1374 if (h > map->glyphSize)
1380 switch (bmp->pixel_mode)
1382 case FT_PIXEL_MODE_MONO:
1383 if (developer_font.integer)
1384 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1386 case FT_PIXEL_MODE_GRAY2:
1387 if (developer_font.integer)
1388 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1390 case FT_PIXEL_MODE_GRAY4:
1391 if (developer_font.integer)
1392 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1394 case FT_PIXEL_MODE_GRAY:
1395 if (developer_font.integer)
1396 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1399 if (developer_font.integer)
1400 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1402 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1405 for (y = 0; y < h; ++y)
1407 dst = imagedata + y * pitch;
1408 src = bmp->buffer + y * bmp->pitch;
1410 switch (bmp->pixel_mode)
1412 case FT_PIXEL_MODE_MONO:
1413 dst += bytesPerPixel - 1; // shift to alpha byte
1414 for (x = 0; x < bmp->width; x += 8)
1416 unsigned char ch = *src++;
1417 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1418 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1419 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1420 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1421 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1422 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1423 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1424 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1427 case FT_PIXEL_MODE_GRAY2:
1428 dst += bytesPerPixel - 1; // shift to alpha byte
1429 for (x = 0; x < bmp->width; x += 4)
1431 unsigned char ch = *src++;
1432 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1433 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1434 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1435 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1438 case FT_PIXEL_MODE_GRAY4:
1439 dst += bytesPerPixel - 1; // shift to alpha byte
1440 for (x = 0; x < bmp->width; x += 2)
1442 unsigned char ch = *src++;
1443 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1444 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1447 case FT_PIXEL_MODE_GRAY:
1448 // in this case pitch should equal width
1449 for (tp = 0; tp < bmp->pitch; ++tp)
1450 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1452 //memcpy((void*)dst, (void*)src, bmp->pitch);
1453 //dst += bmp->pitch;
1464 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1472 Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1476 // now fill map->glyphs[ch - map->start]
1477 mapglyph = &map->glyphs[mapch];
1481 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1483 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1484 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1485 double advance = (glyph->advance.x / 64.0) / map->size;
1486 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1487 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1489 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1490 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1491 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1492 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1493 //mapglyph->vxmin = bearingX;
1494 //mapglyph->vxmax = bearingX + mWidth;
1495 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1496 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1497 //mapglyph->vymin = -bearingY;
1498 //mapglyph->vymax = mHeight - bearingY;
1499 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1500 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1501 //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);
1502 //mapglyph->advance_x = advance * usefont->size;
1503 //mapglyph->advance_x = advance;
1504 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1505 mapglyph->advance_y = 0;
1507 if (developer_font.integer)
1509 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1510 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1511 if (ch >= 32 && ch <= 128)
1512 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1513 Con_DPrintf("glyphinfo: Vertex info:\n");
1514 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1515 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1516 Con_DPrintf("glyphinfo: Texture info:\n");
1517 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1518 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1519 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1522 map->glyphs[mapch].image = false;
1525 if (map->pic->tex == r_texture_notexture)
1527 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1528 int h = map->glyphSize * FONT_CHAR_LINES;
1530 // abuse the Draw_CachePic system to keep track of this texture
1531 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);
1532 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1534 map->pic->tex = tex;
1536 if (r_font_diskcache.integer >= 1)
1538 // swap to BGRA for tga writing...
1542 for (x = 0;x < s;x++)
1545 data[x*4+0] = data[x*4+2];
1548 Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
1549 if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1550 R_SaveTextureDDSFile(tex, va("dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1557 if (map->pic->tex == r_texture_notexture)
1559 // if the first try isn't successful, keep it with a broken texture
1560 // otherwise we retry to load it every single frame where ft2 rendering is used
1561 // this would be bad...
1562 // only `data' must be freed
1563 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1564 font->name, mapstart->size, mapidx);
1572 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1574 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1576 // the first map must have been loaded already
1577 if (!font->font_maps[map_index])
1579 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1582 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1584 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1585 start = start->next;
1586 if (start && start->start > ch)