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)
188 if (r_font_disable_freetype.integer)
196 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
205 Initialize the freetype2 font subsystem
209 void font_start(void)
211 if (!Font_OpenLibrary())
214 if (qFT_Init_FreeType(&font_ft2lib))
216 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
221 font_mempool = Mem_AllocPool("FONT", 0, NULL);
224 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
229 font_texturepool = R_AllocTexturePool();
230 if (!font_texturepool)
232 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
238 void font_shutdown(void)
241 for (i = 0; i < MAX_FONTS; ++i)
245 Font_UnloadFont(dp_fonts[i].ft2);
246 dp_fonts[i].ft2 = NULL;
252 void font_newmap(void)
258 Cvar_RegisterVariable(&r_font_disable_freetype);
259 Cvar_RegisterVariable(&r_font_use_alpha_textures);
260 Cvar_RegisterVariable(&r_font_size_snapping);
261 Cvar_RegisterVariable(&r_font_hinting);
262 Cvar_RegisterVariable(&r_font_antialias);
263 Cvar_RegisterVariable(&r_font_kerning);
264 Cvar_RegisterVariable(&developer_font);
268 ================================================================================
269 Implementation of a more or less lazy font loading and rendering code.
270 ================================================================================
273 #include "ft2_fontdefs.h"
275 ft2_font_t *Font_Alloc(void)
279 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
282 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
284 ft2_attachment_t *na;
286 font->attachmentcount++;
287 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
290 if (font->attachments && font->attachmentcount > 1)
292 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
293 Mem_Free(font->attachments);
295 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
296 font->attachments = na;
300 static float Font_VirtualToRealSize(float sz)
306 vw = ((vid.width > 0) ? vid.width : vid_width.value);
307 vh = ((vid.height > 0) ? vid.height : vid_height.value);
308 // now try to scale to our actual size:
309 sn = sz * vh / vid_conheight.value;
311 if ( sn - (float)si >= 0.5 )
316 static float Font_SnapTo(float val, float snapwidth)
318 return floor(val / snapwidth + 0.5f) * snapwidth;
321 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
322 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
323 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
326 ft2_font_t *ft2, *fbfont, *fb;
335 // check if a fallback font has been specified, if it has been, and the
336 // font fails to load, use the image font as main font
337 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
339 if (dpfnt->fallbacks[i][0])
343 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
345 if (i >= MAX_FONT_FALLBACKS)
351 strlcpy(ft2->name, name, sizeof(ft2->name));
352 ft2->image_font = true;
353 ft2->has_kerning = false;
357 ft2->image_font = false;
360 // attempt to load fallback fonts:
362 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
364 if (!dpfnt->fallbacks[i][0])
366 if (! (fb = Font_Alloc()) )
368 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
371 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
373 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
378 for (s = 0; s < MAX_FONT_SIZES; ++s)
380 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
385 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
390 // at least one size of the fallback font loaded successfully
396 if (fbfont == ft2 && ft2->image_font)
398 // no fallbacks were loaded successfully:
405 for (s = 0; s < MAX_FONT_SIZES; ++s)
407 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
412 // loading failed for every requested size
413 Font_UnloadFont(ft2);
419 //Con_Printf("%i sizes loaded\n", count);
424 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
427 char filename[MAX_QPATH];
431 fs_offset_t datasize;
433 memset(font, 0, sizeof(*font));
435 if (!Font_OpenLibrary())
437 if (!r_font_disable_freetype.integer)
439 Con_Printf("WARNING: can't open load font %s\n"
440 "You need the FreeType2 DLL to load font files\n",
446 namelen = strlen(name);
448 memcpy(filename, name, namelen);
449 memcpy(filename + namelen, ".ttf", 5);
450 data = FS_LoadFile(filename, font_mempool, false, &datasize);
453 memcpy(filename + namelen, ".otf", 5);
454 data = FS_LoadFile(filename, font_mempool, false, &datasize);
458 ft2_attachment_t afm;
460 memcpy(filename + namelen, ".pfb", 5);
461 data = FS_LoadFile(filename, font_mempool, false, &datasize);
465 memcpy(filename + namelen, ".afm", 5);
466 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
469 Font_Attach(font, &afm);
475 // FS_LoadFile being not-quiet should print an error :)
478 Con_Printf("Loading font %s face %i...\n", filename, _face);
480 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
481 if (status && _face != 0)
483 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
485 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
489 Con_Printf("ERROR: can't create face for %s\n"
490 "Error %i\n", // TODO: error strings
492 Font_UnloadFont(font);
496 // add the attachments
497 for (i = 0; i < font->attachmentcount; ++i)
500 memset(&args, 0, sizeof(args));
501 args.flags = FT_OPEN_MEMORY;
502 args.memory_base = (const FT_Byte*)font->attachments[i].data;
503 args.memory_size = font->attachments[i].size;
504 if (qFT_Attach_Stream(font->face, &args))
505 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
508 memcpy(font->name, name, namelen+1);
509 font->image_font = false;
510 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
514 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
515 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
518 ft2_font_map_t *fmap, temp;
520 if (!(size > 0.001f && size < 1000.0f))
525 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
530 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
532 if (!font->font_maps[map_index])
534 // if a similar size has already been loaded, ignore this one
535 //abs(font->font_maps[map_index]->size - size) < 4
536 if (font->font_maps[map_index]->size == size)
540 if (map_index >= MAX_FONT_SIZES)
543 memset(&temp, 0, sizeof(temp));
545 temp.glyphSize = CeilPowerOf2(size*2);
546 temp.sfx = (1.0/64.0)/(double)size;
547 temp.sfy = (1.0/64.0)/(double)size;
548 temp.intSize = -1; // negative value: LoadMap must search now :)
549 if (!Font_LoadMap(font, &temp, 0, &fmap))
551 Con_Printf("ERROR: can't load the first character map for %s\n"
554 Font_UnloadFont(font);
557 font->font_maps[map_index] = temp.next;
559 fmap->sfx = temp.sfx;
560 fmap->sfy = temp.sfy;
564 // load the default kerning vector:
565 if (font->has_kerning)
569 for (l = 0; l < 256; ++l)
571 for (r = 0; r < 256; ++r)
574 ul = qFT_Get_Char_Index(font->face, l);
575 ur = qFT_Get_Char_Index(font->face, r);
576 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
578 fmap->kerning.kerning[l][r][0] = 0;
579 fmap->kerning.kerning[l][r][1] = 0;
583 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
584 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
594 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
599 int matchsize = -10000;
601 float fsize_x, fsize_y;
602 ft2_font_map_t **maps = font->font_maps;
604 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
606 fsize_x = *outw * vid.width / vid_conwidth.value;
608 fsize_y = *outh * vid.height / vid_conheight.value;
613 fsize_x = fsize_y = 16;
623 for (m = 0; m < MAX_FONT_SIZES; ++m)
627 // "round up" to the bigger size if two equally-valued matches exist
628 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
629 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
633 matchsize = maps[m]->size;
634 if (value == 0) // there is no better match
638 if (value <= r_font_size_snapping.value)
640 // do NOT keep the aspect for perfect rendering
641 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
642 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
647 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
649 if (index < 0 || index >= MAX_FONT_SIZES)
651 return font->font_maps[index];
654 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
656 if (font->currenth == h &&
657 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
658 font->currentw == w)) // same size has been requested
662 // sorry, but freetype doesn't seem to care about other sizes
665 if (font->image_font)
667 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
672 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
680 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
682 ft2_font_map_t *fmap;
683 if (!font->has_kerning || !r_font_kerning.integer)
685 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
687 fmap = font->font_maps[map_index];
690 if (left < 256 && right < 256)
692 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
693 // quick-kerning, be aware of the size: scale it
694 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
695 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
703 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
705 if (!Font_SetSize(font, w, h))
707 // this deserves an error message
708 Con_Printf("Failed to get kerning for %s\n", font->name);
711 ul = qFT_Get_Char_Index(font->face, left);
712 ur = qFT_Get_Char_Index(font->face, right);
713 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
715 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
716 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
720 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
722 // this deserves an error message
723 Con_Printf("Failed to get kerning for %s\n", font->name);
726 ul = qFT_Get_Char_Index(font->face, left);
727 ur = qFT_Get_Char_Index(font->face, right);
728 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
730 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
731 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
738 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
740 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
743 static void UnloadMapRec(ft2_font_map_t *map)
747 R_FreeTexture(map->texture);
751 UnloadMapRec(map->next);
755 void Font_UnloadFont(ft2_font_t *font)
758 if (font->attachments && font->attachmentcount)
760 Mem_Free(font->attachments);
761 font->attachmentcount = 0;
762 font->attachments = NULL;
764 for (i = 0; i < MAX_FONT_SIZES; ++i)
766 if (font->font_maps[i])
768 UnloadMapRec(font->font_maps[i]);
769 font->font_maps[i] = NULL;
776 qFT_Done_Face((FT_Face)font->face);
782 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
784 char map_identifier[MAX_QPATH];
785 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
793 int gR, gC; // glyph position: row and column
795 ft2_font_map_t *map, *next;
800 int bytesPerPixel = 4; // change the conversion loop too if you change this!
805 if (r_font_use_alpha_textures.integer)
808 if (font->image_font)
809 fontface = (FT_Face)font->next->face;
811 fontface = (FT_Face)font->face;
813 switch(r_font_antialias.integer)
816 switch(r_font_hinting.integer)
819 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
823 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
827 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
833 switch(r_font_hinting.integer)
836 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
839 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
842 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
846 load_flags = FT_LOAD_TARGET_NORMAL;
852 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
854 if (font->image_font && mapstart->intSize < 0)
855 mapstart->intSize = mapstart->size;
856 if (mapstart->intSize < 0)
858 mapstart->intSize = mapstart->size;
861 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
863 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
866 if ((fontface->size->metrics.height>>6) <= mapstart->size)
868 if (mapstart->intSize < 2)
870 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
875 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
878 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
880 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
884 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
887 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
891 // copy over the information
892 map->size = mapstart->size;
893 map->intSize = mapstart->intSize;
894 map->glyphSize = mapstart->glyphSize;
895 map->sfx = mapstart->sfx;
896 map->sfy = mapstart->sfy;
898 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
899 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
902 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
906 memset(map->width_of, 0, sizeof(map->width_of));
908 // initialize as white texture with zero alpha
910 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
912 if (bytesPerPixel == 4)
922 map->start = mapidx * FONT_CHARS_PER_MAP;
924 while(next->next && next->next->start < map->start)
926 map->next = next->next;
931 for (ch = map->start;
932 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
939 unsigned char *imagedata, *dst, *src;
940 glyph_slot_t *mapglyph;
943 mapch = ch - map->start;
945 if (developer_font.integer)
946 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
949 if (gC >= FONT_CHARS_PER_LINE)
951 gC -= FONT_CHARS_PER_LINE;
955 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
956 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
957 // we need the glyphIndex
960 if (font->image_font && mapch == ch && img_fontmap[mapch])
962 map->glyphs[mapch].image = true;
965 glyphIndex = qFT_Get_Char_Index(face, ch);
968 // by convention, 0 is the "missing-glyph"-glyph
969 // try to load from a fallback font
970 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
972 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
975 face = usefont->face;
976 glyphIndex = qFT_Get_Char_Index(face, ch);
979 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
986 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
987 // now we let it use the "missing-glyph"-glyph
997 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1000 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1001 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1006 glyph = face->glyph;
1007 bmp = &glyph->bitmap;
1012 if (w > map->glyphSize || h > map->glyphSize) {
1013 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1014 if (w > map->glyphSize)
1016 if (h > map->glyphSize)
1020 switch (bmp->pixel_mode)
1022 case FT_PIXEL_MODE_MONO:
1023 if (developer_font.integer)
1024 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1026 case FT_PIXEL_MODE_GRAY2:
1027 if (developer_font.integer)
1028 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1030 case FT_PIXEL_MODE_GRAY4:
1031 if (developer_font.integer)
1032 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1034 case FT_PIXEL_MODE_GRAY:
1035 if (developer_font.integer)
1036 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1039 if (developer_font.integer)
1040 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1042 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1045 for (y = 0; y < h; ++y)
1047 dst = imagedata + y * pitch;
1048 src = bmp->buffer + y * bmp->pitch;
1050 switch (bmp->pixel_mode)
1052 case FT_PIXEL_MODE_MONO:
1053 dst += bytesPerPixel - 1; // shift to alpha byte
1054 for (x = 0; x < bmp->width; x += 8)
1056 unsigned char ch = *src++;
1057 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1058 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1059 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1060 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1061 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1062 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1063 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1064 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1067 case FT_PIXEL_MODE_GRAY2:
1068 dst += bytesPerPixel - 1; // shift to alpha byte
1069 for (x = 0; x < bmp->width; x += 4)
1071 unsigned char ch = *src++;
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;
1075 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1078 case FT_PIXEL_MODE_GRAY4:
1079 dst += bytesPerPixel - 1; // shift to alpha byte
1080 for (x = 0; x < bmp->width; x += 2)
1082 unsigned char ch = *src++;
1083 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1084 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1087 case FT_PIXEL_MODE_GRAY:
1088 // in this case pitch should equal width
1089 for (tp = 0; tp < bmp->pitch; ++tp)
1090 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1092 //memcpy((void*)dst, (void*)src, bmp->pitch);
1093 //dst += bmp->pitch;
1100 // now fill map->glyphs[ch - map->start]
1101 mapglyph = &map->glyphs[mapch];
1105 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1107 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1108 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1109 double advance = (glyph->advance.x / 64.0) / map->size;
1110 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1111 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1113 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1114 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1115 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1116 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1117 //mapglyph->vxmin = bearingX;
1118 //mapglyph->vxmax = bearingX + mWidth;
1119 mapglyph->vxmin = glyph->bitmap_left / map->size;
1120 mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
1121 //mapglyph->vymin = -bearingY;
1122 //mapglyph->vymax = mHeight - bearingY;
1123 mapglyph->vymin = -glyph->bitmap_top / map->size;
1124 mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
1125 //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);
1126 //mapglyph->advance_x = advance * usefont->size;
1127 //mapglyph->advance_x = advance;
1128 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1129 mapglyph->advance_y = 0;
1131 if (developer_font.integer)
1133 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1134 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1135 if (ch >= 32 && ch <= 128)
1136 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1137 Con_DPrintf("glyphinfo: Vertex info:\n");
1138 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1139 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1140 Con_DPrintf("glyphinfo: Texture info:\n");
1141 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1142 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1143 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1146 map->glyphs[mapch].image = false;
1149 // create a texture from the data now
1151 if (developer_font.integer > 100)
1153 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1154 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1155 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1156 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1158 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1160 // probably use bytesPerPixel here instead?
1161 if (r_font_use_alpha_textures.integer)
1163 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1164 map->glyphSize * FONT_CHARS_PER_LINE,
1165 map->glyphSize * FONT_CHAR_LINES,
1166 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1168 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1169 map->glyphSize * FONT_CHARS_PER_LINE,
1170 map->glyphSize * FONT_CHAR_LINES,
1171 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1177 // if the first try isn't successful, keep it with a broken texture
1178 // otherwise we retry to load it every single frame where ft2 rendering is used
1179 // this would be bad...
1180 // only `data' must be freed
1181 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1182 font->name, mapstart->size, mapidx);
1190 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1192 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1194 // the first map must have been loaded already
1195 if (!font->font_maps[map_index])
1197 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1200 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1202 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1203 start = start->next;
1204 if (start && start->start > ch)