1 /* FreeType 2 and UTF-8 encoding support for
8 #include "ft2_fontdefs.h"
11 ================================================================================
12 CVars introduced with the freetype extension
13 ================================================================================
16 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "0", "disable freetype support for fonts entirely"};
17 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"};
20 ================================================================================
21 Function definitions. Taken from the freetype2 headers.
22 ================================================================================
27 (*qFT_Init_FreeType)( FT_Library *alibrary );
29 (*qFT_Done_FreeType)( FT_Library library );
32 (*qFT_New_Face)( FT_Library library,
33 const char* filepathname,
38 (*qFT_New_Memory_Face)( FT_Library library,
39 const FT_Byte* file_base,
44 (*qFT_Done_Face)( FT_Face face );
46 (*qFT_Select_Size)( FT_Face face,
47 FT_Int strike_index );
49 (*qFT_Request_Size)( FT_Face face,
50 FT_Size_Request req );
52 (*qFT_Set_Char_Size)( FT_Face face,
53 FT_F26Dot6 char_width,
54 FT_F26Dot6 char_height,
55 FT_UInt horz_resolution,
56 FT_UInt vert_resolution );
58 (*qFT_Set_Pixel_Sizes)( FT_Face face,
60 FT_UInt pixel_height );
62 (*qFT_Load_Glyph)( FT_Face face,
64 FT_Int32 load_flags );
66 (*qFT_Load_Char)( FT_Face face,
68 FT_Int32 load_flags );
70 (*qFT_Get_Char_Index)( FT_Face face,
73 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
74 FT_Render_Mode render_mode );
76 (*qFT_Get_Kerning)( FT_Face face,
80 FT_Vector *akerning );
82 (*qFT_Attach_Stream)( FT_Face face,
83 FT_Open_Args* parameters );
85 ================================================================================
86 Support for dynamically loading the FreeType2 library
87 ================================================================================
90 static dllfunction_t ft2funcs[] =
92 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
93 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
94 //{"FT_New_Face", (void **) &qFT_New_Face},
95 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
96 {"FT_Done_Face", (void **) &qFT_Done_Face},
97 {"FT_Select_Size", (void **) &qFT_Select_Size},
98 {"FT_Request_Size", (void **) &qFT_Request_Size},
99 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
100 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
101 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
102 {"FT_Load_Char", (void **) &qFT_Load_Char},
103 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
104 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
105 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
106 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
110 /// Handle for FreeType2 DLL
111 static dllhandle_t ft2_dll = NULL;
113 /// Memory pool for fonts
114 static mempool_t *font_mempool= NULL;
115 static rtexturepool_t *font_texturepool = NULL;
117 /// FreeType library handle
118 static FT_Library font_ft2lib = NULL;
124 Unload the FreeType2 DLL
127 void Font_CloseLibrary (void)
130 Mem_FreePool(&font_mempool);
131 if (font_texturepool)
132 R_FreeTexturePool(&font_texturepool);
133 if (font_ft2lib && qFT_Done_FreeType)
135 qFT_Done_FreeType(font_ft2lib);
138 Sys_UnloadLibrary (&ft2_dll);
145 Try to load the FreeType2 DLL
148 qboolean Font_OpenLibrary (void)
150 const char* dllnames [] =
153 #error path for freetype 2 dll
155 #error path for freetype 2 dll
156 #elif defined(MACOSX)
165 if (r_font_disable_freetype.integer)
173 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
182 Initialize the freetype2 font subsystem
186 void font_start(void)
188 if (!Font_OpenLibrary())
191 if (qFT_Init_FreeType(&font_ft2lib))
193 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
198 font_mempool = Mem_AllocPool("FONT", 0, NULL);
201 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
206 font_texturepool = R_AllocTexturePool();
207 if (!font_texturepool)
209 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
215 if (!Font_LoadFont("gfx/test", 16, &test_font))
217 Con_Print("ERROR: Failed to load test font!\n");
224 void font_shutdown(void)
227 for (i = 0; i < MAX_FONTS; ++i)
231 Font_UnloadFont(dp_fonts[i].ft2);
232 dp_fonts[i].ft2 = NULL;
238 void font_newmap(void)
244 Cvar_RegisterVariable(&r_font_disable_freetype);
245 Cvar_RegisterVariable(&r_font_use_alpha_textures);
249 ================================================================================
250 Implementation of a more or less lazy font loading and rendering code.
251 ================================================================================
254 #include "ft2_fontdefs.h"
256 ft2_font_t *Font_Alloc(void)
260 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
263 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
265 ft2_attachment_t *na;
267 font->attachmentcount++;
268 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
271 if (font->attachments && font->attachmentcount > 1)
273 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
274 Mem_Free(font->attachments);
276 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
277 font->attachments = na;
281 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
282 static qboolean Font_LoadSize(ft2_font_t *font, float size);
283 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
286 ft2_font_t *ft2, *fbfont, *fb;
295 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
302 // attempt to load fallback fonts:
304 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
306 if (!dpfnt->fallbacks[i][0])
308 if (! (fb = Font_Alloc()) )
310 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
313 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
319 for (s = 0; s < MAX_FONT_SIZES; ++s)
321 if (Font_LoadSize(fb, dpfnt->req_sizes[s]))
330 // at least one size of the fallback font loaded successfully
337 for (s = 0; s < MAX_FONT_SIZES; ++s)
339 if (Font_LoadSize(ft2, dpfnt->req_sizes[s]))
344 // loading failed for every requested size
345 Font_UnloadFont(ft2);
351 //Con_Printf("%i sizes loaded\n", count);
356 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
359 char filename[PATH_MAX];
363 fs_offset_t datasize;
365 memset(font, 0, sizeof(*font));
367 if (!Font_OpenLibrary())
369 if (!r_font_disable_freetype.integer)
371 Con_Printf("WARNING: can't open load font %s\n"
372 "You need the FreeType2 DLL to load font files\n",
378 namelen = strlen(name);
380 memcpy(filename, name, namelen);
381 memcpy(filename + namelen, ".ttf", 5);
382 data = FS_LoadFile(filename, font_mempool, false, &datasize);
385 memcpy(filename + namelen, ".otf", 5);
386 data = FS_LoadFile(filename, font_mempool, false, &datasize);
390 ft2_attachment_t afm;
392 memcpy(filename + namelen, ".pfb", 5);
393 data = FS_LoadFile(filename, font_mempool, false, &datasize);
397 memcpy(filename + namelen, ".afm", 5);
398 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
401 Font_Attach(font, &afm);
407 // FS_LoadFile being not-quiet should print an error :)
410 Con_Printf("Loading font %s face %i...\n", filename, _face);
412 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
413 if (status && _face != 0)
415 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
417 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
421 Con_Printf("ERROR: can't create face for %s\n"
422 "Error %i\n", // TODO: error strings
424 Font_UnloadFont(font);
428 // add the attachments
429 for (i = 0; i < font->attachmentcount; ++i)
432 memset(&args, 0, sizeof(args));
433 args.flags = FT_OPEN_MEMORY;
434 args.memory_base = (const FT_Byte*)font->attachments[i].data;
435 args.memory_size = font->attachments[i].size;
436 if (qFT_Attach_Stream(font->face, &args))
437 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
440 memcpy(font->name, name, namelen+1);
442 //font->glyphSize = font->size * 2;
443 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
444 //font->sfx = (1.0/64.0) / (double)font->size;
445 //font->sfy = (1.0/64.0) / (double)font->size;
449 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
450 static qboolean Font_LoadSize(ft2_font_t *font, float size)
453 ft2_font_map_t *fmap, temp;
457 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
460 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
462 if (!font->font_maps[map_index])
464 // if a similar size has already been loaded, ignore this one
465 //abs(font->font_maps[map_index]->size - size) < 4
466 if (font->font_maps[map_index]->size == size)
470 if (map_index >= MAX_FONT_SIZES)
473 memset(&temp, 0, sizeof(temp));
475 temp.glyphSize = CeilPowerOf2(size*2);
476 temp.sfx = (1.0/64.0)/(double)size;
477 temp.sfy = (1.0/64.0)/(double)size;
478 if (!Font_LoadMap(font, &temp, 0, &fmap))
480 Con_Printf("ERROR: can't load the first character map for %s\n"
483 Font_UnloadFont(font);
486 font->font_maps[map_index] = temp.next;
488 fmap->sfx = temp.sfx;
489 fmap->sfy = temp.sfy;
491 // load the default kerning vector:
492 if (font->has_kerning)
496 for (l = 0; l < 256; ++l)
498 for (r = 0; r < 256; ++r)
501 ul = qFT_Get_Char_Index(font->face, l);
502 ur = qFT_Get_Char_Index(font->face, r);
503 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
505 fmap->kerning.kerning[l][r][0] = 0;
506 fmap->kerning.kerning[l][r][1] = 0;
510 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
511 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
520 int Font_IndexForSize(ft2_font_t *font, float fsize)
525 int matchsize = -10000;
528 ft2_font_map_t **maps = font->font_maps;
530 fsize = fsize * vid.height / vid_conheight.value;
538 if (fsize - (float)size >= 0.49)
542 for (m = 0; m < MAX_FONT_SIZES; ++m)
546 // "round up" to the bigger size if two equally-valued matches exist
547 nval = abs(maps[m]->size - size);
548 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
552 matchsize = maps[m]->size;
553 if (value == 0) // there is no better match
556 if (fsize != -1 && (fsize < 4.591 || fsize > 4.5914))
557 Con_Printf(" %f -> %i [%i]\n", fsize, match, matchsize);
564 if (fsize != -1 && (fsize < 4.591 || fsize > 4.5914))
565 Con_Printf(" %f -> %i [%i]\n", fsize, match, matchsize);
570 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
572 if (index < 0 || index >= MAX_FONT_SIZES)
574 return font->font_maps[index];
577 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
579 if (qFT_Set_Char_Size((FT_Face)font->face, w*64, h*64, 72, 72))
584 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
586 ft2_font_map_t *fmap;
587 if (!font->has_kerning)
589 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
591 fmap = font->font_maps[map_index];
594 if (left < 256 && right < 256)
596 // quick-kerning, be aware of the size: scale it
597 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
598 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
606 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
607 if (!Font_SetSize(font, w, h))
609 // this deserves an error message
610 Con_Printf("Failed to get kerning for %s\n", font->name);
613 ul = qFT_Get_Char_Index(font->face, left);
614 ur = qFT_Get_Char_Index(font->face, right);
615 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
617 if (outx) *outx = kernvec.x * fmap->sfx;
618 if (outy) *outy = kernvec.y * fmap->sfy;
625 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
627 return Font_GetKerningForMap(font, Font_IndexForSize(font, h), w, h, left, right, outx, outy);
630 static void UnloadMapRec(ft2_font_map_t *map)
634 R_FreeTexture(map->texture);
638 UnloadMapRec(map->next);
642 void Font_UnloadFont(ft2_font_t *font)
647 Mem_Free(font->data);
649 if (font->attachments && font->attachmentcount)
651 Mem_Free(font->attachments);
652 font->attachmentcount = 0;
653 font->attachments = NULL;
655 for (i = 0; i < MAX_FONT_SIZES; ++i)
657 if (font->font_maps[i])
659 UnloadMapRec(font->font_maps[i]);
660 font->font_maps[i] = NULL;
667 qFT_Done_Face((FT_Face)font->face);
673 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
675 char map_identifier[PATH_MAX];
676 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
682 FT_Face face = font->face;
685 int gR, gC; // glyph position: row and column
687 ft2_font_map_t *map, *next;
689 int bytesPerPixel = 4; // change the conversion loop too if you change this!
694 if (r_font_use_alpha_textures.integer)
697 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
699 if (!Font_SetSize(font, mapstart->size, mapstart->size))
701 Con_Printf("ERROR: can't set pixel sizes for font %s\n", font->name);
705 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
708 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
712 // copy over the information
713 map->size = mapstart->size;
714 map->glyphSize = mapstart->glyphSize;
715 map->sfx = mapstart->sfx;
716 map->sfy = mapstart->sfy;
718 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
719 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
722 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
727 // initialize as white texture with zero alpha
729 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
731 if (bytesPerPixel == 4)
741 map->start = mapidx * FONT_CHARS_PER_MAP;
743 while(next->next && next->next->start < map->start)
745 map->next = next->next;
750 for (ch = map->start;
751 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
754 //FT_ULong glyphIndex;
758 unsigned char *imagedata, *dst, *src;
759 glyph_slot_t *mapglyph;
761 if (developer.integer)
762 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
765 if (gC >= FONT_CHARS_PER_LINE)
767 gC -= FONT_CHARS_PER_LINE;
771 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
772 //glyphIndex = qFT_Get_Char_Index(face, ch);
773 //status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
774 status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
777 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
778 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
782 /* obsolete when using FT_LOAD_RENDER
783 if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
785 status = qFT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
788 Con_Printf("failed to render glyph %lu for %s\n", glyphIndex, font->name);
795 bmp = &glyph->bitmap;
800 if (w > map->glyphSize || h > map->glyphSize) {
801 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
802 if (w > map->glyphSize)
804 if (h > map->glyphSize)
808 switch (bmp->pixel_mode)
810 case FT_PIXEL_MODE_MONO:
811 if (developer.integer)
812 Con_Print("glyphinfo: Pixel Mode: MONO\n");
814 case FT_PIXEL_MODE_GRAY2:
815 if (developer.integer)
816 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
818 case FT_PIXEL_MODE_GRAY4:
819 if (developer.integer)
820 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
822 case FT_PIXEL_MODE_GRAY:
823 if (developer.integer)
824 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
827 if (developer.integer)
828 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
832 for (y = 0; y < h; ++y)
834 dst = imagedata + y * pitch;
835 src = bmp->buffer + y * bmp->pitch;
837 switch (bmp->pixel_mode)
839 case FT_PIXEL_MODE_MONO:
840 dst += bytesPerPixel - 1; // shift to alpha byte
841 for (x = 0; x < bmp->width; x += 8)
843 unsigned char ch = *src++;
844 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
845 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
846 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
847 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
848 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
849 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
850 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
851 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
854 case FT_PIXEL_MODE_GRAY2:
855 dst += bytesPerPixel - 1; // shift to alpha byte
856 for (x = 0; x < bmp->width; x += 4)
858 unsigned char ch = *src++;
859 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
860 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
861 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
862 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
865 case FT_PIXEL_MODE_GRAY4:
866 dst += bytesPerPixel - 1; // shift to alpha byte
867 for (x = 0; x < bmp->width; x += 2)
869 unsigned char ch = *src++;
870 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
871 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
874 case FT_PIXEL_MODE_GRAY:
875 // in this case pitch should equal width
876 for (tp = 0; tp < bmp->pitch; ++tp)
877 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
879 //memcpy((void*)dst, (void*)src, bmp->pitch);
887 // now fill map->glyphs[ch - map->start]
888 mapch = ch - map->start;
889 mapglyph = &map->glyphs[mapch];
893 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
895 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
896 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
897 double advance = (glyph->advance.x >> 6) / map->size;
898 double mWidth = (glyph->metrics.width >> 6) / map->size;
899 double mHeight = (glyph->metrics.height >> 6) / map->size;
901 mapglyph->vxmin = bearingX;
902 mapglyph->vxmax = bearingX + mWidth;
903 mapglyph->vymin = -bearingY;
904 mapglyph->vymax = mHeight - bearingY;
905 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
906 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
907 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
908 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
909 //mapglyph->advance_x = advance * font->size;
910 mapglyph->advance_x = advance;
911 mapglyph->advance_y = 0;
913 if (developer.integer)
915 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
916 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
917 if (ch >= 32 && ch <= 128)
918 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
919 Con_Printf("glyphinfo: Vertex info:\n");
920 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
921 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
922 Con_Printf("glyphinfo: Texture info:\n");
923 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
924 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
925 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
930 // create a texture from the data now
932 if (developer.integer)
934 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
935 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
936 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
938 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
940 // probably use bytesPerPixel here instead?
941 if (r_font_use_alpha_textures.integer)
943 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
944 map->glyphSize * FONT_CHARS_PER_LINE,
945 map->glyphSize * FONT_CHAR_LINES,
946 data, TEXTYPE_ALPHA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
948 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
949 map->glyphSize * FONT_CHARS_PER_LINE,
950 map->glyphSize * FONT_CHAR_LINES,
951 data, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
957 // if the first try isn't successful, keep it with a broken texture
958 // otherwise we retry to load it every single frame where ft2 rendering is used
959 // this would be bad...
960 // only `data' must be freed
968 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
970 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
972 // the first map must have been loaded already
973 if (!font->font_maps[map_index])
975 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);