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, qboolean no_texture, qboolean no_kerning);
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))
315 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
320 for (s = 0; s < MAX_FONT_SIZES; ++s)
322 if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
327 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
332 // at least one size of the fallback font loaded successfully
339 for (s = 0; s < MAX_FONT_SIZES; ++s)
341 if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
346 // loading failed for every requested size
347 Font_UnloadFont(ft2);
353 //Con_Printf("%i sizes loaded\n", count);
358 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
361 char filename[PATH_MAX];
365 fs_offset_t datasize;
367 memset(font, 0, sizeof(*font));
369 if (!Font_OpenLibrary())
371 if (!r_font_disable_freetype.integer)
373 Con_Printf("WARNING: can't open load font %s\n"
374 "You need the FreeType2 DLL to load font files\n",
380 namelen = strlen(name);
382 memcpy(filename, name, namelen);
383 memcpy(filename + namelen, ".ttf", 5);
384 data = FS_LoadFile(filename, font_mempool, false, &datasize);
387 memcpy(filename + namelen, ".otf", 5);
388 data = FS_LoadFile(filename, font_mempool, false, &datasize);
392 ft2_attachment_t afm;
394 memcpy(filename + namelen, ".pfb", 5);
395 data = FS_LoadFile(filename, font_mempool, false, &datasize);
399 memcpy(filename + namelen, ".afm", 5);
400 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
403 Font_Attach(font, &afm);
409 // FS_LoadFile being not-quiet should print an error :)
412 Con_Printf("Loading font %s face %i...\n", filename, _face);
414 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
415 if (status && _face != 0)
417 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
419 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
423 Con_Printf("ERROR: can't create face for %s\n"
424 "Error %i\n", // TODO: error strings
426 Font_UnloadFont(font);
430 // add the attachments
431 for (i = 0; i < font->attachmentcount; ++i)
434 memset(&args, 0, sizeof(args));
435 args.flags = FT_OPEN_MEMORY;
436 args.memory_base = (const FT_Byte*)font->attachments[i].data;
437 args.memory_size = font->attachments[i].size;
438 if (qFT_Attach_Stream(font->face, &args))
439 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
442 memcpy(font->name, name, namelen+1);
443 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
447 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
448 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
451 ft2_font_map_t *fmap, temp;
458 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
463 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
465 if (!font->font_maps[map_index])
467 // if a similar size has already been loaded, ignore this one
468 //abs(font->font_maps[map_index]->size - size) < 4
469 if (font->font_maps[map_index]->size == size)
473 if (map_index >= MAX_FONT_SIZES)
476 memset(&temp, 0, sizeof(temp));
478 temp.glyphSize = CeilPowerOf2(size*2);
479 temp.sfx = (1.0/64.0)/(double)size;
480 temp.sfy = (1.0/64.0)/(double)size;
481 if (!Font_LoadMap(font, &temp, 0, &fmap))
483 Con_Printf("ERROR: can't load the first character map for %s\n"
486 Font_UnloadFont(font);
489 font->font_maps[map_index] = temp.next;
491 fmap->sfx = temp.sfx;
492 fmap->sfy = temp.sfy;
496 // load the default kerning vector:
497 if (font->has_kerning)
501 for (l = 0; l < 256; ++l)
503 for (r = 0; r < 256; ++r)
506 ul = qFT_Get_Char_Index(font->face, l);
507 ur = qFT_Get_Char_Index(font->face, r);
508 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
510 fmap->kerning.kerning[l][r][0] = 0;
511 fmap->kerning.kerning[l][r][1] = 0;
515 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
516 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
526 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
531 int matchsize = -10000;
535 ft2_font_map_t **maps = font->font_maps;
537 fsize = _fsize * vid.height / vid_conheight.value;
545 if (fsize - (float)size >= 0.49)
549 for (m = 0; m < MAX_FONT_SIZES; ++m)
553 // "round up" to the bigger size if two equally-valued matches exist
554 nval = abs(maps[m]->size - size);
555 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
559 matchsize = maps[m]->size;
560 if (value == 0) // there is no better match
566 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
567 if (outw) *outw = maps[match]->size * vid_conheight.value / vid.height * *outw / _fsize;
572 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
574 if (index < 0 || index >= MAX_FONT_SIZES)
576 return font->font_maps[index];
579 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
581 if (font->currenth == h &&
582 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
583 font->currentw == w)) // same size has been requested
587 // sorry, but freetype doesn't seem to care about other sizes
590 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
597 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
599 ft2_font_map_t *fmap;
600 if (!font->has_kerning)
602 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
604 fmap = font->font_maps[map_index];
607 if (left < 256 && right < 256)
609 // quick-kerning, be aware of the size: scale it
610 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
611 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
619 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
620 if (!Font_SetSize(font, w, h))
622 // this deserves an error message
623 Con_Printf("Failed to get kerning for %s\n", font->name);
626 ul = qFT_Get_Char_Index(font->face, left);
627 ur = qFT_Get_Char_Index(font->face, right);
628 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
630 if (outx) *outx = kernvec.x * fmap->sfx;
631 if (outy) *outy = kernvec.y * fmap->sfy;
638 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
640 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
643 static void UnloadMapRec(ft2_font_map_t *map)
647 R_FreeTexture(map->texture);
651 UnloadMapRec(map->next);
655 void Font_UnloadFont(ft2_font_t *font)
660 Mem_Free(font->data);
662 if (font->attachments && font->attachmentcount)
664 Mem_Free(font->attachments);
665 font->attachmentcount = 0;
666 font->attachments = NULL;
668 for (i = 0; i < MAX_FONT_SIZES; ++i)
670 if (font->font_maps[i])
672 UnloadMapRec(font->font_maps[i]);
673 font->font_maps[i] = NULL;
680 qFT_Done_Face((FT_Face)font->face);
686 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
688 char map_identifier[PATH_MAX];
689 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
696 int gR, gC; // glyph position: row and column
698 ft2_font_map_t *map, *next;
701 int bytesPerPixel = 4; // change the conversion loop too if you change this!
706 if (r_font_use_alpha_textures.integer)
709 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
711 if (!Font_SetSize(font, mapstart->size, mapstart->size))
713 Con_Printf("ERROR: can't set pixel sizes for font %s: %f\n", font->name, mapstart->size);
717 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
720 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
724 // copy over the information
725 map->size = mapstart->size;
726 map->glyphSize = mapstart->glyphSize;
727 map->sfx = mapstart->sfx;
728 map->sfy = mapstart->sfy;
730 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
731 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
734 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
739 // initialize as white texture with zero alpha
741 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
743 if (bytesPerPixel == 4)
753 map->start = mapidx * FONT_CHARS_PER_MAP;
755 while(next->next && next->next->start < map->start)
757 map->next = next->next;
762 for (ch = map->start;
763 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
770 unsigned char *imagedata, *dst, *src;
771 glyph_slot_t *mapglyph;
774 if (developer.integer)
775 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
778 if (gC >= FONT_CHARS_PER_LINE)
780 gC -= FONT_CHARS_PER_LINE;
784 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
785 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
786 // we need the glyphIndex
789 glyphIndex = qFT_Get_Char_Index(face, ch);
792 // by convention, 0 is the "missing-glyph"-glyph
793 // try to load from a fallback font
794 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
796 if (!Font_SetSize(usefont, mapstart->size, mapstart->size))
799 face = usefont->face;
800 glyphIndex = qFT_Get_Char_Index(face, ch);
803 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
810 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
811 // now we let it use the "missing-glyph"-glyph
821 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
824 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
825 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
830 /* obsolete when using FT_LOAD_RENDER
831 if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
833 status = qFT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
836 Con_Printf("failed to render glyph %lu for %s\n", glyphIndex, font->name);
843 bmp = &glyph->bitmap;
848 if (w > map->glyphSize || h > map->glyphSize) {
849 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
850 if (w > map->glyphSize)
852 if (h > map->glyphSize)
856 switch (bmp->pixel_mode)
858 case FT_PIXEL_MODE_MONO:
859 if (developer.integer)
860 Con_Print("glyphinfo: Pixel Mode: MONO\n");
862 case FT_PIXEL_MODE_GRAY2:
863 if (developer.integer)
864 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
866 case FT_PIXEL_MODE_GRAY4:
867 if (developer.integer)
868 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
870 case FT_PIXEL_MODE_GRAY:
871 if (developer.integer)
872 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
875 if (developer.integer)
876 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
878 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
881 for (y = 0; y < h; ++y)
883 dst = imagedata + y * pitch;
884 src = bmp->buffer + y * bmp->pitch;
886 switch (bmp->pixel_mode)
888 case FT_PIXEL_MODE_MONO:
889 dst += bytesPerPixel - 1; // shift to alpha byte
890 for (x = 0; x < bmp->width; x += 8)
892 unsigned char ch = *src++;
893 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
894 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
895 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
896 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
897 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
898 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
899 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
900 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
903 case FT_PIXEL_MODE_GRAY2:
904 dst += bytesPerPixel - 1; // shift to alpha byte
905 for (x = 0; x < bmp->width; x += 4)
907 unsigned char ch = *src++;
908 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
909 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
910 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
911 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
914 case FT_PIXEL_MODE_GRAY4:
915 dst += bytesPerPixel - 1; // shift to alpha byte
916 for (x = 0; x < bmp->width; x += 2)
918 unsigned char ch = *src++;
919 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
920 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
923 case FT_PIXEL_MODE_GRAY:
924 // in this case pitch should equal width
925 for (tp = 0; tp < bmp->pitch; ++tp)
926 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
928 //memcpy((void*)dst, (void*)src, bmp->pitch);
936 // now fill map->glyphs[ch - map->start]
937 mapch = ch - map->start;
938 mapglyph = &map->glyphs[mapch];
942 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
944 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
945 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
946 double advance = (glyph->advance.x >> 6) / map->size;
947 double mWidth = (glyph->metrics.width >> 6) / map->size;
948 double mHeight = (glyph->metrics.height >> 6) / map->size;
950 mapglyph->vxmin = bearingX;
951 mapglyph->vxmax = bearingX + mWidth;
952 mapglyph->vymin = -bearingY;
953 mapglyph->vymax = mHeight - bearingY;
954 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
955 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
956 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
957 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
958 //mapglyph->advance_x = advance * usefont->size;
959 mapglyph->advance_x = advance;
960 mapglyph->advance_y = 0;
962 if (developer.integer)
964 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
965 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
966 if (ch >= 32 && ch <= 128)
967 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
968 Con_Printf("glyphinfo: Vertex info:\n");
969 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
970 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
971 Con_Printf("glyphinfo: Texture info:\n");
972 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
973 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
974 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
979 // create a texture from the data now
981 if (developer.integer)
983 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
984 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
985 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
987 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
989 // probably use bytesPerPixel here instead?
990 if (r_font_use_alpha_textures.integer)
992 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
993 map->glyphSize * FONT_CHARS_PER_LINE,
994 map->glyphSize * FONT_CHAR_LINES,
995 data, TEXTYPE_ALPHA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
997 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
998 map->glyphSize * FONT_CHARS_PER_LINE,
999 map->glyphSize * FONT_CHAR_LINES,
1000 data, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_ALWAYSPRECACHE/* | TEXF_MIPMAP*/, NULL);
1006 // if the first try isn't successful, keep it with a broken texture
1007 // otherwise we retry to load it every single frame where ft2 rendering is used
1008 // this would be bad...
1009 // only `data' must be freed
1010 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1011 font->name, mapstart->size, mapidx);
1019 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1021 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1023 // the first map must have been loaded already
1024 if (!font->font_maps[map_index])
1026 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1029 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1031 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1032 start = start->next;
1033 if (start && start->start > ch)