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 [] =
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[MAX_QPATH];
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 (value <= r_font_size_snapping.value)
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)
638 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
643 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
651 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
653 ft2_font_map_t *fmap;
654 if (!font->has_kerning)
656 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
658 fmap = font->font_maps[map_index];
661 if (left < 256 && right < 256)
663 // quick-kerning, be aware of the size: scale it
664 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
665 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
673 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
674 if (!Font_SetSize(font, w, h))
676 // this deserves an error message
677 Con_Printf("Failed to get kerning for %s\n", font->name);
680 ul = qFT_Get_Char_Index(font->face, left);
681 ur = qFT_Get_Char_Index(font->face, right);
682 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
684 if (outx) *outx = kernvec.x * fmap->sfx;
685 if (outy) *outy = kernvec.y * fmap->sfy;
692 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
694 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
697 static void UnloadMapRec(ft2_font_map_t *map)
701 R_FreeTexture(map->texture);
705 UnloadMapRec(map->next);
709 void Font_UnloadFont(ft2_font_t *font)
712 if (font->attachments && font->attachmentcount)
714 Mem_Free(font->attachments);
715 font->attachmentcount = 0;
716 font->attachments = NULL;
718 for (i = 0; i < MAX_FONT_SIZES; ++i)
720 if (font->font_maps[i])
722 UnloadMapRec(font->font_maps[i]);
723 font->font_maps[i] = NULL;
730 qFT_Done_Face((FT_Face)font->face);
736 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
738 char map_identifier[MAX_QPATH];
739 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
746 int gR, gC; // glyph position: row and column
748 ft2_font_map_t *map, *next;
753 int bytesPerPixel = 4; // change the conversion loop too if you change this!
758 if (r_font_use_alpha_textures.integer)
761 if (font->image_font)
762 fontface = (FT_Face)font->next->face;
764 fontface = (FT_Face)font->face;
766 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
768 if (font->image_font && mapstart->intSize < 0)
769 mapstart->intSize = mapstart->size;
770 if (mapstart->intSize < 0)
772 mapstart->intSize = mapstart->size;
775 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
777 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
780 if ((fontface->size->metrics.height>>6) <= mapstart->size)
782 if (mapstart->intSize < 2)
784 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
789 if (developer.integer)
790 Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
793 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
795 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
799 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
802 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
806 // copy over the information
807 map->size = mapstart->size;
808 map->intSize = mapstart->intSize;
809 map->glyphSize = mapstart->glyphSize;
810 map->sfx = mapstart->sfx;
811 map->sfy = mapstart->sfy;
813 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
814 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
817 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
822 // initialize as white texture with zero alpha
824 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
826 if (bytesPerPixel == 4)
836 map->start = mapidx * FONT_CHARS_PER_MAP;
838 while(next->next && next->next->start < map->start)
840 map->next = next->next;
845 for (ch = map->start;
846 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
853 unsigned char *imagedata, *dst, *src;
854 glyph_slot_t *mapglyph;
857 mapch = ch - map->start;
859 if (developer.integer)
860 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
863 if (gC >= FONT_CHARS_PER_LINE)
865 gC -= FONT_CHARS_PER_LINE;
869 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
870 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
871 // we need the glyphIndex
874 if (font->image_font && mapch == ch && img_fontmap[mapch])
876 map->glyphs[mapch].image = true;
879 glyphIndex = qFT_Get_Char_Index(face, ch);
882 // by convention, 0 is the "missing-glyph"-glyph
883 // try to load from a fallback font
884 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
886 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
889 face = usefont->face;
890 glyphIndex = qFT_Get_Char_Index(face, ch);
893 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
900 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
901 // now we let it use the "missing-glyph"-glyph
911 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
914 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
915 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
921 bmp = &glyph->bitmap;
926 if (w > map->glyphSize || h > map->glyphSize) {
927 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
928 if (w > map->glyphSize)
930 if (h > map->glyphSize)
934 switch (bmp->pixel_mode)
936 case FT_PIXEL_MODE_MONO:
937 if (developer.integer)
938 Con_Print("glyphinfo: Pixel Mode: MONO\n");
940 case FT_PIXEL_MODE_GRAY2:
941 if (developer.integer)
942 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
944 case FT_PIXEL_MODE_GRAY4:
945 if (developer.integer)
946 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
948 case FT_PIXEL_MODE_GRAY:
949 if (developer.integer)
950 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
953 if (developer.integer)
954 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
956 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
959 for (y = 0; y < h; ++y)
961 dst = imagedata + y * pitch;
962 src = bmp->buffer + y * bmp->pitch;
964 switch (bmp->pixel_mode)
966 case FT_PIXEL_MODE_MONO:
967 dst += bytesPerPixel - 1; // shift to alpha byte
968 for (x = 0; x < bmp->width; x += 8)
970 unsigned char ch = *src++;
971 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
972 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
973 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
974 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
975 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
976 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
977 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
978 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
981 case FT_PIXEL_MODE_GRAY2:
982 dst += bytesPerPixel - 1; // shift to alpha byte
983 for (x = 0; x < bmp->width; x += 4)
985 unsigned char ch = *src++;
986 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
987 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
988 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
989 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
992 case FT_PIXEL_MODE_GRAY4:
993 dst += bytesPerPixel - 1; // shift to alpha byte
994 for (x = 0; x < bmp->width; x += 2)
996 unsigned char ch = *src++;
997 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
998 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1001 case FT_PIXEL_MODE_GRAY:
1002 // in this case pitch should equal width
1003 for (tp = 0; tp < bmp->pitch; ++tp)
1004 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1006 //memcpy((void*)dst, (void*)src, bmp->pitch);
1007 //dst += bmp->pitch;
1014 // now fill map->glyphs[ch - map->start]
1015 mapglyph = &map->glyphs[mapch];
1019 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1021 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1022 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1023 double advance = (glyph->advance.x >> 6) / map->size;
1024 double mWidth = (glyph->metrics.width >> 6) / map->size;
1025 double mHeight = (glyph->metrics.height >> 6) / map->size;
1027 mapglyph->vxmin = bearingX;
1028 mapglyph->vxmax = bearingX + mWidth;
1029 mapglyph->vymin = -bearingY;
1030 mapglyph->vymax = mHeight - bearingY;
1031 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1032 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1033 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1034 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1035 //mapglyph->advance_x = advance * usefont->size;
1036 mapglyph->advance_x = advance;
1037 mapglyph->advance_y = 0;
1039 if (developer.integer)
1041 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1042 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1043 if (ch >= 32 && ch <= 128)
1044 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
1045 Con_Printf("glyphinfo: Vertex info:\n");
1046 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1047 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1048 Con_Printf("glyphinfo: Texture info:\n");
1049 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1050 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1051 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1054 map->glyphs[mapch].image = false;
1057 // create a texture from the data now
1059 if (developer.integer)
1061 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1062 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1063 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1065 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1067 // probably use bytesPerPixel here instead?
1068 if (r_font_use_alpha_textures.integer)
1070 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1071 map->glyphSize * FONT_CHARS_PER_LINE,
1072 map->glyphSize * FONT_CHAR_LINES,
1073 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1075 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1076 map->glyphSize * FONT_CHARS_PER_LINE,
1077 map->glyphSize * FONT_CHAR_LINES,
1078 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1084 // if the first try isn't successful, keep it with a broken texture
1085 // otherwise we retry to load it every single frame where ft2 rendering is used
1086 // this would be bad...
1087 // only `data' must be freed
1088 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1089 font->name, mapstart->size, mapidx);
1097 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1099 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1101 // the first map must have been loaded already
1102 if (!font->font_maps[map_index])
1104 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1107 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1109 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1110 start = start->next;
1111 if (start && start->start > ch)