1 /* FreeType 2 and UTF-8 encoding support for
8 #include "ft2_fontdefs.h"
10 static int img_fontmap[256] = {
11 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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, // shift+digit line
14 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
15 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
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, // small
18 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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
30 ================================================================================
31 CVars introduced with the freetype extension
32 ================================================================================
35 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
36 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"};
37 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!"};
38 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
39 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
42 ================================================================================
43 Function definitions. Taken from the freetype2 headers.
44 ================================================================================
49 (*qFT_Init_FreeType)( FT_Library *alibrary );
51 (*qFT_Done_FreeType)( FT_Library library );
54 (*qFT_New_Face)( FT_Library library,
55 const char* filepathname,
60 (*qFT_New_Memory_Face)( FT_Library library,
61 const FT_Byte* file_base,
66 (*qFT_Done_Face)( FT_Face face );
68 (*qFT_Select_Size)( FT_Face face,
69 FT_Int strike_index );
71 (*qFT_Request_Size)( FT_Face face,
72 FT_Size_Request req );
74 (*qFT_Set_Char_Size)( FT_Face face,
75 FT_F26Dot6 char_width,
76 FT_F26Dot6 char_height,
77 FT_UInt horz_resolution,
78 FT_UInt vert_resolution );
80 (*qFT_Set_Pixel_Sizes)( FT_Face face,
82 FT_UInt pixel_height );
84 (*qFT_Load_Glyph)( FT_Face face,
86 FT_Int32 load_flags );
88 (*qFT_Load_Char)( FT_Face face,
90 FT_Int32 load_flags );
92 (*qFT_Get_Char_Index)( FT_Face face,
95 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
96 FT_Render_Mode render_mode );
98 (*qFT_Get_Kerning)( FT_Face face,
102 FT_Vector *akerning );
103 FT_EXPORT( FT_Error )
104 (*qFT_Attach_Stream)( FT_Face face,
105 FT_Open_Args* parameters );
107 ================================================================================
108 Support for dynamically loading the FreeType2 library
109 ================================================================================
112 static dllfunction_t ft2funcs[] =
114 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
115 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
116 //{"FT_New_Face", (void **) &qFT_New_Face},
117 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
118 {"FT_Done_Face", (void **) &qFT_Done_Face},
119 {"FT_Select_Size", (void **) &qFT_Select_Size},
120 {"FT_Request_Size", (void **) &qFT_Request_Size},
121 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
122 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
123 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
124 {"FT_Load_Char", (void **) &qFT_Load_Char},
125 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
126 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
127 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
128 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
132 /// Handle for FreeType2 DLL
133 static dllhandle_t ft2_dll = NULL;
135 /// Memory pool for fonts
136 static mempool_t *font_mempool= NULL;
137 static rtexturepool_t *font_texturepool = NULL;
139 /// FreeType library handle
140 static FT_Library font_ft2lib = NULL;
142 #define POSTPROCESS_MAXRADIUS 8
145 unsigned char *buf, *buf2;
146 int bufsize, bufwidth, bufheight, bufpitch;
147 float blur, outline, shadowx, shadowy, shadowz;
148 int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
149 unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
150 unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
153 static font_postprocess_t pp;
159 Unload the FreeType2 DLL
162 void Font_CloseLibrary (void)
165 Mem_FreePool(&font_mempool);
166 if (font_texturepool)
167 R_FreeTexturePool(&font_texturepool);
168 if (font_ft2lib && qFT_Done_FreeType)
170 qFT_Done_FreeType(font_ft2lib);
173 Sys_UnloadLibrary (&ft2_dll);
181 Try to load the FreeType2 DLL
184 qboolean Font_OpenLibrary (void)
186 const char* dllnames [] =
191 #elif defined(MACOSX)
192 "libfreetype.6.dylib",
201 if (r_font_disable_freetype.integer)
209 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
218 Initialize the freetype2 font subsystem
222 void font_start(void)
224 if (!Font_OpenLibrary())
227 if (qFT_Init_FreeType(&font_ft2lib))
229 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
234 font_mempool = Mem_AllocPool("FONT", 0, NULL);
237 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
242 font_texturepool = R_AllocTexturePool();
243 if (!font_texturepool)
245 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
251 void font_shutdown(void)
254 for (i = 0; i < dp_fonts.maxsize; ++i)
256 if (dp_fonts.f[i].ft2)
258 Font_UnloadFont(dp_fonts.f[i].ft2);
259 dp_fonts.f[i].ft2 = NULL;
265 void font_newmap(void)
271 Cvar_RegisterVariable(&r_font_disable_freetype);
272 Cvar_RegisterVariable(&r_font_use_alpha_textures);
273 Cvar_RegisterVariable(&r_font_size_snapping);
274 Cvar_RegisterVariable(&r_font_kerning);
275 Cvar_RegisterVariable(&developer_font);
277 // let's open it at startup already
282 ================================================================================
283 Implementation of a more or less lazy font loading and rendering code.
284 ================================================================================
287 #include "ft2_fontdefs.h"
289 ft2_font_t *Font_Alloc(void)
293 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
296 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
298 ft2_attachment_t *na;
300 font->attachmentcount++;
301 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
304 if (font->attachments && font->attachmentcount > 1)
306 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
307 Mem_Free(font->attachments);
309 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
310 font->attachments = na;
314 float Font_VirtualToRealSize(float sz)
322 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
323 vh = ((vid.height > 0) ? vid.height : vid_height.value);
324 // now try to scale to our actual size:
325 sn = sz * vh / vid_conheight.value;
327 if ( sn - (float)si >= 0.5 )
332 float Font_SnapTo(float val, float snapwidth)
334 return floor(val / snapwidth + 0.5f) * snapwidth;
337 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
338 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
339 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
342 ft2_font_t *ft2, *fbfont, *fb;
351 // check if a fallback font has been specified, if it has been, and the
352 // font fails to load, use the image font as main font
353 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
355 if (dpfnt->fallbacks[i][0])
359 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
361 if (i >= MAX_FONT_FALLBACKS)
367 strlcpy(ft2->name, name, sizeof(ft2->name));
368 ft2->image_font = true;
369 ft2->has_kerning = false;
373 ft2->image_font = false;
376 // attempt to load fallback fonts:
378 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
380 if (!dpfnt->fallbacks[i][0])
382 if (! (fb = Font_Alloc()) )
384 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
388 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
390 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
395 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
397 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
402 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
407 // at least one size of the fallback font loaded successfully
413 if (fbfont == ft2 && ft2->image_font)
415 // no fallbacks were loaded successfully:
422 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
424 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
429 // loading failed for every requested size
430 Font_UnloadFont(ft2);
436 //Con_Printf("%i sizes loaded\n", count);
441 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
444 char filename[MAX_QPATH];
448 fs_offset_t datasize;
450 memset(font, 0, sizeof(*font));
452 if (!Font_OpenLibrary())
454 if (!r_font_disable_freetype.integer)
456 Con_Printf("WARNING: can't open load font %s\n"
457 "You need the FreeType2 DLL to load font files\n",
463 font->settings = settings;
465 namelen = strlen(name);
467 // try load direct file
468 memcpy(filename, name, namelen+1);
469 data = FS_LoadFile(filename, font_mempool, false, &datasize);
473 memcpy(filename + namelen, ".ttf", 5);
474 data = FS_LoadFile(filename, font_mempool, false, &datasize);
479 memcpy(filename + namelen, ".otf", 5);
480 data = FS_LoadFile(filename, font_mempool, false, &datasize);
485 ft2_attachment_t afm;
487 memcpy(filename + namelen, ".pfb", 5);
488 data = FS_LoadFile(filename, font_mempool, false, &datasize);
492 memcpy(filename + namelen, ".afm", 5);
493 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
496 Font_Attach(font, &afm);
501 // FS_LoadFile being not-quiet should print an error :)
504 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
506 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
507 if (status && _face != 0)
509 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
511 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
515 Con_Printf("ERROR: can't create face for %s\n"
516 "Error %i\n", // TODO: error strings
518 Font_UnloadFont(font);
522 // add the attachments
523 for (i = 0; i < font->attachmentcount; ++i)
526 memset(&args, 0, sizeof(args));
527 args.flags = FT_OPEN_MEMORY;
528 args.memory_base = (const FT_Byte*)font->attachments[i].data;
529 args.memory_size = font->attachments[i].size;
530 if (qFT_Attach_Stream(font->face, &args))
531 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
534 memcpy(font->name, name, namelen+1);
535 font->image_font = false;
536 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
540 void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
543 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
544 qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
545 qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
546 pp.blur = fnt->settings->blur;
547 pp.outline = fnt->settings->outline;
548 pp.shadowx = fnt->settings->shadowx;
549 pp.shadowy = fnt->settings->shadowy;
550 pp.shadowz = fnt->settings->shadowz;
551 pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
552 pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
553 pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
554 pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
555 pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
556 pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
557 pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
558 pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
559 pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
560 pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
564 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
565 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));
566 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
567 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
568 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
569 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
573 for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
574 for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
576 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
577 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
580 pp.bufwidth = w + pp.padding_l + pp.padding_r;
581 pp.bufheight = h + pp.padding_t + pp.padding_b;
582 pp.bufpitch = pp.bufwidth;
583 needed = pp.bufwidth * pp.bufheight;
584 if(!pp.buf || pp.bufsize < needed * 2)
588 pp.bufsize = needed * 4;
589 pp.buf = Mem_Alloc(font_mempool, pp.bufsize);
590 pp.buf2 = pp.buf + needed;
594 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)
597 Font_Postprocess_Update(fnt, bpp, w, h);
602 // perform operation, not exceeding the passed padding values,
603 // but possibly reducing them
604 *pad_l = min(*pad_l, pp.padding_l);
605 *pad_r = min(*pad_r, pp.padding_r);
606 *pad_t = min(*pad_t, pp.padding_t);
607 *pad_b = min(*pad_b, pp.padding_b);
609 // calculate gauss table
611 // outline the font (RGBA only)
612 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
614 // this is like mplayer subtitle rendering
615 // bbuffer, bitmap buffer: this is our font
616 // abuffer, alpha buffer: this is pp.buf
617 // tmp: this is pp.buf2
619 // create outline buffer
620 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
621 for(y = -*pad_t; y < h + *pad_b; ++y)
622 for(x = -*pad_l; x < w + *pad_r; ++x)
624 int x1 = max(-x, -pp.outlinepadding_r);
625 int y1 = max(-y, -pp.outlinepadding_b);
626 int x2 = min(pp.outlinepadding_l, w-1-x);
627 int y2 = min(pp.outlinepadding_t, h-1-y);
631 for(my = y1; my <= y2; ++my)
632 for(mx = x1; mx <= x2; ++mx)
634 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
638 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
641 // blur the outline buffer
642 if(pp.blur > 0 || pp.shadowz != 0)
645 for(y = 0; y < pp.bufheight; ++y)
646 for(x = 0; x < pp.bufwidth; ++x)
648 int x1 = max(-x, -pp.blurpadding_rb);
649 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
652 for(mx = x1; mx <= x2; ++mx)
653 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
654 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
658 for(y = 0; y < pp.bufheight; ++y)
659 for(x = 0; x < pp.bufwidth; ++x)
661 int y1 = max(-y, -pp.blurpadding_rb);
662 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
665 for(my = y1; my <= y2; ++my)
666 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
667 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
671 // paste the outline below the font
672 for(y = -*pad_t; y < h + *pad_b; ++y)
673 for(x = -*pad_l; x < w + *pad_r; ++x)
675 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
678 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
679 // a' = 1 - (1 - a1) (1 - a2)
680 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
681 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
682 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
683 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
685 for(i = 0; i < bpp-1; ++i)
687 unsigned char c = imagedata[x * bpp + pitch * y + i];
688 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
689 imagedata[x * bpp + pitch * y + i] = c;
691 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
693 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
699 // just calculate parameters
700 *pad_l = pp.padding_l;
701 *pad_r = pp.padding_r;
702 *pad_t = pp.padding_t;
703 *pad_b = pp.padding_b;
707 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
708 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
709 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
712 ft2_font_map_t *fmap, temp;
713 int gpad_l, gpad_r, gpad_t, gpad_b;
715 if (!(size > 0.001f && size < 1000.0f))
720 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
723 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
725 if (!font->font_maps[map_index])
727 // if a similar size has already been loaded, ignore this one
728 //abs(font->font_maps[map_index]->size - size) < 4
729 if (font->font_maps[map_index]->size == size)
733 if (map_index >= MAX_FONT_SIZES)
738 if (font->image_font)
739 fontface = (FT_Face)font->next->face;
741 fontface = (FT_Face)font->face;
742 return (Font_SearchSize(font, fontface, size) > 0);
745 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
747 memset(&temp, 0, sizeof(temp));
749 temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
750 temp.sfx = (1.0/64.0)/(double)size;
751 temp.sfy = (1.0/64.0)/(double)size;
752 temp.intSize = -1; // negative value: LoadMap must search now :)
753 if (!Font_LoadMap(font, &temp, 0, &fmap))
755 Con_Printf("ERROR: can't load the first character map for %s\n"
758 Font_UnloadFont(font);
761 font->font_maps[map_index] = temp.next;
763 fmap->sfx = temp.sfx;
764 fmap->sfy = temp.sfy;
766 // load the default kerning vector:
767 if (font->has_kerning)
771 for (l = 0; l < 256; ++l)
773 for (r = 0; r < 256; ++r)
776 ul = qFT_Get_Char_Index(font->face, l);
777 ur = qFT_Get_Char_Index(font->face, r);
778 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
780 fmap->kerning.kerning[l][r][0] = 0;
781 fmap->kerning.kerning[l][r][1] = 0;
785 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
786 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
794 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
799 int matchsize = -10000;
801 float fsize_x, fsize_y;
802 ft2_font_map_t **maps = font->font_maps;
804 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
806 fsize_x = *outw * vid.width / vid_conwidth.value;
808 fsize_y = *outh * vid.height / vid_conheight.value;
813 fsize_x = fsize_y = 16;
823 for (m = 0; m < MAX_FONT_SIZES; ++m)
827 // "round up" to the bigger size if two equally-valued matches exist
828 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
829 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
833 matchsize = maps[m]->size;
834 if (value == 0) // there is no better match
838 if (value <= r_font_size_snapping.value)
840 // do NOT keep the aspect for perfect rendering
841 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
842 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
847 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
849 if (index < 0 || index >= MAX_FONT_SIZES)
851 return font->font_maps[index];
854 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
856 if (font->currenth == h &&
857 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
858 font->currentw == w)) // same size has been requested
862 // sorry, but freetype doesn't seem to care about other sizes
865 if (font->image_font)
867 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
872 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
880 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
882 ft2_font_map_t *fmap;
883 if (!font->has_kerning || !r_font_kerning.integer)
885 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
887 fmap = font->font_maps[map_index];
890 if (left < 256 && right < 256)
892 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
893 // quick-kerning, be aware of the size: scale it
894 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
895 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
903 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
905 if (!Font_SetSize(font, w, h))
907 // this deserves an error message
908 Con_Printf("Failed to get kerning for %s\n", font->name);
911 ul = qFT_Get_Char_Index(font->face, left);
912 ur = qFT_Get_Char_Index(font->face, right);
913 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
915 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
916 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
920 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
922 // this deserves an error message
923 Con_Printf("Failed to get kerning for %s\n", font->name);
926 ul = qFT_Get_Char_Index(font->face, left);
927 ur = qFT_Get_Char_Index(font->face, right);
928 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
930 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
931 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
938 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
940 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
943 static void UnloadMapRec(ft2_font_map_t *map)
947 R_FreeTexture(map->texture);
951 UnloadMapRec(map->next);
955 void Font_UnloadFont(ft2_font_t *font)
958 if (font->attachments && font->attachmentcount)
960 Mem_Free(font->attachments);
961 font->attachmentcount = 0;
962 font->attachments = NULL;
964 for (i = 0; i < MAX_FONT_SIZES; ++i)
966 if (font->font_maps[i])
968 UnloadMapRec(font->font_maps[i]);
969 font->font_maps[i] = NULL;
976 qFT_Done_Face((FT_Face)font->face);
982 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
984 float intSize = size;
987 if (!Font_SetSize(font, intSize, intSize))
989 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
992 if ((fontface->size->metrics.height>>6) <= size)
996 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1003 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1005 char map_identifier[MAX_QPATH];
1006 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1007 unsigned char *data;
1011 FT_Int32 load_flags;
1012 int gpad_l, gpad_r, gpad_t, gpad_b;
1015 int gR, gC; // glyph position: row and column
1017 ft2_font_map_t *map, *next;
1018 ft2_font_t *usefont;
1022 int bytesPerPixel = 4; // change the conversion loop too if you change this!
1027 if (r_font_use_alpha_textures.integer)
1030 if (font->image_font)
1031 fontface = (FT_Face)font->next->face;
1033 fontface = (FT_Face)font->face;
1035 switch(font->settings->antialias)
1038 switch(font->settings->hinting)
1041 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1045 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1049 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1055 switch(font->settings->hinting)
1058 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1061 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1064 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1068 load_flags = FT_LOAD_TARGET_NORMAL;
1074 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1076 if (font->image_font && mapstart->intSize < 0)
1077 mapstart->intSize = mapstart->size;
1078 if (mapstart->intSize < 0)
1081 mapstart->intSize = mapstart->size;
1084 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1086 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1089 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1091 if (mapstart->intSize < 2)
1093 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1096 --mapstart->intSize;
1099 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1101 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1104 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1106 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1110 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1113 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1117 Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1119 // copy over the information
1120 map->size = mapstart->size;
1121 map->intSize = mapstart->intSize;
1122 map->glyphSize = mapstart->glyphSize;
1123 map->sfx = mapstart->sfx;
1124 map->sfy = mapstart->sfy;
1126 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1127 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1130 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1134 memset(map->width_of, 0, sizeof(map->width_of));
1136 // initialize as white texture with zero alpha
1138 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1140 if (bytesPerPixel == 4)
1150 map->start = mapidx * FONT_CHARS_PER_MAP;
1152 while(next->next && next->next->start < map->start)
1154 map->next = next->next;
1159 for (ch = map->start;
1160 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1163 FT_ULong glyphIndex;
1167 unsigned char *imagedata, *dst, *src;
1168 glyph_slot_t *mapglyph;
1170 int pad_l, pad_r, pad_t, pad_b;
1172 mapch = ch - map->start;
1174 if (developer_font.integer)
1175 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1178 if (gC >= FONT_CHARS_PER_LINE)
1180 gC -= FONT_CHARS_PER_LINE;
1184 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1185 imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1186 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1187 // we need the glyphIndex
1190 if (font->image_font && mapch == ch && img_fontmap[mapch])
1192 map->glyphs[mapch].image = true;
1195 glyphIndex = qFT_Get_Char_Index(face, ch);
1196 if (glyphIndex == 0)
1198 // by convention, 0 is the "missing-glyph"-glyph
1199 // try to load from a fallback font
1200 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1202 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1205 face = usefont->face;
1206 glyphIndex = qFT_Get_Char_Index(face, ch);
1207 if (glyphIndex == 0)
1209 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1216 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1217 // now we let it use the "missing-glyph"-glyph
1227 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1230 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1231 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1236 glyph = face->glyph;
1237 bmp = &glyph->bitmap;
1242 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1243 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1244 if (w > map->glyphSize)
1245 w = map->glyphSize - gpad_l - gpad_r;
1246 if (h > map->glyphSize)
1250 switch (bmp->pixel_mode)
1252 case FT_PIXEL_MODE_MONO:
1253 if (developer_font.integer)
1254 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1256 case FT_PIXEL_MODE_GRAY2:
1257 if (developer_font.integer)
1258 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1260 case FT_PIXEL_MODE_GRAY4:
1261 if (developer_font.integer)
1262 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1264 case FT_PIXEL_MODE_GRAY:
1265 if (developer_font.integer)
1266 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1269 if (developer_font.integer)
1270 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1272 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1275 for (y = 0; y < h; ++y)
1277 dst = imagedata + y * pitch;
1278 src = bmp->buffer + y * bmp->pitch;
1280 switch (bmp->pixel_mode)
1282 case FT_PIXEL_MODE_MONO:
1283 dst += bytesPerPixel - 1; // shift to alpha byte
1284 for (x = 0; x < bmp->width; x += 8)
1286 unsigned char ch = *src++;
1287 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1288 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1289 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1290 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1291 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1292 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1293 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1294 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1297 case FT_PIXEL_MODE_GRAY2:
1298 dst += bytesPerPixel - 1; // shift to alpha byte
1299 for (x = 0; x < bmp->width; x += 4)
1301 unsigned char ch = *src++;
1302 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1303 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1304 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1305 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1308 case FT_PIXEL_MODE_GRAY4:
1309 dst += bytesPerPixel - 1; // shift to alpha byte
1310 for (x = 0; x < bmp->width; x += 2)
1312 unsigned char ch = *src++;
1313 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1314 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1317 case FT_PIXEL_MODE_GRAY:
1318 // in this case pitch should equal width
1319 for (tp = 0; tp < bmp->pitch; ++tp)
1320 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1322 //memcpy((void*)dst, (void*)src, bmp->pitch);
1323 //dst += bmp->pitch;
1334 Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1336 // now fill map->glyphs[ch - map->start]
1337 mapglyph = &map->glyphs[mapch];
1341 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1343 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1344 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1345 double advance = (glyph->advance.x / 64.0) / map->size;
1346 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1347 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1349 mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1350 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1351 mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1352 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1353 //mapglyph->vxmin = bearingX;
1354 //mapglyph->vxmax = bearingX + mWidth;
1355 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1356 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1357 //mapglyph->vymin = -bearingY;
1358 //mapglyph->vymax = mHeight - bearingY;
1359 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1360 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1361 //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);
1362 //mapglyph->advance_x = advance * usefont->size;
1363 //mapglyph->advance_x = advance;
1364 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1365 mapglyph->advance_y = 0;
1367 if (developer_font.integer)
1369 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1370 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1371 if (ch >= 32 && ch <= 128)
1372 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1373 Con_DPrintf("glyphinfo: Vertex info:\n");
1374 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1375 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1376 Con_DPrintf("glyphinfo: Texture info:\n");
1377 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1378 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1379 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1382 map->glyphs[mapch].image = false;
1385 // create a texture from the data now
1387 if (developer_font.integer > 100)
1389 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1390 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1391 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1392 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1394 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1396 // probably use bytesPerPixel here instead?
1397 if (r_font_use_alpha_textures.integer)
1399 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1400 map->glyphSize * FONT_CHARS_PER_LINE,
1401 map->glyphSize * FONT_CHAR_LINES,
1402 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1404 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1405 map->glyphSize * FONT_CHARS_PER_LINE,
1406 map->glyphSize * FONT_CHAR_LINES,
1407 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
1413 // if the first try isn't successful, keep it with a broken texture
1414 // otherwise we retry to load it every single frame where ft2 rendering is used
1415 // this would be bad...
1416 // only `data' must be freed
1417 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1418 font->name, mapstart->size, mapidx);
1426 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1428 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1430 // the first map must have been loaded already
1431 if (!font->font_maps[map_index])
1433 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1436 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1438 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1439 start = start->next;
1440 if (start && start->start > ch)