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);
269 ================================================================================
270 Implementation of a more or less lazy font loading and rendering code.
271 ================================================================================
274 #include "ft2_fontdefs.h"
276 ft2_font_t *Font_Alloc(void)
280 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
283 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
285 ft2_attachment_t *na;
287 font->attachmentcount++;
288 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
291 if (font->attachments && font->attachmentcount > 1)
293 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
294 Mem_Free(font->attachments);
296 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
297 font->attachments = na;
301 static float Font_VirtualToRealSize(float sz)
307 vw = ((vid.width > 0) ? vid.width : vid_width.value);
308 vh = ((vid.height > 0) ? vid.height : vid_height.value);
309 // now try to scale to our actual size:
310 sn = sz * vh / vid_conheight.value;
312 if ( sn - (float)si >= 0.5 )
317 static float Font_SnapTo(float val, float snapwidth)
319 return floor(val / snapwidth + 0.5f) * snapwidth;
322 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
323 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
324 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
327 ft2_font_t *ft2, *fbfont, *fb;
336 // check if a fallback font has been specified, if it has been, and the
337 // font fails to load, use the image font as main font
338 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
340 if (dpfnt->fallbacks[i][0])
344 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
346 if (i >= MAX_FONT_FALLBACKS)
352 strlcpy(ft2->name, name, sizeof(ft2->name));
353 ft2->image_font = true;
354 ft2->has_kerning = false;
358 ft2->image_font = false;
361 // attempt to load fallback fonts:
363 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
365 if (!dpfnt->fallbacks[i][0])
367 if (! (fb = Font_Alloc()) )
369 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
372 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
374 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
379 for (s = 0; s < MAX_FONT_SIZES; ++s)
381 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
386 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
391 // at least one size of the fallback font loaded successfully
397 if (fbfont == ft2 && ft2->image_font)
399 // no fallbacks were loaded successfully:
406 for (s = 0; s < MAX_FONT_SIZES; ++s)
408 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
413 // loading failed for every requested size
414 Font_UnloadFont(ft2);
420 //Con_Printf("%i sizes loaded\n", count);
425 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
428 char filename[MAX_QPATH];
432 fs_offset_t datasize;
434 memset(font, 0, sizeof(*font));
436 if (!Font_OpenLibrary())
438 if (!r_font_disable_freetype.integer)
440 Con_Printf("WARNING: can't open load font %s\n"
441 "You need the FreeType2 DLL to load font files\n",
447 namelen = strlen(name);
449 memcpy(filename, name, namelen);
450 memcpy(filename + namelen, ".ttf", 5);
451 data = FS_LoadFile(filename, font_mempool, false, &datasize);
454 memcpy(filename + namelen, ".otf", 5);
455 data = FS_LoadFile(filename, font_mempool, false, &datasize);
459 ft2_attachment_t afm;
461 memcpy(filename + namelen, ".pfb", 5);
462 data = FS_LoadFile(filename, font_mempool, false, &datasize);
466 memcpy(filename + namelen, ".afm", 5);
467 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
470 Font_Attach(font, &afm);
476 // FS_LoadFile being not-quiet should print an error :)
479 Con_Printf("Loading font %s face %i...\n", filename, _face);
481 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
482 if (status && _face != 0)
484 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
486 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
490 Con_Printf("ERROR: can't create face for %s\n"
491 "Error %i\n", // TODO: error strings
493 Font_UnloadFont(font);
497 // add the attachments
498 for (i = 0; i < font->attachmentcount; ++i)
501 memset(&args, 0, sizeof(args));
502 args.flags = FT_OPEN_MEMORY;
503 args.memory_base = (const FT_Byte*)font->attachments[i].data;
504 args.memory_size = font->attachments[i].size;
505 if (qFT_Attach_Stream(font->face, &args))
506 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
509 memcpy(font->name, name, namelen+1);
510 font->image_font = false;
511 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
515 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
516 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
519 ft2_font_map_t *fmap, temp;
521 if (!(size > 0.001f && size < 1000.0f))
526 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
531 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
533 if (!font->font_maps[map_index])
535 // if a similar size has already been loaded, ignore this one
536 //abs(font->font_maps[map_index]->size - size) < 4
537 if (font->font_maps[map_index]->size == size)
541 if (map_index >= MAX_FONT_SIZES)
544 memset(&temp, 0, sizeof(temp));
546 temp.glyphSize = CeilPowerOf2(size*2);
547 temp.sfx = (1.0/64.0)/(double)size;
548 temp.sfy = (1.0/64.0)/(double)size;
549 temp.intSize = -1; // negative value: LoadMap must search now :)
550 if (!Font_LoadMap(font, &temp, 0, &fmap))
552 Con_Printf("ERROR: can't load the first character map for %s\n"
555 Font_UnloadFont(font);
558 font->font_maps[map_index] = temp.next;
560 fmap->sfx = temp.sfx;
561 fmap->sfy = temp.sfy;
565 // load the default kerning vector:
566 if (font->has_kerning)
570 for (l = 0; l < 256; ++l)
572 for (r = 0; r < 256; ++r)
575 ul = qFT_Get_Char_Index(font->face, l);
576 ur = qFT_Get_Char_Index(font->face, r);
577 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
579 fmap->kerning.kerning[l][r][0] = 0;
580 fmap->kerning.kerning[l][r][1] = 0;
584 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
585 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
595 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
600 int matchsize = -10000;
602 float fsize_x, fsize_y;
603 ft2_font_map_t **maps = font->font_maps;
605 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
607 fsize_x = *outw * vid.width / vid_conwidth.value;
609 fsize_y = *outh * vid.height / vid_conheight.value;
614 fsize_x = fsize_y = 16;
624 for (m = 0; m < MAX_FONT_SIZES; ++m)
628 // "round up" to the bigger size if two equally-valued matches exist
629 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
630 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
634 matchsize = maps[m]->size;
635 if (value == 0) // there is no better match
639 if (value <= r_font_size_snapping.value)
641 // do NOT keep the aspect for perfect rendering
642 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
643 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
648 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
650 if (index < 0 || index >= MAX_FONT_SIZES)
652 return font->font_maps[index];
655 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
657 if (font->currenth == h &&
658 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
659 font->currentw == w)) // same size has been requested
663 // sorry, but freetype doesn't seem to care about other sizes
666 if (font->image_font)
668 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
673 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
681 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
683 ft2_font_map_t *fmap;
684 if (!font->has_kerning || !r_font_kerning.integer)
686 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
688 fmap = font->font_maps[map_index];
691 if (left < 256 && right < 256)
693 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
694 // quick-kerning, be aware of the size: scale it
695 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
696 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
704 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
706 if (!Font_SetSize(font, w, h))
708 // this deserves an error message
709 Con_Printf("Failed to get kerning for %s\n", font->name);
712 ul = qFT_Get_Char_Index(font->face, left);
713 ur = qFT_Get_Char_Index(font->face, right);
714 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
716 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
717 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
721 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
723 // this deserves an error message
724 Con_Printf("Failed to get kerning for %s\n", font->name);
727 ul = qFT_Get_Char_Index(font->face, left);
728 ur = qFT_Get_Char_Index(font->face, right);
729 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
731 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
732 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
739 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
741 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
744 static void UnloadMapRec(ft2_font_map_t *map)
748 R_FreeTexture(map->texture);
752 UnloadMapRec(map->next);
756 void Font_UnloadFont(ft2_font_t *font)
759 if (font->attachments && font->attachmentcount)
761 Mem_Free(font->attachments);
762 font->attachmentcount = 0;
763 font->attachments = NULL;
765 for (i = 0; i < MAX_FONT_SIZES; ++i)
767 if (font->font_maps[i])
769 UnloadMapRec(font->font_maps[i]);
770 font->font_maps[i] = NULL;
777 qFT_Done_Face((FT_Face)font->face);
783 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
785 char map_identifier[MAX_QPATH];
786 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
794 int gR, gC; // glyph position: row and column
796 ft2_font_map_t *map, *next;
801 int bytesPerPixel = 4; // change the conversion loop too if you change this!
806 if (r_font_use_alpha_textures.integer)
809 if (font->image_font)
810 fontface = (FT_Face)font->next->face;
812 fontface = (FT_Face)font->face;
814 switch(r_font_antialias.integer)
817 switch(r_font_hinting.integer)
820 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
824 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
828 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
834 switch(r_font_hinting.integer)
837 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
840 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
843 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
847 load_flags = FT_LOAD_TARGET_NORMAL;
853 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
855 if (font->image_font && mapstart->intSize < 0)
856 mapstart->intSize = mapstart->size;
857 if (mapstart->intSize < 0)
859 mapstart->intSize = mapstart->size;
862 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
864 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
867 if ((fontface->size->metrics.height>>6) <= mapstart->size)
869 if (mapstart->intSize < 2)
871 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
876 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
879 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
881 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
885 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
888 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
892 // copy over the information
893 map->size = mapstart->size;
894 map->intSize = mapstart->intSize;
895 map->glyphSize = mapstart->glyphSize;
896 map->sfx = mapstart->sfx;
897 map->sfy = mapstart->sfy;
899 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
900 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
903 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
907 memset(map->width_of, 0, sizeof(map->width_of));
909 // initialize as white texture with zero alpha
911 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
913 if (bytesPerPixel == 4)
923 map->start = mapidx * FONT_CHARS_PER_MAP;
925 while(next->next && next->next->start < map->start)
927 map->next = next->next;
932 for (ch = map->start;
933 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
940 unsigned char *imagedata, *dst, *src;
941 glyph_slot_t *mapglyph;
944 mapch = ch - map->start;
946 if (developer_font.integer)
947 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
950 if (gC >= FONT_CHARS_PER_LINE)
952 gC -= FONT_CHARS_PER_LINE;
956 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
957 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
958 // we need the glyphIndex
961 if (font->image_font && mapch == ch && img_fontmap[mapch])
963 map->glyphs[mapch].image = true;
966 glyphIndex = qFT_Get_Char_Index(face, ch);
969 // by convention, 0 is the "missing-glyph"-glyph
970 // try to load from a fallback font
971 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
973 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
976 face = usefont->face;
977 glyphIndex = qFT_Get_Char_Index(face, ch);
980 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
987 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
988 // now we let it use the "missing-glyph"-glyph
998 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1001 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1002 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1007 glyph = face->glyph;
1008 bmp = &glyph->bitmap;
1013 if (w > map->glyphSize || h > map->glyphSize) {
1014 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1015 if (w > map->glyphSize)
1017 if (h > map->glyphSize)
1021 switch (bmp->pixel_mode)
1023 case FT_PIXEL_MODE_MONO:
1024 if (developer_font.integer)
1025 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1027 case FT_PIXEL_MODE_GRAY2:
1028 if (developer_font.integer)
1029 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1031 case FT_PIXEL_MODE_GRAY4:
1032 if (developer_font.integer)
1033 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1035 case FT_PIXEL_MODE_GRAY:
1036 if (developer_font.integer)
1037 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1040 if (developer_font.integer)
1041 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1043 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1046 for (y = 0; y < h; ++y)
1048 dst = imagedata + y * pitch;
1049 src = bmp->buffer + y * bmp->pitch;
1051 switch (bmp->pixel_mode)
1053 case FT_PIXEL_MODE_MONO:
1054 dst += bytesPerPixel - 1; // shift to alpha byte
1055 for (x = 0; x < bmp->width; x += 8)
1057 unsigned char ch = *src++;
1058 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1059 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1060 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1061 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1062 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1063 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1064 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1065 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1068 case FT_PIXEL_MODE_GRAY2:
1069 dst += bytesPerPixel - 1; // shift to alpha byte
1070 for (x = 0; x < bmp->width; x += 4)
1072 unsigned char ch = *src++;
1073 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1074 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1075 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1076 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1079 case FT_PIXEL_MODE_GRAY4:
1080 dst += bytesPerPixel - 1; // shift to alpha byte
1081 for (x = 0; x < bmp->width; x += 2)
1083 unsigned char ch = *src++;
1084 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1085 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1088 case FT_PIXEL_MODE_GRAY:
1089 // in this case pitch should equal width
1090 for (tp = 0; tp < bmp->pitch; ++tp)
1091 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1093 //memcpy((void*)dst, (void*)src, bmp->pitch);
1094 //dst += bmp->pitch;
1101 // now fill map->glyphs[ch - map->start]
1102 mapglyph = &map->glyphs[mapch];
1106 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1108 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1109 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1110 double advance = (glyph->advance.x / 64.0) / map->size;
1111 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1112 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1114 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1115 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1116 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1117 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1118 //mapglyph->vxmin = bearingX;
1119 //mapglyph->vxmax = bearingX + mWidth;
1120 mapglyph->vxmin = glyph->bitmap_left / map->size;
1121 mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
1122 //mapglyph->vymin = -bearingY;
1123 //mapglyph->vymax = mHeight - bearingY;
1124 mapglyph->vymin = -glyph->bitmap_top / map->size;
1125 mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
1126 //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);
1127 //mapglyph->advance_x = advance * usefont->size;
1128 //mapglyph->advance_x = advance;
1129 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1130 mapglyph->advance_y = 0;
1132 if (developer_font.integer)
1134 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1135 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1136 if (ch >= 32 && ch <= 128)
1137 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1138 Con_DPrintf("glyphinfo: Vertex info:\n");
1139 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1140 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1141 Con_DPrintf("glyphinfo: Texture info:\n");
1142 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1143 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1144 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1147 map->glyphs[mapch].image = false;
1150 // create a texture from the data now
1152 if (developer_font.integer > 100)
1154 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1155 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1156 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1157 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1159 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1161 // probably use bytesPerPixel here instead?
1162 if (r_font_use_alpha_textures.integer)
1164 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1165 map->glyphSize * FONT_CHARS_PER_LINE,
1166 map->glyphSize * FONT_CHAR_LINES,
1167 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1169 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1170 map->glyphSize * FONT_CHARS_PER_LINE,
1171 map->glyphSize * FONT_CHAR_LINES,
1172 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1178 // if the first try isn't successful, keep it with a broken texture
1179 // otherwise we retry to load it every single frame where ft2 rendering is used
1180 // this would be bad...
1181 // only `data' must be freed
1182 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1183 font->name, mapstart->size, mapidx);
1191 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1193 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1195 // the first map must have been loaded already
1196 if (!font->font_maps[map_index])
1198 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1201 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1203 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1204 start = start->next;
1205 if (start && start->start > ch)