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", "2", "0 = no hinting, 1 = force autohinting, 2 = full hinting"};
41 ================================================================================
42 Function definitions. Taken from the freetype2 headers.
43 ================================================================================
48 (*qFT_Init_FreeType)( FT_Library *alibrary );
50 (*qFT_Done_FreeType)( FT_Library library );
53 (*qFT_New_Face)( FT_Library library,
54 const char* filepathname,
59 (*qFT_New_Memory_Face)( FT_Library library,
60 const FT_Byte* file_base,
65 (*qFT_Done_Face)( FT_Face face );
67 (*qFT_Select_Size)( FT_Face face,
68 FT_Int strike_index );
70 (*qFT_Request_Size)( FT_Face face,
71 FT_Size_Request req );
73 (*qFT_Set_Char_Size)( FT_Face face,
74 FT_F26Dot6 char_width,
75 FT_F26Dot6 char_height,
76 FT_UInt horz_resolution,
77 FT_UInt vert_resolution );
79 (*qFT_Set_Pixel_Sizes)( FT_Face face,
81 FT_UInt pixel_height );
83 (*qFT_Load_Glyph)( FT_Face face,
85 FT_Int32 load_flags );
87 (*qFT_Load_Char)( FT_Face face,
89 FT_Int32 load_flags );
91 (*qFT_Get_Char_Index)( FT_Face face,
94 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
95 FT_Render_Mode render_mode );
97 (*qFT_Get_Kerning)( FT_Face face,
101 FT_Vector *akerning );
102 FT_EXPORT( FT_Error )
103 (*qFT_Attach_Stream)( FT_Face face,
104 FT_Open_Args* parameters );
106 ================================================================================
107 Support for dynamically loading the FreeType2 library
108 ================================================================================
111 static dllfunction_t ft2funcs[] =
113 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
114 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
115 //{"FT_New_Face", (void **) &qFT_New_Face},
116 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
117 {"FT_Done_Face", (void **) &qFT_Done_Face},
118 {"FT_Select_Size", (void **) &qFT_Select_Size},
119 {"FT_Request_Size", (void **) &qFT_Request_Size},
120 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
121 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
122 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
123 {"FT_Load_Char", (void **) &qFT_Load_Char},
124 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
125 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
126 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
127 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
131 /// Handle for FreeType2 DLL
132 static dllhandle_t ft2_dll = NULL;
134 /// Memory pool for fonts
135 static mempool_t *font_mempool= NULL;
136 static rtexturepool_t *font_texturepool = NULL;
138 /// FreeType library handle
139 static FT_Library font_ft2lib = NULL;
145 Unload the FreeType2 DLL
148 void Font_CloseLibrary (void)
151 Mem_FreePool(&font_mempool);
152 if (font_texturepool)
153 R_FreeTexturePool(&font_texturepool);
154 if (font_ft2lib && qFT_Done_FreeType)
156 qFT_Done_FreeType(font_ft2lib);
159 Sys_UnloadLibrary (&ft2_dll);
166 Try to load the FreeType2 DLL
169 qboolean Font_OpenLibrary (void)
171 const char* dllnames [] =
175 #elif defined(MACOSX)
184 if (r_font_disable_freetype.integer)
192 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
201 Initialize the freetype2 font subsystem
205 void font_start(void)
207 if (!Font_OpenLibrary())
210 if (qFT_Init_FreeType(&font_ft2lib))
212 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
217 font_mempool = Mem_AllocPool("FONT", 0, NULL);
220 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
225 font_texturepool = R_AllocTexturePool();
226 if (!font_texturepool)
228 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
234 void font_shutdown(void)
237 for (i = 0; i < MAX_FONTS; ++i)
241 Font_UnloadFont(dp_fonts[i].ft2);
242 dp_fonts[i].ft2 = NULL;
248 void font_newmap(void)
254 Cvar_RegisterVariable(&r_font_disable_freetype);
255 Cvar_RegisterVariable(&r_font_use_alpha_textures);
256 Cvar_RegisterVariable(&r_font_size_snapping);
257 Cvar_RegisterVariable(&r_font_hinting);
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 float Font_VirtualToRealSize(float sz)
299 vw = ((vid.width > 0) ? vid.width : vid_width.value);
300 vh = ((vid.height > 0) ? vid.height : vid_height.value);
301 // now try to scale to our actual size:
302 sn = sz * vh / vid_conheight.value;
304 if ( sn - (float)si >= 0.5 )
309 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
310 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
311 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
314 ft2_font_t *ft2, *fbfont, *fb;
323 // check if a fallback font has been specified, if it has been, and the
324 // font fails to load, use the image font as main font
325 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
327 if (dpfnt->fallbacks[i][0])
331 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
333 if (i >= MAX_FONT_FALLBACKS)
339 strlcpy(ft2->name, name, sizeof(ft2->name));
340 ft2->image_font = true;
341 ft2->has_kerning = false;
345 ft2->image_font = false;
348 // attempt to load fallback fonts:
350 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
352 if (!dpfnt->fallbacks[i][0])
354 if (! (fb = Font_Alloc()) )
356 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
359 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
361 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
366 for (s = 0; s < MAX_FONT_SIZES; ++s)
368 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false))
373 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
378 // at least one size of the fallback font loaded successfully
384 if (fbfont == ft2 && ft2->image_font)
386 // no fallbacks were loaded successfully:
393 for (s = 0; s < MAX_FONT_SIZES; ++s)
395 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false))
400 // loading failed for every requested size
401 Font_UnloadFont(ft2);
407 //Con_Printf("%i sizes loaded\n", count);
412 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
415 char filename[MAX_QPATH];
419 fs_offset_t datasize;
421 memset(font, 0, sizeof(*font));
423 if (!Font_OpenLibrary())
425 if (!r_font_disable_freetype.integer)
427 Con_Printf("WARNING: can't open load font %s\n"
428 "You need the FreeType2 DLL to load font files\n",
434 namelen = strlen(name);
436 memcpy(filename, name, namelen);
437 memcpy(filename + namelen, ".ttf", 5);
438 data = FS_LoadFile(filename, font_mempool, false, &datasize);
441 memcpy(filename + namelen, ".otf", 5);
442 data = FS_LoadFile(filename, font_mempool, false, &datasize);
446 ft2_attachment_t afm;
448 memcpy(filename + namelen, ".pfb", 5);
449 data = FS_LoadFile(filename, font_mempool, false, &datasize);
453 memcpy(filename + namelen, ".afm", 5);
454 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
457 Font_Attach(font, &afm);
463 // FS_LoadFile being not-quiet should print an error :)
466 Con_Printf("Loading font %s face %i...\n", filename, _face);
468 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
469 if (status && _face != 0)
471 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
473 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
477 Con_Printf("ERROR: can't create face for %s\n"
478 "Error %i\n", // TODO: error strings
480 Font_UnloadFont(font);
484 // add the attachments
485 for (i = 0; i < font->attachmentcount; ++i)
488 memset(&args, 0, sizeof(args));
489 args.flags = FT_OPEN_MEMORY;
490 args.memory_base = (const FT_Byte*)font->attachments[i].data;
491 args.memory_size = font->attachments[i].size;
492 if (qFT_Attach_Stream(font->face, &args))
493 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
496 memcpy(font->name, name, namelen+1);
497 font->image_font = false;
498 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
502 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
503 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
506 ft2_font_map_t *fmap, temp;
508 if (!(size > 0.001f && size < 1000.0f))
513 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
518 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
520 if (!font->font_maps[map_index])
522 // if a similar size has already been loaded, ignore this one
523 //abs(font->font_maps[map_index]->size - size) < 4
524 if (font->font_maps[map_index]->size == size)
528 if (map_index >= MAX_FONT_SIZES)
531 memset(&temp, 0, sizeof(temp));
533 temp.glyphSize = CeilPowerOf2(size*2);
534 temp.sfx = (1.0/64.0)/(double)size;
535 temp.sfy = (1.0/64.0)/(double)size;
536 temp.intSize = -1; // negative value: LoadMap must search now :)
537 if (!Font_LoadMap(font, &temp, 0, &fmap))
539 Con_Printf("ERROR: can't load the first character map for %s\n"
542 Font_UnloadFont(font);
545 font->font_maps[map_index] = temp.next;
547 fmap->sfx = temp.sfx;
548 fmap->sfy = temp.sfy;
552 // load the default kerning vector:
553 if (font->has_kerning)
557 for (l = 0; l < 256; ++l)
559 for (r = 0; r < 256; ++r)
562 ul = qFT_Get_Char_Index(font->face, l);
563 ur = qFT_Get_Char_Index(font->face, r);
564 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
566 fmap->kerning.kerning[l][r][0] = 0;
567 fmap->kerning.kerning[l][r][1] = 0;
571 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
572 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
582 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
587 int matchsize = -10000;
591 ft2_font_map_t **maps = font->font_maps;
593 fsize = _fsize * vid.height / vid_conheight.value;
601 if (fsize - (float)size >= 0.49)
605 for (m = 0; m < MAX_FONT_SIZES; ++m)
609 // "round up" to the bigger size if two equally-valued matches exist
610 nval = abs(maps[m]->size - size);
611 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
615 matchsize = maps[m]->size;
616 if (value == 0) // there is no better match
620 if (value <= r_font_size_snapping.value)
624 if (!*outh) *outh = *outw;
625 if (!*outw) *outw = *outh;
628 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
629 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
634 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
636 if (index < 0 || index >= MAX_FONT_SIZES)
638 return font->font_maps[index];
641 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
643 if (font->currenth == h &&
644 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
645 font->currentw == w)) // same size has been requested
649 // sorry, but freetype doesn't seem to care about other sizes
652 if (font->image_font)
654 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
659 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
667 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
669 ft2_font_map_t *fmap;
670 if (!font->has_kerning)
672 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
674 fmap = font->font_maps[map_index];
677 if (left < 256 && right < 256)
679 // quick-kerning, be aware of the size: scale it
680 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
681 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
689 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
690 if (!Font_SetSize(font, w, h))
692 // this deserves an error message
693 Con_Printf("Failed to get kerning for %s\n", font->name);
696 ul = qFT_Get_Char_Index(font->face, left);
697 ur = qFT_Get_Char_Index(font->face, right);
698 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
700 if (outx) *outx = kernvec.x * fmap->sfx;
701 if (outy) *outy = kernvec.y * fmap->sfy;
708 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
710 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
713 static void UnloadMapRec(ft2_font_map_t *map)
717 R_FreeTexture(map->texture);
721 UnloadMapRec(map->next);
725 void Font_UnloadFont(ft2_font_t *font)
728 if (font->attachments && font->attachmentcount)
730 Mem_Free(font->attachments);
731 font->attachmentcount = 0;
732 font->attachments = NULL;
734 for (i = 0; i < MAX_FONT_SIZES; ++i)
736 if (font->font_maps[i])
738 UnloadMapRec(font->font_maps[i]);
739 font->font_maps[i] = NULL;
746 qFT_Done_Face((FT_Face)font->face);
752 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
754 char map_identifier[MAX_QPATH];
755 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
763 int gR, gC; // glyph position: row and column
765 ft2_font_map_t *map, *next;
770 int bytesPerPixel = 4; // change the conversion loop too if you change this!
775 if (r_font_use_alpha_textures.integer)
778 if (font->image_font)
779 fontface = (FT_Face)font->next->face;
781 fontface = (FT_Face)font->face;
783 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
784 if (r_font_hinting.integer == 1)
785 load_flags = FT_LOAD_FORCE_AUTOHINT;
786 else if (r_font_hinting.integer == 2)
789 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
791 if (font->image_font && mapstart->intSize < 0)
792 mapstart->intSize = mapstart->size;
793 if (mapstart->intSize < 0)
795 mapstart->intSize = mapstart->size;
798 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
800 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
803 if ((fontface->size->metrics.height>>6) <= mapstart->size)
805 if (mapstart->intSize < 2)
807 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
812 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
815 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
817 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
821 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
824 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
828 // copy over the information
829 map->size = mapstart->size;
830 map->intSize = mapstart->intSize;
831 map->glyphSize = mapstart->glyphSize;
832 map->sfx = mapstart->sfx;
833 map->sfy = mapstart->sfy;
835 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
836 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
839 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
844 // initialize as white texture with zero alpha
846 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
848 if (bytesPerPixel == 4)
858 map->start = mapidx * FONT_CHARS_PER_MAP;
860 while(next->next && next->next->start < map->start)
862 map->next = next->next;
867 for (ch = map->start;
868 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
875 unsigned char *imagedata, *dst, *src;
876 glyph_slot_t *mapglyph;
879 mapch = ch - map->start;
881 if (developer_extra.integer)
882 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
885 if (gC >= FONT_CHARS_PER_LINE)
887 gC -= FONT_CHARS_PER_LINE;
891 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
892 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
893 // we need the glyphIndex
896 if (font->image_font && mapch == ch && img_fontmap[mapch])
898 map->glyphs[mapch].image = true;
901 glyphIndex = qFT_Get_Char_Index(face, ch);
904 // by convention, 0 is the "missing-glyph"-glyph
905 // try to load from a fallback font
906 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
908 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
911 face = usefont->face;
912 glyphIndex = qFT_Get_Char_Index(face, ch);
915 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
922 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
923 // now we let it use the "missing-glyph"-glyph
933 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
936 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
937 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
943 bmp = &glyph->bitmap;
948 if (w > map->glyphSize || h > map->glyphSize) {
949 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
950 if (w > map->glyphSize)
952 if (h > map->glyphSize)
956 switch (bmp->pixel_mode)
958 case FT_PIXEL_MODE_MONO:
959 if (developer_extra.integer)
960 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
962 case FT_PIXEL_MODE_GRAY2:
963 if (developer_extra.integer)
964 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
966 case FT_PIXEL_MODE_GRAY4:
967 if (developer_extra.integer)
968 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
970 case FT_PIXEL_MODE_GRAY:
971 if (developer_extra.integer)
972 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
975 if (developer_extra.integer)
976 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
978 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
981 for (y = 0; y < h; ++y)
983 dst = imagedata + y * pitch;
984 src = bmp->buffer + y * bmp->pitch;
986 switch (bmp->pixel_mode)
988 case FT_PIXEL_MODE_MONO:
989 dst += bytesPerPixel - 1; // shift to alpha byte
990 for (x = 0; x < bmp->width; x += 8)
992 unsigned char ch = *src++;
993 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
994 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
995 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
996 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
997 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
998 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
999 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
1000 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
1003 case FT_PIXEL_MODE_GRAY2:
1004 dst += bytesPerPixel - 1; // shift to alpha byte
1005 for (x = 0; x < bmp->width; x += 4)
1007 unsigned char ch = *src++;
1008 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1009 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1010 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1011 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1014 case FT_PIXEL_MODE_GRAY4:
1015 dst += bytesPerPixel - 1; // shift to alpha byte
1016 for (x = 0; x < bmp->width; x += 2)
1018 unsigned char ch = *src++;
1019 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1020 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1023 case FT_PIXEL_MODE_GRAY:
1024 // in this case pitch should equal width
1025 for (tp = 0; tp < bmp->pitch; ++tp)
1026 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1028 //memcpy((void*)dst, (void*)src, bmp->pitch);
1029 //dst += bmp->pitch;
1036 // now fill map->glyphs[ch - map->start]
1037 mapglyph = &map->glyphs[mapch];
1041 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1043 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1044 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1045 double advance = (glyph->advance.x >> 6) / map->size;
1046 double mWidth = (glyph->metrics.width >> 6) / map->size;
1047 double mHeight = (glyph->metrics.height >> 6) / map->size;
1049 mapglyph->vxmin = bearingX;
1050 mapglyph->vxmax = bearingX + mWidth;
1051 mapglyph->vymin = -bearingY;
1052 mapglyph->vymax = mHeight - bearingY;
1053 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1054 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1055 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1056 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1057 //mapglyph->advance_x = advance * usefont->size;
1058 mapglyph->advance_x = advance;
1059 mapglyph->advance_y = 0;
1061 if (developer_extra.integer)
1063 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1064 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1065 if (ch >= 32 && ch <= 128)
1066 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1067 Con_DPrintf("glyphinfo: Vertex info:\n");
1068 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1069 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1070 Con_DPrintf("glyphinfo: Texture info:\n");
1071 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1072 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1073 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1076 map->glyphs[mapch].image = false;
1079 // create a texture from the data now
1081 if (developer_extra.integer)
1083 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1084 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1085 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1086 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1088 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1090 // probably use bytesPerPixel here instead?
1091 if (r_font_use_alpha_textures.integer)
1093 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1094 map->glyphSize * FONT_CHARS_PER_LINE,
1095 map->glyphSize * FONT_CHAR_LINES,
1096 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1098 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1099 map->glyphSize * FONT_CHARS_PER_LINE,
1100 map->glyphSize * FONT_CHAR_LINES,
1101 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1107 // if the first try isn't successful, keep it with a broken texture
1108 // otherwise we retry to load it every single frame where ft2 rendering is used
1109 // this would be bad...
1110 // only `data' must be freed
1111 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1112 font->name, mapstart->size, mapidx);
1120 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1122 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1124 // the first map must have been loaded already
1125 if (!font->font_maps[map_index])
1127 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1130 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1132 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1133 start = start->next;
1134 if (start && start->start > ch)