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_autohinting = {CVAR_SAVE, "r_font_autohinting", "1", "enable autohinting if possible"};
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_autohinting);
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;
784 if (r_font_autohinting.integer == 0)
785 load_flags = FT_LOAD_NO_AUTOHINT;
786 if (r_font_autohinting.integer <= -1)
787 load_flags |= FT_LOAD_NO_HINTING;
788 if (r_font_autohinting.integer <= -2)
789 load_flags |= FT_LOAD_NO_AUTOHINT;
791 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
793 if (font->image_font && mapstart->intSize < 0)
794 mapstart->intSize = mapstart->size;
795 if (mapstart->intSize < 0)
797 mapstart->intSize = mapstart->size;
800 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
802 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
805 if ((fontface->size->metrics.height>>6) <= mapstart->size)
807 if (mapstart->intSize < 2)
809 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
814 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
817 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
819 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
823 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
826 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
830 // copy over the information
831 map->size = mapstart->size;
832 map->intSize = mapstart->intSize;
833 map->glyphSize = mapstart->glyphSize;
834 map->sfx = mapstart->sfx;
835 map->sfy = mapstart->sfy;
837 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
838 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
841 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
846 // initialize as white texture with zero alpha
848 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
850 if (bytesPerPixel == 4)
860 map->start = mapidx * FONT_CHARS_PER_MAP;
862 while(next->next && next->next->start < map->start)
864 map->next = next->next;
869 for (ch = map->start;
870 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
877 unsigned char *imagedata, *dst, *src;
878 glyph_slot_t *mapglyph;
881 mapch = ch - map->start;
883 if (developer_extra.integer)
884 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
887 if (gC >= FONT_CHARS_PER_LINE)
889 gC -= FONT_CHARS_PER_LINE;
893 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
894 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
895 // we need the glyphIndex
898 if (font->image_font && mapch == ch && img_fontmap[mapch])
900 map->glyphs[mapch].image = true;
903 glyphIndex = qFT_Get_Char_Index(face, ch);
906 // by convention, 0 is the "missing-glyph"-glyph
907 // try to load from a fallback font
908 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
910 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
913 face = usefont->face;
914 glyphIndex = qFT_Get_Char_Index(face, ch);
917 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
924 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
925 // now we let it use the "missing-glyph"-glyph
935 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
938 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
939 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
945 bmp = &glyph->bitmap;
950 if (w > map->glyphSize || h > map->glyphSize) {
951 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
952 if (w > map->glyphSize)
954 if (h > map->glyphSize)
958 switch (bmp->pixel_mode)
960 case FT_PIXEL_MODE_MONO:
961 if (developer_extra.integer)
962 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
964 case FT_PIXEL_MODE_GRAY2:
965 if (developer_extra.integer)
966 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
968 case FT_PIXEL_MODE_GRAY4:
969 if (developer_extra.integer)
970 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
972 case FT_PIXEL_MODE_GRAY:
973 if (developer_extra.integer)
974 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
977 if (developer_extra.integer)
978 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
980 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
983 for (y = 0; y < h; ++y)
985 dst = imagedata + y * pitch;
986 src = bmp->buffer + y * bmp->pitch;
988 switch (bmp->pixel_mode)
990 case FT_PIXEL_MODE_MONO:
991 dst += bytesPerPixel - 1; // shift to alpha byte
992 for (x = 0; x < bmp->width; x += 8)
994 unsigned char ch = *src++;
995 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
996 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
997 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
998 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
999 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
1000 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
1001 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
1002 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
1005 case FT_PIXEL_MODE_GRAY2:
1006 dst += bytesPerPixel - 1; // shift to alpha byte
1007 for (x = 0; x < bmp->width; x += 4)
1009 unsigned char ch = *src++;
1010 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1011 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1012 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1013 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
1016 case FT_PIXEL_MODE_GRAY4:
1017 dst += bytesPerPixel - 1; // shift to alpha byte
1018 for (x = 0; x < bmp->width; x += 2)
1020 unsigned char ch = *src++;
1021 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
1022 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
1025 case FT_PIXEL_MODE_GRAY:
1026 // in this case pitch should equal width
1027 for (tp = 0; tp < bmp->pitch; ++tp)
1028 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1030 //memcpy((void*)dst, (void*)src, bmp->pitch);
1031 //dst += bmp->pitch;
1038 // now fill map->glyphs[ch - map->start]
1039 mapglyph = &map->glyphs[mapch];
1043 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1045 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1046 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1047 double advance = (glyph->advance.x >> 6) / map->size;
1048 double mWidth = (glyph->metrics.width >> 6) / map->size;
1049 double mHeight = (glyph->metrics.height >> 6) / map->size;
1051 mapglyph->vxmin = bearingX;
1052 mapglyph->vxmax = bearingX + mWidth;
1053 mapglyph->vymin = -bearingY;
1054 mapglyph->vymax = mHeight - bearingY;
1055 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1056 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1057 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1058 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1059 //mapglyph->advance_x = advance * usefont->size;
1060 mapglyph->advance_x = advance;
1061 mapglyph->advance_y = 0;
1063 if (developer_extra.integer)
1065 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1066 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1067 if (ch >= 32 && ch <= 128)
1068 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1069 Con_DPrintf("glyphinfo: Vertex info:\n");
1070 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1071 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1072 Con_DPrintf("glyphinfo: Texture info:\n");
1073 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1074 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1075 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1078 map->glyphs[mapch].image = false;
1081 // create a texture from the data now
1083 if (developer_extra.integer)
1085 // LordHavoc: why are we writing this? And why not write it as TGA using the appropriate function?
1086 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1087 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1088 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1090 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1092 // probably use bytesPerPixel here instead?
1093 if (r_font_use_alpha_textures.integer)
1095 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1096 map->glyphSize * FONT_CHARS_PER_LINE,
1097 map->glyphSize * FONT_CHAR_LINES,
1098 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1100 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1101 map->glyphSize * FONT_CHARS_PER_LINE,
1102 map->glyphSize * FONT_CHAR_LINES,
1103 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1109 // if the first try isn't successful, keep it with a broken texture
1110 // otherwise we retry to load it every single frame where ft2 rendering is used
1111 // this would be bad...
1112 // only `data' must be freed
1113 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1114 font->name, mapstart->size, mapidx);
1122 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1124 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1126 // the first map must have been loaded already
1127 if (!font->font_maps[map_index])
1129 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1132 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1134 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1135 start = start->next;
1136 if (start && start->start > ch)