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_UnloadLibrary (&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 // let's open it at startup already
429 void Font_Init_Commands(void)
431 Cvar_RegisterVariable(&r_font_nonpoweroftwo);
432 Cvar_RegisterVariable(&r_font_disable_freetype);
433 Cvar_RegisterVariable(&r_font_use_alpha_textures);
434 Cvar_RegisterVariable(&r_font_size_snapping);
435 Cvar_RegisterVariable(&r_font_kerning);
436 Cvar_RegisterVariable(&r_font_diskcache);
437 Cvar_RegisterVariable(&r_font_compress);
438 Cvar_RegisterVariable(&developer_font);
442 ================================================================================
443 Implementation of a more or less lazy font loading and rendering code.
444 ================================================================================
447 #include "ft2_fontdefs.h"
449 ft2_font_t *Font_Alloc(void)
451 #ifndef DP_FREETYPE_STATIC
454 if (r_font_disable_freetype.integer)
457 return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
460 static qbool Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
462 ft2_attachment_t *na;
464 font->attachmentcount++;
465 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
468 if (font->attachments && font->attachmentcount > 1)
470 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
471 Mem_Free(font->attachments);
473 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
474 font->attachments = na;
478 float Font_VirtualToRealSize(float sz)
486 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
487 vh = ((vid.height > 0) ? vid.height : vid_height.value);
488 // now try to scale to our actual size:
489 sn = sz * vh / vid_conheight.value;
491 if ( sn - (float)si >= 0.5 )
496 float Font_SnapTo(float val, float snapwidth)
498 return floor(val / snapwidth + 0.5f) * snapwidth;
501 static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
502 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only);
503 qbool Font_LoadFont(const char *name, dp_font_t *dpfnt)
506 ft2_font_t *ft2, *fbfont, *fb;
516 // check if a fallback font has been specified, if it has been, and the
517 // font fails to load, use the image font as main font
518 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
520 if (dpfnt->fallbacks[i][0])
524 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
526 if (i >= MAX_FONT_FALLBACKS)
532 strlcpy(ft2->name, name, sizeof(ft2->name));
533 ft2->image_font = true;
534 ft2->has_kerning = false;
538 ft2->image_font = false;
541 // attempt to load fallback fonts:
543 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
545 if (!dpfnt->fallbacks[i][0])
547 if (! (fb = Font_Alloc()) )
549 Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
553 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
555 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i])))
556 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i])))
557 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i])))
558 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i])))
559 Con_Printf(CON_ERROR "Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
564 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
566 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
571 Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
576 // at least one size of the fallback font loaded successfully
582 if (fbfont == ft2 && ft2->image_font)
584 // no fallbacks were loaded successfully:
591 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
593 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
598 // loading failed for every requested size
599 Font_UnloadFont(ft2);
605 //Con_Printf("%i sizes loaded\n", count);
610 static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
613 char filename[MAX_QPATH];
616 const unsigned char *data;
617 fs_offset_t datasize;
619 memset(font, 0, sizeof(*font));
621 if (!Font_OpenLibrary())
623 if (!r_font_disable_freetype.integer)
625 Con_Printf(CON_WARN "WARNING: can't open load font %s\n"
626 "You need the FreeType2 DLL to load font files\n",
632 font->settings = settings;
634 namelen = strlen(name);
635 if (namelen + 5 > sizeof(filename))
637 Con_Printf(CON_WARN "WARNING: too long font name. Cannot load this.\n");
641 // try load direct file
642 memcpy(filename, name, namelen+1);
643 data = fontfilecache_LoadFile(filename, false, &datasize);
647 memcpy(filename + namelen, ".ttf", 5);
648 data = fontfilecache_LoadFile(filename, false, &datasize);
653 memcpy(filename + namelen, ".otf", 5);
654 data = fontfilecache_LoadFile(filename, false, &datasize);
659 ft2_attachment_t afm;
661 memcpy(filename + namelen, ".pfb", 5);
662 data = fontfilecache_LoadFile(filename, false, &datasize);
666 memcpy(filename + namelen, ".afm", 5);
667 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
670 Font_Attach(font, &afm);
675 // FS_LoadFile being not-quiet should print an error :)
678 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
680 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
681 if (status && _face != 0)
683 Con_Printf(CON_ERROR "Failed to load face %i of %s. Falling back to face 0\n", _face, name);
685 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
690 Con_Printf(CON_ERROR "ERROR: can't create face for %s\n"
691 "Error %i\n", // TODO: error strings
693 Font_UnloadFont(font);
697 // add the attachments
698 for (i = 0; i < font->attachmentcount; ++i)
701 memset(&args, 0, sizeof(args));
702 args.flags = FT_OPEN_MEMORY;
703 args.memory_base = (const FT_Byte*)font->attachments[i].data;
704 args.memory_size = font->attachments[i].size;
705 if (qFT_Attach_Stream((FT_Face)font->face, &args))
706 Con_Printf(CON_ERROR "Failed to add attachment %u to %s\n", (unsigned)i, font->name);
709 strlcpy(font->name, name, sizeof(font->name));
710 font->image_font = false;
711 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
715 static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
718 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
719 qbool need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
720 qbool need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
721 pp.blur = fnt->settings->blur;
722 pp.outline = fnt->settings->outline;
723 pp.shadowx = fnt->settings->shadowx;
724 pp.shadowy = fnt->settings->shadowy;
725 pp.shadowz = fnt->settings->shadowz;
726 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
727 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
728 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
729 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
730 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
731 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
732 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
733 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
734 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
735 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
739 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
740 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));
741 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
742 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
743 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
744 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
748 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
749 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
751 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
752 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
755 pp.bufwidth = w + pp.padding_l + pp.padding_r;
756 pp.bufheight = h + pp.padding_t + pp.padding_b;
757 pp.bufpitch = pp.bufwidth;
758 needed = pp.bufwidth * pp.bufheight;
759 if(!pp.buf || pp.bufsize < needed * 2)
763 pp.bufsize = needed * 4;
764 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
765 pp.buf2 = pp.buf + needed;
769 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)
773 // calculate gauss table
774 Font_Postprocess_Update(fnt, bpp, w, h);
779 // perform operation, not exceeding the passed padding values,
780 // but possibly reducing them
781 *pad_l = min(*pad_l, pp.padding_l);
782 *pad_r = min(*pad_r, pp.padding_r);
783 *pad_t = min(*pad_t, pp.padding_t);
784 *pad_b = min(*pad_b, pp.padding_b);
786 // outline the font (RGBA only)
787 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
789 // this is like mplayer subtitle rendering
790 // bbuffer, bitmap buffer: this is our font
791 // abuffer, alpha buffer: this is pp.buf
792 // tmp: this is pp.buf2
794 // create outline buffer
795 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
796 for(y = -*pad_t; y < h + *pad_b; ++y)
797 for(x = -*pad_l; x < w + *pad_r; ++x)
799 int x1 = max(-x, -pp.outlinepadding_r);
800 int y1 = max(-y, -pp.outlinepadding_b);
801 int x2 = min(pp.outlinepadding_l, w-1-x);
802 int y2 = min(pp.outlinepadding_t, h-1-y);
806 for(my = y1; my <= y2; ++my)
807 for(mx = x1; mx <= x2; ++mx)
809 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
813 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
816 // blur the outline buffer
817 if(pp.blur > 0 || pp.shadowz != 0)
820 for(y = 0; y < pp.bufheight; ++y)
821 for(x = 0; x < pp.bufwidth; ++x)
823 int x1 = max(-x, -pp.blurpadding_rb);
824 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
827 for(mx = x1; mx <= x2; ++mx)
828 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
829 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
833 for(y = 0; y < pp.bufheight; ++y)
834 for(x = 0; x < pp.bufwidth; ++x)
836 int y1 = max(-y, -pp.blurpadding_rb);
837 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
840 for(my = y1; my <= y2; ++my)
841 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
842 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
846 // paste the outline below the font
847 for(y = -*pad_t; y < h + *pad_b; ++y)
848 for(x = -*pad_l; x < w + *pad_r; ++x)
850 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
853 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
854 // a' = 1 - (1 - a1) (1 - a2)
855 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
856 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
857 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
858 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
860 for(i = 0; i < bpp-1; ++i)
862 unsigned char c = imagedata[x * bpp + pitch * y + i];
863 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
864 imagedata[x * bpp + pitch * y + i] = c;
866 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
868 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
874 // perform operation, not exceeding the passed padding values,
875 // but possibly reducing them
876 *pad_l = min(*pad_l, pp.padding_l);
877 *pad_r = min(*pad_r, pp.padding_r);
878 *pad_t = min(*pad_t, pp.padding_t);
879 *pad_b = min(*pad_b, pp.padding_b);
883 // just calculate parameters
884 *pad_l = pp.padding_l;
885 *pad_r = pp.padding_r;
886 *pad_t = pp.padding_t;
887 *pad_b = pp.padding_b;
891 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
892 static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
893 static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only)
896 ft2_font_map_t *fmap, temp;
897 int gpad_l, gpad_r, gpad_t, gpad_b;
899 if (!(size > 0.001f && size < 1000.0f))
904 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
907 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
909 if (!font->font_maps[map_index])
911 // if a similar size has already been loaded, ignore this one
912 //abs(font->font_maps[map_index]->size - size) < 4
913 if (font->font_maps[map_index]->size == size)
917 if (map_index >= MAX_FONT_SIZES)
922 if (font->image_font)
923 fontface = (FT_Face)font->next->face;
925 fontface = (FT_Face)font->face;
926 return (Font_SearchSize(font, fontface, size) > 0);
929 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
931 memset(&temp, 0, sizeof(temp));
933 temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
934 if (!r_font_nonpoweroftwo.integer)
935 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
936 temp.sfx = (1.0/64.0)/(double)size;
937 temp.sfy = (1.0/64.0)/(double)size;
938 temp.intSize = -1; // negative value: LoadMap must search now :)
939 if (!Font_LoadMap(font, &temp, 0, &fmap))
941 Con_Printf(CON_ERROR "ERROR: can't load the first character map for %s\n"
944 Font_UnloadFont(font);
947 font->font_maps[map_index] = temp.next;
949 fmap->sfx = temp.sfx;
950 fmap->sfy = temp.sfy;
952 // load the default kerning vector:
953 if (font->has_kerning)
957 for (l = 0; l < 256; ++l)
959 for (r = 0; r < 256; ++r)
962 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
963 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
964 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
966 fmap->kerning.kerning[l][r][0] = 0;
967 fmap->kerning.kerning[l][r][1] = 0;
971 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
972 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
980 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
983 float value = 1000000;
985 int matchsize = -10000;
987 float fsize_x, fsize_y;
988 ft2_font_map_t **maps = font->font_maps;
990 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
992 fsize_x = *outw * vid.width / vid_conwidth.value;
994 fsize_y = *outh * vid.height / vid_conheight.value;
999 fsize_x = fsize_y = 16;
1009 for (m = 0; m < MAX_FONT_SIZES; ++m)
1013 // "round up" to the bigger size if two equally-valued matches exist
1014 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1015 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1019 matchsize = maps[m]->size;
1020 if (value == 0) // there is no better match
1024 if (value <= r_font_size_snapping.value)
1026 // do NOT keep the aspect for perfect rendering
1027 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
1028 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
1033 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1035 if (index < 0 || index >= MAX_FONT_SIZES)
1037 return font->font_maps[index];
1040 static qbool Font_SetSize(ft2_font_t *font, float w, float h)
1042 if (font->currenth == h &&
1043 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1044 font->currentw == w)) // same size has been requested
1048 // sorry, but freetype doesn't seem to care about other sizes
1051 if (font->image_font)
1053 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1058 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1066 qbool Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1068 ft2_font_map_t *fmap;
1069 if (!font->has_kerning || !r_font_kerning.integer)
1071 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1073 fmap = font->font_maps[map_index];
1076 if (left < 256 && right < 256)
1078 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1079 // quick-kerning, be aware of the size: scale it
1080 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
1081 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
1089 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1091 if (!Font_SetSize(font, w, h))
1093 // this deserves an error message
1094 Con_Printf("Failed to get kerning for %s\n", font->name);
1097 ul = qFT_Get_Char_Index(font->face, left);
1098 ur = qFT_Get_Char_Index(font->face, right);
1099 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1101 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1102 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1106 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1108 // this deserves an error message
1109 Con_Printf(CON_ERROR "Failed to get kerning for %s\n", font->name);
1112 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1113 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1114 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1116 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1117 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1124 qbool Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1126 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1129 static void UnloadMapRec(ft2_font_map_t *map)
1133 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1137 UnloadMapRec(map->next);
1141 void Font_UnloadFont(ft2_font_t *font)
1147 Font_UnloadFont(font->next);
1149 if (font->attachments && font->attachmentcount)
1151 for (i = 0; i < (int)font->attachmentcount; ++i) {
1152 if (font->attachments[i].data)
1153 fontfilecache_Free(font->attachments[i].data);
1155 Mem_Free(font->attachments);
1156 font->attachmentcount = 0;
1157 font->attachments = NULL;
1159 for (i = 0; i < MAX_FONT_SIZES; ++i)
1161 if (font->font_maps[i])
1163 UnloadMapRec(font->font_maps[i]);
1164 font->font_maps[i] = NULL;
1167 #ifndef DP_FREETYPE_STATIC
1170 if (!r_font_disable_freetype.integer)
1175 qFT_Done_Face((FT_Face)font->face);
1180 fontfilecache_Free(font->data);
1185 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1187 float intSize = size;
1190 if (!Font_SetSize(font, intSize, intSize))
1192 Con_Printf(CON_ERROR "ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1195 if ((fontface->size->metrics.height>>6) <= size)
1199 Con_Printf(CON_ERROR "ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1206 static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1208 char map_identifier[MAX_QPATH];
1209 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1210 unsigned char *data = NULL;
1214 FT_Int32 load_flags;
1215 int gpad_l, gpad_r, gpad_t, gpad_b;
1219 int gR, gC; // glyph position: row and column
1221 ft2_font_map_t *map, *next;
1222 ft2_font_t *usefont;
1226 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1231 if (r_font_use_alpha_textures.integer)
1234 if (font->image_font)
1235 fontface = (FT_Face)font->next->face;
1237 fontface = (FT_Face)font->face;
1239 switch(font->settings->antialias)
1242 switch(font->settings->hinting)
1245 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1249 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1253 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1259 switch(font->settings->hinting)
1262 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1265 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1268 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1272 load_flags = FT_LOAD_TARGET_NORMAL;
1278 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1280 if (font->image_font && mapstart->intSize < 0)
1281 mapstart->intSize = mapstart->size;
1282 if (mapstart->intSize < 0)
1285 mapstart->intSize = mapstart->size;
1288 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1290 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1293 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1295 if (mapstart->intSize < 2)
1297 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1300 --mapstart->intSize;
1303 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1305 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1308 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1310 Con_Printf(CON_ERROR "ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1314 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1317 Con_Printf(CON_ERROR "ERROR: Out of memory when loading fontmap for %s\n", font->name);
1321 // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1322 dpsnprintf(map_identifier, sizeof(map_identifier),
1323 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1325 (double) mapstart->intSize,
1327 (double) font->settings->blur,
1328 (double) font->settings->outline,
1329 (double) font->settings->shadowx,
1330 (double) font->settings->shadowy,
1331 (double) font->settings->shadowz,
1334 // create a cachepic_t from the data now, or reuse an existing one
1335 if (developer_font.integer)
1336 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1338 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1340 // copy over the information
1341 map->size = mapstart->size;
1342 map->intSize = mapstart->intSize;
1343 map->glyphSize = mapstart->glyphSize;
1344 map->sfx = mapstart->sfx;
1345 map->sfy = mapstart->sfy;
1347 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1348 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1351 Con_Printf(CON_ERROR "ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1355 // initialize as white texture with zero alpha
1357 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1359 if (bytesPerPixel == 4)
1368 memset(map->width_of, 0, sizeof(map->width_of));
1371 map->start = mapidx * FONT_CHARS_PER_MAP;
1373 while(next->next && next->next->start < map->start)
1375 map->next = next->next;
1380 for (ch = map->start;
1381 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1384 FT_ULong glyphIndex;
1388 unsigned char *imagedata = NULL, *dst, *src;
1389 glyph_slot_t *mapglyph;
1391 int pad_l, pad_r, pad_t, pad_b;
1393 mapch = ch - map->start;
1395 if (developer_font.integer)
1396 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1399 if (gC >= FONT_CHARS_PER_LINE)
1401 gC -= FONT_CHARS_PER_LINE;
1407 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1408 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1410 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1411 // we need the glyphIndex
1412 face = (FT_Face)font->face;
1414 if (font->image_font && mapch == ch && img_fontmap[mapch])
1416 map->glyphs[mapch].image = true;
1419 glyphIndex = qFT_Get_Char_Index(face, ch);
1420 if (glyphIndex == 0)
1422 // by convention, 0 is the "missing-glyph"-glyph
1423 // try to load from a fallback font
1424 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1426 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1429 face = (FT_Face)usefont->face;
1430 glyphIndex = qFT_Get_Char_Index(face, ch);
1431 if (glyphIndex == 0)
1433 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1440 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1441 // now we let it use the "missing-glyph"-glyph
1442 face = (FT_Face)font->face;
1450 face = (FT_Face)font->face;
1451 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1454 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1455 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1460 glyph = face->glyph;
1461 bmp = &glyph->bitmap;
1466 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1467 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);
1468 if (w > map->glyphSize)
1469 w = map->glyphSize - gpad_l - gpad_r;
1470 if (h > map->glyphSize)
1476 switch (bmp->pixel_mode)
1478 case FT_PIXEL_MODE_MONO:
1479 if (developer_font.integer)
1480 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1482 case FT_PIXEL_MODE_GRAY2:
1483 if (developer_font.integer)
1484 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1486 case FT_PIXEL_MODE_GRAY4:
1487 if (developer_font.integer)
1488 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1490 case FT_PIXEL_MODE_GRAY:
1491 if (developer_font.integer)
1492 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1495 if (developer_font.integer)
1496 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1498 Con_Printf(CON_ERROR "ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1501 for (y = 0; y < h; ++y)
1503 dst = imagedata + y * pitch;
1504 src = bmp->buffer + y * bmp->pitch;
1506 switch (bmp->pixel_mode)
1508 case FT_PIXEL_MODE_MONO:
1509 dst += bytesPerPixel - 1; // shift to alpha byte
1510 for (x = 0; x < bmp->width; x += 8)
1512 unsigned char c = *src++;
1513 *dst = 255 * !!((c & 0x80) >> 7); dst += bytesPerPixel;
1514 *dst = 255 * !!((c & 0x40) >> 6); dst += bytesPerPixel;
1515 *dst = 255 * !!((c & 0x20) >> 5); dst += bytesPerPixel;
1516 *dst = 255 * !!((c & 0x10) >> 4); dst += bytesPerPixel;
1517 *dst = 255 * !!((c & 0x08) >> 3); dst += bytesPerPixel;
1518 *dst = 255 * !!((c & 0x04) >> 2); dst += bytesPerPixel;
1519 *dst = 255 * !!((c & 0x02) >> 1); dst += bytesPerPixel;
1520 *dst = 255 * !!((c & 0x01) >> 0); dst += bytesPerPixel;
1523 case FT_PIXEL_MODE_GRAY2:
1524 dst += bytesPerPixel - 1; // shift to alpha byte
1525 for (x = 0; x < bmp->width; x += 4)
1527 unsigned char c = *src++;
1528 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1529 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1530 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1531 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1534 case FT_PIXEL_MODE_GRAY4:
1535 dst += bytesPerPixel - 1; // shift to alpha byte
1536 for (x = 0; x < bmp->width; x += 2)
1538 unsigned char c = *src++;
1539 *dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1540 *dst = ( ((c & 0x0F) ) * 0x11); dst += bytesPerPixel;
1543 case FT_PIXEL_MODE_GRAY:
1544 // in this case pitch should equal width
1545 for (tp = 0; tp < bmp->pitch; ++tp)
1546 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1548 //memcpy((void*)dst, (void*)src, bmp->pitch);
1549 //dst += bmp->pitch;
1560 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1568 Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1572 // now fill map->glyphs[ch - map->start]
1573 mapglyph = &map->glyphs[mapch];
1577 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1579 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1580 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1581 double advance = (glyph->advance.x / 64.0) / map->size;
1582 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1583 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1585 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1586 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1587 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1588 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1589 //mapglyph->vxmin = bearingX;
1590 //mapglyph->vxmax = bearingX + mWidth;
1591 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1592 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1593 //mapglyph->vymin = -bearingY;
1594 //mapglyph->vymax = mHeight - bearingY;
1595 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1596 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1597 //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);
1598 //mapglyph->advance_x = advance * usefont->size;
1599 //mapglyph->advance_x = advance;
1600 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1601 mapglyph->advance_y = 0;
1603 if (developer_font.integer)
1605 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1606 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1607 if (ch >= 32 && ch <= 128)
1608 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1609 Con_DPrintf("glyphinfo: Vertex info:\n");
1610 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1611 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1612 Con_DPrintf("glyphinfo: Texture info:\n");
1613 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1614 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1615 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1618 map->glyphs[mapch].image = false;
1622 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1623 int h = map->glyphSize * FONT_CHAR_LINES;
1624 // update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1625 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));
1627 if (r_font_diskcache.integer >= 1)
1629 // swap to BGRA for tga writing...
1633 for (x = 0;x < s;x++)
1636 data[x*4+0] = data[x*4+2];
1639 Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data);
1641 if (r_font_compress.integer && Draw_IsPicLoaded(map->pic))
1642 R_SaveTextureDDSFile(Draw_GetPicTexture(map->pic), va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1650 if (!Draw_IsPicLoaded(map->pic))
1652 // if the first try isn't successful, keep it with a broken texture
1653 // otherwise we retry to load it every single frame where ft2 rendering is used
1654 // this would be bad...
1655 // only `data' must be freed
1656 Con_Printf(CON_ERROR "ERROR: Failed to generate texture for font %s size %f map %lu\n",
1657 font->name, mapstart->size, mapidx);
1665 qbool Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1667 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1669 // the first map must have been loaded already
1670 if (!font->font_maps[map_index])
1672 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1675 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1677 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1678 start = start->next;
1679 if (start && start->start > ch)