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 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
518 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
519 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
522 ft2_font_map_t *fmap, temp;
524 if (!(size > 0.001f && size < 1000.0f))
529 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
532 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
534 if (!font->font_maps[map_index])
536 // if a similar size has already been loaded, ignore this one
537 //abs(font->font_maps[map_index]->size - size) < 4
538 if (font->font_maps[map_index]->size == size)
542 if (map_index >= MAX_FONT_SIZES)
547 if (font->image_font)
548 fontface = (FT_Face)font->next->face;
550 fontface = (FT_Face)font->face;
551 return (Font_SearchSize(font, fontface, size) > 0);
554 memset(&temp, 0, sizeof(temp));
556 temp.glyphSize = CeilPowerOf2(size*2);
557 temp.sfx = (1.0/64.0)/(double)size;
558 temp.sfy = (1.0/64.0)/(double)size;
559 temp.intSize = -1; // negative value: LoadMap must search now :)
560 if (!Font_LoadMap(font, &temp, 0, &fmap))
562 Con_Printf("ERROR: can't load the first character map for %s\n"
565 Font_UnloadFont(font);
568 font->font_maps[map_index] = temp.next;
570 fmap->sfx = temp.sfx;
571 fmap->sfy = temp.sfy;
573 // load the default kerning vector:
574 if (font->has_kerning)
578 for (l = 0; l < 256; ++l)
580 for (r = 0; r < 256; ++r)
583 ul = qFT_Get_Char_Index(font->face, l);
584 ur = qFT_Get_Char_Index(font->face, r);
585 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
587 fmap->kerning.kerning[l][r][0] = 0;
588 fmap->kerning.kerning[l][r][1] = 0;
592 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
593 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
601 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
606 int matchsize = -10000;
608 float fsize_x, fsize_y;
609 ft2_font_map_t **maps = font->font_maps;
611 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
613 fsize_x = *outw * vid.width / vid_conwidth.value;
615 fsize_y = *outh * vid.height / vid_conheight.value;
620 fsize_x = fsize_y = 16;
630 for (m = 0; m < MAX_FONT_SIZES; ++m)
634 // "round up" to the bigger size if two equally-valued matches exist
635 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
636 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
640 matchsize = maps[m]->size;
641 if (value == 0) // there is no better match
645 if (value <= r_font_size_snapping.value)
647 // do NOT keep the aspect for perfect rendering
648 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
649 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
654 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
656 if (index < 0 || index >= MAX_FONT_SIZES)
658 return font->font_maps[index];
661 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
663 if (font->currenth == h &&
664 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
665 font->currentw == w)) // same size has been requested
669 // sorry, but freetype doesn't seem to care about other sizes
672 if (font->image_font)
674 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
679 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
687 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
689 ft2_font_map_t *fmap;
690 if (!font->has_kerning || !r_font_kerning.integer)
692 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
694 fmap = font->font_maps[map_index];
697 if (left < 256 && right < 256)
699 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
700 // quick-kerning, be aware of the size: scale it
701 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
702 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
710 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
712 if (!Font_SetSize(font, w, h))
714 // this deserves an error message
715 Con_Printf("Failed to get kerning for %s\n", font->name);
718 ul = qFT_Get_Char_Index(font->face, left);
719 ur = qFT_Get_Char_Index(font->face, right);
720 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
722 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
723 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
727 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
729 // this deserves an error message
730 Con_Printf("Failed to get kerning for %s\n", font->name);
733 ul = qFT_Get_Char_Index(font->face, left);
734 ur = qFT_Get_Char_Index(font->face, right);
735 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
737 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
738 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
745 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
747 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
750 static void UnloadMapRec(ft2_font_map_t *map)
754 R_FreeTexture(map->texture);
758 UnloadMapRec(map->next);
762 void Font_UnloadFont(ft2_font_t *font)
765 if (font->attachments && font->attachmentcount)
767 Mem_Free(font->attachments);
768 font->attachmentcount = 0;
769 font->attachments = NULL;
771 for (i = 0; i < MAX_FONT_SIZES; ++i)
773 if (font->font_maps[i])
775 UnloadMapRec(font->font_maps[i]);
776 font->font_maps[i] = NULL;
783 qFT_Done_Face((FT_Face)font->face);
789 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
791 float intSize = size;
794 if (!Font_SetSize(font, intSize, intSize))
796 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
799 if ((fontface->size->metrics.height>>6) <= size)
803 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
810 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
812 char map_identifier[MAX_QPATH];
813 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
821 int gR, gC; // glyph position: row and column
823 ft2_font_map_t *map, *next;
828 int bytesPerPixel = 4; // change the conversion loop too if you change this!
833 if (r_font_use_alpha_textures.integer)
836 if (font->image_font)
837 fontface = (FT_Face)font->next->face;
839 fontface = (FT_Face)font->face;
841 switch(r_font_antialias.integer)
844 switch(r_font_hinting.integer)
847 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
851 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
855 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
861 switch(r_font_hinting.integer)
864 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
867 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
870 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
874 load_flags = FT_LOAD_TARGET_NORMAL;
880 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
882 if (font->image_font && mapstart->intSize < 0)
883 mapstart->intSize = mapstart->size;
884 if (mapstart->intSize < 0)
887 mapstart->intSize = mapstart->size;
890 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
892 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
895 if ((fontface->size->metrics.height>>6) <= mapstart->size)
897 if (mapstart->intSize < 2)
899 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
905 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
907 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
910 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
912 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
916 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
919 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
923 // copy over the information
924 map->size = mapstart->size;
925 map->intSize = mapstart->intSize;
926 map->glyphSize = mapstart->glyphSize;
927 map->sfx = mapstart->sfx;
928 map->sfy = mapstart->sfy;
930 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
931 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
934 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
938 memset(map->width_of, 0, sizeof(map->width_of));
940 // initialize as white texture with zero alpha
942 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
944 if (bytesPerPixel == 4)
954 map->start = mapidx * FONT_CHARS_PER_MAP;
956 while(next->next && next->next->start < map->start)
958 map->next = next->next;
963 for (ch = map->start;
964 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
971 unsigned char *imagedata, *dst, *src;
972 glyph_slot_t *mapglyph;
975 mapch = ch - map->start;
977 if (developer_font.integer)
978 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
981 if (gC >= FONT_CHARS_PER_LINE)
983 gC -= FONT_CHARS_PER_LINE;
987 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
988 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
989 // we need the glyphIndex
992 if (font->image_font && mapch == ch && img_fontmap[mapch])
994 map->glyphs[mapch].image = true;
997 glyphIndex = qFT_Get_Char_Index(face, ch);
1000 // by convention, 0 is the "missing-glyph"-glyph
1001 // try to load from a fallback font
1002 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1004 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1007 face = usefont->face;
1008 glyphIndex = qFT_Get_Char_Index(face, ch);
1009 if (glyphIndex == 0)
1011 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1018 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1019 // now we let it use the "missing-glyph"-glyph
1029 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1032 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1033 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1038 glyph = face->glyph;
1039 bmp = &glyph->bitmap;
1044 if (w > map->glyphSize || h > map->glyphSize) {
1045 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1046 if (w > map->glyphSize)
1048 if (h > map->glyphSize)
1052 switch (bmp->pixel_mode)
1054 case FT_PIXEL_MODE_MONO:
1055 if (developer_font.integer)
1056 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1058 case FT_PIXEL_MODE_GRAY2:
1059 if (developer_font.integer)
1060 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1062 case FT_PIXEL_MODE_GRAY4:
1063 if (developer_font.integer)
1064 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1066 case FT_PIXEL_MODE_GRAY:
1067 if (developer_font.integer)
1068 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1071 if (developer_font.integer)
1072 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1074 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1077 for (y = 0; y < h; ++y)
1079 dst = imagedata + y * pitch;
1080 src = bmp->buffer + y * bmp->pitch;
1082 switch (bmp->pixel_mode)
1084 case FT_PIXEL_MODE_MONO:
1085 dst += bytesPerPixel - 1; // shift to alpha byte
1086 for (x = 0; x < bmp->width; x += 8)
1088 unsigned char ch = *src++;
1089 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1090 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1091 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1092 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1093 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1094 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1095 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1096 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1099 case FT_PIXEL_MODE_GRAY2:
1100 dst += bytesPerPixel - 1; // shift to alpha byte
1101 for (x = 0; x < bmp->width; x += 4)
1103 unsigned char ch = *src++;
1104 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1105 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1106 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1107 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1110 case FT_PIXEL_MODE_GRAY4:
1111 dst += bytesPerPixel - 1; // shift to alpha byte
1112 for (x = 0; x < bmp->width; x += 2)
1114 unsigned char ch = *src++;
1115 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1116 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1119 case FT_PIXEL_MODE_GRAY:
1120 // in this case pitch should equal width
1121 for (tp = 0; tp < bmp->pitch; ++tp)
1122 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1124 //memcpy((void*)dst, (void*)src, bmp->pitch);
1125 //dst += bmp->pitch;
1132 // now fill map->glyphs[ch - map->start]
1133 mapglyph = &map->glyphs[mapch];
1137 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1139 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1140 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1141 double advance = (glyph->advance.x / 64.0) / map->size;
1142 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1143 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1145 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1146 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1147 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1148 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1149 //mapglyph->vxmin = bearingX;
1150 //mapglyph->vxmax = bearingX + mWidth;
1151 mapglyph->vxmin = glyph->bitmap_left / map->size;
1152 mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
1153 //mapglyph->vymin = -bearingY;
1154 //mapglyph->vymax = mHeight - bearingY;
1155 mapglyph->vymin = -glyph->bitmap_top / map->size;
1156 mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
1157 //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);
1158 //mapglyph->advance_x = advance * usefont->size;
1159 //mapglyph->advance_x = advance;
1160 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1161 mapglyph->advance_y = 0;
1163 if (developer_font.integer)
1165 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1166 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1167 if (ch >= 32 && ch <= 128)
1168 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1169 Con_DPrintf("glyphinfo: Vertex info:\n");
1170 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1171 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1172 Con_DPrintf("glyphinfo: Texture info:\n");
1173 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1174 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1175 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1178 map->glyphs[mapch].image = false;
1181 // create a texture from the data now
1183 if (developer_font.integer > 100)
1185 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1186 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1187 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1188 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1190 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1192 // probably use bytesPerPixel here instead?
1193 if (r_font_use_alpha_textures.integer)
1195 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1196 map->glyphSize * FONT_CHARS_PER_LINE,
1197 map->glyphSize * FONT_CHAR_LINES,
1198 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1200 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1201 map->glyphSize * FONT_CHARS_PER_LINE,
1202 map->glyphSize * FONT_CHAR_LINES,
1203 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1209 // if the first try isn't successful, keep it with a broken texture
1210 // otherwise we retry to load it every single frame where ft2 rendering is used
1211 // this would be bad...
1212 // only `data' must be freed
1213 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1214 font->name, mapstart->size, mapidx);
1222 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1224 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1226 // the first map must have been loaded already
1227 if (!font->font_maps[map_index])
1229 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1232 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1234 while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1235 start = start->next;
1236 if (start && start->start > ch)