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" */};
42 ================================================================================
43 Function definitions. Taken from the freetype2 headers.
44 ================================================================================
49 (*qFT_Init_FreeType)( FT_Library *alibrary );
51 (*qFT_Done_FreeType)( FT_Library library );
54 (*qFT_New_Face)( FT_Library library,
55 const char* filepathname,
60 (*qFT_New_Memory_Face)( FT_Library library,
61 const FT_Byte* file_base,
66 (*qFT_Done_Face)( FT_Face face );
68 (*qFT_Select_Size)( FT_Face face,
69 FT_Int strike_index );
71 (*qFT_Request_Size)( FT_Face face,
72 FT_Size_Request req );
74 (*qFT_Set_Char_Size)( FT_Face face,
75 FT_F26Dot6 char_width,
76 FT_F26Dot6 char_height,
77 FT_UInt horz_resolution,
78 FT_UInt vert_resolution );
80 (*qFT_Set_Pixel_Sizes)( FT_Face face,
82 FT_UInt pixel_height );
84 (*qFT_Load_Glyph)( FT_Face face,
86 FT_Int32 load_flags );
88 (*qFT_Load_Char)( FT_Face face,
90 FT_Int32 load_flags );
92 (*qFT_Get_Char_Index)( FT_Face face,
95 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
96 FT_Render_Mode render_mode );
98 (*qFT_Get_Kerning)( FT_Face face,
102 FT_Vector *akerning );
103 FT_EXPORT( FT_Error )
104 (*qFT_Attach_Stream)( FT_Face face,
105 FT_Open_Args* parameters );
107 ================================================================================
108 Support for dynamically loading the FreeType2 library
109 ================================================================================
112 static dllfunction_t ft2funcs[] =
114 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
115 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
116 //{"FT_New_Face", (void **) &qFT_New_Face},
117 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
118 {"FT_Done_Face", (void **) &qFT_Done_Face},
119 {"FT_Select_Size", (void **) &qFT_Select_Size},
120 {"FT_Request_Size", (void **) &qFT_Request_Size},
121 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
122 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
123 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
124 {"FT_Load_Char", (void **) &qFT_Load_Char},
125 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
126 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
127 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
128 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
132 /// Handle for FreeType2 DLL
133 static dllhandle_t ft2_dll = NULL;
135 /// Memory pool for fonts
136 static mempool_t *font_mempool= NULL;
137 static rtexturepool_t *font_texturepool = NULL;
139 /// FreeType library handle
140 static FT_Library font_ft2lib = NULL;
146 Unload the FreeType2 DLL
149 void Font_CloseLibrary (void)
152 Mem_FreePool(&font_mempool);
153 if (font_texturepool)
154 R_FreeTexturePool(&font_texturepool);
155 if (font_ft2lib && qFT_Done_FreeType)
157 qFT_Done_FreeType(font_ft2lib);
160 Sys_UnloadLibrary (&ft2_dll);
167 Try to load the FreeType2 DLL
170 qboolean Font_OpenLibrary (void)
172 const char* dllnames [] =
176 #elif defined(MACOSX)
185 if (r_font_disable_freetype.integer)
193 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
202 Initialize the freetype2 font subsystem
206 void font_start(void)
208 if (!Font_OpenLibrary())
211 if (qFT_Init_FreeType(&font_ft2lib))
213 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
218 font_mempool = Mem_AllocPool("FONT", 0, NULL);
221 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
226 font_texturepool = R_AllocTexturePool();
227 if (!font_texturepool)
229 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
235 void font_shutdown(void)
238 for (i = 0; i < MAX_FONTS; ++i)
242 Font_UnloadFont(dp_fonts[i].ft2);
243 dp_fonts[i].ft2 = NULL;
249 void font_newmap(void)
255 Cvar_RegisterVariable(&r_font_disable_freetype);
256 Cvar_RegisterVariable(&r_font_use_alpha_textures);
257 Cvar_RegisterVariable(&r_font_size_snapping);
258 Cvar_RegisterVariable(&r_font_hinting);
259 Cvar_RegisterVariable(&r_font_antialias);
263 ================================================================================
264 Implementation of a more or less lazy font loading and rendering code.
265 ================================================================================
268 #include "ft2_fontdefs.h"
270 ft2_font_t *Font_Alloc(void)
274 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
277 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
279 ft2_attachment_t *na;
281 font->attachmentcount++;
282 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
285 if (font->attachments && font->attachmentcount > 1)
287 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
288 Mem_Free(font->attachments);
290 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
291 font->attachments = na;
295 static float Font_VirtualToRealSize(float sz)
301 vw = ((vid.width > 0) ? vid.width : vid_width.value);
302 vh = ((vid.height > 0) ? vid.height : vid_height.value);
303 // now try to scale to our actual size:
304 sn = sz * vh / vid_conheight.value;
306 if ( sn - (float)si >= 0.5 )
311 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
312 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
313 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
316 ft2_font_t *ft2, *fbfont, *fb;
325 // check if a fallback font has been specified, if it has been, and the
326 // font fails to load, use the image font as main font
327 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
329 if (dpfnt->fallbacks[i][0])
333 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
335 if (i >= MAX_FONT_FALLBACKS)
341 strlcpy(ft2->name, name, sizeof(ft2->name));
342 ft2->image_font = true;
343 ft2->has_kerning = false;
347 ft2->image_font = false;
350 // attempt to load fallback fonts:
352 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
354 if (!dpfnt->fallbacks[i][0])
356 if (! (fb = Font_Alloc()) )
358 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
361 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
363 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
368 for (s = 0; s < MAX_FONT_SIZES; ++s)
370 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
375 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
380 // at least one size of the fallback font loaded successfully
386 if (fbfont == ft2 && ft2->image_font)
388 // no fallbacks were loaded successfully:
395 for (s = 0; s < MAX_FONT_SIZES; ++s)
397 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
402 // loading failed for every requested size
403 Font_UnloadFont(ft2);
409 //Con_Printf("%i sizes loaded\n", count);
414 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
417 char filename[MAX_QPATH];
421 fs_offset_t datasize;
423 memset(font, 0, sizeof(*font));
425 if (!Font_OpenLibrary())
427 if (!r_font_disable_freetype.integer)
429 Con_Printf("WARNING: can't open load font %s\n"
430 "You need the FreeType2 DLL to load font files\n",
436 namelen = strlen(name);
438 memcpy(filename, name, namelen);
439 memcpy(filename + namelen, ".ttf", 5);
440 data = FS_LoadFile(filename, font_mempool, false, &datasize);
443 memcpy(filename + namelen, ".otf", 5);
444 data = FS_LoadFile(filename, font_mempool, false, &datasize);
448 ft2_attachment_t afm;
450 memcpy(filename + namelen, ".pfb", 5);
451 data = FS_LoadFile(filename, font_mempool, false, &datasize);
455 memcpy(filename + namelen, ".afm", 5);
456 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
459 Font_Attach(font, &afm);
465 // FS_LoadFile being not-quiet should print an error :)
468 Con_Printf("Loading font %s face %i...\n", filename, _face);
470 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
471 if (status && _face != 0)
473 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
475 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
479 Con_Printf("ERROR: can't create face for %s\n"
480 "Error %i\n", // TODO: error strings
482 Font_UnloadFont(font);
486 // add the attachments
487 for (i = 0; i < font->attachmentcount; ++i)
490 memset(&args, 0, sizeof(args));
491 args.flags = FT_OPEN_MEMORY;
492 args.memory_base = (const FT_Byte*)font->attachments[i].data;
493 args.memory_size = font->attachments[i].size;
494 if (qFT_Attach_Stream(font->face, &args))
495 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
498 memcpy(font->name, name, namelen+1);
499 font->image_font = false;
500 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
504 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
505 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
508 ft2_font_map_t *fmap, temp;
510 if (!(size > 0.001f && size < 1000.0f))
515 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
520 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
522 if (!font->font_maps[map_index])
524 // if a similar size has already been loaded, ignore this one
525 //abs(font->font_maps[map_index]->size - size) < 4
526 if (font->font_maps[map_index]->size == size)
530 if (map_index >= MAX_FONT_SIZES)
533 memset(&temp, 0, sizeof(temp));
535 temp.glyphSize = CeilPowerOf2(size*2);
536 temp.sfx = (1.0/64.0)/(double)size;
537 temp.sfy = (1.0/64.0)/(double)size;
538 temp.intSize = -1; // negative value: LoadMap must search now :)
539 if (!Font_LoadMap(font, &temp, 0, &fmap))
541 Con_Printf("ERROR: can't load the first character map for %s\n"
544 Font_UnloadFont(font);
547 font->font_maps[map_index] = temp.next;
549 fmap->sfx = temp.sfx;
550 fmap->sfy = temp.sfy;
554 // load the default kerning vector:
555 if (font->has_kerning)
559 for (l = 0; l < 256; ++l)
561 for (r = 0; r < 256; ++r)
564 ul = qFT_Get_Char_Index(font->face, l);
565 ur = qFT_Get_Char_Index(font->face, r);
566 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
568 fmap->kerning.kerning[l][r][0] = 0;
569 fmap->kerning.kerning[l][r][1] = 0;
573 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
574 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
584 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
589 int matchsize = -10000;
593 ft2_font_map_t **maps = font->font_maps;
595 fsize = _fsize * vid.height / vid_conheight.value;
603 if (fsize - (float)size >= 0.49)
607 for (m = 0; m < MAX_FONT_SIZES; ++m)
611 // "round up" to the bigger size if two equally-valued matches exist
612 nval = abs(maps[m]->size - size);
613 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
617 matchsize = maps[m]->size;
618 if (value == 0) // there is no better match
622 if (value <= r_font_size_snapping.value)
626 if (!*outh) *outh = *outw;
627 if (!*outw) *outw = *outh;
630 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
631 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
636 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
638 if (index < 0 || index >= MAX_FONT_SIZES)
640 return font->font_maps[index];
643 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
645 if (font->currenth == h &&
646 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
647 font->currentw == w)) // same size has been requested
651 // sorry, but freetype doesn't seem to care about other sizes
654 if (font->image_font)
656 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
661 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
669 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
671 ft2_font_map_t *fmap;
672 if (!font->has_kerning)
674 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
676 fmap = font->font_maps[map_index];
679 if (left < 256 && right < 256)
681 // quick-kerning, be aware of the size: scale it
682 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
683 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
691 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
692 if (!Font_SetSize(font, w, h))
694 // this deserves an error message
695 Con_Printf("Failed to get kerning for %s\n", font->name);
698 ul = qFT_Get_Char_Index(font->face, left);
699 ur = qFT_Get_Char_Index(font->face, right);
700 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
702 if (outx) *outx = kernvec.x * fmap->sfx;
703 if (outy) *outy = kernvec.y * fmap->sfy;
710 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
712 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
715 static void UnloadMapRec(ft2_font_map_t *map)
719 R_FreeTexture(map->texture);
723 UnloadMapRec(map->next);
727 void Font_UnloadFont(ft2_font_t *font)
730 if (font->attachments && font->attachmentcount)
732 Mem_Free(font->attachments);
733 font->attachmentcount = 0;
734 font->attachments = NULL;
736 for (i = 0; i < MAX_FONT_SIZES; ++i)
738 if (font->font_maps[i])
740 UnloadMapRec(font->font_maps[i]);
741 font->font_maps[i] = NULL;
748 qFT_Done_Face((FT_Face)font->face);
754 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
756 char map_identifier[MAX_QPATH];
757 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
765 int gR, gC; // glyph position: row and column
767 ft2_font_map_t *map, *next;
772 int bytesPerPixel = 4; // change the conversion loop too if you change this!
777 if (r_font_use_alpha_textures.integer)
780 if (font->image_font)
781 fontface = (FT_Face)font->next->face;
783 fontface = (FT_Face)font->face;
785 switch(r_font_antialias.integer)
788 switch(r_font_hinting.integer)
791 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
795 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
799 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
805 switch(r_font_hinting.integer)
808 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
811 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
814 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
818 load_flags = FT_LOAD_TARGET_NORMAL;
824 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
826 if (font->image_font && mapstart->intSize < 0)
827 mapstart->intSize = mapstart->size;
828 if (mapstart->intSize < 0)
830 mapstart->intSize = mapstart->size;
833 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
835 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
838 if ((fontface->size->metrics.height>>6) <= mapstart->size)
840 if (mapstart->intSize < 2)
842 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
847 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
850 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
852 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
856 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
859 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
863 // copy over the information
864 map->size = mapstart->size;
865 map->intSize = mapstart->intSize;
866 map->glyphSize = mapstart->glyphSize;
867 map->sfx = mapstart->sfx;
868 map->sfy = mapstart->sfy;
870 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
871 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
874 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
879 // initialize as white texture with zero alpha
881 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
883 if (bytesPerPixel == 4)
893 map->start = mapidx * FONT_CHARS_PER_MAP;
895 while(next->next && next->next->start < map->start)
897 map->next = next->next;
902 for (ch = map->start;
903 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
910 unsigned char *imagedata, *dst, *src;
911 glyph_slot_t *mapglyph;
914 mapch = ch - map->start;
916 if (developer_extra.integer)
917 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
920 if (gC >= FONT_CHARS_PER_LINE)
922 gC -= FONT_CHARS_PER_LINE;
926 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
927 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
928 // we need the glyphIndex
931 if (font->image_font && mapch == ch && img_fontmap[mapch])
933 map->glyphs[mapch].image = true;
936 glyphIndex = qFT_Get_Char_Index(face, ch);
939 // by convention, 0 is the "missing-glyph"-glyph
940 // try to load from a fallback font
941 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
943 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
946 face = usefont->face;
947 glyphIndex = qFT_Get_Char_Index(face, ch);
950 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
957 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
958 // now we let it use the "missing-glyph"-glyph
968 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
971 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
972 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
978 bmp = &glyph->bitmap;
983 if (w > map->glyphSize || h > map->glyphSize) {
984 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
985 if (w > map->glyphSize)
987 if (h > map->glyphSize)
991 switch (bmp->pixel_mode)
993 case FT_PIXEL_MODE_MONO:
994 if (developer_extra.integer)
995 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
997 case FT_PIXEL_MODE_GRAY2:
998 if (developer_extra.integer)
999 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1001 case FT_PIXEL_MODE_GRAY4:
1002 if (developer_extra.integer)
1003 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1005 case FT_PIXEL_MODE_GRAY:
1006 if (developer_extra.integer)
1007 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1010 if (developer_extra.integer)
1011 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1013 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1016 for (y = 0; y < h; ++y)
1018 dst = imagedata + y * pitch;
1019 src = bmp->buffer + y * bmp->pitch;
1021 switch (bmp->pixel_mode)
1023 case FT_PIXEL_MODE_MONO:
1024 dst += bytesPerPixel - 1; // shift to alpha byte
1025 for (x = 0; x < bmp->width; x += 8)
1027 unsigned char ch = *src++;
1028 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1029 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1030 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1031 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1032 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1033 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1034 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1035 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1038 case FT_PIXEL_MODE_GRAY2:
1039 dst += bytesPerPixel - 1; // shift to alpha byte
1040 for (x = 0; x < bmp->width; x += 4)
1042 unsigned char ch = *src++;
1043 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1044 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1045 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1046 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1049 case FT_PIXEL_MODE_GRAY4:
1050 dst += bytesPerPixel - 1; // shift to alpha byte
1051 for (x = 0; x < bmp->width; x += 2)
1053 unsigned char ch = *src++;
1054 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1055 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1058 case FT_PIXEL_MODE_GRAY:
1059 // in this case pitch should equal width
1060 for (tp = 0; tp < bmp->pitch; ++tp)
1061 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1063 //memcpy((void*)dst, (void*)src, bmp->pitch);
1064 //dst += bmp->pitch;
1071 // now fill map->glyphs[ch - map->start]
1072 mapglyph = &map->glyphs[mapch];
1076 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1078 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1079 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1080 double advance = (glyph->advance.x >> 6) / map->size;
1081 double mWidth = (glyph->metrics.width >> 6) / map->size;
1082 double mHeight = (glyph->metrics.height >> 6) / map->size;
1084 mapglyph->vxmin = bearingX;
1085 mapglyph->vxmax = bearingX + mWidth;
1086 mapglyph->vymin = -bearingY;
1087 mapglyph->vymax = mHeight - bearingY;
1088 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1089 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1090 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1091 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1092 //Con_Printf("dpi = %f %f (%f %d)\n", (mapglyph->vxmax - mapglyph->vxmin) / (mapglyph->txmax - mapglyph->txmin), (mapglyph->vymax - mapglyph->vymin) / (mapglyph->tymax - mapglyph->tymin), map->size, map->glyphSize);
1093 //mapglyph->advance_x = advance * usefont->size;
1094 mapglyph->advance_x = advance;
1095 mapglyph->advance_y = 0;
1097 if (developer_extra.integer)
1099 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1100 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1101 if (ch >= 32 && ch <= 128)
1102 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1103 Con_DPrintf("glyphinfo: Vertex info:\n");
1104 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1105 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1106 Con_DPrintf("glyphinfo: Texture info:\n");
1107 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1108 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1109 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1112 map->glyphs[mapch].image = false;
1115 // create a texture from the data now
1117 if (developer_extra.integer)
1119 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1120 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1121 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1122 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1124 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1126 // probably use bytesPerPixel here instead?
1127 if (r_font_use_alpha_textures.integer)
1129 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1130 map->glyphSize * FONT_CHARS_PER_LINE,
1131 map->glyphSize * FONT_CHAR_LINES,
1132 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1134 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1135 map->glyphSize * FONT_CHARS_PER_LINE,
1136 map->glyphSize * FONT_CHAR_LINES,
1137 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1143 // if the first try isn't successful, keep it with a broken texture
1144 // otherwise we retry to load it every single frame where ft2 rendering is used
1145 // this would be bad...
1146 // only `data' must be freed
1147 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1148 font->name, mapstart->size, mapidx);
1156 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1158 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1160 // the first map must have been loaded already
1161 if (!font->font_maps[map_index])
1163 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1166 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1168 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1169 start = start->next;
1170 if (start && start->start > ch)