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);
633 // try load direct file
634 memcpy(filename, name, namelen+1);
635 data = fontfilecache_LoadFile(filename, false, &datasize);
639 memcpy(filename + namelen, ".ttf", 5);
640 data = fontfilecache_LoadFile(filename, false, &datasize);
645 memcpy(filename + namelen, ".otf", 5);
646 data = fontfilecache_LoadFile(filename, false, &datasize);
651 ft2_attachment_t afm;
653 memcpy(filename + namelen, ".pfb", 5);
654 data = fontfilecache_LoadFile(filename, false, &datasize);
658 memcpy(filename + namelen, ".afm", 5);
659 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
662 Font_Attach(font, &afm);
667 // FS_LoadFile being not-quiet should print an error :)
670 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
672 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
673 if (status && _face != 0)
675 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
677 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
682 Con_Printf("ERROR: can't create face for %s\n"
683 "Error %i\n", // TODO: error strings
685 Font_UnloadFont(font);
689 // add the attachments
690 for (i = 0; i < font->attachmentcount; ++i)
693 memset(&args, 0, sizeof(args));
694 args.flags = FT_OPEN_MEMORY;
695 args.memory_base = (const FT_Byte*)font->attachments[i].data;
696 args.memory_size = font->attachments[i].size;
697 if (qFT_Attach_Stream((FT_Face)font->face, &args))
698 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
701 memcpy(font->name, name, namelen+1);
702 font->image_font = false;
703 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
707 static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
710 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
711 qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
712 qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
713 pp.blur = fnt->settings->blur;
714 pp.outline = fnt->settings->outline;
715 pp.shadowx = fnt->settings->shadowx;
716 pp.shadowy = fnt->settings->shadowy;
717 pp.shadowz = fnt->settings->shadowz;
718 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
719 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
720 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
721 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
722 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
723 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
724 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
725 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
726 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
727 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
731 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
732 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));
733 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
734 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
735 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
736 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
740 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
741 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
743 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
744 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
747 pp.bufwidth = w + pp.padding_l + pp.padding_r;
748 pp.bufheight = h + pp.padding_t + pp.padding_b;
749 pp.bufpitch = pp.bufwidth;
750 needed = pp.bufwidth * pp.bufheight;
751 if(!pp.buf || pp.bufsize < needed * 2)
755 pp.bufsize = needed * 4;
756 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
757 pp.buf2 = pp.buf + needed;
761 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)
765 // calculate gauss table
766 Font_Postprocess_Update(fnt, bpp, w, h);
771 // perform operation, not exceeding the passed padding values,
772 // but possibly reducing them
773 *pad_l = min(*pad_l, pp.padding_l);
774 *pad_r = min(*pad_r, pp.padding_r);
775 *pad_t = min(*pad_t, pp.padding_t);
776 *pad_b = min(*pad_b, pp.padding_b);
778 // outline the font (RGBA only)
779 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
781 // this is like mplayer subtitle rendering
782 // bbuffer, bitmap buffer: this is our font
783 // abuffer, alpha buffer: this is pp.buf
784 // tmp: this is pp.buf2
786 // create outline buffer
787 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
788 for(y = -*pad_t; y < h + *pad_b; ++y)
789 for(x = -*pad_l; x < w + *pad_r; ++x)
791 int x1 = max(-x, -pp.outlinepadding_r);
792 int y1 = max(-y, -pp.outlinepadding_b);
793 int x2 = min(pp.outlinepadding_l, w-1-x);
794 int y2 = min(pp.outlinepadding_t, h-1-y);
798 for(my = y1; my <= y2; ++my)
799 for(mx = x1; mx <= x2; ++mx)
801 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
805 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
808 // blur the outline buffer
809 if(pp.blur > 0 || pp.shadowz != 0)
812 for(y = 0; y < pp.bufheight; ++y)
813 for(x = 0; x < pp.bufwidth; ++x)
815 int x1 = max(-x, -pp.blurpadding_rb);
816 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
819 for(mx = x1; mx <= x2; ++mx)
820 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
821 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
825 for(y = 0; y < pp.bufheight; ++y)
826 for(x = 0; x < pp.bufwidth; ++x)
828 int y1 = max(-y, -pp.blurpadding_rb);
829 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
832 for(my = y1; my <= y2; ++my)
833 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
834 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
838 // paste the outline below the font
839 for(y = -*pad_t; y < h + *pad_b; ++y)
840 for(x = -*pad_l; x < w + *pad_r; ++x)
842 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
845 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
846 // a' = 1 - (1 - a1) (1 - a2)
847 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
848 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
849 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
850 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
852 for(i = 0; i < bpp-1; ++i)
854 unsigned char c = imagedata[x * bpp + pitch * y + i];
855 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
856 imagedata[x * bpp + pitch * y + i] = c;
858 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
860 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
866 // perform operation, not exceeding the passed padding values,
867 // but possibly reducing them
868 *pad_l = min(*pad_l, pp.padding_l);
869 *pad_r = min(*pad_r, pp.padding_r);
870 *pad_t = min(*pad_t, pp.padding_t);
871 *pad_b = min(*pad_b, pp.padding_b);
875 // just calculate parameters
876 *pad_l = pp.padding_l;
877 *pad_r = pp.padding_r;
878 *pad_t = pp.padding_t;
879 *pad_b = pp.padding_b;
883 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
884 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
885 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
888 ft2_font_map_t *fmap, temp;
889 int gpad_l, gpad_r, gpad_t, gpad_b;
891 if (!(size > 0.001f && size < 1000.0f))
896 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
899 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
901 if (!font->font_maps[map_index])
903 // if a similar size has already been loaded, ignore this one
904 //abs(font->font_maps[map_index]->size - size) < 4
905 if (font->font_maps[map_index]->size == size)
909 if (map_index >= MAX_FONT_SIZES)
914 if (font->image_font)
915 fontface = (FT_Face)font->next->face;
917 fontface = (FT_Face)font->face;
918 return (Font_SearchSize(font, fontface, size) > 0);
921 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
923 memset(&temp, 0, sizeof(temp));
925 temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
926 if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
927 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
928 temp.sfx = (1.0/64.0)/(double)size;
929 temp.sfy = (1.0/64.0)/(double)size;
930 temp.intSize = -1; // negative value: LoadMap must search now :)
931 if (!Font_LoadMap(font, &temp, 0, &fmap))
933 Con_Printf("ERROR: can't load the first character map for %s\n"
936 Font_UnloadFont(font);
939 font->font_maps[map_index] = temp.next;
941 fmap->sfx = temp.sfx;
942 fmap->sfy = temp.sfy;
944 // load the default kerning vector:
945 if (font->has_kerning)
949 for (l = 0; l < 256; ++l)
951 for (r = 0; r < 256; ++r)
954 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
955 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
956 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
958 fmap->kerning.kerning[l][r][0] = 0;
959 fmap->kerning.kerning[l][r][1] = 0;
963 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
964 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
972 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
975 float value = 1000000;
977 int matchsize = -10000;
979 float fsize_x, fsize_y;
980 ft2_font_map_t **maps = font->font_maps;
982 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
984 fsize_x = *outw * vid.width / vid_conwidth.value;
986 fsize_y = *outh * vid.height / vid_conheight.value;
991 fsize_x = fsize_y = 16;
1001 for (m = 0; m < MAX_FONT_SIZES; ++m)
1005 // "round up" to the bigger size if two equally-valued matches exist
1006 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1007 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1011 matchsize = maps[m]->size;
1012 if (value == 0) // there is no better match
1016 if (value <= r_font_size_snapping.value)
1018 // do NOT keep the aspect for perfect rendering
1019 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
1020 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
1025 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1027 if (index < 0 || index >= MAX_FONT_SIZES)
1029 return font->font_maps[index];
1032 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
1034 if (font->currenth == h &&
1035 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1036 font->currentw == w)) // same size has been requested
1040 // sorry, but freetype doesn't seem to care about other sizes
1043 if (font->image_font)
1045 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1050 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1058 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1060 ft2_font_map_t *fmap;
1061 if (!font->has_kerning || !r_font_kerning.integer)
1063 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1065 fmap = font->font_maps[map_index];
1068 if (left < 256 && right < 256)
1070 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1071 // quick-kerning, be aware of the size: scale it
1072 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
1073 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
1081 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1083 if (!Font_SetSize(font, w, h))
1085 // this deserves an error message
1086 Con_Printf("Failed to get kerning for %s\n", font->name);
1089 ul = qFT_Get_Char_Index(font->face, left);
1090 ur = qFT_Get_Char_Index(font->face, right);
1091 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1093 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1094 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1098 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1100 // this deserves an error message
1101 Con_Printf("Failed to get kerning for %s\n", font->name);
1104 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1105 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1106 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1108 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1109 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1116 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1118 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1121 static void UnloadMapRec(ft2_font_map_t *map)
1125 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1129 UnloadMapRec(map->next);
1133 void Font_UnloadFont(ft2_font_t *font)
1139 Font_UnloadFont(font->next);
1141 if (font->attachments && font->attachmentcount)
1143 for (i = 0; i < (int)font->attachmentcount; ++i) {
1144 if (font->attachments[i].data)
1145 fontfilecache_Free(font->attachments[i].data);
1147 Mem_Free(font->attachments);
1148 font->attachmentcount = 0;
1149 font->attachments = NULL;
1151 for (i = 0; i < MAX_FONT_SIZES; ++i)
1153 if (font->font_maps[i])
1155 UnloadMapRec(font->font_maps[i]);
1156 font->font_maps[i] = NULL;
1159 #ifndef DP_FREETYPE_STATIC
1162 if (!r_font_disable_freetype.integer)
1167 qFT_Done_Face((FT_Face)font->face);
1172 fontfilecache_Free(font->data);
1177 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1179 float intSize = size;
1182 if (!Font_SetSize(font, intSize, intSize))
1184 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1187 if ((fontface->size->metrics.height>>6) <= size)
1191 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1198 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1200 char map_identifier[MAX_QPATH];
1201 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1202 unsigned char *data = NULL;
1206 FT_Int32 load_flags;
1207 int gpad_l, gpad_r, gpad_t, gpad_b;
1211 int gR, gC; // glyph position: row and column
1213 ft2_font_map_t *map, *next;
1214 ft2_font_t *usefont;
1218 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1223 if (r_font_use_alpha_textures.integer)
1226 if (font->image_font)
1227 fontface = (FT_Face)font->next->face;
1229 fontface = (FT_Face)font->face;
1231 switch(font->settings->antialias)
1234 switch(font->settings->hinting)
1237 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1241 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1245 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1251 switch(font->settings->hinting)
1254 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1257 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1260 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1264 load_flags = FT_LOAD_TARGET_NORMAL;
1270 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1272 if (font->image_font && mapstart->intSize < 0)
1273 mapstart->intSize = mapstart->size;
1274 if (mapstart->intSize < 0)
1277 mapstart->intSize = mapstart->size;
1280 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1282 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1285 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1287 if (mapstart->intSize < 2)
1289 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1292 --mapstart->intSize;
1295 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1297 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1300 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1302 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1306 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1309 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1313 // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1314 dpsnprintf(map_identifier, sizeof(map_identifier),
1315 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1317 (double) mapstart->intSize,
1319 (double) font->settings->blur,
1320 (double) font->settings->outline,
1321 (double) font->settings->shadowx,
1322 (double) font->settings->shadowy,
1323 (double) font->settings->shadowz,
1326 // create a cachepic_t from the data now, or reuse an existing one
1327 map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1328 if (developer_font.integer)
1330 if (map->pic->tex == r_texture_notexture)
1331 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1333 Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1336 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1338 // copy over the information
1339 map->size = mapstart->size;
1340 map->intSize = mapstart->intSize;
1341 map->glyphSize = mapstart->glyphSize;
1342 map->sfx = mapstart->sfx;
1343 map->sfy = mapstart->sfy;
1345 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1346 if (map->pic->tex == r_texture_notexture)
1348 data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1351 Con_Printf("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)
1369 memset(map->width_of, 0, sizeof(map->width_of));
1372 map->start = mapidx * FONT_CHARS_PER_MAP;
1374 while(next->next && next->next->start < map->start)
1376 map->next = next->next;
1381 for (ch = map->start;
1382 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1385 FT_ULong glyphIndex;
1389 unsigned char *imagedata = NULL, *dst, *src;
1390 glyph_slot_t *mapglyph;
1392 int pad_l, pad_r, pad_t, pad_b;
1394 mapch = ch - map->start;
1396 if (developer_font.integer)
1397 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1400 if (gC >= FONT_CHARS_PER_LINE)
1402 gC -= FONT_CHARS_PER_LINE;
1408 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1409 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1411 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1412 // we need the glyphIndex
1413 face = (FT_Face)font->face;
1415 if (font->image_font && mapch == ch && img_fontmap[mapch])
1417 map->glyphs[mapch].image = true;
1420 glyphIndex = qFT_Get_Char_Index(face, ch);
1421 if (glyphIndex == 0)
1423 // by convention, 0 is the "missing-glyph"-glyph
1424 // try to load from a fallback font
1425 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1427 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1430 face = (FT_Face)usefont->face;
1431 glyphIndex = qFT_Get_Char_Index(face, ch);
1432 if (glyphIndex == 0)
1434 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1441 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1442 // now we let it use the "missing-glyph"-glyph
1443 face = (FT_Face)font->face;
1451 face = (FT_Face)font->face;
1452 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1455 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1456 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1461 glyph = face->glyph;
1462 bmp = &glyph->bitmap;
1467 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1468 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1469 if (w > map->glyphSize)
1470 w = map->glyphSize - gpad_l - gpad_r;
1471 if (h > map->glyphSize)
1477 switch (bmp->pixel_mode)
1479 case FT_PIXEL_MODE_MONO:
1480 if (developer_font.integer)
1481 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1483 case FT_PIXEL_MODE_GRAY2:
1484 if (developer_font.integer)
1485 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1487 case FT_PIXEL_MODE_GRAY4:
1488 if (developer_font.integer)
1489 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1491 case FT_PIXEL_MODE_GRAY:
1492 if (developer_font.integer)
1493 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1496 if (developer_font.integer)
1497 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1499 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1502 for (y = 0; y < h; ++y)
1504 dst = imagedata + y * pitch;
1505 src = bmp->buffer + y * bmp->pitch;
1507 switch (bmp->pixel_mode)
1509 case FT_PIXEL_MODE_MONO:
1510 dst += bytesPerPixel - 1; // shift to alpha byte
1511 for (x = 0; x < bmp->width; x += 8)
1513 unsigned char ch = *src++;
1514 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1515 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1516 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1517 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1518 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1519 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1520 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1521 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1524 case FT_PIXEL_MODE_GRAY2:
1525 dst += bytesPerPixel - 1; // shift to alpha byte
1526 for (x = 0; x < bmp->width; x += 4)
1528 unsigned char ch = *src++;
1529 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1530 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1531 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1532 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1535 case FT_PIXEL_MODE_GRAY4:
1536 dst += bytesPerPixel - 1; // shift to alpha byte
1537 for (x = 0; x < bmp->width; x += 2)
1539 unsigned char ch = *src++;
1540 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1541 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1544 case FT_PIXEL_MODE_GRAY:
1545 // in this case pitch should equal width
1546 for (tp = 0; tp < bmp->pitch; ++tp)
1547 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1549 //memcpy((void*)dst, (void*)src, bmp->pitch);
1550 //dst += bmp->pitch;
1561 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1569 Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1573 // now fill map->glyphs[ch - map->start]
1574 mapglyph = &map->glyphs[mapch];
1578 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1580 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1581 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1582 double advance = (glyph->advance.x / 64.0) / map->size;
1583 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1584 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1586 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1587 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1588 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1589 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1590 //mapglyph->vxmin = bearingX;
1591 //mapglyph->vxmax = bearingX + mWidth;
1592 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1593 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1594 //mapglyph->vymin = -bearingY;
1595 //mapglyph->vymax = mHeight - bearingY;
1596 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1597 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1598 //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);
1599 //mapglyph->advance_x = advance * usefont->size;
1600 //mapglyph->advance_x = advance;
1601 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1602 mapglyph->advance_y = 0;
1604 if (developer_font.integer)
1606 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1607 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1608 if (ch >= 32 && ch <= 128)
1609 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1610 Con_DPrintf("glyphinfo: Vertex info:\n");
1611 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1612 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1613 Con_DPrintf("glyphinfo: Texture info:\n");
1614 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1615 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1616 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1619 map->glyphs[mapch].image = false;
1622 if (map->pic->tex == r_texture_notexture)
1624 int w = map->glyphSize * FONT_CHARS_PER_LINE;
1625 int h = map->glyphSize * FONT_CHAR_LINES;
1627 // abuse the Draw_CachePic system to keep track of this texture
1628 tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL);
1629 // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
1631 map->pic->tex = tex;
1633 if (r_font_diskcache.integer >= 1)
1635 // swap to BGRA for tga writing...
1639 for (x = 0;x < s;x++)
1642 data[x*4+0] = data[x*4+2];
1645 Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data);
1647 if (r_font_compress.integer && qglGetCompressedTexImageARB && tex)
1648 R_SaveTextureDDSFile(tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1656 if (map->pic->tex == r_texture_notexture)
1658 // if the first try isn't successful, keep it with a broken texture
1659 // otherwise we retry to load it every single frame where ft2 rendering is used
1660 // this would be bad...
1661 // only `data' must be freed
1662 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1663 font->name, mapstart->size, mapidx);
1671 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1673 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1675 // the first map must have been loaded already
1676 if (!font->font_maps[map_index])
1678 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1681 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1683 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1684 start = start->next;
1685 if (start && start->start > ch)