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 = {CF_CLIENT | CF_ARCHIVE, "r_font_disable_freetype", "0", "disable freetype support for fonts entirely"};
37 cvar_t r_font_use_alpha_textures = {CF_CLIENT | CF_ARCHIVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
38 cvar_t r_font_size_snapping = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_font_kerning", "1", "Use kerning if available"};
40 cvar_t r_font_diskcache = {CF_CLIENT | CF_ARCHIVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"};
41 cvar_t r_font_compress = {CF_CLIENT | CF_ARCHIVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
42 cvar_t r_font_nonpoweroftwo = {CF_CLIENT | CF_ARCHIVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
43 cvar_t developer_font = {CF_CLIENT | CF_ARCHIVE, "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, qbool 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_FreeLibrary (&ft2_dll);
339 Try to load the FreeType2 DLL
342 qbool 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(CON_ERROR "ERROR: Failed to initialize the FreeType2 library!\n");
396 font_mempool = Mem_AllocPool("FONT", 0, NULL);
399 Con_Print(CON_ERROR "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 qbool 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 qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
499 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only);
500 qbool 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(CON_ERROR "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(CON_ERROR "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(CON_ERROR "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 qbool 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(CON_WARN "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(CON_WARN "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(CON_ERROR "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(CON_ERROR "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(CON_ERROR "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 qbool need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
717 qbool 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 qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
890 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool 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)
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(CON_ERROR "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 qbool 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 qbool 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(CON_ERROR "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 qbool 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(CON_ERROR "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(CON_ERROR "ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1203 static qbool 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(CON_ERROR "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(CON_ERROR "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 if (developer_font.integer)
1333 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1335 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1337 // copy over the information
1338 map->size = mapstart->size;
1339 map->intSize = mapstart->intSize;
1340 map->glyphSize = mapstart->glyphSize;
1341 map->sfx = mapstart->sfx;
1342 map->sfy = mapstart->sfy;
1344 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1345 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1348 Con_Printf(CON_ERROR "ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1352 // initialize as white texture with zero alpha
1354 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1356 if (bytesPerPixel == 4)
1365 memset(map->width_of, 0, sizeof(map->width_of));
1368 map->start = mapidx * FONT_CHARS_PER_MAP;
1370 while(next->next && next->next->start < map->start)
1372 map->next = next->next;
1377 for (ch = map->start;
1378 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1381 FT_ULong glyphIndex;
1385 unsigned char *imagedata = NULL, *dst, *src;
1386 glyph_slot_t *mapglyph;
1388 int pad_l, pad_r, pad_t, pad_b;
1390 mapch = ch - map->start;
1392 if (developer_font.integer)
1393 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1396 if (gC >= FONT_CHARS_PER_LINE)
1398 gC -= FONT_CHARS_PER_LINE;
1404 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1405 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1407 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1408 // we need the glyphIndex
1409 face = (FT_Face)font->face;
1411 if (font->image_font && mapch == ch && img_fontmap[mapch])
1413 map->glyphs[mapch].image = true;
1416 glyphIndex = qFT_Get_Char_Index(face, ch);
1417 if (glyphIndex == 0)
1419 // by convention, 0 is the "missing-glyph"-glyph
1420 // try to load from a fallback font
1421 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1423 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1426 face = (FT_Face)usefont->face;
1427 glyphIndex = qFT_Get_Char_Index(face, ch);
1428 if (glyphIndex == 0)
1430 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1437 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1438 // now we let it use the "missing-glyph"-glyph
1439 face = (FT_Face)font->face;
1447 face = (FT_Face)font->face;
1448 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1451 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1452 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1457 glyph = face->glyph;
1458 bmp = &glyph->bitmap;
1463 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1464 Con_Printf(CON_WARN "WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1465 if (w > map->glyphSize)
1466 w = map->glyphSize - gpad_l - gpad_r;
1467 if (h > map->glyphSize)
1473 switch (bmp->pixel_mode)
1475 case FT_PIXEL_MODE_MONO:
1476 if (developer_font.integer)
1477 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1479 case FT_PIXEL_MODE_GRAY2:
1480 if (developer_font.integer)
1481 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1483 case FT_PIXEL_MODE_GRAY4:
1484 if (developer_font.integer)
1485 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1487 case FT_PIXEL_MODE_GRAY:
1488 if (developer_font.integer)
1489 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1492 if (developer_font.integer)
1493 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1495 Con_Printf(CON_ERROR "ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1498 for (y = 0; y < h; ++y)
1500 dst = imagedata + y * pitch;
1501 src = bmp->buffer + y * bmp->pitch;
1503 switch (bmp->pixel_mode)
1505 case FT_PIXEL_MODE_MONO:
1506 dst += bytesPerPixel - 1; // shift to alpha byte
1507 for (x = 0; x < bmp->width; x += 8)
1509 unsigned char c = *src++;
1510 *dst = 255 * !!((c & 0x80) >> 7); dst += bytesPerPixel;
1511 *dst = 255 * !!((c & 0x40) >> 6); dst += bytesPerPixel;
1512 *dst = 255 * !!((c & 0x20) >> 5); dst += bytesPerPixel;
1513 *dst = 255 * !!((c & 0x10) >> 4); dst += bytesPerPixel;
1514 *dst = 255 * !!((c & 0x08) >> 3); dst += bytesPerPixel;
1515 *dst = 255 * !!((c & 0x04) >> 2); dst += bytesPerPixel;
1516 *dst = 255 * !!((c & 0x02) >> 1); dst += bytesPerPixel;
1517 *dst = 255 * !!((c & 0x01) >> 0); dst += bytesPerPixel;
1520 case FT_PIXEL_MODE_GRAY2:
1521 dst += bytesPerPixel - 1; // shift to alpha byte
1522 for (x = 0; x < bmp->width; x += 4)
1524 unsigned char c = *src++;
1525 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1526 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1527 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1528 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1531 case FT_PIXEL_MODE_GRAY4:
1532 dst += bytesPerPixel - 1; // shift to alpha byte
1533 for (x = 0; x < bmp->width; x += 2)
1535 unsigned char c = *src++;
1536 *dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1537 *dst = ( ((c & 0x0F) ) * 0x11); dst += bytesPerPixel;
1540 case FT_PIXEL_MODE_GRAY:
1541 // in this case pitch should equal width
1542 for (tp = 0; tp < bmp->pitch; ++tp)
1543 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1545 //memcpy((void*)dst, (void*)src, bmp->pitch);
1546 //dst += bmp->pitch;
1557 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1565 Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1569 // now fill map->glyphs[ch - map->start]
1570 mapglyph = &map->glyphs[mapch];
1574 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1576 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1577 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1578 double advance = (glyph->advance.x / 64.0) / map->size;
1579 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1580 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1582 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1583 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1584 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1585 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1586 //mapglyph->vxmin = bearingX;
1587 //mapglyph->vxmax = bearingX + mWidth;
1588 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1589 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1590 //mapglyph->vymin = -bearingY;
1591 //mapglyph->vymax = mHeight - bearingY;
1592 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1593 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1594 //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);
1595 //mapglyph->advance_x = advance * usefont->size;
1596 //mapglyph->advance_x = advance;
1597 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1598 mapglyph->advance_y = 0;
1600 if (developer_font.integer)
1602 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1603 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1604 if (ch >= 32 && ch <= 128)
1605 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1606 Con_DPrintf("glyphinfo: Vertex info:\n");
1607 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1608 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1609 Con_DPrintf("glyphinfo: Texture info:\n");
1610 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1611 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1612 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1615 map->glyphs[mapch].image = false;
1619 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1620 int h = map->glyphSize * FONT_CHAR_LINES;
1621 // update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1622 map->pic = Draw_NewPic(map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | TEXF_CLAMP | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0));
1624 if (r_font_diskcache.integer >= 1)
1626 // swap to BGRA for tga writing...
1630 for (x = 0;x < s;x++)
1633 data[x*4+0] = data[x*4+2];
1636 Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data);
1638 if (r_font_compress.integer && Draw_IsPicLoaded(map->pic))
1639 R_SaveTextureDDSFile(Draw_GetPicTexture(map->pic), va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1647 if (!Draw_IsPicLoaded(map->pic))
1649 // if the first try isn't successful, keep it with a broken texture
1650 // otherwise we retry to load it every single frame where ft2 rendering is used
1651 // this would be bad...
1652 // only `data' must be freed
1653 Con_Printf(CON_ERROR "ERROR: Failed to generate texture for font %s size %f map %lu\n",
1654 font->name, mapstart->size, mapidx);
1662 qbool Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1664 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1666 // the first map must have been loaded already
1667 if (!font->font_maps[map_index])
1669 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1672 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1674 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1675 start = start->next;
1676 if (start && start->start > ch)