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 no_texture, qboolean no_kerning);
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, false))
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, 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 qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
518 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
521 ft2_font_map_t *fmap, temp;
523 if (!(size > 0.001f && size < 1000.0f))
528 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
533 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
535 if (!font->font_maps[map_index])
537 // if a similar size has already been loaded, ignore this one
538 //abs(font->font_maps[map_index]->size - size) < 4
539 if (font->font_maps[map_index]->size == size)
543 if (map_index >= MAX_FONT_SIZES)
546 memset(&temp, 0, sizeof(temp));
548 temp.glyphSize = CeilPowerOf2(size*2);
549 temp.sfx = (1.0/64.0)/(double)size;
550 temp.sfy = (1.0/64.0)/(double)size;
551 temp.intSize = -1; // negative value: LoadMap must search now :)
552 if (!Font_LoadMap(font, &temp, 0, &fmap))
554 Con_Printf("ERROR: can't load the first character map for %s\n"
557 Font_UnloadFont(font);
560 font->font_maps[map_index] = temp.next;
562 fmap->sfx = temp.sfx;
563 fmap->sfy = temp.sfy;
567 // load the default kerning vector:
568 if (font->has_kerning)
572 for (l = 0; l < 256; ++l)
574 for (r = 0; r < 256; ++r)
577 ul = qFT_Get_Char_Index(font->face, l);
578 ur = qFT_Get_Char_Index(font->face, r);
579 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
581 fmap->kerning.kerning[l][r][0] = 0;
582 fmap->kerning.kerning[l][r][1] = 0;
586 fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
587 fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
597 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
602 int matchsize = -10000;
604 float fsize_x, fsize_y;
605 ft2_font_map_t **maps = font->font_maps;
607 fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
609 fsize_x = *outw * vid.width / vid_conwidth.value;
611 fsize_y = *outh * vid.height / vid_conheight.value;
616 fsize_x = fsize_y = 16;
626 for (m = 0; m < MAX_FONT_SIZES; ++m)
630 // "round up" to the bigger size if two equally-valued matches exist
631 nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
632 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
636 matchsize = maps[m]->size;
637 if (value == 0) // there is no better match
641 if (value <= r_font_size_snapping.value)
643 // do NOT keep the aspect for perfect rendering
644 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
645 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
650 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
652 if (index < 0 || index >= MAX_FONT_SIZES)
654 return font->font_maps[index];
657 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
659 if (font->currenth == h &&
660 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
661 font->currentw == w)) // same size has been requested
665 // sorry, but freetype doesn't seem to care about other sizes
668 if (font->image_font)
670 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
675 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
683 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
685 ft2_font_map_t *fmap;
686 if (!font->has_kerning || !r_font_kerning.integer)
688 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
690 fmap = font->font_maps[map_index];
693 if (left < 256 && right < 256)
695 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
696 // quick-kerning, be aware of the size: scale it
697 if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
698 if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
706 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
708 if (!Font_SetSize(font, w, h))
710 // this deserves an error message
711 Con_Printf("Failed to get kerning for %s\n", font->name);
714 ul = qFT_Get_Char_Index(font->face, left);
715 ur = qFT_Get_Char_Index(font->face, right);
716 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
718 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
719 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
723 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
725 // this deserves an error message
726 Con_Printf("Failed to get kerning for %s\n", font->name);
729 ul = qFT_Get_Char_Index(font->face, left);
730 ur = qFT_Get_Char_Index(font->face, right);
731 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
733 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
734 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
741 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
743 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
746 static void UnloadMapRec(ft2_font_map_t *map)
750 R_FreeTexture(map->texture);
754 UnloadMapRec(map->next);
758 void Font_UnloadFont(ft2_font_t *font)
761 if (font->attachments && font->attachmentcount)
763 Mem_Free(font->attachments);
764 font->attachmentcount = 0;
765 font->attachments = NULL;
767 for (i = 0; i < MAX_FONT_SIZES; ++i)
769 if (font->font_maps[i])
771 UnloadMapRec(font->font_maps[i]);
772 font->font_maps[i] = NULL;
779 qFT_Done_Face((FT_Face)font->face);
785 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
787 char map_identifier[MAX_QPATH];
788 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
796 int gR, gC; // glyph position: row and column
798 ft2_font_map_t *map, *next;
803 int bytesPerPixel = 4; // change the conversion loop too if you change this!
808 if (r_font_use_alpha_textures.integer)
811 if (font->image_font)
812 fontface = (FT_Face)font->next->face;
814 fontface = (FT_Face)font->face;
816 switch(r_font_antialias.integer)
819 switch(r_font_hinting.integer)
822 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
826 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
830 load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
836 switch(r_font_hinting.integer)
839 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
842 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
845 load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
849 load_flags = FT_LOAD_TARGET_NORMAL;
855 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
857 if (font->image_font && mapstart->intSize < 0)
858 mapstart->intSize = mapstart->size;
859 if (mapstart->intSize < 0)
861 mapstart->intSize = mapstart->size;
864 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
866 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
869 if ((fontface->size->metrics.height>>6) <= mapstart->size)
871 if (mapstart->intSize < 2)
873 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
878 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
881 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
883 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
887 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
890 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
894 // copy over the information
895 map->size = mapstart->size;
896 map->intSize = mapstart->intSize;
897 map->glyphSize = mapstart->glyphSize;
898 map->sfx = mapstart->sfx;
899 map->sfy = mapstart->sfy;
901 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
902 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
905 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
909 memset(map->width_of, 0, sizeof(map->width_of));
911 // initialize as white texture with zero alpha
913 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
915 if (bytesPerPixel == 4)
925 map->start = mapidx * FONT_CHARS_PER_MAP;
927 while(next->next && next->next->start < map->start)
929 map->next = next->next;
934 for (ch = map->start;
935 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
942 unsigned char *imagedata, *dst, *src;
943 glyph_slot_t *mapglyph;
946 mapch = ch - map->start;
948 if (developer_font.integer)
949 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
952 if (gC >= FONT_CHARS_PER_LINE)
954 gC -= FONT_CHARS_PER_LINE;
958 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
959 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
960 // we need the glyphIndex
963 if (font->image_font && mapch == ch && img_fontmap[mapch])
965 map->glyphs[mapch].image = true;
968 glyphIndex = qFT_Get_Char_Index(face, ch);
971 // by convention, 0 is the "missing-glyph"-glyph
972 // try to load from a fallback font
973 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
975 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
978 face = usefont->face;
979 glyphIndex = qFT_Get_Char_Index(face, ch);
982 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
989 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
990 // now we let it use the "missing-glyph"-glyph
1000 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1003 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1004 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1009 glyph = face->glyph;
1010 bmp = &glyph->bitmap;
1015 if (w > map->glyphSize || h > map->glyphSize) {
1016 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1017 if (w > map->glyphSize)
1019 if (h > map->glyphSize)
1023 switch (bmp->pixel_mode)
1025 case FT_PIXEL_MODE_MONO:
1026 if (developer_font.integer)
1027 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1029 case FT_PIXEL_MODE_GRAY2:
1030 if (developer_font.integer)
1031 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1033 case FT_PIXEL_MODE_GRAY4:
1034 if (developer_font.integer)
1035 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1037 case FT_PIXEL_MODE_GRAY:
1038 if (developer_font.integer)
1039 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1042 if (developer_font.integer)
1043 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1045 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1048 for (y = 0; y < h; ++y)
1050 dst = imagedata + y * pitch;
1051 src = bmp->buffer + y * bmp->pitch;
1053 switch (bmp->pixel_mode)
1055 case FT_PIXEL_MODE_MONO:
1056 dst += bytesPerPixel - 1; // shift to alpha byte
1057 for (x = 0; x < bmp->width; x += 8)
1059 unsigned char ch = *src++;
1060 *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
1061 *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
1062 *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
1063 *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
1064 *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
1065 *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
1066 *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
1067 *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
1070 case FT_PIXEL_MODE_GRAY2:
1071 dst += bytesPerPixel - 1; // shift to alpha byte
1072 for (x = 0; x < bmp->width; x += 4)
1074 unsigned char ch = *src++;
1075 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1076 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1077 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1078 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1081 case FT_PIXEL_MODE_GRAY4:
1082 dst += bytesPerPixel - 1; // shift to alpha byte
1083 for (x = 0; x < bmp->width; x += 2)
1085 unsigned char ch = *src++;
1086 *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1087 *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
1090 case FT_PIXEL_MODE_GRAY:
1091 // in this case pitch should equal width
1092 for (tp = 0; tp < bmp->pitch; ++tp)
1093 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1095 //memcpy((void*)dst, (void*)src, bmp->pitch);
1096 //dst += bmp->pitch;
1103 // now fill map->glyphs[ch - map->start]
1104 mapglyph = &map->glyphs[mapch];
1108 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1110 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1111 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1112 double advance = (glyph->advance.x / 64.0) / map->size;
1113 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1114 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1116 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1117 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1118 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1119 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1120 //mapglyph->vxmin = bearingX;
1121 //mapglyph->vxmax = bearingX + mWidth;
1122 mapglyph->vxmin = glyph->bitmap_left / map->size;
1123 mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
1124 //mapglyph->vymin = -bearingY;
1125 //mapglyph->vymax = mHeight - bearingY;
1126 mapglyph->vymin = -glyph->bitmap_top / map->size;
1127 mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
1128 //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);
1129 //mapglyph->advance_x = advance * usefont->size;
1130 //mapglyph->advance_x = advance;
1131 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1132 mapglyph->advance_y = 0;
1134 if (developer_font.integer)
1136 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1137 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1138 if (ch >= 32 && ch <= 128)
1139 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1140 Con_DPrintf("glyphinfo: Vertex info:\n");
1141 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1142 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1143 Con_DPrintf("glyphinfo: Texture info:\n");
1144 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1145 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1146 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1149 map->glyphs[mapch].image = false;
1152 // create a texture from the data now
1154 if (developer_font.integer > 100)
1156 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1157 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1158 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1159 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1161 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1163 // probably use bytesPerPixel here instead?
1164 if (r_font_use_alpha_textures.integer)
1166 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1167 map->glyphSize * FONT_CHARS_PER_LINE,
1168 map->glyphSize * FONT_CHAR_LINES,
1169 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1171 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1172 map->glyphSize * FONT_CHARS_PER_LINE,
1173 map->glyphSize * FONT_CHAR_LINES,
1174 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1180 // if the first try isn't successful, keep it with a broken texture
1181 // otherwise we retry to load it every single frame where ft2 rendering is used
1182 // this would be bad...
1183 // only `data' must be freed
1184 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1185 font->name, mapstart->size, mapidx);
1193 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1195 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1197 // the first map must have been loaded already
1198 if (!font->font_maps[map_index])
1200 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1203 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1205 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1206 start = start->next;
1207 if (start && start->start > ch)