1 /* FreeType 2 and UTF-8 encoding support for
8 #include "ft2_fontdefs.h"
10 static int img_fontmap[256] = {
11 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
12 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
13 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
14 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
15 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
16 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps
17 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
18 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
30 ================================================================================
31 CVars introduced with the freetype extension
32 ================================================================================
35 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
36 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
37 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
40 ================================================================================
41 Function definitions. Taken from the freetype2 headers.
42 ================================================================================
47 (*qFT_Init_FreeType)( FT_Library *alibrary );
49 (*qFT_Done_FreeType)( FT_Library library );
52 (*qFT_New_Face)( FT_Library library,
53 const char* filepathname,
58 (*qFT_New_Memory_Face)( FT_Library library,
59 const FT_Byte* file_base,
64 (*qFT_Done_Face)( FT_Face face );
66 (*qFT_Select_Size)( FT_Face face,
67 FT_Int strike_index );
69 (*qFT_Request_Size)( FT_Face face,
70 FT_Size_Request req );
72 (*qFT_Set_Char_Size)( FT_Face face,
73 FT_F26Dot6 char_width,
74 FT_F26Dot6 char_height,
75 FT_UInt horz_resolution,
76 FT_UInt vert_resolution );
78 (*qFT_Set_Pixel_Sizes)( FT_Face face,
80 FT_UInt pixel_height );
82 (*qFT_Load_Glyph)( FT_Face face,
84 FT_Int32 load_flags );
86 (*qFT_Load_Char)( FT_Face face,
88 FT_Int32 load_flags );
90 (*qFT_Get_Char_Index)( FT_Face face,
93 (*qFT_Render_Glyph)( FT_GlyphSlot slot,
94 FT_Render_Mode render_mode );
96 (*qFT_Get_Kerning)( FT_Face face,
100 FT_Vector *akerning );
101 FT_EXPORT( FT_Error )
102 (*qFT_Attach_Stream)( FT_Face face,
103 FT_Open_Args* parameters );
105 ================================================================================
106 Support for dynamically loading the FreeType2 library
107 ================================================================================
110 static dllfunction_t ft2funcs[] =
112 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
113 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
114 //{"FT_New_Face", (void **) &qFT_New_Face},
115 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
116 {"FT_Done_Face", (void **) &qFT_Done_Face},
117 {"FT_Select_Size", (void **) &qFT_Select_Size},
118 {"FT_Request_Size", (void **) &qFT_Request_Size},
119 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
120 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
121 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
122 {"FT_Load_Char", (void **) &qFT_Load_Char},
123 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
124 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
125 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
126 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
130 /// Handle for FreeType2 DLL
131 static dllhandle_t ft2_dll = NULL;
133 /// Memory pool for fonts
134 static mempool_t *font_mempool= NULL;
135 static rtexturepool_t *font_texturepool = NULL;
137 /// FreeType library handle
138 static FT_Library font_ft2lib = NULL;
144 Unload the FreeType2 DLL
147 void Font_CloseLibrary (void)
150 Mem_FreePool(&font_mempool);
151 if (font_texturepool)
152 R_FreeTexturePool(&font_texturepool);
153 if (font_ft2lib && qFT_Done_FreeType)
155 qFT_Done_FreeType(font_ft2lib);
158 Sys_UnloadLibrary (&ft2_dll);
165 Try to load the FreeType2 DLL
168 qboolean Font_OpenLibrary (void)
170 const char* dllnames [] =
174 #elif defined(MACOSX)
183 if (r_font_disable_freetype.integer)
191 if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
200 Initialize the freetype2 font subsystem
204 void font_start(void)
206 if (!Font_OpenLibrary())
209 if (qFT_Init_FreeType(&font_ft2lib))
211 Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
216 font_mempool = Mem_AllocPool("FONT", 0, NULL);
219 Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
224 font_texturepool = R_AllocTexturePool();
225 if (!font_texturepool)
227 Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
233 void font_shutdown(void)
236 for (i = 0; i < MAX_FONTS; ++i)
240 Font_UnloadFont(dp_fonts[i].ft2);
241 dp_fonts[i].ft2 = NULL;
247 void font_newmap(void)
253 Cvar_RegisterVariable(&r_font_disable_freetype);
254 Cvar_RegisterVariable(&r_font_use_alpha_textures);
255 Cvar_RegisterVariable(&r_font_size_snapping);
259 ================================================================================
260 Implementation of a more or less lazy font loading and rendering code.
261 ================================================================================
264 #include "ft2_fontdefs.h"
266 ft2_font_t *Font_Alloc(void)
270 return Mem_Alloc(font_mempool, sizeof(ft2_font_t));
273 qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
275 ft2_attachment_t *na;
277 font->attachmentcount++;
278 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
281 if (font->attachments && font->attachmentcount > 1)
283 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
284 Mem_Free(font->attachments);
286 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
287 font->attachments = na;
291 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
292 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
293 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
296 ft2_font_t *ft2, *fbfont, *fb;
305 // check if a fallback font has been specified, if it has been, and the
306 // font fails to load, use the image font as main font
307 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
309 if (dpfnt->fallbacks[i][0])
313 if (!Font_LoadFile(name, dpfnt->req_face, ft2))
315 if (i >= MAX_FONT_FALLBACKS)
321 strlcpy(ft2->name, name, sizeof(ft2->name));
322 ft2->image_font = true;
323 ft2->has_kerning = false;
327 ft2->image_font = false;
330 // attempt to load fallback fonts:
332 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
334 if (!dpfnt->fallbacks[i][0])
336 if (! (fb = Font_Alloc()) )
338 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
341 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], fb))
343 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
348 for (s = 0; s < MAX_FONT_SIZES; ++s)
350 if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
355 Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
360 // at least one size of the fallback font loaded successfully
366 if (fbfont == ft2 && ft2->image_font)
368 // no fallbacks were loaded successfully:
375 for (s = 0; s < MAX_FONT_SIZES; ++s)
377 if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
382 // loading failed for every requested size
383 Font_UnloadFont(ft2);
389 //Con_Printf("%i sizes loaded\n", count);
394 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
397 char filename[MAX_QPATH];
401 fs_offset_t datasize;
403 memset(font, 0, sizeof(*font));
405 if (!Font_OpenLibrary())
407 if (!r_font_disable_freetype.integer)
409 Con_Printf("WARNING: can't open load font %s\n"
410 "You need the FreeType2 DLL to load font files\n",
416 namelen = strlen(name);
418 memcpy(filename, name, namelen);
419 memcpy(filename + namelen, ".ttf", 5);
420 data = FS_LoadFile(filename, font_mempool, false, &datasize);
423 memcpy(filename + namelen, ".otf", 5);
424 data = FS_LoadFile(filename, font_mempool, false, &datasize);
428 ft2_attachment_t afm;
430 memcpy(filename + namelen, ".pfb", 5);
431 data = FS_LoadFile(filename, font_mempool, false, &datasize);
435 memcpy(filename + namelen, ".afm", 5);
436 afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size);
439 Font_Attach(font, &afm);
445 // FS_LoadFile being not-quiet should print an error :)
448 Con_Printf("Loading font %s face %i...\n", filename, _face);
450 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
451 if (status && _face != 0)
453 Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
455 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, 0, (FT_Face*)&font->face);
459 Con_Printf("ERROR: can't create face for %s\n"
460 "Error %i\n", // TODO: error strings
462 Font_UnloadFont(font);
466 // add the attachments
467 for (i = 0; i < font->attachmentcount; ++i)
470 memset(&args, 0, sizeof(args));
471 args.flags = FT_OPEN_MEMORY;
472 args.memory_base = (const FT_Byte*)font->attachments[i].data;
473 args.memory_size = font->attachments[i].size;
474 if (qFT_Attach_Stream(font->face, &args))
475 Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
478 memcpy(font->name, name, namelen+1);
479 font->image_font = false;
480 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
484 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
485 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
488 ft2_font_map_t *fmap, temp;
495 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
500 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
502 if (!font->font_maps[map_index])
504 // if a similar size has already been loaded, ignore this one
505 //abs(font->font_maps[map_index]->size - size) < 4
506 if (font->font_maps[map_index]->size == size)
510 if (map_index >= MAX_FONT_SIZES)
513 memset(&temp, 0, sizeof(temp));
515 temp.glyphSize = CeilPowerOf2(size*2);
516 temp.sfx = (1.0/64.0)/(double)size;
517 temp.sfy = (1.0/64.0)/(double)size;
518 temp.intSize = -1; // negative value: LoadMap must search now :)
519 if (!Font_LoadMap(font, &temp, 0, &fmap))
521 Con_Printf("ERROR: can't load the first character map for %s\n"
524 Font_UnloadFont(font);
527 font->font_maps[map_index] = temp.next;
529 fmap->sfx = temp.sfx;
530 fmap->sfy = temp.sfy;
534 // load the default kerning vector:
535 if (font->has_kerning)
539 for (l = 0; l < 256; ++l)
541 for (r = 0; r < 256; ++r)
544 ul = qFT_Get_Char_Index(font->face, l);
545 ur = qFT_Get_Char_Index(font->face, r);
546 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
548 fmap->kerning.kerning[l][r][0] = 0;
549 fmap->kerning.kerning[l][r][1] = 0;
553 fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
554 fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
564 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
569 int matchsize = -10000;
573 ft2_font_map_t **maps = font->font_maps;
575 fsize = _fsize * vid.height / vid_conheight.value;
583 if (fsize - (float)size >= 0.49)
587 for (m = 0; m < MAX_FONT_SIZES; ++m)
591 // "round up" to the bigger size if two equally-valued matches exist
592 nval = abs(maps[m]->size - size);
593 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
597 matchsize = maps[m]->size;
598 if (value == 0) // there is no better match
602 if (value <= r_font_size_snapping.value)
606 if (!*outh) *outh = *outw;
607 if (!*outw) *outw = *outh;
610 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
611 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width * *outw / _fsize;
616 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
618 if (index < 0 || index >= MAX_FONT_SIZES)
620 return font->font_maps[index];
623 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
625 if (font->currenth == h &&
626 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
627 font->currentw == w)) // same size has been requested
631 // sorry, but freetype doesn't seem to care about other sizes
634 if (font->image_font)
636 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
641 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
649 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
651 ft2_font_map_t *fmap;
652 if (!font->has_kerning)
654 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
656 fmap = font->font_maps[map_index];
659 if (left < 256 && right < 256)
661 // quick-kerning, be aware of the size: scale it
662 if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
663 if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
671 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
672 if (!Font_SetSize(font, w, h))
674 // this deserves an error message
675 Con_Printf("Failed to get kerning for %s\n", font->name);
678 ul = qFT_Get_Char_Index(font->face, left);
679 ur = qFT_Get_Char_Index(font->face, right);
680 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
682 if (outx) *outx = kernvec.x * fmap->sfx;
683 if (outy) *outy = kernvec.y * fmap->sfy;
690 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
692 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
695 static void UnloadMapRec(ft2_font_map_t *map)
699 R_FreeTexture(map->texture);
703 UnloadMapRec(map->next);
707 void Font_UnloadFont(ft2_font_t *font)
710 if (font->attachments && font->attachmentcount)
712 Mem_Free(font->attachments);
713 font->attachmentcount = 0;
714 font->attachments = NULL;
716 for (i = 0; i < MAX_FONT_SIZES; ++i)
718 if (font->font_maps[i])
720 UnloadMapRec(font->font_maps[i]);
721 font->font_maps[i] = NULL;
728 qFT_Done_Face((FT_Face)font->face);
734 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
736 char map_identifier[MAX_QPATH];
737 unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
744 int gR, gC; // glyph position: row and column
746 ft2_font_map_t *map, *next;
751 int bytesPerPixel = 4; // change the conversion loop too if you change this!
756 if (r_font_use_alpha_textures.integer)
759 if (font->image_font)
760 fontface = (FT_Face)font->next->face;
762 fontface = (FT_Face)font->face;
764 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
766 if (font->image_font && mapstart->intSize < 0)
767 mapstart->intSize = mapstart->size;
768 if (mapstart->intSize < 0)
770 mapstart->intSize = mapstart->size;
773 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
775 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
778 if ((fontface->size->metrics.height>>6) <= mapstart->size)
780 if (mapstart->intSize < 2)
782 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
787 if (developer.integer)
788 Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
791 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
793 Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
797 map = Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
800 Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
804 // copy over the information
805 map->size = mapstart->size;
806 map->intSize = mapstart->intSize;
807 map->glyphSize = mapstart->glyphSize;
808 map->sfx = mapstart->sfx;
809 map->sfy = mapstart->sfy;
811 pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
812 data = Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
815 Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
820 // initialize as white texture with zero alpha
822 while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
824 if (bytesPerPixel == 4)
834 map->start = mapidx * FONT_CHARS_PER_MAP;
836 while(next->next && next->next->start < map->start)
838 map->next = next->next;
843 for (ch = map->start;
844 ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
851 unsigned char *imagedata, *dst, *src;
852 glyph_slot_t *mapglyph;
855 mapch = ch - map->start;
857 if (developer.integer)
858 Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
861 if (gC >= FONT_CHARS_PER_LINE)
863 gC -= FONT_CHARS_PER_LINE;
867 imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
868 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
869 // we need the glyphIndex
872 if (font->image_font && mapch == ch && img_fontmap[mapch])
874 map->glyphs[mapch].image = true;
877 glyphIndex = qFT_Get_Char_Index(face, ch);
880 // by convention, 0 is the "missing-glyph"-glyph
881 // try to load from a fallback font
882 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
884 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
887 face = usefont->face;
888 glyphIndex = qFT_Get_Char_Index(face, ch);
891 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
898 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
899 // now we let it use the "missing-glyph"-glyph
909 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
912 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
913 Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
919 bmp = &glyph->bitmap;
924 if (w > map->glyphSize || h > map->glyphSize) {
925 Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
926 if (w > map->glyphSize)
928 if (h > map->glyphSize)
932 switch (bmp->pixel_mode)
934 case FT_PIXEL_MODE_MONO:
935 if (developer.integer)
936 Con_Print("glyphinfo: Pixel Mode: MONO\n");
938 case FT_PIXEL_MODE_GRAY2:
939 if (developer.integer)
940 Con_Print("glyphinfo: Pixel Mode: GRAY2\n");
942 case FT_PIXEL_MODE_GRAY4:
943 if (developer.integer)
944 Con_Print("glyphinfo: Pixel Mode: GRAY4\n");
946 case FT_PIXEL_MODE_GRAY:
947 if (developer.integer)
948 Con_Print("glyphinfo: Pixel Mode: GRAY\n");
951 if (developer.integer)
952 Con_Printf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
954 Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
957 for (y = 0; y < h; ++y)
959 dst = imagedata + y * pitch;
960 src = bmp->buffer + y * bmp->pitch;
962 switch (bmp->pixel_mode)
964 case FT_PIXEL_MODE_MONO:
965 dst += bytesPerPixel - 1; // shift to alpha byte
966 for (x = 0; x < bmp->width; x += 8)
968 unsigned char ch = *src++;
969 *dst = 255 * ((ch & 0x80) >> 7); dst += bytesPerPixel;
970 *dst = 255 * ((ch & 0x40) >> 6); dst += bytesPerPixel;
971 *dst = 255 * ((ch & 0x20) >> 5); dst += bytesPerPixel;
972 *dst = 255 * ((ch & 0x10) >> 4); dst += bytesPerPixel;
973 *dst = 255 * ((ch & 0x08) >> 3); dst += bytesPerPixel;
974 *dst = 255 * ((ch & 0x04) >> 2); dst += bytesPerPixel;
975 *dst = 255 * ((ch & 0x02) >> 1); dst += bytesPerPixel;
976 *dst = 255 * ((ch & 0x01) >> 0); dst += bytesPerPixel;
979 case FT_PIXEL_MODE_GRAY2:
980 dst += bytesPerPixel - 1; // shift to alpha byte
981 for (x = 0; x < bmp->width; x += 4)
983 unsigned char ch = *src++;
984 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
985 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
986 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
987 *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
990 case FT_PIXEL_MODE_GRAY4:
991 dst += bytesPerPixel - 1; // shift to alpha byte
992 for (x = 0; x < bmp->width; x += 2)
994 unsigned char ch = *src++;
995 *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
996 *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
999 case FT_PIXEL_MODE_GRAY:
1000 // in this case pitch should equal width
1001 for (tp = 0; tp < bmp->pitch; ++tp)
1002 dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1004 //memcpy((void*)dst, (void*)src, bmp->pitch);
1005 //dst += bmp->pitch;
1012 // now fill map->glyphs[ch - map->start]
1013 mapglyph = &map->glyphs[mapch];
1017 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1019 double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
1020 double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1021 double advance = (glyph->advance.x >> 6) / map->size;
1022 double mWidth = (glyph->metrics.width >> 6) / map->size;
1023 double mHeight = (glyph->metrics.height >> 6) / map->size;
1025 mapglyph->vxmin = bearingX;
1026 mapglyph->vxmax = bearingX + mWidth;
1027 mapglyph->vymin = -bearingY;
1028 mapglyph->vymax = mHeight - bearingY;
1029 mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1030 mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1031 mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1032 mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1033 //mapglyph->advance_x = advance * usefont->size;
1034 mapglyph->advance_x = advance;
1035 mapglyph->advance_y = 0;
1037 if (developer.integer)
1039 Con_Printf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR);
1040 Con_Printf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1041 if (ch >= 32 && ch <= 128)
1042 Con_Printf("glyphinfo: Character: %c\n", (int)ch);
1043 Con_Printf("glyphinfo: Vertex info:\n");
1044 Con_Printf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1045 Con_Printf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1046 Con_Printf("glyphinfo: Texture info:\n");
1047 Con_Printf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1048 Con_Printf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1049 Con_Printf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1052 map->glyphs[mapch].image = false;
1055 // create a texture from the data now
1057 if (developer.integer)
1059 // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
1060 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1061 FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
1063 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
1065 // probably use bytesPerPixel here instead?
1066 if (r_font_use_alpha_textures.integer)
1068 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1069 map->glyphSize * FONT_CHARS_PER_LINE,
1070 map->glyphSize * FONT_CHAR_LINES,
1071 data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1073 map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
1074 map->glyphSize * FONT_CHARS_PER_LINE,
1075 map->glyphSize * FONT_CHAR_LINES,
1076 data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, NULL);
1082 // if the first try isn't successful, keep it with a broken texture
1083 // otherwise we retry to load it every single frame where ft2 rendering is used
1084 // this would be bad...
1085 // only `data' must be freed
1086 Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1087 font->name, mapstart->size, mapidx);
1095 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1097 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1099 // the first map must have been loaded already
1100 if (!font->font_maps[map_index])
1102 return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1105 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1107 while (start && start->start + FONT_CHARS_PER_MAP < ch)
1108 start = start->next;
1109 if (start && start->start > ch)