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"};
45 #ifndef DP_FREETYPE_STATIC
48 ================================================================================
49 Function definitions. Taken from the freetype2 headers.
50 ================================================================================
55 (*qFT_Init_FreeType)( FT_Library *alibrary );
57 (*qFT_Done_FreeType)( FT_Library library );
60 (*qFT_New_Face)( FT_Library library,
61 const char* filepathname,
66 (*qFT_New_Memory_Face)( FT_Library library,
67 const FT_Byte* file_base,
72 (*qFT_Done_Face)( FT_Face face );
74 (*qFT_Select_Size)( FT_Face face,
75 FT_Int strike_index );
77 (*qFT_Request_Size)( FT_Face face,
78 FT_Size_Request req );
80 (*qFT_Set_Char_Size)( FT_Face face,
81 FT_F26Dot6 char_width,
82 FT_F26Dot6 char_height,
83 FT_UInt horz_resolution,
84 FT_UInt vert_resolution );
86 (*qFT_Set_Pixel_Sizes)( FT_Face face,
88 FT_UInt pixel_height );
90 (*qFT_Load_Glyph)( FT_Face face,
92 FT_Int32 load_flags );
94 (*qFT_Load_Char)( FT_Face face,
96 FT_Int32 load_flags );
98 (*qFT_Get_Char_Index)( FT_Face face,
100 FT_EXPORT( FT_Error )
101 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
102 FT_Render_Mode render_mode );
103 FT_EXPORT( FT_Error )
104 (*qFT_Get_Kerning)( FT_Face face,
108 FT_Vector *akerning );
109 FT_EXPORT( FT_Error )
110 (*qFT_Attach_Stream)( FT_Face face,
111 FT_Open_Args* parameters );
113 ================================================================================
114 Support for dynamically loading the FreeType2 library
115 ================================================================================
118 static dllfunction_t ft2funcs[] =
120 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
121 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
122 //{"FT_New_Face", (void **) &qFT_New_Face},
123 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
124 {"FT_Done_Face", (void **) &qFT_Done_Face},
125 {"FT_Select_Size", (void **) &qFT_Select_Size},
126 {"FT_Request_Size", (void **) &qFT_Request_Size},
127 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
128 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
129 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
130 {"FT_Load_Char", (void **) &qFT_Load_Char},
131 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
132 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
133 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
134 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
138 /// Handle for FreeType2 DLL
139 static dllhandle_t ft2_dll = NULL;
143 FT_EXPORT( FT_Error )
144 (FT_Init_FreeType)( FT_Library *alibrary );
145 FT_EXPORT( FT_Error )
146 (FT_Done_FreeType)( FT_Library library );
148 FT_EXPORT( FT_Error )
149 (FT_New_Face)( FT_Library library,
150 const char* filepathname,
154 FT_EXPORT( FT_Error )
155 (FT_New_Memory_Face)( FT_Library library,
156 const FT_Byte* file_base,
160 FT_EXPORT( FT_Error )
161 (FT_Done_Face)( FT_Face face );
162 FT_EXPORT( FT_Error )
163 (FT_Select_Size)( FT_Face face,
164 FT_Int strike_index );
165 FT_EXPORT( FT_Error )
166 (FT_Request_Size)( FT_Face face,
167 FT_Size_Request req );
168 FT_EXPORT( FT_Error )
169 (FT_Set_Char_Size)( FT_Face face,
170 FT_F26Dot6 char_width,
171 FT_F26Dot6 char_height,
172 FT_UInt horz_resolution,
173 FT_UInt vert_resolution );
174 FT_EXPORT( FT_Error )
175 (FT_Set_Pixel_Sizes)( FT_Face face,
177 FT_UInt pixel_height );
178 FT_EXPORT( FT_Error )
179 (FT_Load_Glyph)( FT_Face face,
181 FT_Int32 load_flags );
182 FT_EXPORT( FT_Error )
183 (FT_Load_Char)( FT_Face face,
185 FT_Int32 load_flags );
187 (FT_Get_Char_Index)( FT_Face face,
189 FT_EXPORT( FT_Error )
190 (FT_Render_Glyph)( FT_GlyphSlot slot,
191 FT_Render_Mode render_mode );
192 FT_EXPORT( FT_Error )
193 (FT_Get_Kerning)( FT_Face face,
197 FT_Vector *akerning );
198 FT_EXPORT( FT_Error )
199 (FT_Attach_Stream)( FT_Face face,
200 FT_Open_Args* parameters );
202 #define qFT_Init_FreeType FT_Init_FreeType
203 #define qFT_Done_FreeType FT_Done_FreeType
204 //#define qFT_New_Face FT_New_Face
205 #define qFT_New_Memory_Face FT_New_Memory_Face
206 #define qFT_Done_Face FT_Done_Face
207 #define qFT_Select_Size FT_Select_Size
208 #define qFT_Request_Size FT_Request_Size
209 #define qFT_Set_Char_Size FT_Set_Char_Size
210 #define qFT_Set_Pixel_Sizes FT_Set_Pixel_Sizes
211 #define qFT_Load_Glyph FT_Load_Glyph
212 #define qFT_Load_Char FT_Load_Char
213 #define qFT_Get_Char_Index FT_Get_Char_Index
214 #define qFT_Render_Glyph FT_Render_Glyph
215 #define qFT_Get_Kerning FT_Get_Kerning
216 #define qFT_Attach_Stream FT_Attach_Stream
220 /// Memory pool for fonts
221 static mempool_t *font_mempool= NULL;
223 /// FreeType library handle
224 static FT_Library font_ft2lib = NULL;
226 #define POSTPROCESS_MAXRADIUS 8
229 unsigned char *buf, *buf2;
230 int bufsize, bufwidth, bufheight, bufpitch;
231 float blur, outline, shadowx, shadowy, shadowz;
232 int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
233 unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
234 unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
237 static font_postprocess_t pp;
239 typedef struct fontfilecache_s
244 char path[MAX_QPATH];
247 #define MAX_FONTFILES 8
248 static fontfilecache_t fontfiles[MAX_FONTFILES];
249 static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer)
254 for(i = 0; i < MAX_FONTFILES; ++i)
256 if(fontfiles[i].refcount > 0)
257 if(!strcmp(path, fontfiles[i].path))
259 *filesizepointer = fontfiles[i].len;
260 ++fontfiles[i].refcount;
261 return fontfiles[i].buf;
265 buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
268 for(i = 0; i < MAX_FONTFILES; ++i)
269 if(fontfiles[i].refcount <= 0)
271 strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
272 fontfiles[i].len = *filesizepointer;
273 fontfiles[i].buf = buf;
274 fontfiles[i].refcount = 1;
281 static void fontfilecache_Free(const unsigned char *buf)
284 for(i = 0; i < MAX_FONTFILES; ++i)
286 if(fontfiles[i].refcount > 0)
287 if(fontfiles[i].buf == buf)
289 if(--fontfiles[i].refcount <= 0)
291 Mem_Free(fontfiles[i].buf);
292 fontfiles[i].buf = NULL;
297 // if we get here, it used regular allocation
298 Mem_Free((void *) buf);
300 static void fontfilecache_FreeAll(void)
303 for(i = 0; i < MAX_FONTFILES; ++i)
305 if(fontfiles[i].refcount > 0)
306 Mem_Free(fontfiles[i].buf);
307 fontfiles[i].buf = NULL;
308 fontfiles[i].refcount = 0;
316 Unload the FreeType2 DLL
319 void Font_CloseLibrary (void)
321 fontfilecache_FreeAll();
323 Mem_FreePool(&font_mempool);
324 if (font_ft2lib && qFT_Done_FreeType)
326 qFT_Done_FreeType(font_ft2lib);
329 #ifndef DP_FREETYPE_STATIC
330 Sys_UnloadLibrary (&ft2_dll);
339 Try to load the FreeType2 DLL
342 qboolean Font_OpenLibrary (void)
344 #ifndef DP_FREETYPE_STATIC
345 const char* dllnames [] =
350 #elif defined(MACOSX)
351 "libfreetype.6.dylib",
361 if (r_font_disable_freetype.integer)
364 #ifndef DP_FREETYPE_STATIC
370 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
380 Initialize the freetype2 font subsystem
384 void font_start(void)
386 if (!Font_OpenLibrary())
389 if (qFT_Init_FreeType(&font_ft2lib))
391 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
396 font_mempool = Mem_AllocPool("FONT", 0, NULL);
399 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
405 void font_shutdown(void)
408 for (i = 0; i < dp_fonts.maxsize; ++i)
410 if (dp_fonts.f[i].ft2)
412 Font_UnloadFont(dp_fonts.f[i].ft2);
413 dp_fonts.f[i].ft2 = NULL;
419 void font_newmap(void)
425 Cvar_RegisterVariable(&r_font_nonpoweroftwo);
426 Cvar_RegisterVariable(&r_font_disable_freetype);
427 Cvar_RegisterVariable(&r_font_use_alpha_textures);
428 Cvar_RegisterVariable(&r_font_size_snapping);
429 Cvar_RegisterVariable(&r_font_kerning);
430 Cvar_RegisterVariable(&r_font_diskcache);
431 Cvar_RegisterVariable(&r_font_compress);
432 Cvar_RegisterVariable(&developer_font);
434 // let's open it at startup already
439 ================================================================================
440 Implementation of a more or less lazy font loading and rendering code.
441 ================================================================================
444 #include "ft2_fontdefs.h"
446 ft2_font_t *Font_Alloc(void)
448 #ifndef DP_FREETYPE_STATIC
451 if (r_font_disable_freetype.integer)
454 return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
457 static qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
459 ft2_attachment_t *na;
461 font->attachmentcount++;
462 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
465 if (font->attachments && font->attachmentcount > 1)
467 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
468 Mem_Free(font->attachments);
470 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
471 font->attachments = na;
475 float Font_VirtualToRealSize(float sz)
483 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
484 vh = ((vid.height > 0) ? vid.height : vid_height.value);
485 // now try to scale to our actual size:
486 sn = sz * vh / vid_conheight.value;
488 if ( sn - (float)si >= 0.5 )
493 float Font_SnapTo(float val, float snapwidth)
495 return floor(val / snapwidth + 0.5f) * snapwidth;
498 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
499 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
500 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
503 ft2_font_t *ft2, *fbfont, *fb;
513 // check if a fallback font has been specified, if it has been, and the
514 // font fails to load, use the image font as main font
515 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
517 if (dpfnt->fallbacks[i][0])
521 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
523 if (i >= MAX_FONT_FALLBACKS)
529 strlcpy(ft2->name, name, sizeof(ft2->name));
530 ft2->image_font = true;
531 ft2->has_kerning = false;
535 ft2->image_font = false;
538 // attempt to load fallback fonts:
540 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
542 if (!dpfnt->fallbacks[i][0])
544 if (! (fb = Font_Alloc()) )
546 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
550 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
552 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i])))
553 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i])))
554 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i])))
555 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i])))
556 Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
561 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
563 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
568 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
573 // at least one size of the fallback font loaded successfully
579 if (fbfont == ft2 && ft2->image_font)
581 // no fallbacks were loaded successfully:
588 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
590 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
595 // loading failed for every requested size
596 Font_UnloadFont(ft2);
602 //Con_Printf("%i sizes loaded\n", count);
607 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
610 char filename[MAX_QPATH];
613 const unsigned char *data;
614 fs_offset_t datasize;
616 memset(font, 0, sizeof(*font));
618 if (!Font_OpenLibrary())
620 if (!r_font_disable_freetype.integer)
622 Con_Printf("WARNING: can't open load font %s\n"
623 "You need the FreeType2 DLL to load font files\n",
629 font->settings = settings;
631 namelen = strlen(name);
632 if (namelen + 5 > sizeof(filename))
634 Con_Printf("WARNING: too long font name. Cannot load this.\n");
638 // try load direct file
639 memcpy(filename, name, namelen+1);
640 data = fontfilecache_LoadFile(filename, false, &datasize);
644 memcpy(filename + namelen, ".ttf", 5);
645 data = fontfilecache_LoadFile(filename, false, &datasize);
650 memcpy(filename + namelen, ".otf", 5);
651 data = fontfilecache_LoadFile(filename, false, &datasize);
656 ft2_attachment_t afm;
658 memcpy(filename + namelen, ".pfb", 5);
659 data = fontfilecache_LoadFile(filename, false, &datasize);
663 memcpy(filename + namelen, ".afm", 5);
664 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
667 Font_Attach(font, &afm);
672 // FS_LoadFile being not-quiet should print an error :)
675 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
677 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
678 if (status && _face != 0)
680 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
682 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
687 Con_Printf("ERROR: can't create face for %s\n"
688 "Error %i\n", // TODO: error strings
690 Font_UnloadFont(font);
694 // add the attachments
695 for (i = 0; i < font->attachmentcount; ++i)
698 memset(&args, 0, sizeof(args));
699 args.flags = FT_OPEN_MEMORY;
700 args.memory_base = (const FT_Byte*)font->attachments[i].data;
701 args.memory_size = font->attachments[i].size;
702 if (qFT_Attach_Stream((FT_Face)font->face, &args))
703 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
706 strlcpy(font->name, name, sizeof(font->name));
707 font->image_font = false;
708 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
712 static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
715 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
716 qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
717 qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
718 pp.blur = fnt->settings->blur;
719 pp.outline = fnt->settings->outline;
720 pp.shadowx = fnt->settings->shadowx;
721 pp.shadowy = fnt->settings->shadowy;
722 pp.shadowz = fnt->settings->shadowz;
723 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
724 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
725 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
726 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
727 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
728 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
729 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
730 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
731 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
732 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
736 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
737 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));
738 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
739 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
740 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
741 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
745 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
746 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
748 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
749 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
752 pp.bufwidth = w + pp.padding_l + pp.padding_r;
753 pp.bufheight = h + pp.padding_t + pp.padding_b;
754 pp.bufpitch = pp.bufwidth;
755 needed = pp.bufwidth * pp.bufheight;
756 if(!pp.buf || pp.bufsize < needed * 2)
760 pp.bufsize = needed * 4;
761 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
762 pp.buf2 = pp.buf + needed;
766 static 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)
770 // calculate gauss table
771 Font_Postprocess_Update(fnt, bpp, w, h);
776 // perform operation, not exceeding the passed padding values,
777 // but possibly reducing them
778 *pad_l = min(*pad_l, pp.padding_l);
779 *pad_r = min(*pad_r, pp.padding_r);
780 *pad_t = min(*pad_t, pp.padding_t);
781 *pad_b = min(*pad_b, pp.padding_b);
783 // outline the font (RGBA only)
784 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
786 // this is like mplayer subtitle rendering
787 // bbuffer, bitmap buffer: this is our font
788 // abuffer, alpha buffer: this is pp.buf
789 // tmp: this is pp.buf2
791 // create outline buffer
792 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
793 for(y = -*pad_t; y < h + *pad_b; ++y)
794 for(x = -*pad_l; x < w + *pad_r; ++x)
796 int x1 = max(-x, -pp.outlinepadding_r);
797 int y1 = max(-y, -pp.outlinepadding_b);
798 int x2 = min(pp.outlinepadding_l, w-1-x);
799 int y2 = min(pp.outlinepadding_t, h-1-y);
803 for(my = y1; my <= y2; ++my)
804 for(mx = x1; mx <= x2; ++mx)
806 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
810 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
813 // blur the outline buffer
814 if(pp.blur > 0 || pp.shadowz != 0)
817 for(y = 0; y < pp.bufheight; ++y)
818 for(x = 0; x < pp.bufwidth; ++x)
820 int x1 = max(-x, -pp.blurpadding_rb);
821 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
824 for(mx = x1; mx <= x2; ++mx)
825 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
826 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
830 for(y = 0; y < pp.bufheight; ++y)
831 for(x = 0; x < pp.bufwidth; ++x)
833 int y1 = max(-y, -pp.blurpadding_rb);
834 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
837 for(my = y1; my <= y2; ++my)
838 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
839 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
843 // paste the outline below the font
844 for(y = -*pad_t; y < h + *pad_b; ++y)
845 for(x = -*pad_l; x < w + *pad_r; ++x)
847 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
850 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
851 // a' = 1 - (1 - a1) (1 - a2)
852 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
853 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
854 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
855 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
857 for(i = 0; i < bpp-1; ++i)
859 unsigned char c = imagedata[x * bpp + pitch * y + i];
860 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
861 imagedata[x * bpp + pitch * y + i] = c;
863 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
865 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
871 // perform operation, not exceeding the passed padding values,
872 // but possibly reducing them
873 *pad_l = min(*pad_l, pp.padding_l);
874 *pad_r = min(*pad_r, pp.padding_r);
875 *pad_t = min(*pad_t, pp.padding_t);
876 *pad_b = min(*pad_b, pp.padding_b);
880 // just calculate parameters
881 *pad_l = pp.padding_l;
882 *pad_r = pp.padding_r;
883 *pad_t = pp.padding_t;
884 *pad_b = pp.padding_b;
888 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
889 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
890 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
893 ft2_font_map_t *fmap, temp;
894 int gpad_l, gpad_r, gpad_t, gpad_b;
896 if (!(size > 0.001f && size < 1000.0f))
901 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
904 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
906 if (!font->font_maps[map_index])
908 // if a similar size has already been loaded, ignore this one
909 //abs(font->font_maps[map_index]->size - size) < 4
910 if (font->font_maps[map_index]->size == size)
914 if (map_index >= MAX_FONT_SIZES)
919 if (font->image_font)
920 fontface = (FT_Face)font->next->face;
922 fontface = (FT_Face)font->face;
923 return (Font_SearchSize(font, fontface, size) > 0);
926 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
928 memset(&temp, 0, sizeof(temp));
930 temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
931 if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
932 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
933 temp.sfx = (1.0/64.0)/(double)size;
934 temp.sfy = (1.0/64.0)/(double)size;
935 temp.intSize = -1; // negative value: LoadMap must search now :)
936 if (!Font_LoadMap(font, &temp, 0, &fmap))
938 Con_Printf("ERROR: can't load the first character map for %s\n"
941 Font_UnloadFont(font);
944 font->font_maps[map_index] = temp.next;
946 fmap->sfx = temp.sfx;
947 fmap->sfy = temp.sfy;
949 // load the default kerning vector:
950 if (font->has_kerning)
954 for (l = 0; l < 256; ++l)
956 for (r = 0; r < 256; ++r)
959 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
960 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
961 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
963 fmap->kerning.kerning[l][r][0] = 0;
964 fmap->kerning.kerning[l][r][1] = 0;
968 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
969 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
977 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
980 float value = 1000000;
982 int matchsize = -10000;
984 float fsize_x, fsize_y;
985 ft2_font_map_t **maps = font->font_maps;
987 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
989 fsize_x = *outw * vid.width / vid_conwidth.value;
991 fsize_y = *outh * vid.height / vid_conheight.value;
996 fsize_x = fsize_y = 16;
1006 for (m = 0; m < MAX_FONT_SIZES; ++m)
1010 // "round up" to the bigger size if two equally-valued matches exist
1011 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1012 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1016 matchsize = maps[m]->size;
1017 if (value == 0) // there is no better match
1021 if (value <= r_font_size_snapping.value)
1023 // do NOT keep the aspect for perfect rendering
1024 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
1025 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
1030 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1032 if (index < 0 || index >= MAX_FONT_SIZES)
1034 return font->font_maps[index];
1037 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
1039 if (font->currenth == h &&
1040 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1041 font->currentw == w)) // same size has been requested
1045 // sorry, but freetype doesn't seem to care about other sizes
1048 if (font->image_font)
1050 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1055 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1063 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1065 ft2_font_map_t *fmap;
1066 if (!font->has_kerning || !r_font_kerning.integer)
1068 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1070 fmap = font->font_maps[map_index];
1073 if (left < 256 && right < 256)
1075 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1076 // quick-kerning, be aware of the size: scale it
1077 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
1078 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
1086 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1088 if (!Font_SetSize(font, w, h))
1090 // this deserves an error message
1091 Con_Printf("Failed to get kerning for %s\n", font->name);
1094 ul = qFT_Get_Char_Index(font->face, left);
1095 ur = qFT_Get_Char_Index(font->face, right);
1096 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1098 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1099 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1103 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1105 // this deserves an error message
1106 Con_Printf("Failed to get kerning for %s\n", font->name);
1109 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1110 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1111 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1113 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1114 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1121 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1123 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1126 static void UnloadMapRec(ft2_font_map_t *map)
1130 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1134 UnloadMapRec(map->next);
1138 void Font_UnloadFont(ft2_font_t *font)
1144 Font_UnloadFont(font->next);
1146 if (font->attachments && font->attachmentcount)
1148 for (i = 0; i < (int)font->attachmentcount; ++i) {
1149 if (font->attachments[i].data)
1150 fontfilecache_Free(font->attachments[i].data);
1152 Mem_Free(font->attachments);
1153 font->attachmentcount = 0;
1154 font->attachments = NULL;
1156 for (i = 0; i < MAX_FONT_SIZES; ++i)
1158 if (font->font_maps[i])
1160 UnloadMapRec(font->font_maps[i]);
1161 font->font_maps[i] = NULL;
1164 #ifndef DP_FREETYPE_STATIC
1167 if (!r_font_disable_freetype.integer)
1172 qFT_Done_Face((FT_Face)font->face);
1177 fontfilecache_Free(font->data);
1182 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1184 float intSize = size;
1187 if (!Font_SetSize(font, intSize, intSize))
1189 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1192 if ((fontface->size->metrics.height>>6) <= size)
1196 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1203 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1205 char map_identifier[MAX_QPATH];
1206 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1207 unsigned char *data = NULL;
1211 FT_Int32 load_flags;
1212 int gpad_l, gpad_r, gpad_t, gpad_b;
1216 int gR, gC; // glyph position: row and column
1218 ft2_font_map_t *map, *next;
1219 ft2_font_t *usefont;
1223 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1228 if (r_font_use_alpha_textures.integer)
1231 if (font->image_font)
1232 fontface = (FT_Face)font->next->face;
1234 fontface = (FT_Face)font->face;
1236 switch(font->settings->antialias)
1239 switch(font->settings->hinting)
1242 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1246 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1250 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1256 switch(font->settings->hinting)
1259 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1262 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1265 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1269 load_flags = FT_LOAD_TARGET_NORMAL;
1275 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1277 if (font->image_font && mapstart->intSize < 0)
1278 mapstart->intSize = mapstart->size;
1279 if (mapstart->intSize < 0)
1282 mapstart->intSize = mapstart->size;
1285 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1287 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1290 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1292 if (mapstart->intSize < 2)
1294 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1297 --mapstart->intSize;
1300 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1302 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1305 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1307 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1311 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1314 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1318 // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1319 dpsnprintf(map_identifier, sizeof(map_identifier),
1320 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1322 (double) mapstart->intSize,
1324 (double) font->settings->blur,
1325 (double) font->settings->outline,
1326 (double) font->settings->shadowx,
1327 (double) font->settings->shadowy,
1328 (double) font->settings->shadowz,
1331 // create a cachepic_t from the data now, or reuse an existing one
1332 map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1333 if (developer_font.integer)
1335 if (!Draw_IsPicLoaded(map->pic))
1336 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1338 Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1341 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1343 // copy over the information
1344 map->size = mapstart->size;
1345 map->intSize = mapstart->intSize;
1346 map->glyphSize = mapstart->glyphSize;
1347 map->sfx = mapstart->sfx;
1348 map->sfy = mapstart->sfy;
1350 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1351 if (!Draw_IsPicLoaded(map->pic))
1353 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1356 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1360 // initialize as white texture with zero alpha
1362 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1364 if (bytesPerPixel == 4)
1374 memset(map->width_of, 0, sizeof(map->width_of));
1377 map->start = mapidx * FONT_CHARS_PER_MAP;
1379 while(next->next && next->next->start < map->start)
1381 map->next = next->next;
1386 for (ch = map->start;
1387 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1390 FT_ULong glyphIndex;
1394 unsigned char *imagedata = NULL, *dst, *src;
1395 glyph_slot_t *mapglyph;
1397 int pad_l, pad_r, pad_t, pad_b;
1399 mapch = ch - map->start;
1401 if (developer_font.integer)
1402 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1405 if (gC >= FONT_CHARS_PER_LINE)
1407 gC -= FONT_CHARS_PER_LINE;
1413 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1414 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1416 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1417 // we need the glyphIndex
1418 face = (FT_Face)font->face;
1420 if (font->image_font && mapch == ch && img_fontmap[mapch])
1422 map->glyphs[mapch].image = true;
1425 glyphIndex = qFT_Get_Char_Index(face, ch);
1426 if (glyphIndex == 0)
1428 // by convention, 0 is the "missing-glyph"-glyph
1429 // try to load from a fallback font
1430 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1432 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1435 face = (FT_Face)usefont->face;
1436 glyphIndex = qFT_Get_Char_Index(face, ch);
1437 if (glyphIndex == 0)
1439 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1446 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1447 // now we let it use the "missing-glyph"-glyph
1448 face = (FT_Face)font->face;
1456 face = (FT_Face)font->face;
1457 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1460 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1461 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1466 glyph = face->glyph;
1467 bmp = &glyph->bitmap;
1472 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1473 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1474 if (w > map->glyphSize)
1475 w = map->glyphSize - gpad_l - gpad_r;
1476 if (h > map->glyphSize)
1482 switch (bmp->pixel_mode)
1484 case FT_PIXEL_MODE_MONO:
1485 if (developer_font.integer)
1486 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1488 case FT_PIXEL_MODE_GRAY2:
1489 if (developer_font.integer)
1490 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1492 case FT_PIXEL_MODE_GRAY4:
1493 if (developer_font.integer)
1494 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1496 case FT_PIXEL_MODE_GRAY:
1497 if (developer_font.integer)
1498 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1501 if (developer_font.integer)
1502 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1504 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1507 for (y = 0; y < h; ++y)
1509 dst = imagedata + y * pitch;
1510 src = bmp->buffer + y * bmp->pitch;
1512 switch (bmp->pixel_mode)
1514 case FT_PIXEL_MODE_MONO:
1515 dst += bytesPerPixel - 1; // shift to alpha byte
1516 for (x = 0; x < bmp->width; x += 8)
1518 unsigned char c = *src++;
1519 *dst = 255 * !!((c & 0x80) >> 7); dst += bytesPerPixel;
1520 *dst = 255 * !!((c & 0x40) >> 6); dst += bytesPerPixel;
1521 *dst = 255 * !!((c & 0x20) >> 5); dst += bytesPerPixel;
1522 *dst = 255 * !!((c & 0x10) >> 4); dst += bytesPerPixel;
1523 *dst = 255 * !!((c & 0x08) >> 3); dst += bytesPerPixel;
1524 *dst = 255 * !!((c & 0x04) >> 2); dst += bytesPerPixel;
1525 *dst = 255 * !!((c & 0x02) >> 1); dst += bytesPerPixel;
1526 *dst = 255 * !!((c & 0x01) >> 0); dst += bytesPerPixel;
1529 case FT_PIXEL_MODE_GRAY2:
1530 dst += bytesPerPixel - 1; // shift to alpha byte
1531 for (x = 0; x < bmp->width; x += 4)
1533 unsigned char c = *src++;
1534 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1535 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1536 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1537 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1540 case FT_PIXEL_MODE_GRAY4:
1541 dst += bytesPerPixel - 1; // shift to alpha byte
1542 for (x = 0; x < bmp->width; x += 2)
1544 unsigned char c = *src++;
1545 *dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1546 *dst = ( ((c & 0x0F) ) * 0x11); dst += bytesPerPixel;
1549 case FT_PIXEL_MODE_GRAY:
1550 // in this case pitch should equal width
1551 for (tp = 0; tp < bmp->pitch; ++tp)
1552 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1554 //memcpy((void*)dst, (void*)src, bmp->pitch);
1555 //dst += bmp->pitch;
1566 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1574 Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1578 // now fill map->glyphs[ch - map->start]
1579 mapglyph = &map->glyphs[mapch];
1583 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1585 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1586 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1587 double advance = (glyph->advance.x / 64.0) / map->size;
1588 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1589 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1591 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1592 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1593 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1594 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1595 //mapglyph->vxmin = bearingX;
1596 //mapglyph->vxmax = bearingX + mWidth;
1597 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1598 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1599 //mapglyph->vymin = -bearingY;
1600 //mapglyph->vymax = mHeight - bearingY;
1601 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1602 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1603 //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);
1604 //mapglyph->advance_x = advance * usefont->size;
1605 //mapglyph->advance_x = advance;
1606 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1607 mapglyph->advance_y = 0;
1609 if (developer_font.integer)
1611 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1612 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1613 if (ch >= 32 && ch <= 128)
1614 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1615 Con_DPrintf("glyphinfo: Vertex info:\n");
1616 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1617 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1618 Con_DPrintf("glyphinfo: Texture info:\n");
1619 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1620 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1621 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1624 map->glyphs[mapch].image = false;
1627 if (!Draw_IsPicLoaded(map->pic))
1629 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1630 int h = map->glyphSize * FONT_CHAR_LINES;
1631 // update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1632 Draw_NewPic(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));
1634 if (r_font_diskcache.integer >= 1)
1636 // swap to BGRA for tga writing...
1640 for (x = 0;x < s;x++)
1643 data[x*4+0] = data[x*4+2];
1646 Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data);
1648 if (r_font_compress.integer && qglGetCompressedTexImageARB && Draw_IsPicLoaded(map->pic))
1649 R_SaveTextureDDSFile(Draw_GetPicTexture(map->pic), va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1657 if (!Draw_IsPicLoaded(map->pic))
1659 // if the first try isn't successful, keep it with a broken texture
1660 // otherwise we retry to load it every single frame where ft2 rendering is used
1661 // this would be bad...
1662 // only `data' must be freed
1663 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1664 font->name, mapstart->size, mapidx);
1672 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1674 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1676 // the first map must have been loaded already
1677 if (!font->font_maps[map_index])
1679 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1682 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1684 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1685 start = start->next;
1686 if (start && start->start > ch)