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_hinting = {CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"};
39 cvar_t r_font_antialias = {CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */};
40 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
41 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
44 ================================================================================
45 Function definitions. Taken from the freetype2 headers.
46 ================================================================================
51 (*qFT_Init_FreeType)( FT_Library *alibrary );
53 (*qFT_Done_FreeType)( FT_Library library );
56 (*qFT_New_Face)( FT_Library library,
57 const char* filepathname,
62 (*qFT_New_Memory_Face)( FT_Library library,
63 const FT_Byte* file_base,
68 (*qFT_Done_Face)( FT_Face face );
70 (*qFT_Select_Size)( FT_Face face,
71 FT_Int strike_index );
73 (*qFT_Request_Size)( FT_Face face,
74 FT_Size_Request req );
76 (*qFT_Set_Char_Size)( FT_Face face,
77 FT_F26Dot6 char_width,
78 FT_F26Dot6 char_height,
79 FT_UInt horz_resolution,
80 FT_UInt vert_resolution );
82 (*qFT_Set_Pixel_Sizes)( FT_Face face,
84 FT_UInt pixel_height );
86 (*qFT_Load_Glyph)( FT_Face face,
88 FT_Int32 load_flags );
90 (*qFT_Load_Char)( FT_Face face,
92 FT_Int32 load_flags );
94 (*qFT_Get_Char_Index)( FT_Face face,
97 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
98 FT_Render_Mode render_mode );
100 (*qFT_Get_Kerning)( FT_Face face,
104 FT_Vector *akerning );
105 FT_EXPORT( FT_Error )
106 (*qFT_Attach_Stream)( FT_Face face,
107 FT_Open_Args* parameters );
109 ================================================================================
110 Support for dynamically loading the FreeType2 library
111 ================================================================================
114 static dllfunction_t ft2funcs[] =
116 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
117 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
118 //{"FT_New_Face", (void **) &qFT_New_Face},
119 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
120 {"FT_Done_Face", (void **) &qFT_Done_Face},
121 {"FT_Select_Size", (void **) &qFT_Select_Size},
122 {"FT_Request_Size", (void **) &qFT_Request_Size},
123 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
124 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
125 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
126 {"FT_Load_Char", (void **) &qFT_Load_Char},
127 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
128 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
129 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
130 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
134 /// Handle for FreeType2 DLL
135 static dllhandle_t ft2_dll = NULL;
137 /// Memory pool for fonts
138 static mempool_t *font_mempool= NULL;
139 static rtexturepool_t *font_texturepool = NULL;
141 /// FreeType library handle
142 static FT_Library font_ft2lib = NULL;
148 Unload the FreeType2 DLL
151 void Font_CloseLibrary (void)
154 Mem_FreePool(&font_mempool);
155 if (font_texturepool)
156 R_FreeTexturePool(&font_texturepool);
157 if (font_ft2lib && qFT_Done_FreeType)
159 qFT_Done_FreeType(font_ft2lib);
162 Sys_UnloadLibrary (&ft2_dll);
169 Try to load the FreeType2 DLL
172 qboolean Font_OpenLibrary (void)
174 const char* dllnames [] =
179 #elif defined(MACOSX)
180 "libfreetype.6.dylib",
189 if (r_font_disable_freetype.integer)
197 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
206 Initialize the freetype2 font subsystem
210 void font_start(void)
212 if (!Font_OpenLibrary())
215 if (qFT_Init_FreeType(&font_ft2lib))
217 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
222 font_mempool = Mem_AllocPool("FONT", 0, NULL);
225 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
230 font_texturepool = R_AllocTexturePool();
231 if (!font_texturepool)
233 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
239 void font_shutdown(void)
242 for (i = 0; i < MAX_FONTS; ++i)
246 Font_UnloadFont(dp_fonts[i].ft2);
247 dp_fonts[i].ft2 = NULL;
253 void font_newmap(void)
259 Cvar_RegisterVariable(&r_font_disable_freetype);
260 Cvar_RegisterVariable(&r_font_use_alpha_textures);
261 Cvar_RegisterVariable(&r_font_size_snapping);
262 Cvar_RegisterVariable(&r_font_hinting);
263 Cvar_RegisterVariable(&r_font_antialias);
264 Cvar_RegisterVariable(&r_font_kerning);
265 Cvar_RegisterVariable(&developer_font);
266 // let's open it at startup already
271 ================================================================================
272 Implementation of a more or less lazy font loading and rendering code.
273 ================================================================================
276 #include "ft2_fontdefs.h"
278 ft2_font_t *Font_Alloc(void)
282 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
285 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
287 ft2_attachment_t *na;
289 font->attachmentcount++;
290 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
293 if (font->attachments && font->attachmentcount > 1)
295 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
296 Mem_Free(font->attachments);
298 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
299 font->attachments = na;
303 float Font_VirtualToRealSize(float sz)
309 vw = ((vid.width > 0) ? vid.width : vid_width.value);
310 vh = ((vid.height > 0) ? vid.height : vid_height.value);
311 // now try to scale to our actual size:
312 sn = sz * vh / vid_conheight.value;
314 if ( sn - (float)si >= 0.5 )
319 float Font_SnapTo(float val, float snapwidth)
321 return floor(val / snapwidth + 0.5f) * snapwidth;
324 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
325 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
326 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
329 ft2_font_t *ft2, *fbfont, *fb;
338 // check if a fallback font has been specified, if it has been, and the
339 // font fails to load, use the image font as main font
340 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
342 if (dpfnt->fallbacks[i][0])
346 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
348 if (i >= MAX_FONT_FALLBACKS)
354 strlcpy(ft2->name, name, sizeof(ft2->name));
355 ft2->image_font = true;
356 ft2->has_kerning = false;
360 ft2->image_font = false;
363 // attempt to load fallback fonts:
365 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
367 if (!dpfnt->fallbacks[i][0])
369 if (! (fb = Font_Alloc()) )
371 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
374 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
376 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
381 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
383 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
388 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
393 // at least one size of the fallback font loaded successfully
399 if (fbfont == ft2 && ft2->image_font)
401 // no fallbacks were loaded successfully:
408 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
410 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
415 // loading failed for every requested size
416 Font_UnloadFont(ft2);
422 //Con_Printf("%i sizes loaded\n", count);
427 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
430 char filename[MAX_QPATH];
434 fs_offset_t datasize;
436 memset(font, 0, sizeof(*font));
438 if (!Font_OpenLibrary())
440 if (!r_font_disable_freetype.integer)
442 Con_Printf("WARNING: can't open load font %s\n"
443 "You need the FreeType2 DLL to load font files\n",
449 namelen = strlen(name);
451 memcpy(filename, name, namelen);
452 memcpy(filename + namelen, ".ttf", 5);
453 data = FS_LoadFile(filename, font_mempool, false, &datasize);
456 memcpy(filename + namelen, ".otf", 5);
457 data = FS_LoadFile(filename, font_mempool, false, &datasize);
461 ft2_attachment_t afm;
463 memcpy(filename + namelen, ".pfb", 5);
464 data = FS_LoadFile(filename, font_mempool, false, &datasize);
468 memcpy(filename + namelen, ".afm", 5);
469 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
472 Font_Attach(font, &afm);
478 // FS_LoadFile being not-quiet should print an error :)
481 Con_Printf("Loading font %s face %i...\n", filename, _face);
483 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
484 if (status && _face != 0)
486 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
488 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
492 Con_Printf("ERROR: can't create face for %s\n"
493 "Error %i\n", // TODO: error strings
495 Font_UnloadFont(font);
499 // add the attachments
500 for (i = 0; i < font->attachmentcount; ++i)
503 memset(&args, 0, sizeof(args));
504 args.flags = FT_OPEN_MEMORY;
505 args.memory_base = (const FT_Byte*)font->attachments[i].data;
506 args.memory_size = font->attachments[i].size;
507 if (qFT_Attach_Stream(font->face, &args))
508 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
511 memcpy(font->name, name, namelen+1);
512 font->image_font = false;
513 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
517 void Font_Postprocess(unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b)
521 // perform operation, not exceeding the passed padding values,
522 // but possibly reducing them
526 // calculate parameters
527 *pad_l = *pad_r = *pad_t = *pad_b = 0;
531 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
532 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
533 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
536 ft2_font_map_t *fmap, temp;
537 int gpad_l, gpad_r, gpad_t, gpad_b;
539 if (!(size > 0.001f && size < 1000.0f))
544 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
547 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
549 if (!font->font_maps[map_index])
551 // if a similar size has already been loaded, ignore this one
552 //abs(font->font_maps[map_index]->size - size) < 4
553 if (font->font_maps[map_index]->size == size)
557 if (map_index >= MAX_FONT_SIZES)
562 if (font->image_font)
563 fontface = (FT_Face)font->next->face;
565 fontface = (FT_Face)font->face;
566 return (Font_SearchSize(font, fontface, size) > 0);
569 Font_Postprocess(NULL, 0, 0, 0, 0, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
571 memset(&temp, 0, sizeof(temp));
573 temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
574 temp.sfx = (1.0/64.0)/(double)size;
575 temp.sfy = (1.0/64.0)/(double)size;
576 temp.intSize = -1; // negative value: LoadMap must search now :)
577 if (!Font_LoadMap(font, &temp, 0, &fmap))
579 Con_Printf("ERROR: can't load the first character map for %s\n"
582 Font_UnloadFont(font);
585 font->font_maps[map_index] = temp.next;
587 fmap->sfx = temp.sfx;
588 fmap->sfy = temp.sfy;
590 // load the default kerning vector:
591 if (font->has_kerning)
595 for (l = 0; l < 256; ++l)
597 for (r = 0; r < 256; ++r)
600 ul = qFT_Get_Char_Index(font->face, l);
601 ur = qFT_Get_Char_Index(font->face, r);
602 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
604 fmap->kerning.kerning[l][r][0] = 0;
605 fmap->kerning.kerning[l][r][1] = 0;
609 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
610 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
618 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
623 int matchsize = -10000;
625 float fsize_x, fsize_y;
626 ft2_font_map_t **maps = font->font_maps;
628 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
630 fsize_x = *outw * vid.width / vid_conwidth.value;
632 fsize_y = *outh * vid.height / vid_conheight.value;
637 fsize_x = fsize_y = 16;
647 for (m = 0; m < MAX_FONT_SIZES; ++m)
651 // "round up" to the bigger size if two equally-valued matches exist
652 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
653 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
657 matchsize = maps[m]->size;
658 if (value == 0) // there is no better match
662 if (value <= r_font_size_snapping.value)
664 // do NOT keep the aspect for perfect rendering
665 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
666 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
671 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
673 if (index < 0 || index >= MAX_FONT_SIZES)
675 return font->font_maps[index];
678 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
680 if (font->currenth == h &&
681 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
682 font->currentw == w)) // same size has been requested
686 // sorry, but freetype doesn't seem to care about other sizes
689 if (font->image_font)
691 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
696 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
704 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
706 ft2_font_map_t *fmap;
707 if (!font->has_kerning || !r_font_kerning.integer)
709 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
711 fmap = font->font_maps[map_index];
714 if (left < 256 && right < 256)
716 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
717 // quick-kerning, be aware of the size: scale it
718 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
719 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
727 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
729 if (!Font_SetSize(font, w, h))
731 // this deserves an error message
732 Con_Printf("Failed to get kerning for %s\n", font->name);
735 ul = qFT_Get_Char_Index(font->face, left);
736 ur = qFT_Get_Char_Index(font->face, right);
737 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
739 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
740 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
744 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
746 // this deserves an error message
747 Con_Printf("Failed to get kerning for %s\n", font->name);
750 ul = qFT_Get_Char_Index(font->face, left);
751 ur = qFT_Get_Char_Index(font->face, right);
752 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
754 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
755 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
762 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
764 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
767 static void UnloadMapRec(ft2_font_map_t *map)
771 R_FreeTexture(map->texture);
775 UnloadMapRec(map->next);
779 void Font_UnloadFont(ft2_font_t *font)
782 if (font->attachments && font->attachmentcount)
784 Mem_Free(font->attachments);
785 font->attachmentcount = 0;
786 font->attachments = NULL;
788 for (i = 0; i < MAX_FONT_SIZES; ++i)
790 if (font->font_maps[i])
792 UnloadMapRec(font->font_maps[i]);
793 font->font_maps[i] = NULL;
800 qFT_Done_Face((FT_Face)font->face);
806 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
808 float intSize = size;
811 if (!Font_SetSize(font, intSize, intSize))
813 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
816 if ((fontface->size->metrics.height>>6) <= size)
820 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
827 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
829 char map_identifier[MAX_QPATH];
830 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
836 int gpad_l, gpad_r, gpad_t, gpad_b;
839 int gR, gC; // glyph position: row and column
841 ft2_font_map_t *map, *next;
846 int bytesPerPixel = 4; // change the conversion loop too if you change this!
851 if (r_font_use_alpha_textures.integer)
854 if (font->image_font)
855 fontface = (FT_Face)font->next->face;
857 fontface = (FT_Face)font->face;
859 switch(r_font_antialias.integer)
862 switch(r_font_hinting.integer)
865 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
869 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
873 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
879 switch(r_font_hinting.integer)
882 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
885 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
888 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
892 load_flags = FT_LOAD_TARGET_NORMAL;
898 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
900 if (font->image_font && mapstart->intSize < 0)
901 mapstart->intSize = mapstart->size;
902 if (mapstart->intSize < 0)
905 mapstart->intSize = mapstart->size;
908 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
910 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
913 if ((fontface->size->metrics.height>>6) <= mapstart->size)
915 if (mapstart->intSize < 2)
917 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
923 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
925 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
928 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
930 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
934 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
937 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
941 Font_Postprocess(NULL, 0, 0, 0, 0, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
943 // copy over the information
944 map->size = mapstart->size;
945 map->intSize = mapstart->intSize;
946 map->glyphSize = mapstart->glyphSize;
947 map->sfx = mapstart->sfx;
948 map->sfy = mapstart->sfy;
950 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
951 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
954 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
958 memset(map->width_of, 0, sizeof(map->width_of));
960 // initialize as white texture with zero alpha
962 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
964 if (bytesPerPixel == 4)
974 map->start = mapidx * FONT_CHARS_PER_MAP;
976 while(next->next && next->next->start < map->start)
978 map->next = next->next;
983 for (ch = map->start;
984 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
991 unsigned char *imagedata, *dst, *src;
992 glyph_slot_t *mapglyph;
994 int pad_l, pad_r, pad_t, pad_b;
996 mapch = ch - map->start;
998 if (developer_font.integer)
999 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1002 if (gC >= FONT_CHARS_PER_LINE)
1004 gC -= FONT_CHARS_PER_LINE;
1008 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1009 imagedata += gpad_t * pitch + gpad_l;
1010 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1011 // we need the glyphIndex
1014 if (font->image_font && mapch == ch && img_fontmap[mapch])
1016 map->glyphs[mapch].image = true;
1019 glyphIndex = qFT_Get_Char_Index(face, ch);
1020 if (glyphIndex == 0)
1022 // by convention, 0 is the "missing-glyph"-glyph
1023 // try to load from a fallback font
1024 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1026 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1029 face = usefont->face;
1030 glyphIndex = qFT_Get_Char_Index(face, ch);
1031 if (glyphIndex == 0)
1033 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1040 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1041 // now we let it use the "missing-glyph"-glyph
1051 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1054 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1055 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1060 glyph = face->glyph;
1061 bmp = &glyph->bitmap;
1066 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1067 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1068 if (w > map->glyphSize)
1069 w = map->glyphSize - gpad_l - gpad_r;
1070 if (h > map->glyphSize)
1074 switch (bmp->pixel_mode)
1076 case FT_PIXEL_MODE_MONO:
1077 if (developer_font.integer)
1078 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1080 case FT_PIXEL_MODE_GRAY2:
1081 if (developer_font.integer)
1082 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1084 case FT_PIXEL_MODE_GRAY4:
1085 if (developer_font.integer)
1086 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1088 case FT_PIXEL_MODE_GRAY:
1089 if (developer_font.integer)
1090 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1093 if (developer_font.integer)
1094 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1096 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1099 for (y = 0; y < h; ++y)
1101 dst = imagedata + y * pitch;
1102 src = bmp->buffer + y * bmp->pitch;
1104 switch (bmp->pixel_mode)
1106 case FT_PIXEL_MODE_MONO:
1107 dst += bytesPerPixel - 1; // shift to alpha byte
1108 for (x = 0; x < bmp->width; x += 8)
1110 unsigned char ch = *src++;
1111 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1112 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1113 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1114 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1115 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1116 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1117 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1118 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1121 case FT_PIXEL_MODE_GRAY2:
1122 dst += bytesPerPixel - 1; // shift to alpha byte
1123 for (x = 0; x < bmp->width; x += 4)
1125 unsigned char ch = *src++;
1126 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1127 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1128 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1129 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1132 case FT_PIXEL_MODE_GRAY4:
1133 dst += bytesPerPixel - 1; // shift to alpha byte
1134 for (x = 0; x < bmp->width; x += 2)
1136 unsigned char ch = *src++;
1137 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1138 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1141 case FT_PIXEL_MODE_GRAY:
1142 // in this case pitch should equal width
1143 for (tp = 0; tp < bmp->pitch; ++tp)
1144 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1146 //memcpy((void*)dst, (void*)src, bmp->pitch);
1147 //dst += bmp->pitch;
1158 Font_Postprocess(imagedata, pitch, w, h, bytesPerPixel, &pad_l, &pad_r, &pad_t, &pad_b);
1160 // now fill map->glyphs[ch - map->start]
1161 mapglyph = &map->glyphs[mapch];
1165 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1167 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1168 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1169 double advance = (glyph->advance.x / 64.0) / map->size;
1170 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1171 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1173 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1174 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1175 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1176 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1177 //mapglyph->vxmin = bearingX;
1178 //mapglyph->vxmax = bearingX + mWidth;
1179 mapglyph->vxmin = glyph->bitmap_left / map->size;
1180 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1181 //mapglyph->vymin = -bearingY;
1182 //mapglyph->vymax = mHeight - bearingY;
1183 mapglyph->vymin = -glyph->bitmap_top / map->size;
1184 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1185 //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);
1186 //mapglyph->advance_x = advance * usefont->size;
1187 //mapglyph->advance_x = advance;
1188 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1189 mapglyph->advance_y = 0;
1191 if (developer_font.integer)
1193 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1194 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1195 if (ch >= 32 && ch <= 128)
1196 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1197 Con_DPrintf("glyphinfo: Vertex info:\n");
1198 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1199 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1200 Con_DPrintf("glyphinfo: Texture info:\n");
1201 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1202 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1203 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1206 map->glyphs[mapch].image = false;
1209 // create a texture from the data now
1211 if (developer_font.integer > 100)
1213 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1214 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1215 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1216 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1218 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1220 // probably use bytesPerPixel here instead?
1221 if (r_font_use_alpha_textures.integer)
1223 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1224 map->glyphSize * FONT_CHARS_PER_LINE,
1225 map->glyphSize * FONT_CHAR_LINES,
1226 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1228 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1229 map->glyphSize * FONT_CHARS_PER_LINE,
1230 map->glyphSize * FONT_CHAR_LINES,
1231 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1237 // if the first try isn't successful, keep it with a broken texture
1238 // otherwise we retry to load it every single frame where ft2 rendering is used
1239 // this would be bad...
1240 // only `data' must be freed
1241 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1242 font->name, mapstart->size, mapidx);
1250 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1252 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1254 // the first map must have been loaded already
1255 if (!font->font_maps[map_index])
1257 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1260 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1262 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1263 start = start->next;
1264 if (start && start->start > ch)