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 [] =
178 #elif defined(MACOSX)
187 if (r_font_disable_freetype.integer)
195 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
204 Initialize the freetype2 font subsystem
208 void font_start(void)
210 if (!Font_OpenLibrary())
213 if (qFT_Init_FreeType(&font_ft2lib))
215 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
220 font_mempool = Mem_AllocPool("FONT", 0, NULL);
223 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
228 font_texturepool = R_AllocTexturePool();
229 if (!font_texturepool)
231 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
237 void font_shutdown(void)
240 for (i = 0; i < MAX_FONTS; ++i)
244 Font_UnloadFont(dp_fonts[i].ft2);
245 dp_fonts[i].ft2 = NULL;
251 void font_newmap(void)
257 Cvar_RegisterVariable(&r_font_disable_freetype);
258 Cvar_RegisterVariable(&r_font_use_alpha_textures);
259 Cvar_RegisterVariable(&r_font_size_snapping);
260 Cvar_RegisterVariable(&r_font_hinting);
261 Cvar_RegisterVariable(&r_font_antialias);
262 Cvar_RegisterVariable(&r_font_kerning);
263 Cvar_RegisterVariable(&developer_font);
267 ================================================================================
268 Implementation of a more or less lazy font loading and rendering code.
269 ================================================================================
272 #include "ft2_fontdefs.h"
274 ft2_font_t *Font_Alloc(void)
278 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
281 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
283 ft2_attachment_t *na;
285 font->attachmentcount++;
286 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
289 if (font->attachments && font->attachmentcount > 1)
291 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
292 Mem_Free(font->attachments);
294 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
295 font->attachments = na;
299 static float Font_VirtualToRealSize(float sz)
305 vw = ((vid.width > 0) ? vid.width : vid_width.value);
306 vh = ((vid.height > 0) ? vid.height : vid_height.value);
307 // now try to scale to our actual size:
308 sn = sz * vh / vid_conheight.value;
310 if ( sn - (float)si >= 0.5 )
315 static float Font_SnapTo(float val, float snapwidth)
317 return rint(val / snapwidth) * snapwidth;
320 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
321 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
322 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
325 ft2_font_t *ft2, *fbfont, *fb;
334 // check if a fallback font has been specified, if it has been, and the
335 // font fails to load, use the image font as main font
336 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
338 if (dpfnt->fallbacks[i][0])
342 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
344 if (i >= MAX_FONT_FALLBACKS)
350 strlcpy(ft2->name, name, sizeof(ft2->name));
351 ft2->image_font = true;
352 ft2->has_kerning = false;
356 ft2->image_font = false;
359 // attempt to load fallback fonts:
361 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
363 if (!dpfnt->fallbacks[i][0])
365 if (! (fb = Font_Alloc()) )
367 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
370 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
372 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
377 for (s = 0; s < MAX_FONT_SIZES; ++s)
379 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
384 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
389 // at least one size of the fallback font loaded successfully
395 if (fbfont == ft2 && ft2->image_font)
397 // no fallbacks were loaded successfully:
404 for (s = 0; s < MAX_FONT_SIZES; ++s)
406 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
411 // loading failed for every requested size
412 Font_UnloadFont(ft2);
418 //Con_Printf("%i sizes loaded\n", count);
423 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
426 char filename[MAX_QPATH];
430 fs_offset_t datasize;
432 memset(font, 0, sizeof(*font));
434 if (!Font_OpenLibrary())
436 if (!r_font_disable_freetype.integer)
438 Con_Printf("WARNING: can't open load font %s\n"
439 "You need the FreeType2 DLL to load font files\n",
445 namelen = strlen(name);
447 memcpy(filename, name, namelen);
448 memcpy(filename + namelen, ".ttf", 5);
449 data = FS_LoadFile(filename, font_mempool, false, &datasize);
452 memcpy(filename + namelen, ".otf", 5);
453 data = FS_LoadFile(filename, font_mempool, false, &datasize);
457 ft2_attachment_t afm;
459 memcpy(filename + namelen, ".pfb", 5);
460 data = FS_LoadFile(filename, font_mempool, false, &datasize);
464 memcpy(filename + namelen, ".afm", 5);
465 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
468 Font_Attach(font, &afm);
474 // FS_LoadFile being not-quiet should print an error :)
477 Con_Printf("Loading font %s face %i...\n", filename, _face);
479 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
480 if (status && _face != 0)
482 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
484 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
488 Con_Printf("ERROR: can't create face for %s\n"
489 "Error %i\n", // TODO: error strings
491 Font_UnloadFont(font);
495 // add the attachments
496 for (i = 0; i < font->attachmentcount; ++i)
499 memset(&args, 0, sizeof(args));
500 args.flags = FT_OPEN_MEMORY;
501 args.memory_base = (const FT_Byte*)font->attachments[i].data;
502 args.memory_size = font->attachments[i].size;
503 if (qFT_Attach_Stream(font->face, &args))
504 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
507 memcpy(font->name, name, namelen+1);
508 font->image_font = false;
509 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
513 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
514 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
517 ft2_font_map_t *fmap, temp;
519 if (!(size > 0.001f && size < 1000.0f))
524 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
529 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
531 if (!font->font_maps[map_index])
533 // if a similar size has already been loaded, ignore this one
534 //abs(font->font_maps[map_index]->size - size) < 4
535 if (font->font_maps[map_index]->size == size)
539 if (map_index >= MAX_FONT_SIZES)
542 memset(&temp, 0, sizeof(temp));
544 temp.glyphSize = CeilPowerOf2(size*2);
545 temp.sfx = (1.0/64.0)/(double)size;
546 temp.sfy = (1.0/64.0)/(double)size;
547 temp.intSize = -1; // negative value: LoadMap must search now :)
548 if (!Font_LoadMap(font, &temp, 0, &fmap))
550 Con_Printf("ERROR: can't load the first character map for %s\n"
553 Font_UnloadFont(font);
556 font->font_maps[map_index] = temp.next;
558 fmap->sfx = temp.sfx;
559 fmap->sfy = temp.sfy;
563 // load the default kerning vector:
564 if (font->has_kerning)
568 for (l = 0; l < 256; ++l)
570 for (r = 0; r < 256; ++r)
573 ul = qFT_Get_Char_Index(font->face, l);
574 ur = qFT_Get_Char_Index(font->face, r);
575 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
577 fmap->kerning.kerning[l][r][0] = 0;
578 fmap->kerning.kerning[l][r][1] = 0;
582 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
583 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
593 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
598 int matchsize = -10000;
600 float fsize_x, fsize_y;
601 ft2_font_map_t **maps = font->font_maps;
603 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
605 fsize_x = *outw * vid.width / vid_conwidth.value;
607 fsize_y = *outh * vid.height / vid_conheight.value;
612 fsize_x = fsize_y = 16;
622 for (m = 0; m < MAX_FONT_SIZES; ++m)
626 // "round up" to the bigger size if two equally-valued matches exist
627 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
628 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
632 matchsize = maps[m]->size;
633 if (value == 0) // there is no better match
637 if (value <= r_font_size_snapping.value)
639 // do NOT keep the aspect for perfect rendering
640 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
641 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
646 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
648 if (index < 0 || index >= MAX_FONT_SIZES)
650 return font->font_maps[index];
653 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
655 if (font->currenth == h &&
656 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
657 font->currentw == w)) // same size has been requested
661 // sorry, but freetype doesn't seem to care about other sizes
664 if (font->image_font)
666 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
671 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
679 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
681 ft2_font_map_t *fmap;
682 if (!font->has_kerning || !r_font_kerning.integer)
684 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
686 fmap = font->font_maps[map_index];
689 if (left < 256 && right < 256)
691 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
692 // quick-kerning, be aware of the size: scale it
693 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
694 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
702 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
704 if (!Font_SetSize(font, w, h))
706 // this deserves an error message
707 Con_Printf("Failed to get kerning for %s\n", font->name);
710 ul = qFT_Get_Char_Index(font->face, left);
711 ur = qFT_Get_Char_Index(font->face, right);
712 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
714 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
715 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
719 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
721 // this deserves an error message
722 Con_Printf("Failed to get kerning for %s\n", font->name);
725 ul = qFT_Get_Char_Index(font->face, left);
726 ur = qFT_Get_Char_Index(font->face, right);
727 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
729 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
730 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
737 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
739 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
742 static void UnloadMapRec(ft2_font_map_t *map)
746 R_FreeTexture(map->texture);
750 UnloadMapRec(map->next);
754 void Font_UnloadFont(ft2_font_t *font)
757 if (font->attachments && font->attachmentcount)
759 Mem_Free(font->attachments);
760 font->attachmentcount = 0;
761 font->attachments = NULL;
763 for (i = 0; i < MAX_FONT_SIZES; ++i)
765 if (font->font_maps[i])
767 UnloadMapRec(font->font_maps[i]);
768 font->font_maps[i] = NULL;
775 qFT_Done_Face((FT_Face)font->face);
781 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
783 char map_identifier[MAX_QPATH];
784 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
792 int gR, gC; // glyph position: row and column
794 ft2_font_map_t *map, *next;
799 int bytesPerPixel = 4; // change the conversion loop too if you change this!
804 if (r_font_use_alpha_textures.integer)
807 if (font->image_font)
808 fontface = (FT_Face)font->next->face;
810 fontface = (FT_Face)font->face;
812 switch(r_font_antialias.integer)
815 switch(r_font_hinting.integer)
818 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
822 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
826 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
832 switch(r_font_hinting.integer)
835 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
838 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
841 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
845 load_flags = FT_LOAD_TARGET_NORMAL;
851 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
853 if (font->image_font && mapstart->intSize < 0)
854 mapstart->intSize = mapstart->size;
855 if (mapstart->intSize < 0)
857 mapstart->intSize = mapstart->size;
860 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
862 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
865 if ((fontface->size->metrics.height>>6) <= mapstart->size)
867 if (mapstart->intSize < 2)
869 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
874 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
877 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
879 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
883 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
886 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
890 // copy over the information
891 map->size = mapstart->size;
892 map->intSize = mapstart->intSize;
893 map->glyphSize = mapstart->glyphSize;
894 map->sfx = mapstart->sfx;
895 map->sfy = mapstart->sfy;
897 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
898 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
901 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
905 memset(map->width_of, 0, sizeof(map->width_of));
907 // initialize as white texture with zero alpha
909 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
911 if (bytesPerPixel == 4)
921 map->start = mapidx * FONT_CHARS_PER_MAP;
923 while(next->next && next->next->start < map->start)
925 map->next = next->next;
930 for (ch = map->start;
931 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
938 unsigned char *imagedata, *dst, *src;
939 glyph_slot_t *mapglyph;
942 mapch = ch - map->start;
944 if (developer_font.integer)
945 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
948 if (gC >= FONT_CHARS_PER_LINE)
950 gC -= FONT_CHARS_PER_LINE;
954 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
955 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
956 // we need the glyphIndex
959 if (font->image_font && mapch == ch && img_fontmap[mapch])
961 map->glyphs[mapch].image = true;
964 glyphIndex = qFT_Get_Char_Index(face, ch);
967 // by convention, 0 is the "missing-glyph"-glyph
968 // try to load from a fallback font
969 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
971 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
974 face = usefont->face;
975 glyphIndex = qFT_Get_Char_Index(face, ch);
978 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
985 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
986 // now we let it use the "missing-glyph"-glyph
996 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
999 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1000 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1005 glyph = face->glyph;
1006 bmp = &glyph->bitmap;
1011 if (w > map->glyphSize || h > map->glyphSize) {
1012 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1013 if (w > map->glyphSize)
1015 if (h > map->glyphSize)
1019 switch (bmp->pixel_mode)
1021 case FT_PIXEL_MODE_MONO:
1022 if (developer_font.integer)
1023 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1025 case FT_PIXEL_MODE_GRAY2:
1026 if (developer_font.integer)
1027 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1029 case FT_PIXEL_MODE_GRAY4:
1030 if (developer_font.integer)
1031 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1033 case FT_PIXEL_MODE_GRAY:
1034 if (developer_font.integer)
1035 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1038 if (developer_font.integer)
1039 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1041 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1044 for (y = 0; y < h; ++y)
1046 dst = imagedata + y * pitch;
1047 src = bmp->buffer + y * bmp->pitch;
1049 switch (bmp->pixel_mode)
1051 case FT_PIXEL_MODE_MONO:
1052 dst += bytesPerPixel - 1; // shift to alpha byte
1053 for (x = 0; x < bmp->width; x += 8)
1055 unsigned char ch = *src++;
1056 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1057 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1058 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1059 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1060 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1061 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1062 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1063 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1066 case FT_PIXEL_MODE_GRAY2:
1067 dst += bytesPerPixel - 1; // shift to alpha byte
1068 for (x = 0; x < bmp->width; x += 4)
1070 unsigned char ch = *src++;
1071 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1072 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1073 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1074 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1077 case FT_PIXEL_MODE_GRAY4:
1078 dst += bytesPerPixel - 1; // shift to alpha byte
1079 for (x = 0; x < bmp->width; x += 2)
1081 unsigned char ch = *src++;
1082 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1083 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1086 case FT_PIXEL_MODE_GRAY:
1087 // in this case pitch should equal width
1088 for (tp = 0; tp < bmp->pitch; ++tp)
1089 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1091 //memcpy((void*)dst, (void*)src, bmp->pitch);
1092 //dst += bmp->pitch;
1099 // now fill map->glyphs[ch - map->start]
1100 mapglyph = &map->glyphs[mapch];
1104 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1106 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1107 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1108 double advance = (glyph->advance.x / 64.0) / map->size;
1109 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1110 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1112 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1113 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1114 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1115 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1116 //mapglyph->vxmin = bearingX;
1117 //mapglyph->vxmax = bearingX + mWidth;
1118 mapglyph->vxmin = glyph->bitmap_left / map->size;
1119 mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
1120 //mapglyph->vymin = -bearingY;
1121 //mapglyph->vymax = mHeight - bearingY;
1122 mapglyph->vymin = -glyph->bitmap_top / map->size;
1123 mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
1124 //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);
1125 //mapglyph->advance_x = advance * usefont->size;
1126 //mapglyph->advance_x = advance;
1127 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1128 mapglyph->advance_y = 0;
1130 if (developer_font.integer)
1132 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1133 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1134 if (ch >= 32 && ch <= 128)
1135 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1136 Con_DPrintf("glyphinfo: Vertex info:\n");
1137 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1138 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1139 Con_DPrintf("glyphinfo: Texture info:\n");
1140 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1141 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1142 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1145 map->glyphs[mapch].image = false;
1148 // create a texture from the data now
1150 if (developer_font.integer > 100)
1152 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1153 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1154 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1155 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1157 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1159 // probably use bytesPerPixel here instead?
1160 if (r_font_use_alpha_textures.integer)
1162 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1163 map->glyphSize * FONT_CHARS_PER_LINE,
1164 map->glyphSize * FONT_CHAR_LINES,
1165 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1167 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1168 map->glyphSize * FONT_CHARS_PER_LINE,
1169 map->glyphSize * FONT_CHAR_LINES,
1170 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1176 // if the first try isn't successful, keep it with a broken texture
1177 // otherwise we retry to load it every single frame where ft2 rendering is used
1178 // this would be bad...
1179 // only `data' must be freed
1180 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1181 font->name, mapstart->size, mapidx);
1189 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1191 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1193 // the first map must have been loaded already
1194 if (!font->font_maps[map_index])
1196 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1199 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1201 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1202 start = start->next;
1203 if (start && start->start > ch)