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!"};
40 ================================================================================
41 Function definitions. Taken from the freetype2 headers.
42 ================================================================================
47 (*qFT_Init_FreeType)( FT_Library *alibrary );
49 (*qFT_Done_FreeType)( FT_Library library );
52 (*qFT_New_Face)( FT_Library library,
53 const char* filepathname,
58 (*qFT_New_Memory_Face)( FT_Library library,
59 const FT_Byte* file_base,
64 (*qFT_Done_Face)( FT_Face face );
66 (*qFT_Select_Size)( FT_Face face,
67 FT_Int strike_index );
69 (*qFT_Request_Size)( FT_Face face,
70 FT_Size_Request req );
72 (*qFT_Set_Char_Size)( FT_Face face,
73 FT_F26Dot6 char_width,
74 FT_F26Dot6 char_height,
75 FT_UInt horz_resolution,
76 FT_UInt vert_resolution );
78 (*qFT_Set_Pixel_Sizes)( FT_Face face,
80 FT_UInt pixel_height );
82 (*qFT_Load_Glyph)( FT_Face face,
84 FT_Int32 load_flags );
86 (*qFT_Load_Char)( FT_Face face,
88 FT_Int32 load_flags );
90 (*qFT_Get_Char_Index)( FT_Face face,
93 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
94 FT_Render_Mode render_mode );
96 (*qFT_Get_Kerning)( FT_Face face,
100 FT_Vector *akerning );
101 FT_EXPORT( FT_Error )
102 (*qFT_Attach_Stream)( FT_Face face,
103 FT_Open_Args* parameters );
105 ================================================================================
106 Support for dynamically loading the FreeType2 library
107 ================================================================================
110 static dllfunction_t ft2funcs[] =
112 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
113 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
114 //{"FT_New_Face", (void **) &qFT_New_Face},
115 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
116 {"FT_Done_Face", (void **) &qFT_Done_Face},
117 {"FT_Select_Size", (void **) &qFT_Select_Size},
118 {"FT_Request_Size", (void **) &qFT_Request_Size},
119 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
120 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
121 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
122 {"FT_Load_Char", (void **) &qFT_Load_Char},
123 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
124 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
125 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
126 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
130 /// Handle for FreeType2 DLL
131 static dllhandle_t ft2_dll = NULL;
133 /// Memory pool for fonts
134 static mempool_t *font_mempool= NULL;
135 static rtexturepool_t *font_texturepool = NULL;
137 /// FreeType library handle
138 static FT_Library font_ft2lib = NULL;
144 Unload the FreeType2 DLL
147 void Font_CloseLibrary (void)
150 Mem_FreePool(&font_mempool);
151 if (font_texturepool)
152 R_FreeTexturePool(&font_texturepool);
153 if (font_ft2lib && qFT_Done_FreeType)
155 qFT_Done_FreeType(font_ft2lib);
158 Sys_UnloadLibrary (&ft2_dll);
165 Try to load the FreeType2 DLL
168 qboolean Font_OpenLibrary (void)
170 const char* dllnames [] =
174 #elif defined(MACOSX)
183 if (r_font_disable_freetype.integer)
191 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
200 Initialize the freetype2 font subsystem
204 void font_start(void)
206 if (!Font_OpenLibrary())
209 if (qFT_Init_FreeType(&font_ft2lib))
211 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
216 font_mempool = Mem_AllocPool("FONT", 0, NULL);
219 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
224 font_texturepool = R_AllocTexturePool();
225 if (!font_texturepool)
227 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
233 void font_shutdown(void)
236 for (i = 0; i < MAX_FONTS; ++i)
240 Font_UnloadFont(dp_fonts[i].ft2);
241 dp_fonts[i].ft2 = NULL;
247 void font_newmap(void)
253 Cvar_RegisterVariable(&r_font_disable_freetype);
254 Cvar_RegisterVariable(&r_font_use_alpha_textures);
255 Cvar_RegisterVariable(&r_font_size_snapping);
259 ================================================================================
260 Implementation of a more or less lazy font loading and rendering code.
261 ================================================================================
264 #include "ft2_fontdefs.h"
266 ft2_font_t *Font_Alloc(void)
270 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
273 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
275 ft2_attachment_t *na;
277 font->attachmentcount++;
278 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
281 if (font->attachments && font->attachmentcount > 1)
283 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
284 Mem_Free(font->attachments);
286 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
287 font->attachments = na;
291 static float Font_VirtualToRealSize(float sz)
297 vw = ((vid.width > 0) ? vid.width : vid_width.value);
298 vh = ((vid.height > 0) ? vid.height : vid_height.value);
299 // now try to scale to our actual size:
300 sn = sz * vh / vid_conheight.value;
302 if ( sn - (float)si >= 0.5 )
307 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
308 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
309 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
312 ft2_font_t *ft2, *fbfont, *fb;
321 // check if a fallback font has been specified, if it has been, and the
322 // font fails to load, use the image font as main font
323 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
325 if (dpfnt->fallbacks[i][0])
329 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
331 if (i >= MAX_FONT_FALLBACKS)
337 strlcpy(ft2->name, name, sizeof(ft2->name));
338 ft2->image_font = true;
339 ft2->has_kerning = false;
343 ft2->image_font = false;
346 // attempt to load fallback fonts:
348 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
350 if (!dpfnt->fallbacks[i][0])
352 if (! (fb = Font_Alloc()) )
354 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
357 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
359 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
364 for (s = 0; s < MAX_FONT_SIZES; ++s)
366 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
371 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
376 // at least one size of the fallback font loaded successfully
382 if (fbfont == ft2 && ft2->image_font)
384 // no fallbacks were loaded successfully:
391 for (s = 0; s < MAX_FONT_SIZES; ++s)
393 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
398 // loading failed for every requested size
399 Font_UnloadFont(ft2);
405 //Con_Printf("%i sizes loaded\n", count);
410 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
413 char filename[MAX_QPATH];
417 fs_offset_t datasize;
419 memset(font, 0, sizeof(*font));
421 if (!Font_OpenLibrary())
423 if (!r_font_disable_freetype.integer)
425 Con_Printf("WARNING: can't open load font %s\n"
426 "You need the FreeType2 DLL to load font files\n",
432 namelen = strlen(name);
434 memcpy(filename, name, namelen);
435 memcpy(filename + namelen, ".ttf", 5);
436 data = FS_LoadFile(filename, font_mempool, false, &datasize);
439 memcpy(filename + namelen, ".otf", 5);
440 data = FS_LoadFile(filename, font_mempool, false, &datasize);
444 ft2_attachment_t afm;
446 memcpy(filename + namelen, ".pfb", 5);
447 data = FS_LoadFile(filename, font_mempool, false, &datasize);
451 memcpy(filename + namelen, ".afm", 5);
452 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
455 Font_Attach(font, &afm);
461 // FS_LoadFile being not-quiet should print an error :)
464 Con_Printf("Loading font %s face %i...\n", filename, _face);
466 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
467 if (status && _face != 0)
469 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
471 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
475 Con_Printf("ERROR: can't create face for %s\n"
476 "Error %i\n", // TODO: error strings
478 Font_UnloadFont(font);
482 // add the attachments
483 for (i = 0; i < font->attachmentcount; ++i)
486 memset(&args, 0, sizeof(args));
487 args.flags = FT_OPEN_MEMORY;
488 args.memory_base = (const FT_Byte*)font->attachments[i].data;
489 args.memory_size = font->attachments[i].size;
490 if (qFT_Attach_Stream(font->face, &args))
491 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
494 memcpy(font->name, name, namelen+1);
495 font->image_font = false;
496 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
500 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
501 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
504 ft2_font_map_t *fmap, temp;
511 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
516 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
518 if (!font->font_maps[map_index])
520 // if a similar size has already been loaded, ignore this one
521 //abs(font->font_maps[map_index]->size - size) < 4
522 if (font->font_maps[map_index]->size == size)
526 if (map_index >= MAX_FONT_SIZES)
529 memset(&temp, 0, sizeof(temp));
531 temp.glyphSize = CeilPowerOf2(size*2);
532 temp.sfx = (1.0/64.0)/(double)size;
533 temp.sfy = (1.0/64.0)/(double)size;
534 temp.intSize = -1; // negative value: LoadMap must search now :)
535 if (!Font_LoadMap(font, &temp, 0, &fmap))
537 Con_Printf("ERROR: can't load the first character map for %s\n"
540 Font_UnloadFont(font);
543 font->font_maps[map_index] = temp.next;
545 fmap->sfx = temp.sfx;
546 fmap->sfy = temp.sfy;
550 // load the default kerning vector:
551 if (font->has_kerning)
555 for (l = 0; l < 256; ++l)
557 for (r = 0; r < 256; ++r)
560 ul = qFT_Get_Char_Index(font->face, l);
561 ur = qFT_Get_Char_Index(font->face, r);
562 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
564 fmap->kerning.kerning[l][r][0] = 0;
565 fmap->kerning.kerning[l][r][1] = 0;
569 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
570 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
580 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
585 int matchsize = -10000;
589 ft2_font_map_t **maps = font->font_maps;
591 fsize = _fsize * vid.height / vid_conheight.value;
599 if (fsize - (float)size >= 0.49)
603 for (m = 0; m < MAX_FONT_SIZES; ++m)
607 // "round up" to the bigger size if two equally-valued matches exist
608 nval = abs(maps[m]->size - size);
609 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
613 matchsize = maps[m]->size;
614 if (value == 0) // there is no better match
618 if (value <= r_font_size_snapping.value)
622 if (!*outh) *outh = *outw;
623 if (!*outw) *outw = *outh;
626 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
627 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
632 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
634 if (index < 0 || index >= MAX_FONT_SIZES)
636 return font->font_maps[index];
639 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
641 if (font->currenth == h &&
642 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
643 font->currentw == w)) // same size has been requested
647 // sorry, but freetype doesn't seem to care about other sizes
650 if (font->image_font)
652 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
657 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
665 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
667 ft2_font_map_t *fmap;
668 if (!font->has_kerning)
670 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
672 fmap = font->font_maps[map_index];
675 if (left < 256 && right < 256)
677 // quick-kerning, be aware of the size: scale it
678 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
679 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
687 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
688 if (!Font_SetSize(font, w, h))
690 // this deserves an error message
691 Con_Printf("Failed to get kerning for %s\n", font->name);
694 ul = qFT_Get_Char_Index(font->face, left);
695 ur = qFT_Get_Char_Index(font->face, right);
696 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
698 if (outx) *outx = kernvec.x * fmap->sfx;
699 if (outy) *outy = kernvec.y * fmap->sfy;
706 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
708 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
711 static void UnloadMapRec(ft2_font_map_t *map)
715 R_FreeTexture(map->texture);
719 UnloadMapRec(map->next);
723 void Font_UnloadFont(ft2_font_t *font)
726 if (font->attachments && font->attachmentcount)
728 Mem_Free(font->attachments);
729 font->attachmentcount = 0;
730 font->attachments = NULL;
732 for (i = 0; i < MAX_FONT_SIZES; ++i)
734 if (font->font_maps[i])
736 UnloadMapRec(font->font_maps[i]);
737 font->font_maps[i] = NULL;
744 qFT_Done_Face((FT_Face)font->face);
750 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
752 char map_identifier[MAX_QPATH];
753 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
760 int gR, gC; // glyph position: row and column
762 ft2_font_map_t *map, *next;
767 int bytesPerPixel = 4; // change the conversion loop too if you change this!
772 if (r_font_use_alpha_textures.integer)
775 if (font->image_font)
776 fontface = (FT_Face)font->next->face;
778 fontface = (FT_Face)font->face;
780 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
782 if (font->image_font && mapstart->intSize < 0)
783 mapstart->intSize = mapstart->size;
784 if (mapstart->intSize < 0)
786 mapstart->intSize = mapstart->size;
789 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
791 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
794 if ((fontface->size->metrics.height>>6) <= mapstart->size)
796 if (mapstart->intSize < 2)
798 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
803 if (developer.integer)
804 Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
807 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
809 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
813 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
816 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
820 // copy over the information
821 map->size = mapstart->size;
822 map->intSize = mapstart->intSize;
823 map->glyphSize = mapstart->glyphSize;
824 map->sfx = mapstart->sfx;
825 map->sfy = mapstart->sfy;
827 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
828 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
831 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
836 // initialize as white texture with zero alpha
838 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
840 if (bytesPerPixel == 4)
850 map->start = mapidx * FONT_CHARS_PER_MAP;
852 while(next->next && next->next->start < map->start)
854 map->next = next->next;
859 for (ch = map->start;
860 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
867 unsigned char *imagedata, *dst, *src;
868 glyph_slot_t *mapglyph;
871 mapch = ch - map->start;
873 if (developer.integer)
874 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
877 if (gC >= FONT_CHARS_PER_LINE)
879 gC -= FONT_CHARS_PER_LINE;
883 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
884 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
885 // we need the glyphIndex
888 if (font->image_font && mapch == ch && img_fontmap[mapch])
890 map->glyphs[mapch].image = true;
893 glyphIndex = qFT_Get_Char_Index(face, ch);
896 // by convention, 0 is the "missing-glyph"-glyph
897 // try to load from a fallback font
898 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
900 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
903 face = usefont->face;
904 glyphIndex = qFT_Get_Char_Index(face, ch);
907 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
914 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
915 // now we let it use the "missing-glyph"-glyph
925 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
928 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
929 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
935 bmp = &glyph->bitmap;
940 if (w > map->glyphSize || h > map->glyphSize) {
941 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
942 if (w > map->glyphSize)
944 if (h > map->glyphSize)
948 switch (bmp->pixel_mode)
950 case FT_PIXEL_MODE_MONO:
951 if (developer.integer)
952 Con_Print("glyphinfo: Pixel Mode: MONO\n");
954 case FT_PIXEL_MODE_GRAY2:
955 if (developer.integer)
956 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
958 case FT_PIXEL_MODE_GRAY4:
959 if (developer.integer)
960 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
962 case FT_PIXEL_MODE_GRAY:
963 if (developer.integer)
964 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
967 if (developer.integer)
968 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
970 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
973 for (y = 0; y < h; ++y)
975 dst = imagedata + y * pitch;
976 src = bmp->buffer + y * bmp->pitch;
978 switch (bmp->pixel_mode)
980 case FT_PIXEL_MODE_MONO:
981 dst += bytesPerPixel - 1; // shift to alpha byte
982 for (x = 0; x < bmp->width; x += 8)
984 unsigned char ch = *src++;
985 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
986 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
987 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
988 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
989 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
990 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
991 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
992 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
995 case FT_PIXEL_MODE_GRAY2:
996 dst += bytesPerPixel - 1; // shift to alpha byte
997 for (x = 0; x < bmp->width; x += 4)
999 unsigned char ch = *src++;
1000 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1001 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1002 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1003 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1006 case FT_PIXEL_MODE_GRAY4:
1007 dst += bytesPerPixel - 1; // shift to alpha byte
1008 for (x = 0; x < bmp->width; x += 2)
1010 unsigned char ch = *src++;
1011 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1012 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1015 case FT_PIXEL_MODE_GRAY:
1016 // in this case pitch should equal width
1017 for (tp = 0; tp < bmp->pitch; ++tp)
1018 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1020 //memcpy((void*)dst, (void*)src, bmp->pitch);
1021 //dst += bmp->pitch;
1028 // now fill map->glyphs[ch - map->start]
1029 mapglyph = &map->glyphs[mapch];
1033 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1035 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1036 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1037 double advance = (glyph->advance.x >> 6) / map->size;
1038 double mWidth = (glyph->metrics.width >> 6) / map->size;
1039 double mHeight = (glyph->metrics.height >> 6) / map->size;
1041 mapglyph->vxmin = bearingX;
1042 mapglyph->vxmax = bearingX + mWidth;
1043 mapglyph->vymin = -bearingY;
1044 mapglyph->vymax = mHeight - bearingY;
1045 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1046 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1047 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1048 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1049 //mapglyph->advance_x = advance * usefont->size;
1050 mapglyph->advance_x = advance;
1051 mapglyph->advance_y = 0;
1053 if (developer.integer)
1055 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1056 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1057 if (ch >= 32 && ch <= 128)
1058 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
1059 Con_Printf("glyphinfo: Vertex info:\n");
1060 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1061 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1062 Con_Printf("glyphinfo: Texture info:\n");
1063 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1064 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1065 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1068 map->glyphs[mapch].image = false;
1071 // create a texture from the data now
1073 if (developer.integer)
1075 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1076 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1077 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1079 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1081 // probably use bytesPerPixel here instead?
1082 if (r_font_use_alpha_textures.integer)
1084 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1085 map->glyphSize * FONT_CHARS_PER_LINE,
1086 map->glyphSize * FONT_CHAR_LINES,
1087 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1089 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1090 map->glyphSize * FONT_CHARS_PER_LINE,
1091 map->glyphSize * FONT_CHAR_LINES,
1092 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1098 // if the first try isn't successful, keep it with a broken texture
1099 // otherwise we retry to load it every single frame where ft2 rendering is used
1100 // this would be bad...
1101 // only `data' must be freed
1102 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1103 font->name, mapstart->size, mapidx);
1111 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1113 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1115 // the first map must have been loaded already
1116 if (!font->font_maps[map_index])
1118 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1121 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1123 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1124 start = start->next;
1125 if (start && start->start > ch)