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", "0", "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", "0", "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 [] =
173 #error path for freetype 2 dll
175 #error path for freetype 2 dll
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);
261 ================================================================================
262 Implementation of a more or less lazy font loading and rendering code.
263 ================================================================================
266 #include "ft2_fontdefs.h"
268 ft2_font_t *Font_Alloc(void)
272 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
275 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
277 ft2_attachment_t *na;
279 font->attachmentcount++;
280 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
283 if (font->attachments && font->attachmentcount > 1)
285 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
286 Mem_Free(font->attachments);
288 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
289 font->attachments = na;
293 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
294 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
295 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
298 ft2_font_t *ft2, *fbfont, *fb;
307 // check if a fallback font has been specified, if it has been, and the
308 // font fails to load, use the image font as main font
309 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
311 if (dpfnt->fallbacks[i][0])
315 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
317 if (i >= MAX_FONT_FALLBACKS)
323 strlcpy(ft2->name, name, sizeof(ft2->name));
324 ft2->image_font = true;
325 ft2->has_kerning = false;
329 ft2->image_font = false;
332 // attempt to load fallback fonts:
334 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
336 if (!dpfnt->fallbacks[i][0])
338 if (! (fb = Font_Alloc()) )
340 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
343 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
345 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
350 for (s = 0; s < MAX_FONT_SIZES; ++s)
352 if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
357 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
362 // at least one size of the fallback font loaded successfully
368 if (fbfont == ft2 && ft2->image_font)
370 // no fallbacks were loaded successfully:
377 for (s = 0; s < MAX_FONT_SIZES; ++s)
379 if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
384 // loading failed for every requested size
385 Font_UnloadFont(ft2);
391 //Con_Printf("%i sizes loaded\n", count);
396 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
399 char filename[PATH_MAX];
403 fs_offset_t datasize;
405 memset(font, 0, sizeof(*font));
407 if (!Font_OpenLibrary())
409 if (!r_font_disable_freetype.integer)
411 Con_Printf("WARNING: can't open load font %s\n"
412 "You need the FreeType2 DLL to load font files\n",
418 namelen = strlen(name);
420 memcpy(filename, name, namelen);
421 memcpy(filename + namelen, ".ttf", 5);
422 data = FS_LoadFile(filename, font_mempool, false, &datasize);
425 memcpy(filename + namelen, ".otf", 5);
426 data = FS_LoadFile(filename, font_mempool, false, &datasize);
430 ft2_attachment_t afm;
432 memcpy(filename + namelen, ".pfb", 5);
433 data = FS_LoadFile(filename, font_mempool, false, &datasize);
437 memcpy(filename + namelen, ".afm", 5);
438 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
441 Font_Attach(font, &afm);
447 // FS_LoadFile being not-quiet should print an error :)
450 Con_Printf("Loading font %s face %i...\n", filename, _face);
452 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
453 if (status && _face != 0)
455 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
457 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
461 Con_Printf("ERROR: can't create face for %s\n"
462 "Error %i\n", // TODO: error strings
464 Font_UnloadFont(font);
468 // add the attachments
469 for (i = 0; i < font->attachmentcount; ++i)
472 memset(&args, 0, sizeof(args));
473 args.flags = FT_OPEN_MEMORY;
474 args.memory_base = (const FT_Byte*)font->attachments[i].data;
475 args.memory_size = font->attachments[i].size;
476 if (qFT_Attach_Stream(font->face, &args))
477 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
480 memcpy(font->name, name, namelen+1);
481 font->image_font = false;
482 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
486 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
487 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
490 ft2_font_map_t *fmap, temp;
497 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
502 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
504 if (!font->font_maps[map_index])
506 // if a similar size has already been loaded, ignore this one
507 //abs(font->font_maps[map_index]->size - size) < 4
508 if (font->font_maps[map_index]->size == size)
512 if (map_index >= MAX_FONT_SIZES)
515 memset(&temp, 0, sizeof(temp));
517 temp.glyphSize = CeilPowerOf2(size*2);
518 temp.sfx = (1.0/64.0)/(double)size;
519 temp.sfy = (1.0/64.0)/(double)size;
520 temp.intSize = -1; // negative value: LoadMap must search now :)
521 if (!Font_LoadMap(font, &temp, 0, &fmap))
523 Con_Printf("ERROR: can't load the first character map for %s\n"
526 Font_UnloadFont(font);
529 font->font_maps[map_index] = temp.next;
531 fmap->sfx = temp.sfx;
532 fmap->sfy = temp.sfy;
536 // load the default kerning vector:
537 if (font->has_kerning)
541 for (l = 0; l < 256; ++l)
543 for (r = 0; r < 256; ++r)
546 ul = qFT_Get_Char_Index(font->face, l);
547 ur = qFT_Get_Char_Index(font->face, r);
548 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
550 fmap->kerning.kerning[l][r][0] = 0;
551 fmap->kerning.kerning[l][r][1] = 0;
555 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
556 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
566 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
571 int matchsize = -10000;
575 ft2_font_map_t **maps = font->font_maps;
577 fsize = _fsize * vid.height / vid_conheight.value;
585 if (fsize - (float)size >= 0.49)
589 for (m = 0; m < MAX_FONT_SIZES; ++m)
593 // "round up" to the bigger size if two equally-valued matches exist
594 nval = abs(maps[m]->size - size);
595 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
599 matchsize = maps[m]->size;
600 if (value == 0) // there is no better match
604 if (r_font_size_snapping.integer && value <= 1)
608 if (!*outh) *outh = *outw;
609 if (!*outw) *outw = *outh;
612 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
613 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
618 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
620 if (index < 0 || index >= MAX_FONT_SIZES)
622 return font->font_maps[index];
625 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
627 if (font->currenth == h &&
628 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
629 font->currentw == w)) // same size has been requested
633 // sorry, but freetype doesn't seem to care about other sizes
636 if (font->image_font)
640 Con_Print("ASSERTION FAULT: no fallback for image font!\n");
643 if (!font->next->face)
645 Con_Print("ASSERTION FAULT: no face for fallback\n");
648 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
653 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
661 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
663 ft2_font_map_t *fmap;
664 if (!font->has_kerning)
666 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
668 fmap = font->font_maps[map_index];
671 if (left < 256 && right < 256)
673 // quick-kerning, be aware of the size: scale it
674 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
675 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
683 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
684 if (!Font_SetSize(font, w, h))
686 // this deserves an error message
687 Con_Printf("Failed to get kerning for %s\n", font->name);
690 ul = qFT_Get_Char_Index(font->face, left);
691 ur = qFT_Get_Char_Index(font->face, right);
692 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
694 if (outx) *outx = kernvec.x * fmap->sfx;
695 if (outy) *outy = kernvec.y * fmap->sfy;
702 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
704 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
707 static void UnloadMapRec(ft2_font_map_t *map)
711 R_FreeTexture(map->texture);
715 UnloadMapRec(map->next);
719 void Font_UnloadFont(ft2_font_t *font)
722 if (font->attachments && font->attachmentcount)
724 Mem_Free(font->attachments);
725 font->attachmentcount = 0;
726 font->attachments = NULL;
728 for (i = 0; i < MAX_FONT_SIZES; ++i)
730 if (font->font_maps[i])
732 UnloadMapRec(font->font_maps[i]);
733 font->font_maps[i] = NULL;
740 qFT_Done_Face((FT_Face)font->face);
746 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
748 char map_identifier[PATH_MAX];
749 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
756 int gR, gC; // glyph position: row and column
758 ft2_font_map_t *map, *next;
763 int bytesPerPixel = 4; // change the conversion loop too if you change this!
768 if (r_font_use_alpha_textures.integer)
771 if (font->image_font)
772 fontface = (FT_Face)font->next->face;
774 fontface = (FT_Face)font->face;
776 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
778 if (font->image_font && mapstart->intSize < 0)
779 mapstart->intSize = mapstart->size;
780 if (mapstart->intSize < 0)
782 mapstart->intSize = mapstart->size;
785 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
787 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
790 if ((fontface->size->metrics.height>>6) <= mapstart->size)
792 if (mapstart->intSize < 2)
794 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
799 if (developer.integer)
800 Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
803 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
805 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
809 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
812 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
816 // copy over the information
817 map->size = mapstart->size;
818 map->intSize = mapstart->intSize;
819 map->glyphSize = mapstart->glyphSize;
820 map->sfx = mapstart->sfx;
821 map->sfy = mapstart->sfy;
823 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
824 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
827 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
832 // initialize as white texture with zero alpha
834 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
836 if (bytesPerPixel == 4)
846 map->start = mapidx * FONT_CHARS_PER_MAP;
848 while(next->next && next->next->start < map->start)
850 map->next = next->next;
855 for (ch = map->start;
856 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
863 unsigned char *imagedata, *dst, *src;
864 glyph_slot_t *mapglyph;
867 mapch = ch - map->start;
869 if (developer.integer)
870 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
873 if (gC >= FONT_CHARS_PER_LINE)
875 gC -= FONT_CHARS_PER_LINE;
879 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
880 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
881 // we need the glyphIndex
884 if (font->image_font && mapch == ch && img_fontmap[mapch])
886 map->glyphs[mapch].image = true;
889 glyphIndex = qFT_Get_Char_Index(face, ch);
892 // by convention, 0 is the "missing-glyph"-glyph
893 // try to load from a fallback font
894 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
896 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
899 face = usefont->face;
900 glyphIndex = qFT_Get_Char_Index(face, ch);
903 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
910 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
911 // now we let it use the "missing-glyph"-glyph
921 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
924 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
925 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
931 bmp = &glyph->bitmap;
936 if (w > map->glyphSize || h > map->glyphSize) {
937 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
938 if (w > map->glyphSize)
940 if (h > map->glyphSize)
944 switch (bmp->pixel_mode)
946 case FT_PIXEL_MODE_MONO:
947 if (developer.integer)
948 Con_Print("glyphinfo: Pixel Mode: MONO\n");
950 case FT_PIXEL_MODE_GRAY2:
951 if (developer.integer)
952 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
954 case FT_PIXEL_MODE_GRAY4:
955 if (developer.integer)
956 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
958 case FT_PIXEL_MODE_GRAY:
959 if (developer.integer)
960 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
963 if (developer.integer)
964 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
966 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
969 for (y = 0; y < h; ++y)
971 dst = imagedata + y * pitch;
972 src = bmp->buffer + y * bmp->pitch;
974 switch (bmp->pixel_mode)
976 case FT_PIXEL_MODE_MONO:
977 dst += bytesPerPixel - 1; // shift to alpha byte
978 for (x = 0; x < bmp->width; x += 8)
980 unsigned char ch = *src++;
981 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
982 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
983 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
984 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
985 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
986 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
987 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
988 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
991 case FT_PIXEL_MODE_GRAY2:
992 dst += bytesPerPixel - 1; // shift to alpha byte
993 for (x = 0; x < bmp->width; x += 4)
995 unsigned char ch = *src++;
996 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
997 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
998 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
999 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1002 case FT_PIXEL_MODE_GRAY4:
1003 dst += bytesPerPixel - 1; // shift to alpha byte
1004 for (x = 0; x < bmp->width; x += 2)
1006 unsigned char ch = *src++;
1007 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1008 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1011 case FT_PIXEL_MODE_GRAY:
1012 // in this case pitch should equal width
1013 for (tp = 0; tp < bmp->pitch; ++tp)
1014 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1016 //memcpy((void*)dst, (void*)src, bmp->pitch);
1017 //dst += bmp->pitch;
1024 // now fill map->glyphs[ch - map->start]
1025 mapglyph = &map->glyphs[mapch];
1029 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1031 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1032 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1033 double advance = (glyph->advance.x >> 6) / map->size;
1034 double mWidth = (glyph->metrics.width >> 6) / map->size;
1035 double mHeight = (glyph->metrics.height >> 6) / map->size;
1037 mapglyph->vxmin = bearingX;
1038 mapglyph->vxmax = bearingX + mWidth;
1039 mapglyph->vymin = -bearingY;
1040 mapglyph->vymax = mHeight - bearingY;
1041 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1042 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1043 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1044 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1045 //mapglyph->advance_x = advance * usefont->size;
1046 mapglyph->advance_x = advance;
1047 mapglyph->advance_y = 0;
1049 if (developer.integer)
1051 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1052 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1053 if (ch >= 32 && ch <= 128)
1054 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
1055 Con_Printf("glyphinfo: Vertex info:\n");
1056 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1057 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1058 Con_Printf("glyphinfo: Texture info:\n");
1059 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1060 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1061 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1064 map->glyphs[mapch].image = false;
1067 // create a texture from the data now
1069 if (developer.integer)
1071 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1072 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1073 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1075 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1077 // probably use bytesPerPixel here instead?
1078 if (r_font_use_alpha_textures.integer)
1080 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1081 map->glyphSize * FONT_CHARS_PER_LINE,
1082 map->glyphSize * FONT_CHAR_LINES,
1083 data, TEXTYPE_ALPHA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
1085 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1086 map->glyphSize * FONT_CHARS_PER_LINE,
1087 map->glyphSize * FONT_CHAR_LINES,
1088 data, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
1094 // if the first try isn't successful, keep it with a broken texture
1095 // otherwise we retry to load it every single frame where ft2 rendering is used
1096 // this would be bad...
1097 // only `data' must be freed
1098 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1099 font->name, mapstart->size, mapidx);
1107 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1109 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1111 // the first map must have been loaded already
1112 if (!font->font_maps[map_index])
1114 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1117 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1119 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1120 start = start->next;
1121 if (start && start->start > ch)