DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
ft2.c
Go to the documentation of this file.
1/* FreeType 2 and UTF-8 encoding support for
2 * DarkPlaces
3 */
4#include "quakedef.h"
5
6#include "ft2.h"
7#include "ft2_defs.h"
8#include "ft2_fontdefs.h"
9#include "image.h"
10
11static int img_fontmap[256] = {
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,
14 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line
15 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits
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, // caps
18 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
19 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces
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,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
28};
29
30/*
31 * Some big blocks of Unicode characters, according to
32 * http://www.unicode.org/Public/UNIDATA/Blocks.txt
33 *
34 * Let's call these "bigblocks".
35 * These characters are "spreaded", and ordinary maps will
36 * waste huge amount of resources rendering/caching unused glyphs.
37 *
38 * So, a new design is introduced to solve the problem:
39 * incremental maps, in which only used glyphs are stored.
40 */
41static const Uchar unicode_bigblocks[] = {
42 0x3400, 0x4DBF, // 6592 CJK Unified Ideographs Extension A
43 0x4E00, 0x9FFF, // 20992 CJK Unified Ideographs
44 0xAC00, 0xD7AF, // 11184 Hangul Syllables
45 0xE000, 0xF8FF, // 6400 Private Use Area
46 0x10000, 0x10FFFF // Everything above
47};
48
49/*
50================================================================================
51CVars introduced with the freetype extension
52================================================================================
53*/
54
55cvar_t r_font_disable_freetype = {CF_CLIENT | CF_ARCHIVE, "r_font_disable_freetype", "0", "disable freetype support for fonts entirely"};
56cvar_t r_font_size_snapping = {CF_CLIENT | CF_ARCHIVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
57cvar_t r_font_kerning = {CF_CLIENT | CF_ARCHIVE, "r_font_kerning", "1", "Use kerning if available"};
58cvar_t r_font_diskcache = {CF_CLIENT | CF_ARCHIVE, "r_font_diskcache", "0", "[deprecated, not effective] save font textures to disk for future loading rather than generating them every time"};
59cvar_t r_font_compress = {CF_CLIENT | CF_ARCHIVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
60cvar_t r_font_nonpoweroftwo = {CF_CLIENT | CF_ARCHIVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
61cvar_t developer_font = {CF_CLIENT | CF_ARCHIVE, "developer_font", "0", "prints debug messages about fonts"};
62
63cvar_t r_font_disable_incmaps = {CF_CLIENT | CF_ARCHIVE, "r_font_disable_incmaps", "0", "always to load a full glyph map for individual unmapped character, even when it will mean extreme resources waste"};
64
65#ifndef DP_FREETYPE_STATIC
66
67/*
68================================================================================
69Function definitions. Taken from the freetype2 headers.
70================================================================================
71*/
72
73
75(*qFT_Init_FreeType)( FT_Library *alibrary );
77(*qFT_Done_FreeType)( FT_Library library );
78/*
79FT_EXPORT( FT_Error )
80(*qFT_New_Face)( FT_Library library,
81 const char* filepathname,
82 FT_Long face_index,
83 FT_Face *aface );
84*/
86(*qFT_New_Memory_Face)( FT_Library library,
87 const FT_Byte* file_base,
88 FT_Long file_size,
89 FT_Long face_index,
90 FT_Face *aface );
92(*qFT_Done_Face)( FT_Face face );
94(*qFT_Select_Size)( FT_Face face,
95 FT_Int strike_index );
97(*qFT_Request_Size)( FT_Face face,
98 FT_Size_Request req );
100(*qFT_Set_Char_Size)( FT_Face face,
101 FT_F26Dot6 char_width,
102 FT_F26Dot6 char_height,
103 FT_UInt horz_resolution,
104 FT_UInt vert_resolution );
106(*qFT_Set_Pixel_Sizes)( FT_Face face,
107 FT_UInt pixel_width,
108 FT_UInt pixel_height );
110(*qFT_Load_Glyph)( FT_Face face,
111 FT_UInt glyph_index,
112 FT_Int32 load_flags );
114(*qFT_Load_Char)( FT_Face face,
115 FT_ULong char_code,
116 FT_Int32 load_flags );
118(*qFT_Get_Char_Index)( FT_Face face,
119 FT_ULong charcode );
121(*qFT_Render_Glyph)( FT_GlyphSlot slot,
122 FT_Render_Mode render_mode );
124(*qFT_Get_Kerning)( FT_Face face,
125 FT_UInt left_glyph,
126 FT_UInt right_glyph,
127 FT_UInt kern_mode,
128 FT_Vector *akerning );
130(*qFT_Attach_Stream)( FT_Face face,
131 FT_Open_Args* parameters );
132/*
133================================================================================
134Support for dynamically loading the FreeType2 library
135================================================================================
136*/
137
139{
140 {"FT_Init_FreeType", (void **) &qFT_Init_FreeType},
141 {"FT_Done_FreeType", (void **) &qFT_Done_FreeType},
142 //{"FT_New_Face", (void **) &qFT_New_Face},
143 {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face},
144 {"FT_Done_Face", (void **) &qFT_Done_Face},
145 {"FT_Select_Size", (void **) &qFT_Select_Size},
146 {"FT_Request_Size", (void **) &qFT_Request_Size},
147 {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size},
148 {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes},
149 {"FT_Load_Glyph", (void **) &qFT_Load_Glyph},
150 {"FT_Load_Char", (void **) &qFT_Load_Char},
151 {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index},
152 {"FT_Render_Glyph", (void **) &qFT_Render_Glyph},
153 {"FT_Get_Kerning", (void **) &qFT_Get_Kerning},
154 {"FT_Attach_Stream", (void **) &qFT_Attach_Stream},
155 {NULL, NULL}
156};
157
160
161#else
162
164(FT_Init_FreeType)( FT_Library *alibrary );
166(FT_Done_FreeType)( FT_Library library );
167/*
168FT_EXPORT( FT_Error )
169(FT_New_Face)( FT_Library library,
170 const char* filepathname,
171 FT_Long face_index,
172 FT_Face *aface );
173*/
175(FT_New_Memory_Face)( FT_Library library,
176 const FT_Byte* file_base,
177 FT_Long file_size,
178 FT_Long face_index,
179 FT_Face *aface );
181(FT_Done_Face)( FT_Face face );
183(FT_Select_Size)( FT_Face face,
184 FT_Int strike_index );
186(FT_Request_Size)( FT_Face face,
187 FT_Size_Request req );
189(FT_Set_Char_Size)( FT_Face face,
190 FT_F26Dot6 char_width,
191 FT_F26Dot6 char_height,
192 FT_UInt horz_resolution,
193 FT_UInt vert_resolution );
195(FT_Set_Pixel_Sizes)( FT_Face face,
196 FT_UInt pixel_width,
197 FT_UInt pixel_height );
199(FT_Load_Glyph)( FT_Face face,
200 FT_UInt glyph_index,
201 FT_Int32 load_flags );
203(FT_Load_Char)( FT_Face face,
204 FT_ULong char_code,
205 FT_Int32 load_flags );
207(FT_Get_Char_Index)( FT_Face face,
208 FT_ULong charcode );
210(FT_Render_Glyph)( FT_GlyphSlot slot,
211 FT_Render_Mode render_mode );
213(FT_Get_Kerning)( FT_Face face,
214 FT_UInt left_glyph,
215 FT_UInt right_glyph,
216 FT_UInt kern_mode,
217 FT_Vector *akerning );
219(FT_Attach_Stream)( FT_Face face,
220 FT_Open_Args* parameters );
221
222#define qFT_Init_FreeType FT_Init_FreeType
223#define qFT_Done_FreeType FT_Done_FreeType
224//#define qFT_New_Face FT_New_Face
225#define qFT_New_Memory_Face FT_New_Memory_Face
226#define qFT_Done_Face FT_Done_Face
227#define qFT_Select_Size FT_Select_Size
228#define qFT_Request_Size FT_Request_Size
229#define qFT_Set_Char_Size FT_Set_Char_Size
230#define qFT_Set_Pixel_Sizes FT_Set_Pixel_Sizes
231#define qFT_Load_Glyph FT_Load_Glyph
232#define qFT_Load_Char FT_Load_Char
233#define qFT_Get_Char_Index FT_Get_Char_Index
234#define qFT_Render_Glyph FT_Render_Glyph
235#define qFT_Get_Kerning FT_Get_Kerning
236#define qFT_Attach_Stream FT_Attach_Stream
237
238#endif
239
242
245
246#define POSTPROCESS_MAXRADIUS 8
247typedef struct
248{
249 unsigned char *buf, *buf2;
250 int bufsize, bufwidth, bufheight, bufpitch;
251 float blur, outline, shadowx, shadowy, shadowz;
252 int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
253 unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
254 unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
255}
258
259typedef struct fontfilecache_s
260{
261 unsigned char *buf;
264 char path[MAX_QPATH];
265}
267#define MAX_FONTFILES 8
269static const unsigned char *fontfilecache_LoadFile(const char *path, qbool quiet, fs_offset_t *filesizepointer)
270{
271 int i;
272 unsigned char *buf;
273
274 for(i = 0; i < MAX_FONTFILES; ++i)
275 {
276 if(fontfiles[i].refcount > 0)
277 if(!strcmp(path, fontfiles[i].path))
278 {
279 *filesizepointer = fontfiles[i].len;
281 return fontfiles[i].buf;
282 }
283 }
284
285 buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
286 if(buf)
287 {
288 for(i = 0; i < MAX_FONTFILES; ++i)
289 if(fontfiles[i].refcount <= 0)
290 {
291 dp_strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
292 fontfiles[i].len = *filesizepointer;
293 fontfiles[i].buf = buf;
294 fontfiles[i].refcount = 1;
295 return buf;
296 }
297 }
298
299 return buf;
300}
301static void fontfilecache_Free(const unsigned char *buf)
302{
303 int i;
304 for(i = 0; i < MAX_FONTFILES; ++i)
305 {
306 if(fontfiles[i].refcount > 0)
307 if(fontfiles[i].buf == buf)
308 {
309 if(--fontfiles[i].refcount <= 0)
310 {
312 fontfiles[i].buf = NULL;
313 }
314 return;
315 }
316 }
317 // if we get here, it used regular allocation
318 Mem_Free((void *) buf);
319}
320static void fontfilecache_FreeAll(void)
321{
322 int i;
323 for(i = 0; i < MAX_FONTFILES; ++i)
324 {
325 if(fontfiles[i].refcount > 0)
327 fontfiles[i].buf = NULL;
328 fontfiles[i].refcount = 0;
329 }
330}
331
332/*
333====================
334Font_CloseLibrary
335
336Unload the FreeType2 DLL
337====================
338*/
340{
342 if (font_mempool)
345 {
348 }
349#ifndef DP_FREETYPE_STATIC
351#endif
352 pp.buf = NULL;
353}
354
355/*
356====================
357Font_OpenLibrary
358
359Try to load the FreeType2 DLL
360====================
361*/
363{
364#ifndef DP_FREETYPE_STATIC
365 const char* dllnames [] =
366 {
367#if defined(WIN32)
368 "libfreetype-6.dll",
369 "freetype6.dll",
370#elif defined(MACOSX)
371 "libfreetype.6.dylib",
372 "libfreetype.dylib",
373#else
374 "libfreetype.so.6",
375 "libfreetype.so",
376#endif
377 NULL
378 };
379#endif
380
382 return false;
383
384#ifndef DP_FREETYPE_STATIC
385 // Already loaded?
386 if (ft2_dll)
387 return true;
388
389 // Load the DLL
390 if (!Sys_LoadDependency (dllnames, &ft2_dll, ft2funcs))
391 return false;
392#endif
393 return true;
394}
395
396/*
397====================
398Font_Init
399
400Initialize the freetype2 font subsystem
401====================
402*/
403
404void font_start(void)
405{
406 if (!Font_OpenLibrary())
407 return;
408
410 {
411 Con_Print(CON_ERROR "ERROR: Failed to initialize the FreeType2 library!\n");
413 return;
414 }
415
416 font_mempool = Mem_AllocPool("FONT", 0, NULL);
417 if (!font_mempool)
418 {
419 Con_Print(CON_ERROR "ERROR: Failed to allocate FONT memory pool!\n");
421 return;
422 }
423}
424
426{
427 int i;
428 for (i = 0; i < dp_fonts.maxsize; ++i)
429 {
430 if (dp_fonts.f[i].ft2)
431 {
433 dp_fonts.f[i].ft2 = NULL;
434 }
435 }
437}
438
439void font_newmap(void)
440{
441}
442
458
459/*
460================================================================================
461Implementation of a more or less lazy font loading and rendering code.
462================================================================================
463*/
464
465#include "ft2_fontdefs.h"
466
468{
469#ifndef DP_FREETYPE_STATIC
470 if (!ft2_dll)
471#else
473#endif
474 return NULL;
475 return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
476}
477
478static qbool Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
479{
480 ft2_attachment_t *na;
481
482 font->attachmentcount++;
483 na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
484 if (na == NULL)
485 return false;
486 if (font->attachments && font->attachmentcount > 1)
487 {
488 memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
489 Mem_Free(font->attachments);
490 }
491 memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
492 font->attachments = na;
493 return true;
494}
495
497{
498 int vh;
499 //int vw;
500 int si;
501 float sn;
502 if(sz < 0)
503 return sz;
504 //vw = ((vid.width > 0) ? vid.width : vid_width.value);
505 vh = ((vid.mode.height > 0) ? vid.mode.height : vid_height.value);
506 // now try to scale to our actual size:
507 sn = sz * vh / vid_conheight.value;
508 si = (int)sn;
509 if ( sn - (float)si >= 0.5 )
510 ++si;
511 return si;
512}
513
514float Font_SnapTo(float val, float snapwidth)
515{
516 return floor(val / snapwidth + 0.5f) * snapwidth;
517}
518
519static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
520static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only);
521qbool Font_LoadFont(const char *name, dp_font_t *dpfnt)
522{
523 int s, count, i;
524 ft2_font_t *ft2, *fbfont, *fb;
525 char vabuf[1024];
526
527 ft2 = Font_Alloc();
528 if (!ft2)
529 {
530 dpfnt->ft2 = NULL;
531 return false;
532 }
533
534 // check if a fallback font has been specified, if it has been, and the
535 // font fails to load, use the image font as main font
536 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
537 {
538 if (dpfnt->fallbacks[i][0])
539 break;
540 }
541
542 if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
543 {
544 if (i >= MAX_FONT_FALLBACKS)
545 {
546 dpfnt->ft2 = NULL;
547 Mem_Free(ft2);
548 return false;
549 }
550 dp_strlcpy(ft2->name, name, sizeof(ft2->name));
551 ft2->image_font = true;
552 ft2->has_kerning = false;
553 }
554 else
555 {
556 ft2->image_font = false;
557 }
558
559 // attempt to load fallback fonts:
560 fbfont = ft2;
561 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
562 {
563 if (!dpfnt->fallbacks[i][0])
564 break;
565 if (! (fb = Font_Alloc()) )
566 {
567 Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
568 break;
569 }
570
571 if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
572 {
573 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i])))
574 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i])))
575 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i])))
576 if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i])))
577 Con_Printf(CON_ERROR "Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
578 Mem_Free(fb);
579 continue;
580 }
581 count = 0;
582 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
583 {
584 if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
585 ++count;
586 }
587 if (!count)
588 {
589 Con_Printf(CON_ERROR "Failed to allocate font for fallback %i of font %s\n", i, name);
590 Font_UnloadFont(fb);
591 Mem_Free(fb);
592 break;
593 }
594 // at least one size of the fallback font loaded successfully
595 // link it:
596 fbfont->next = fb;
597 fbfont = fb;
598 }
599
600 if (fbfont == ft2 && ft2->image_font)
601 {
602 // no fallbacks were loaded successfully:
603 dpfnt->ft2 = NULL;
604 Mem_Free(ft2);
605 return false;
606 }
607
608 count = 0;
609 for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
610 {
611 if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
612 ++count;
613 }
614 if (!count)
615 {
616 // loading failed for every requested size
617 Font_UnloadFont(ft2);
618 Mem_Free(ft2);
619 dpfnt->ft2 = NULL;
620 return false;
621 }
622
623 //Con_Printf("%i sizes loaded\n", count);
624 dpfnt->ft2 = ft2;
625 return true;
626}
627
628static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
629{
630 size_t namelen;
631 char filename[MAX_QPATH];
632 int status;
633 size_t i;
634 const unsigned char *data;
635 fs_offset_t datasize;
636
637 memset(font, 0, sizeof(*font));
638
639 if (!Font_OpenLibrary())
640 {
642 {
643 Con_Printf(CON_WARN "WARNING: can't open load font %s\n"
644 "You need the FreeType2 DLL to load font files\n",
645 name);
646 }
647 return false;
648 }
649
650 font->settings = settings;
651
652 namelen = strlen(name);
653 if (namelen + 5 > sizeof(filename))
654 {
655 Con_Printf(CON_WARN "WARNING: too long font name. Cannot load this.\n");
656 return false;
657 }
658
659 // try load direct file
660 memcpy(filename, name, namelen+1);
661 data = fontfilecache_LoadFile(filename, false, &datasize);
662 // try load .ttf
663 if (!data)
664 {
665 memcpy(filename + namelen, ".ttf", 5);
666 data = fontfilecache_LoadFile(filename, false, &datasize);
667 }
668 // try load .otf
669 if (!data)
670 {
671 memcpy(filename + namelen, ".otf", 5);
672 data = fontfilecache_LoadFile(filename, false, &datasize);
673 }
674 // try load .pfb/afm
675 if (!data)
676 {
677 ft2_attachment_t afm;
678
679 memcpy(filename + namelen, ".pfb", 5);
680 data = fontfilecache_LoadFile(filename, false, &datasize);
681
682 if (data)
683 {
684 memcpy(filename + namelen, ".afm", 5);
685 afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
686
687 if (afm.data)
688 Font_Attach(font, &afm);
689 }
690 }
691 if (!data)
692 {
693 // FS_LoadFile being not-quiet should print an error :)
694 return false;
695 }
696 Con_DPrintf("Loading font %s face %i...\n", filename, _face);
697
698 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
699 if (status && _face != 0)
700 {
701 Con_Printf(CON_ERROR "Failed to load face %i of %s. Falling back to face 0\n", _face, name);
702 _face = 0;
703 status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
704 }
705 font->data = data;
706 if (status)
707 {
708 Con_Printf(CON_ERROR "ERROR: can't create face for %s\n"
709 "Error %i\n", // TODO: error strings
710 name, status);
711 Font_UnloadFont(font);
712 return false;
713 }
714
715 // add the attachments
716 for (i = 0; i < font->attachmentcount; ++i)
717 {
718 FT_Open_Args args;
719 memset(&args, 0, sizeof(args));
720 args.flags = FT_OPEN_MEMORY;
721 args.memory_base = (const FT_Byte*)font->attachments[i].data;
722 args.memory_size = font->attachments[i].size;
723 if (qFT_Attach_Stream((FT_Face)font->face, &args))
724 Con_Printf(CON_ERROR "Failed to add attachment %u to %s\n", (unsigned)i, font->name);
725 }
726
727 dp_strlcpy(font->name, name, sizeof(font->name));
728 font->image_font = false;
729 font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
730 return true;
731}
732
733static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
734{
735 int needed, x, y;
736 float gausstable[2*POSTPROCESS_MAXRADIUS+1];
737 qbool need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
738 qbool need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
739 pp.blur = fnt->settings->blur;
740 pp.outline = fnt->settings->outline;
741 pp.shadowx = fnt->settings->shadowx;
742 pp.shadowy = fnt->settings->shadowy;
743 pp.shadowz = fnt->settings->shadowz;
754 if(need_gauss)
755 {
756 float sum = 0;
758 gausstable[POSTPROCESS_MAXRADIUS+x] = (pp.blur > 0 ? exp(-(pow(x + pp.shadowz, 2))/(pp.blur*pp.blur * 2)) : (floor(x + pp.shadowz + 0.5) == 0));
759 for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
760 sum += gausstable[POSTPROCESS_MAXRADIUS+x];
762 pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
763 }
764 if(need_circle)
765 {
768 {
769 float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
770 pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
771 }
772 }
776 needed = pp.bufwidth * pp.bufheight;
777 if(!pp.buf || pp.bufsize < needed * 2)
778 {
779 if(pp.buf)
780 Mem_Free(pp.buf);
781 pp.bufsize = needed * 4;
782 pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
783 pp.buf2 = pp.buf + needed;
784 }
785}
786
787static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b)
788{
789 int x, y;
790
791 // calculate gauss table
792 Font_Postprocess_Update(fnt, bpp, w, h);
793
794 if(imagedata)
795 {
796 // enlarge buffer
797 // perform operation, not exceeding the passed padding values,
798 // but possibly reducing them
799 *pad_l = min(*pad_l, pp.padding_l);
800 *pad_r = min(*pad_r, pp.padding_r);
801 *pad_t = min(*pad_t, pp.padding_t);
802 *pad_b = min(*pad_b, pp.padding_b);
803
804 // outline the font (RGBA only)
805 if(bpp == 4 && (pp.outline > 0 || pp.blur > 0 || pp.shadowx != 0 || pp.shadowy != 0 || pp.shadowz != 0)) // we can only do this in BGRA
806 {
807 // this is like mplayer subtitle rendering
808 // bbuffer, bitmap buffer: this is our font
809 // abuffer, alpha buffer: this is pp.buf
810 // tmp: this is pp.buf2
811
812 // create outline buffer
813 memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
814 for(y = -*pad_t; y < h + *pad_b; ++y)
815 for(x = -*pad_l; x < w + *pad_r; ++x)
816 {
817 int x1 = max(-x, -pp.outlinepadding_r);
818 int y1 = max(-y, -pp.outlinepadding_b);
819 int x2 = min(pp.outlinepadding_l, w-1-x);
820 int y2 = min(pp.outlinepadding_t, h-1-y);
821 int mx, my;
822 int cur = 0;
823 int highest = 0;
824 for(my = y1; my <= y2; ++my)
825 for(mx = x1; mx <= x2; ++mx)
826 {
827 cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
828 if(cur > highest)
829 highest = cur;
830 }
831 pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
832 }
833
834 // blur the outline buffer
835 if(pp.blur > 0 || pp.shadowz != 0)
836 {
837 // horizontal blur
838 for(y = 0; y < pp.bufheight; ++y)
839 for(x = 0; x < pp.bufwidth; ++x)
840 {
841 int x1 = max(-x, -pp.blurpadding_rb);
842 int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
843 int mx;
844 int blurred = 0;
845 for(mx = x1; mx <= x2; ++mx)
846 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
847 pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
848 }
849
850 // vertical blur
851 for(y = 0; y < pp.bufheight; ++y)
852 for(x = 0; x < pp.bufwidth; ++x)
853 {
854 int y1 = max(-y, -pp.blurpadding_rb);
855 int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
856 int my;
857 int blurred = 0;
858 for(my = y1; my <= y2; ++my)
859 blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
860 pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
861 }
862 }
863
864 // paste the outline below the font
865 for(y = -*pad_t; y < h + *pad_b; ++y)
866 for(x = -*pad_l; x < w + *pad_r; ++x)
867 {
868 unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
869 if(outlinealpha > 0)
870 {
871 unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
872 // a' = 1 - (1 - a1) (1 - a2)
873 unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
874 // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
875 unsigned char oldfactor = (255 * (int)oldalpha) / newalpha;
876 //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
877 int i;
878 for(i = 0; i < bpp-1; ++i)
879 {
880 unsigned char c = imagedata[x * bpp + pitch * y + i];
881 c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
882 imagedata[x * bpp + pitch * y + i] = c;
883 }
884 imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
885 }
886 //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
887 }
888 }
889 }
890 else if(pitch)
891 {
892 // perform operation, not exceeding the passed padding values,
893 // but possibly reducing them
894 *pad_l = min(*pad_l, pp.padding_l);
895 *pad_r = min(*pad_r, pp.padding_r);
896 *pad_t = min(*pad_t, pp.padding_t);
897 *pad_b = min(*pad_b, pp.padding_b);
898 }
899 else
900 {
901 // just calculate parameters
902 *pad_l = pp.padding_l;
903 *pad_r = pp.padding_r;
904 *pad_t = pp.padding_t;
905 *pad_b = pp.padding_b;
906 }
907}
908
909static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
910static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap, int *outmapch, qbool incmap_ok);
911static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only)
912{
913 int map_index;
914 ft2_font_map_t *fmap, temp;
915 int gpad_l, gpad_r, gpad_t, gpad_b;
916
917 if (!(size > 0.001f && size < 1000.0f))
918 size = 0;
919
920 if (!size)
921 size = 16;
922 if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
923 return false;
924
925 for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
926 {
927 if (!font->font_maps[map_index])
928 break;
929 // if a similar size has already been loaded, ignore this one
930 //abs(font->font_maps[map_index]->size - size) < 4
931 if (font->font_maps[map_index]->size == size)
932 return true;
933 }
934
935 if (map_index >= MAX_FONT_SIZES)
936 return false;
937
938 if (check_only) {
939 FT_Face fontface;
940 if (font->image_font)
941 fontface = (FT_Face)font->next->face;
942 else
943 fontface = (FT_Face)font->face;
944 return (Font_SearchSize(font, fontface, size) > 0);
945 }
946
947 Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
948
949 memset(&temp, 0, sizeof(temp));
950 temp.size = size;
951 temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
953 temp.glyphSize = CeilPowerOf2(temp.glyphSize);
954 temp.sfx = (1.0/64.0)/(double)size;
955 temp.sfy = (1.0/64.0)/(double)size;
956 temp.intSize = -1; // negative value: LoadMap must search now :)
957 if (!Font_LoadMap(font, &temp, 0, &fmap, NULL, false))
958 {
959 Con_Printf(CON_ERROR "ERROR: can't load the first character map for %s\n"
960 "This is fatal\n",
961 font->name);
962 Font_UnloadFont(font);
963 return false;
964 }
965 font->font_maps[map_index] = temp.next;
966
967 fmap->sfx = temp.sfx;
968 fmap->sfy = temp.sfy;
969
970 // load the default kerning vector:
971 if (font->has_kerning)
972 {
973 Uchar l, r;
974 FT_Vector kernvec;
975 fmap->kerning = (ft2_kerning_t *)Mem_Alloc(font_mempool, sizeof(ft2_kerning_t));
976 for (l = 0; l < 256; ++l)
977 {
978 for (r = 0; r < 256; ++r)
979 {
980 FT_ULong ul, ur;
981 ul = qFT_Get_Char_Index((FT_Face)font->face, l);
982 ur = qFT_Get_Char_Index((FT_Face)font->face, r);
983 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
984 {
985 fmap->kerning->kerning[l][r][0] = 0;
986 fmap->kerning->kerning[l][r][1] = 0;
987 }
988 else
989 {
990 fmap->kerning->kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
991 fmap->kerning->kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
992 }
993 }
994 }
995 }
996 return true;
997}
998
999int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
1000{
1001 int match = -1;
1002 float value = 1000000;
1003 float nval;
1004 int matchsize = -10000;
1005 int m;
1006 float fsize_x, fsize_y;
1007 ft2_font_map_t **maps = font->font_maps;
1008
1009 fsize_x = fsize_y = _fsize * vid.mode.height / vid_conheight.value;
1010 if(outw && *outw)
1011 fsize_x = *outw * vid.mode.width / vid_conwidth.value;
1012 if(outh && *outh)
1013 fsize_y = *outh * vid.mode.height / vid_conheight.value;
1014
1015 if (fsize_x < 0)
1016 {
1017 if(fsize_y < 0)
1018 fsize_x = fsize_y = 16;
1019 else
1020 fsize_x = fsize_y;
1021 }
1022 else
1023 {
1024 if(fsize_y < 0)
1025 fsize_y = fsize_x;
1026 }
1027
1028 for (m = 0; m < MAX_FONT_SIZES; ++m)
1029 {
1030 if (!maps[m])
1031 continue;
1032 // "round up" to the bigger size if two equally-valued matches exist
1033 nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1034 if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1035 {
1036 value = nval;
1037 match = m;
1038 matchsize = maps[m]->size;
1039 if (value == 0) // there is no better match
1040 break;
1041 }
1042 }
1044 {
1045 // do NOT keep the aspect for perfect rendering
1046 if (outh) *outh = maps[match]->size * vid_conheight.value / vid.mode.height;
1047 if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.mode.width;
1048 }
1049 return match;
1050}
1051
1052ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1053{
1055 return NULL;
1056 return font->font_maps[index];
1057}
1058
1059static qbool Font_SetSize(ft2_font_t *font, float w, float h)
1060{
1061 if (font->currenth == h &&
1062 ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1063 font->currentw == w)) // same size has been requested
1064 {
1065 return true;
1066 }
1067 // sorry, but freetype doesn't seem to care about other sizes
1068 w = (int)w;
1069 h = (int)h;
1070 if (font->image_font)
1071 {
1072 if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1073 return false;
1074 }
1075 else
1076 {
1077 if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1078 return false;
1079 }
1080 font->currentw = w;
1081 font->currenth = h;
1082 return true;
1083}
1084
1085qbool Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1086{
1087 ft2_font_map_t *fmap;
1088 if (!font->has_kerning || !r_font_kerning.integer)
1089 return false;
1090 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1091 return false;
1092 fmap = font->font_maps[map_index];
1093 if (!fmap)
1094 return false;
1095 if (left < 256 && right < 256)
1096 {
1097 //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1098 // quick-kerning, be aware of the size: scale it
1099 if (outx) *outx = fmap->kerning->kerning[left][right][0];// * (w / (float)fmap->size);
1100 if (outy) *outy = fmap->kerning->kerning[left][right][1];// * (h / (float)fmap->size);
1101 return true;
1102 }
1103 else
1104 {
1105 FT_Vector kernvec;
1106 FT_ULong ul, ur;
1107
1108 //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1109#if 0
1110 if (!Font_SetSize(font, w, h))
1111 {
1112 // this deserves an error message
1113 Con_Printf("Failed to get kerning for %s\n", font->name);
1114 return false;
1115 }
1116 ul = qFT_Get_Char_Index(font->face, left);
1117 ur = qFT_Get_Char_Index(font->face, right);
1118 if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1119 {
1120 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1121 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1122 return true;
1123 }
1124#endif
1125 if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1126 {
1127 // this deserves an error message
1128 Con_Printf(CON_ERROR "Failed to get kerning for %s\n", font->name);
1129 return false;
1130 }
1131 ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1132 ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1133 if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1134 {
1135 if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1136 if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1137 return true;
1138 }
1139 return false;
1140 }
1141}
1142
1143qbool Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1144{
1145 return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1146}
1147
1148// this is used to gracefully unload a map chain; the passed map
1149// needs not necessarily be a startmap, so maps ahead of it can be kept
1150static void UnloadMapChain(ft2_font_map_t *map)
1151{
1152 int i;
1153 ft2_font_map_t *nextmap;
1154 // these may only be in a startmap
1155 if (map->kerning != NULL)
1156 Mem_Free(map->kerning);
1157 if (map->incmap != NULL)
1158 {
1159 for (i = 0; i < FONT_CHARS_PER_LINE; ++i)
1160 if (map->incmap->data_tier1[i] != NULL)
1161 Mem_Free(map->incmap->data_tier1[i]);
1162 else
1163 break;
1164 for (i = 0; i < FONT_CHAR_LINES; ++i)
1165 if (map->incmap->data_tier2[i] != NULL)
1166 Mem_Free(map->incmap->data_tier2[i]);
1167 else
1168 break;
1169 Mem_Free(map->incmap);
1170 }
1171 while (map != NULL)
1172 {
1173 if (map->pic)
1174 {
1175 //Draw_FreePic(map->pic); // FIXME: refcounting needed...
1176 map->pic = NULL;
1177 }
1178 nextmap = map->next;
1179 Mem_Free(map);
1180 map = nextmap;
1181 }
1182}
1183
1185{
1186 int i;
1187
1188 // unload fallbacks
1189 if(font->next)
1190 Font_UnloadFont(font->next);
1191
1192 if (font->attachments && font->attachmentcount)
1193 {
1194 for (i = 0; i < (int)font->attachmentcount; ++i) {
1195 if (font->attachments[i].data)
1196 fontfilecache_Free(font->attachments[i].data);
1197 }
1198 Mem_Free(font->attachments);
1199 font->attachmentcount = 0;
1200 font->attachments = NULL;
1201 }
1202 for (i = 0; i < MAX_FONT_SIZES; ++i)
1203 {
1204 if (font->font_maps[i])
1205 {
1206 UnloadMapChain(font->font_maps[i]);
1207 font->font_maps[i] = NULL;
1208 }
1209 }
1210#ifndef DP_FREETYPE_STATIC
1211 if (ft2_dll)
1212#else
1214#endif
1215 {
1216 if (font->face)
1217 {
1218 qFT_Done_Face((FT_Face)font->face);
1219 font->face = NULL;
1220 }
1221 }
1222 if (font->data) {
1223 fontfilecache_Free(font->data);
1224 font->data = NULL;
1225 }
1226}
1227
1228static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1229{
1230 float intSize = size;
1231 while (1)
1232 {
1233 if (!Font_SetSize(font, intSize, intSize))
1234 {
1235 Con_Printf(CON_ERROR "ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1236 return -1;
1237 }
1238 if ((fontface->size->metrics.height>>6) <= size)
1239 return intSize;
1240 if (intSize < 2)
1241 {
1242 Con_Printf(CON_ERROR "ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1243 return -1;
1244 }
1245 --intSize;
1246 }
1247}
1248
1249// helper inline functions for incmap_post_process:
1250
1251static inline void update_pic_for_fontmap(ft2_font_map_t *fontmap, const char *identifier,
1252 int width, int height, unsigned char *data)
1253{
1254 fontmap->pic = Draw_NewPic(identifier, width, height, data, TEXTYPE_RGBA,
1256}
1257
1258// glyphs' texture coords needs to be fixed when merging to bigger texture
1259static inline void transform_glyph_coords(glyph_slot_t *glyph, float shiftx, float shifty, float scalex, float scaley)
1260{
1261 glyph->txmin = glyph->txmin * scalex + shiftx;
1262 glyph->txmax = glyph->txmax * scalex + shiftx;
1263 glyph->tymin = glyph->tymin * scaley + shifty;
1264 glyph->tymax = glyph->tymax * scaley + shifty;
1265}
1266#define fix_glyph_coords_tier1(glyph, order) transform_glyph_coords(glyph, order / (float)FONT_CHARS_PER_LINE, 0.0f, 1.0f / (float)FONT_CHARS_PER_LINE, 1.0f)
1267#define fix_glyph_coords_tier2(glyph, order) transform_glyph_coords(glyph, 0.0f, order / (float)FONT_CHARS_PER_LINE, 1.0f, 1.0f / (float)FONT_CHARS_PER_LINE)
1268
1269// pull glyph things from sourcemap to targetmap
1270static inline void merge_single_map(ft2_font_map_t *targetmap, int targetindex, ft2_font_map_t *sourcemap, int sourceindex)
1271{
1272 targetmap->glyphs[targetindex] = sourcemap->glyphs[sourceindex];
1273 targetmap->glyphchars[targetindex] = sourcemap->glyphchars[sourceindex];
1274}
1275
1276#define calc_data_arguments(w, h) \
1277 width = startmap->glyphSize * w; \
1278 height = startmap->glyphSize * h; \
1279 pitch = width * bytes_per_pixel; \
1280 datasize = height * pitch;
1281
1282// do incremental map process
1283static inline void incmap_post_process(font_incmap_t *incmap, Uchar ch,
1284 unsigned char *data, ft2_font_map_t **outmap, int *outmapch)
1285{
1286 #define bytes_per_pixel 4
1287
1288 int index, targetmap_at;
1289 // where will the next `data` be placed
1290 int tier1_data_index, tier2_data_index;
1291 // metrics of data to manipulate
1292 int width, height, pitch, datasize;
1293 int i, j, x, y;
1294 unsigned char *newdata, *chunk;
1295 ft2_font_map_t *startmap, *targetmap, *currentmap;
1296 #define M FONT_CHARS_PER_LINE
1297 #define N FONT_CHAR_LINES
1298
1299 startmap = incmap->fontmap;
1300 index = incmap->charcount;
1301 tier1_data_index = index % M;
1302 tier2_data_index = incmap->tier1_merged;
1303
1304 incmap->data_tier1[tier1_data_index] = data;
1305
1306 if (index % M == M - 1)
1307 {
1308 // tier 1 reduction, pieces to line
1309 calc_data_arguments(1, 1);
1310 targetmap_at = incmap->tier2_merged + incmap->tier1_merged;
1311 targetmap = startmap;
1312 for (i = 0; i < targetmap_at; ++i)
1313 targetmap = targetmap->next;
1314 currentmap = targetmap;
1315 newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * M);
1316 for (i = 0; i < M; ++i)
1317 {
1318 chunk = incmap->data_tier1[i];
1319 if (chunk == NULL)
1320 continue;
1321 for (y = 0; y < datasize; y += pitch)
1322 for (x = 0; x < pitch; ++x)
1323 newdata[y * M + i * pitch + x] = chunk[y + x];
1324 Mem_Free(chunk);
1325 incmap->data_tier1[i] = NULL;
1326 merge_single_map(targetmap, i, currentmap, 0);
1327 fix_glyph_coords_tier1(&targetmap->glyphs[i], (float)i);
1328 currentmap = currentmap->next;
1329 }
1330 update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width * M, height, newdata);
1331 UnloadMapChain(targetmap->next);
1332 targetmap->next = NULL;
1333 incmap->data_tier2[tier2_data_index] = newdata;
1334 ++incmap->tier1_merged;
1335 incmap->tier1_merged %= M;
1336 incmap->newmap_start = INCMAP_START + targetmap_at + 1;
1337 // then give this merged map
1338 *outmap = targetmap;
1339 *outmapch = FONT_CHARS_PER_LINE - 1;
1340 }
1341 if (index % (M * N) == M * N - 1)
1342 {
1343 // tier 2 reduction, lines to full map
1345 targetmap_at = incmap->tier2_merged;
1346 targetmap = startmap;
1347 for (i = 0; i < targetmap_at; ++i)
1348 targetmap = targetmap->next;
1349 currentmap = targetmap;
1350 newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * N);
1351 for (i = 0; i < N; ++i)
1352 {
1353 chunk = incmap->data_tier2[i];
1354 if (chunk == NULL)
1355 continue;
1356 for (x = 0; x < datasize; ++x)
1357 newdata[i * datasize + x] = chunk[x];
1358 Mem_Free(chunk);
1359 incmap->data_tier2[i] = NULL;
1360 for (j = 0; j < M; ++j)
1361 {
1362 merge_single_map(targetmap, i * M + j, currentmap, j);
1363 fix_glyph_coords_tier2(&targetmap->glyphs[i * M + j], (float)i);
1364 }
1365 currentmap = currentmap->next;
1366 }
1367 update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width, height * N, newdata);
1368 UnloadMapChain(targetmap->next);
1369 targetmap->next = NULL;
1370 Mem_Free(newdata);
1371 ++incmap->tier2_merged;
1372 incmap->newmap_start = INCMAP_START + targetmap_at + 1;
1373 // then give this merged map
1374 *outmap = targetmap;
1375 *outmapch = FONT_CHARS_PER_MAP - 1;
1376 }
1377
1378 ++incmap->charcount;
1379 ++incmap->newmap_start;
1380
1381 #undef M
1382 #undef N
1383}
1384
1385static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch,
1386 ft2_font_map_t **outmap, int *outmapch, qbool use_incmap)
1387{
1388 #define bytes_per_pixel 4
1389
1390 char map_identifier[MAX_QPATH];
1391 unsigned long map_startglyph = _ch / FONT_CHARS_PER_MAP * FONT_CHARS_PER_MAP;
1392 unsigned char *data = NULL;
1393 FT_ULong ch = 0, mapch = 0;
1394 int status;
1395 int tp;
1396 FT_Int32 load_flags;
1397 int gpad_l, gpad_r, gpad_t, gpad_b;
1398
1399 int pitch;
1400 int width, height, datasize;
1401 int glyph_row, glyph_column;
1402
1403 int chars_per_line = FONT_CHARS_PER_LINE;
1404 int char_lines = FONT_CHAR_LINES;
1405 int chars_per_map = FONT_CHARS_PER_MAP;
1406
1407 ft2_font_t *usefont;
1408 ft2_font_map_t *map, *next;
1409 font_incmap_t *incmap;
1410
1411 FT_Face fontface;
1412
1413 incmap = mapstart->incmap;
1414 if (use_incmap)
1415 {
1416 // only render one character in this map;
1417 // such small maps will be merged together later in `incmap_post_process`
1418 chars_per_line = char_lines = chars_per_map = 1;
1419 // and the index is incremental
1420 map_startglyph = incmap ? incmap->newmap_start : INCMAP_START;
1421 }
1422
1423 if (font->image_font)
1424 fontface = (FT_Face)font->next->face;
1425 else
1426 fontface = (FT_Face)font->face;
1427
1428 switch(font->settings->antialias)
1429 {
1430 case 0:
1431 switch(font->settings->hinting)
1432 {
1433 case 0:
1435 break;
1436 case 1:
1437 case 2:
1439 break;
1440 default:
1441 case 3:
1443 break;
1444 }
1445 break;
1446 default:
1447 case 1:
1448 switch(font->settings->hinting)
1449 {
1450 case 0:
1452 break;
1453 case 1:
1455 break;
1456 case 2:
1458 break;
1459 default:
1460 case 3:
1461 load_flags = FT_LOAD_TARGET_NORMAL;
1462 break;
1463 }
1464 break;
1465 }
1466
1467 //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1468 //if (status)
1469 if (font->image_font && mapstart->intSize < 0)
1470 mapstart->intSize = mapstart->size;
1471 if (mapstart->intSize < 0)
1472 {
1473 /*
1474 mapstart->intSize = mapstart->size;
1475 while (1)
1476 {
1477 if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1478 {
1479 Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1480 return false;
1481 }
1482 if ((fontface->size->metrics.height>>6) <= mapstart->size)
1483 break;
1484 if (mapstart->intSize < 2)
1485 {
1486 Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1487 return false;
1488 }
1489 --mapstart->intSize;
1490 }
1491 */
1492 if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1493 return false;
1494 Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1495 }
1496
1497 if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1498 {
1499 Con_Printf(CON_ERROR "ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1500 return false;
1501 }
1502
1503 map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1504 if (!map)
1505 {
1506 Con_Printf(CON_ERROR "ERROR: Out of memory when allocating fontmap for %s\n", font->name);
1507 return false;
1508 }
1509
1510 map->start = map_startglyph;
1511
1512 // create a unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1513 /*
1514 dpsnprintf(map_identifier, sizeof(map_identifier),
1515 "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u_%lx",
1516 font->name,
1517 (double) mapstart->intSize,
1518 (int) load_flags,
1519 (double) font->settings->blur,
1520 (double) font->settings->outline,
1521 (double) font->settings->shadowx,
1522 (double) font->settings->shadowy,
1523 (double) font->settings->shadowz,
1524 (unsigned) map_startglyph,
1525 // add pointer as a unique part to avoid earlier incmaps' state being trashed
1526 use_incmap ? (unsigned long)mapstart : 0x0);
1527 */
1528 /*
1529 * note 1: it appears that different font instances may have the same metrics, causing this pic being overwritten
1530 * will use startmap's pointer as a unique part to avoid earlier incmaps' dynamic pics being trashed
1531 * note 2: if this identifier is made too long, significient performance drop will take place
1532 * note 3: blur/outline/shadow are per-font settings, so a pointer to startmap & map size
1533 * already made these unique, hence they are omitted
1534 * note 4: font_diskcache is removed, this name can be less meaningful
1535 */
1536 dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%g_%p_%u",
1537 font->name, mapstart->intSize, mapstart, (unsigned) map_startglyph);
1538
1539 // create a cachepic_t from the data now, or reuse an existing one
1541 Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1542
1543 Font_Postprocess(font, NULL, 0, bytes_per_pixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1544
1545 // copy over the information
1546 map->size = mapstart->size;
1547 map->intSize = mapstart->intSize;
1548 map->glyphSize = mapstart->glyphSize;
1549 map->sfx = mapstart->sfx;
1550 map->sfy = mapstart->sfy;
1551
1552 width = map->glyphSize * chars_per_line;
1553 height = map->glyphSize * char_lines;
1554 pitch = width * bytes_per_pixel;
1555 datasize = height * pitch;
1556 data = (unsigned char *)Mem_Alloc(font_mempool, datasize);
1557 if (!data)
1558 {
1559 Con_Printf(CON_ERROR "ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1560 Mem_Free(map);
1561 return false;
1562 }
1563
1564 if (use_incmap)
1565 {
1566 if (mapstart->incmap == NULL)
1567 {
1568 // initial incmap
1569 incmap = mapstart->incmap = (font_incmap_t *)Mem_Alloc(font_mempool, sizeof(font_incmap_t));
1570 if (!incmap)
1571 {
1572 Con_Printf(CON_ERROR "ERROR: Out of memory when allocating incremental fontmap for %s\n", font->name);
1573 return false;
1574 }
1575 // this will be the startmap of incmap
1576 incmap->fontmap = map;
1577 incmap->newmap_start = INCMAP_START;
1578 }
1579 else
1580 {
1581 // new maps for incmap shall always be the last one
1582 next = incmap->fontmap;
1583 while (next->next != NULL)
1584 next = next->next;
1585 next->next = map;
1586 }
1587 }
1588 else
1589 {
1590 // insert this normal map
1591 next = use_incmap ? incmap->fontmap : mapstart;
1592 while(next->next && next->next->start < map->start)
1593 next = next->next;
1594 map->next = next->next;
1595 next->next = map;
1596 }
1597
1598 // initialize as white texture with zero alpha
1599 tp = 0;
1600 while (tp < datasize)
1601 {
1602 if (bytes_per_pixel == 4)
1603 {
1604 data[tp++] = 0xFF;
1605 data[tp++] = 0xFF;
1606 data[tp++] = 0xFF;
1607 }
1608 data[tp++] = 0x00;
1609 }
1610
1611 glyph_row = 0;
1612 glyph_column = 0;
1613 ch = (FT_ULong)(use_incmap ? _ch : map->start);
1614 mapch = 0;
1615 while (true)
1616 {
1617 FT_ULong glyphIndex;
1618 int w, h, x, y;
1619 FT_GlyphSlot glyph;
1620 FT_Bitmap *bmp;
1621 unsigned char *imagedata = NULL, *dst, *src;
1622 glyph_slot_t *mapglyph;
1623 FT_Face face;
1624 int pad_l, pad_r, pad_t, pad_b;
1625
1627 Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1628
1629 map->glyphchars[mapch] = (Uchar)ch;
1630
1631 if (data)
1632 {
1633 imagedata = data + glyph_row * pitch * map->glyphSize + glyph_column * map->glyphSize * bytes_per_pixel;
1634 imagedata += gpad_t * pitch + gpad_l * bytes_per_pixel;
1635 }
1636 //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1637 // we need the glyphIndex
1638 face = (FT_Face)font->face;
1639 usefont = NULL;
1640 if (font->image_font && mapch == ch && img_fontmap[mapch])
1641 {
1642 map->glyphs[mapch].image = true;
1643 continue;
1644 }
1645 glyphIndex = qFT_Get_Char_Index(face, ch);
1646 if (glyphIndex == 0)
1647 {
1648 // by convention, 0 is the "missing-glyph"-glyph
1649 // try to load from a fallback font
1650 for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1651 {
1652 if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1653 continue;
1654 // try that glyph
1655 face = (FT_Face)usefont->face;
1656 glyphIndex = qFT_Get_Char_Index(face, ch);
1657 if (glyphIndex == 0)
1658 continue;
1659 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1660 if (status)
1661 continue;
1662 break;
1663 }
1664 if (!usefont)
1665 {
1666 //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1667 // now we let it use the "missing-glyph"-glyph
1668 face = (FT_Face)font->face;
1669 glyphIndex = 0;
1670 }
1671 }
1672
1673 if (!usefont)
1674 {
1675 usefont = font;
1676 face = (FT_Face)font->face;
1677 status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1678 if (status)
1679 {
1680 //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1681 Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1682 continue;
1683 }
1684 }
1685
1686 glyph = face->glyph;
1687 bmp = &glyph->bitmap;
1688
1689 w = bmp->width;
1690 h = bmp->rows;
1691
1692 if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1693 Con_Printf(CON_WARN "WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1694 if (w > map->glyphSize)
1695 w = map->glyphSize - gpad_l - gpad_r;
1696 if (h > map->glyphSize)
1697 h = map->glyphSize;
1698 }
1699
1700 if (imagedata)
1701 {
1702 switch (bmp->pixel_mode)
1703 {
1704 case FT_PIXEL_MODE_MONO:
1706 Con_DPrint("glyphinfo: Pixel Mode: MONO\n");
1707 break;
1710 Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n");
1711 break;
1714 Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n");
1715 break;
1716 case FT_PIXEL_MODE_GRAY:
1718 Con_DPrint("glyphinfo: Pixel Mode: GRAY\n");
1719 break;
1720 default:
1722 Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1723 Mem_Free(data);
1724 Con_Printf(CON_ERROR "ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1725 return false;
1726 }
1727 for (y = 0; y < h; ++y)
1728 {
1729 dst = imagedata + y * pitch;
1730 src = bmp->buffer + y * bmp->pitch;
1731
1732 switch (bmp->pixel_mode)
1733 {
1734 case FT_PIXEL_MODE_MONO:
1735 dst += bytes_per_pixel - 1; // shift to alpha byte
1736 for (x = 0; x < bmp->width; x += 8)
1737 {
1738 unsigned char c = *src++;
1739 *dst = 255 * !!((c & 0x80) >> 7); dst += bytes_per_pixel;
1740 *dst = 255 * !!((c & 0x40) >> 6); dst += bytes_per_pixel;
1741 *dst = 255 * !!((c & 0x20) >> 5); dst += bytes_per_pixel;
1742 *dst = 255 * !!((c & 0x10) >> 4); dst += bytes_per_pixel;
1743 *dst = 255 * !!((c & 0x08) >> 3); dst += bytes_per_pixel;
1744 *dst = 255 * !!((c & 0x04) >> 2); dst += bytes_per_pixel;
1745 *dst = 255 * !!((c & 0x02) >> 1); dst += bytes_per_pixel;
1746 *dst = 255 * !!((c & 0x01) >> 0); dst += bytes_per_pixel;
1747 }
1748 break;
1750 dst += bytes_per_pixel - 1; // shift to alpha byte
1751 for (x = 0; x < bmp->width; x += 4)
1752 {
1753 unsigned char c = *src++;
1754 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1755 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1756 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1757 *dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytes_per_pixel;
1758 }
1759 break;
1761 dst += bytes_per_pixel - 1; // shift to alpha byte
1762 for (x = 0; x < bmp->width; x += 2)
1763 {
1764 unsigned char c = *src++;
1765 *dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytes_per_pixel;
1766 *dst = ( ((c & 0x0F) ) * 0x11); dst += bytes_per_pixel;
1767 }
1768 break;
1769 case FT_PIXEL_MODE_GRAY:
1770 // in this case pitch should equal width
1771 for (tp = 0; tp < bmp->pitch; ++tp)
1772 dst[(bytes_per_pixel - 1) + tp*bytes_per_pixel] = src[tp]; // copy the grey value into the alpha bytes
1773
1774 //memcpy((void*)dst, (void*)src, bmp->pitch);
1775 //dst += bmp->pitch;
1776 break;
1777 default:
1778 break;
1779 }
1780 }
1781
1782 pad_l = gpad_l;
1783 pad_r = gpad_r;
1784 pad_t = gpad_t;
1785 pad_b = gpad_b;
1786 Font_Postprocess(font, imagedata, pitch, bytes_per_pixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1787 }
1788 else
1789 {
1790 pad_l = gpad_l;
1791 pad_r = gpad_r;
1792 pad_t = gpad_t;
1793 pad_b = gpad_b;
1794 Font_Postprocess(font, NULL, pitch, bytes_per_pixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1795 }
1796
1797
1798 // now fill map->glyphs[ch - map->start]
1799 mapglyph = &map->glyphs[mapch];
1800
1801 {
1802 // old way
1803 // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1804
1805 double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1806 //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1807 double advance = (glyph->advance.x / 64.0) / map->size;
1808 //double mWidth = (glyph->metrics.width >> 6) / map->size;
1809 //double mHeight = (glyph->metrics.height >> 6) / map->size;
1810
1811 mapglyph->txmin = ( (double)(glyph_column * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * chars_per_line) );
1812 mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * chars_per_line) );
1813 mapglyph->tymin = ( (double)(glyph_row * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * char_lines) );
1814 mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * char_lines) );
1815 //mapglyph->vxmin = bearingX;
1816 //mapglyph->vxmax = bearingX + mWidth;
1817 mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1818 mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1819 //mapglyph->vymin = -bearingY;
1820 //mapglyph->vymax = mHeight - bearingY;
1821 mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1822 mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1823 //Con_Printf("dpi = %f %f (%f %d) %d %d\n", bmp->width / (mapglyph->vxmax - mapglyph->vxmin), bmp->rows / (mapglyph->vymax - mapglyph->vymin), map->size, map->glyphSize, (int)fontface->size->metrics.x_ppem, (int)fontface->size->metrics.y_ppem);
1824 //mapglyph->advance_x = advance * usefont->size;
1825 //mapglyph->advance_x = advance;
1826 mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1827 mapglyph->advance_y = 0;
1828
1830 {
1831 Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, glyph_column, glyph_row);
1832 Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1833 if (ch >= 32 && ch <= 128)
1834 Con_DPrintf("glyphinfo: Character: %c\n", (int)ch);
1835 Con_DPrintf("glyphinfo: Vertex info:\n");
1836 Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1837 Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax);
1838 Con_DPrintf("glyphinfo: Texture info:\n");
1839 Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax);
1840 Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax);
1841 Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1842 }
1843 }
1844 map->glyphs[mapch].image = false;
1845
1846 ++mapch; ++ch;
1847 if ((int)mapch == chars_per_map)
1848 break;
1849 if (++glyph_column % chars_per_line == 0)
1850 {
1851 glyph_column = 0;
1852 ++glyph_row;
1853 }
1854 }
1855
1856 // update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1857 update_pic_for_fontmap(map, map_identifier, width, height, data);
1858
1859 if (!Draw_IsPicLoaded(map->pic))
1860 {
1861 // if the first try isn't successful, keep it with a broken texture
1862 // otherwise we retry to load it every single frame where ft2 rendering is used
1863 // this would be bad...
1864 // only `data' must be freed
1865 Con_Printf(CON_ERROR "ERROR: Failed to generate texture for font %s size %f map %lu\n",
1866 font->name, mapstart->size, map_startglyph);
1867 return false;
1868 }
1869
1870 if (use_incmap)
1871 {
1872 *outmap = map;
1873 *outmapch = 0;
1874 // data will be kept in incmap for being merged later, freed afterward
1875 incmap_post_process(incmap, _ch, data, outmap, outmapch);
1876 }
1877 else if (data)
1878 {
1879 Mem_Free(data);
1880 *outmap = map;
1881 if (outmapch != NULL)
1882 *outmapch = _ch - map->start;
1883 }
1884
1885 return true;
1886}
1887
1889static inline void alert_legacy_font_api(const char *name)
1890{
1892 {
1893 Con_DPrintf(CON_WARN "Warning: You are using an legacy API '%s', which have certain limitations; please use 'Font_GetMapForChar' instead\n", name);
1895 }
1896}
1897
1898// legacy font API, please use `Font_GetMapForChar` instead
1899qbool Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap)
1900{
1901 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1902 return false;
1903 // the first map must have been loaded already
1904 if (!font->font_maps[map_index])
1905 return false;
1906 alert_legacy_font_api("Font_LoadMapForIndex");
1907 return Font_LoadMap(font, font->font_maps[map_index], ch, outmap, NULL, false);
1908}
1909
1910// legacy font API. please use `Font_GetMapForChar` instead
1911ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1912{
1913 ft2_font_map_t *map = start;
1914 while (map && map->start + FONT_CHARS_PER_MAP <= ch)
1915 map = map->next;
1916 if (map && map->start > ch)
1917 return NULL;
1918 alert_legacy_font_api("FontMap_FindForChar");
1919 return map;
1920}
1921
1923{
1924 int i;
1925 // optimize: a simple check logic for usual conditions
1926 if (ch < unicode_bigblocks[0])
1927 return false;
1929 return false;
1930 for (i = 0; i < (int)(sizeof(unicode_bigblocks) / sizeof(Uchar)); i += 2)
1931 if (unicode_bigblocks[i] <= ch && ch <= unicode_bigblocks[i + 1])
1932 return true;
1933 return false;
1934}
1935
1936static inline qbool get_char_from_incmap(ft2_font_map_t *map, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
1937{
1938 int i;
1939 font_incmap_t *incmap;
1940
1941 incmap = map->incmap;
1942 *outmapch = 0;
1943
1944 if (incmap != NULL)
1945 {
1946 map = incmap->fontmap;
1947 while (map != NULL)
1948 {
1949 for (i = 0; i < FONT_CHARS_PER_MAP; ++i)
1950 {
1951 if (map->glyphchars[i] == ch)
1952 {
1953 *outmap = map;
1954 *outmapch = i;
1955 return true;
1956 }
1957 else if (map->glyphchars[i] == 0)
1958 // this tier0/tier1 map ends here
1959 break;
1960 }
1961 map = map->next;
1962 }
1963 }
1964 return false;
1965}
1966
1971qbool Font_GetMapForChar(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
1972{
1973 qbool use_incmap;
1974 ft2_font_map_t *map;
1975
1976 // startmap
1977 map = Font_MapForIndex(font, map_index);
1978
1979 // optimize: the first map must have been loaded already
1980 if (ch < FONT_CHARS_PER_MAP)
1981 {
1982 *outmapch = ch;
1983 *outmap = map;
1984 return true;
1985 }
1986
1987 // search for the character
1988
1989 use_incmap = should_use_incmap(ch);
1990
1991 if (!use_incmap)
1992 {
1993 // normal way
1994 *outmapch = ch % FONT_CHARS_PER_MAP;
1995 while (map && map->start + FONT_CHARS_PER_MAP <= ch)
1996 map = map->next;
1997 if (map && map->start <= ch)
1998 {
1999 *outmap = map;
2000 return true;
2001 }
2002 }
2003 else if (get_char_from_incmap(map, ch, outmap, outmapch))
2004 // got it
2005 return true;
2006
2007 // so no appropriate map was found, load one
2008
2009 if (map_index < 0 || map_index >= MAX_FONT_SIZES)
2010 return false;
2011 return Font_LoadMap(font, font->font_maps[map_index], ch, outmap, outmapch, use_incmap);
2012}
cvar_t vid_conheight
Definition cl_screen.c:57
cvar_t vid_conwidth
Definition cl_screen.c:56
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:997
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
#define CON_WARN
Definition console.h:101
#define CON_ERROR
Definition console.h:102
vector size
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599
cachepic_t * Draw_NewPic(const char *picname, int width, int height, unsigned char *pixels, textype_t textype, int texflags)
Definition gl_draw.c:256
const char * Draw_GetPicName(cachepic_t *pic)
Definition gl_draw.c:190
dp_fonts_t dp_fonts
Definition gl_draw.c:50
#define MAX_FONT_FALLBACKS
Definition draw.h:95
#define MAX_FONT_SIZES
Definition draw.h:94
qbool Draw_IsPicLoaded(cachepic_t *pic)
Definition gl_draw.c:211
unsigned char * FS_LoadFile(const char *path, mempool_t *pool, qbool quiet, fs_offset_t *filesizepointer)
Definition fs.c:3540
static int(ZEXPORT *qz_inflate)(z_stream *strm
const char * FS_FileExists(const char *filename)
Look for a file in the packages and in the filesystem Returns its canonical name (same case as used i...
Definition fs.c:3693
int64_t fs_offset_t
Definition fs.h:37
#define N
void font_newmap(void)
Definition ft2.c:439
#define MAX_FONTFILES
Definition ft2.c:267
(* qFT_Get_Char_Index)(FT_Face face, FT_ULong charcode)
Definition ft2.c:118
static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b)
Definition ft2.c:787
cvar_t r_font_size_snapping
Definition ft2.c:56
#define fix_glyph_coords_tier2(glyph, order)
Definition ft2.c:1267
(* qFT_Set_Pixel_Sizes)(FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height)
Definition ft2.c:106
static const Uchar unicode_bigblocks[]
Definition ft2.c:41
static qbool Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
Definition ft2.c:628
cvar_t r_font_disable_incmaps
Definition ft2.c:63
cvar_t r_font_nonpoweroftwo
Definition ft2.c:60
(* qFT_Set_Char_Size)(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution)
Definition ft2.c:100
qbool Font_OpenLibrary(void)
Definition ft2.c:362
static int img_fontmap[256]
Definition ft2.c:11
(* qFT_Done_FreeType)(FT_Library library)
Definition ft2.c:77
ft2_font_map_t * Font_MapForIndex(ft2_font_t *font, int index)
Definition ft2.c:1052
static qbool Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
Definition ft2.c:478
static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap, int *outmapch, qbool incmap_ok)
Definition ft2.c:1385
cvar_t r_font_disable_freetype
Definition ft2.c:55
(* qFT_New_Memory_Face)(FT_Library library, const FT_Byte *file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface)
Definition ft2.c:86
#define M
static void incmap_post_process(font_incmap_t *incmap, Uchar ch, unsigned char *data, ft2_font_map_t **outmap, int *outmapch)
Definition ft2.c:1283
(* qFT_Select_Size)(FT_Face face, FT_Int strike_index)
Definition ft2.c:94
float Font_SnapTo(float val, float snapwidth)
Definition ft2.c:514
static FT_Library font_ft2lib
FreeType library handle.
Definition ft2.c:244
ft2_font_t * Font_Alloc(void)
Definition ft2.c:467
qbool Font_LoadFont(const char *name, dp_font_t *dpfnt)
Definition ft2.c:521
void font_start(void)
Definition ft2.c:404
static void UnloadMapChain(ft2_font_map_t *map)
Definition ft2.c:1150
static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
Definition ft2.c:1228
qbool Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
Definition ft2.c:1085
int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
Definition ft2.c:999
static void merge_single_map(ft2_font_map_t *targetmap, int targetindex, ft2_font_map_t *sourcemap, int sourceindex)
Definition ft2.c:1270
static qbool get_char_from_incmap(ft2_font_map_t *map, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
Definition ft2.c:1936
static qbool Font_SetSize(ft2_font_t *font, float w, float h)
Definition ft2.c:1059
void Font_CloseLibrary(void)
Definition ft2.c:339
float Font_VirtualToRealSize(float sz)
Definition ft2.c:496
static void fontfilecache_FreeAll(void)
Definition ft2.c:320
static const unsigned char * fontfilecache_LoadFile(const char *path, qbool quiet, fs_offset_t *filesizepointer)
Definition ft2.c:269
static void fontfilecache_Free(const unsigned char *buf)
Definition ft2.c:301
cvar_t r_font_compress
Definition ft2.c:59
ft2_font_map_t * FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
Definition ft2.c:1911
void Font_Init(void)
Definition ft2.c:443
static void transform_glyph_coords(glyph_slot_t *glyph, float shiftx, float shifty, float scalex, float scaley)
Definition ft2.c:1259
(* qFT_Init_FreeType)(FT_Library *alibrary)
Definition ft2.c:75
cvar_t r_font_kerning
Definition ft2.c:57
static void update_pic_for_fontmap(ft2_font_map_t *fontmap, const char *identifier, int width, int height, unsigned char *data)
Definition ft2.c:1251
#define bytes_per_pixel
(* qFT_Render_Glyph)(FT_GlyphSlot slot, FT_Render_Mode render_mode)
Definition ft2.c:121
qbool Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap)
Definition ft2.c:1899
(* qFT_Attach_Stream)(FT_Face face, FT_Open_Args *parameters)
Definition ft2.c:130
static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
Definition ft2.c:733
#define POSTPROCESS_MAXRADIUS
Definition ft2.c:246
qbool Font_GetMapForChar(ft2_font_t *font, int map_index, Uchar ch, ft2_font_map_t **outmap, int *outmapch)
Query for or load a font map for a character, with the character's place on it.
Definition ft2.c:1971
void font_shutdown(void)
Definition ft2.c:425
#define calc_data_arguments(w, h)
Definition ft2.c:1276
cvar_t r_font_diskcache
Definition ft2.c:58
static qbool Font_LoadSize(ft2_font_t *font, float size, qbool check_only)
Definition ft2.c:911
void Font_UnloadFont(ft2_font_t *font)
Definition ft2.c:1184
static dllfunction_t ft2funcs[]
Definition ft2.c:138
static qbool legacy_font_loading_api_alerted
Definition ft2.c:1888
qbool Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
Definition ft2.c:1143
static mempool_t * font_mempool
Memory pool for fonts.
Definition ft2.c:241
static void alert_legacy_font_api(const char *name)
Definition ft2.c:1889
(* qFT_Get_Kerning)(FT_Face face, FT_UInt left_glyph, FT_UInt right_glyph, FT_UInt kern_mode, FT_Vector *akerning)
Definition ft2.c:124
(* qFT_Load_Char)(FT_Face face, FT_ULong char_code, FT_Int32 load_flags)
Definition ft2.c:114
static dllhandle_t ft2_dll
Handle for FreeType2 DLL.
Definition ft2.c:159
static font_postprocess_t pp
Definition ft2.c:257
(* qFT_Done_Face)(FT_Face face)
Definition ft2.c:92
static qbool should_use_incmap(Uchar ch)
Definition ft2.c:1922
static fontfilecache_t fontfiles[MAX_FONTFILES]
Definition ft2.c:268
cvar_t developer_font
Definition ft2.c:61
#define fix_glyph_coords_tier1(glyph, order)
Definition ft2.c:1266
(* qFT_Request_Size)(FT_Face face, FT_Size_Request req)
Definition ft2.c:97
(* qFT_Load_Glyph)(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition ft2.c:110
#define FT_FACE_FLAG_KERNING
Definition ft2_defs.h:484
#define FT_LOAD_RENDER
Definition ft2_defs.h:267
#define FT_LOAD_TARGET_MONO
Definition ft2_defs.h:284
#define FT_LOAD_TARGET_NORMAL
Definition ft2_defs.h:282
FT_Render_Mode
Definition ft2_defs.h:70
signed long FT_F26Dot6
Definition ft2_defs.h:31
@ FT_PIXEL_MODE_GRAY2
Definition ft2_defs.h:63
@ FT_PIXEL_MODE_MONO
Definition ft2_defs.h:61
@ FT_PIXEL_MODE_GRAY
Definition ft2_defs.h:62
@ FT_PIXEL_MODE_GRAY4
Definition ft2_defs.h:64
#define FT_LOAD_NO_HINTING
Definition ft2_defs.h:266
unsigned long FT_ULong
Definition ft2_defs.h:28
unsigned char FT_Byte
Definition ft2_defs.h:19
@ FT_KERNING_DEFAULT
Definition ft2_defs.h:495
#define FT_LOAD_FORCE_AUTOHINT
Definition ft2_defs.h:270
int FT_Error
Definition ft2_defs.h:16
void * FT_Library
Definition ft2_defs.h:35
int32_t FT_Int32
Definition ft2_defs.h:12
#define FT_LOAD_MONOCHROME
Definition ft2_defs.h:276
struct FT_Size_RequestRec_ * FT_Size_Request
Definition ft2_defs.h:262
struct FT_GlyphSlotRec_ * FT_GlyphSlot
Definition ft2_defs.h:40
struct FT_FaceRec_ * FT_Face
Definition ft2_defs.h:36
signed long FT_Long
Definition ft2_defs.h:26
#define FT_OPEN_MEMORY
Definition ft2_defs.h:220
#define FT_LOAD_NO_AUTOHINT
Definition ft2_defs.h:278
#define FT_EXPORT(x)
Definition ft2_defs.h:218
unsigned int FT_UInt
Definition ft2_defs.h:25
const FT_Byte * FT_Bytes
Definition ft2_defs.h:20
#define FT_LOAD_TARGET_LIGHT
Definition ft2_defs.h:283
signed int FT_Int
Definition ft2_defs.h:24
#define FONT_CHARS_PER_MAP
Definition ft2_fontdefs.h:8
#define FONT_CHARS_PER_LINE
Definition ft2_fontdefs.h:6
#define INCMAP_START
#define FONT_CHAR_LINES
Definition ft2_fontdefs.h:7
GLenum GLsizei width
Definition glquake.h:622
GLenum GLsizei GLsizei height
Definition glquake.h:622
GLubyte GLubyte GLubyte GLubyte w
Definition glquake.h:782
GLsizei const GLfloat * value
Definition glquake.h:740
GLenum GLenum GLsizei count
Definition glquake.h:656
GLint GLenum GLint GLint y
Definition glquake.h:651
GLint GLenum GLint x
Definition glquake.h:651
GLsizeiptr const GLvoid * data
Definition glquake.h:639
GLenum attachment
Definition glquake.h:612
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glquake.h:657
const GLchar * name
Definition glquake.h:601
GLuint index
Definition glquake.h:629
unsigned int CeilPowerOf2(unsigned int value)
returns the smallest integer greater than or equal to "value", or 0 if "value" is too big
Definition mathlib.c:292
#define max(A, B)
Definition mathlib.h:38
#define min(A, B)
Definition mathlib.h:37
#define bound(min, num, max)
Definition mathlib.h:34
float pow(float a, float b)
float ceil(float f)
float strlen(string s)
float sqrt(float f)
float fabs(float f)
float floor(float f)
prvm_eval_t * src
int i
#define MAX_QPATH
max length of a quake game pathname
Definition qdefs.h:169
#define NULL
Definition qtypes.h:12
bool qbool
Definition qtypes.h:9
#define TEXF_ALPHA
Definition r_textures.h:9
#define TEXF_COMPRESS
Definition r_textures.h:23
@ TEXTYPE_RGBA
Definition r_textures.h:51
#define TEXF_CLAMP
Definition r_textures.h:15
dp_FragColor r
vec3 y2
vec3 x2
vec3 x1
int width
Definition ft2_defs.h:89
int rows
Definition ft2_defs.h:88
char pixel_mode
Definition ft2_defs.h:93
unsigned char * buffer
Definition ft2_defs.h:91
int pitch
Definition ft2_defs.h:90
FT_UInt flags
Definition ft2_defs.h:234
FT_Long memory_size
Definition ft2_defs.h:236
const FT_Byte * memory_base
Definition ft2_defs.h:235
FT_Pos x
Definition ft2_defs.h:48
FT_Pos y
Definition ft2_defs.h:49
Definition cvar.h:66
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
struct ft2_font_s * ft2
Definition draw.h:110
int req_face
Definition draw.h:106
float req_sizes[MAX_FONT_SIZES]
Definition draw.h:107
int fallback_faces[MAX_FONT_FALLBACKS]
Definition draw.h:109
ft2_settings_t settings
Definition draw.h:112
char fallbacks[MAX_FONT_FALLBACKS][MAX_QPATH]
Definition draw.h:108
int maxsize
Definition draw.h:121
dp_font_t * f
Definition draw.h:120
int outlinepadding_t
Definition ft2.c:252
int outlinepadding_r
Definition ft2.c:252
float shadowx
Definition ft2.c:251
float outline
Definition ft2.c:251
unsigned char * buf2
Definition ft2.c:249
unsigned char * buf
Definition ft2.c:249
int outlinepadding_b
Definition ft2.c:252
int outlinepadding_l
Definition ft2.c:252
float shadowy
Definition ft2.c:251
float shadowz
Definition ft2.c:251
int blurpadding_rb
Definition ft2.c:252
int blurpadding_lt
Definition ft2.c:252
unsigned char circlematrix[2 *POSTPROCESS_MAXRADIUS+1][2 *POSTPROCESS_MAXRADIUS+1]
Definition ft2.c:253
unsigned char gausstable[2 *POSTPROCESS_MAXRADIUS+1]
Definition ft2.c:254
fs_offset_t len
Definition ft2.c:262
unsigned char * buf
Definition ft2.c:261
int refcount
Definition ft2.c:263
ft2_font_map_t * font_maps[MAX_FONT_SIZES]
Definition ft2.h:57
float currenth
Definition ft2.h:45
qbool image_font
Definition ft2.h:48
ft2_settings_t * settings
Definition ft2.h:64
void * face
Definition ft2.h:54
size_t attachmentcount
Definition ft2.h:61
char name[64]
Definition ft2.h:41
qbool has_kerning
Definition ft2.h:42
ft2_attachment_t * attachments
Definition ft2.h:62
struct ft2_font_s * next
Definition ft2.h:67
float currentw
Definition ft2.h:44
const unsigned char * data
Definition ft2.h:52
float shadowy
Definition draw.h:91
float outline
Definition draw.h:91
int antialias
Definition draw.h:90
float shadowz
Definition draw.h:91
int hinting
Definition draw.h:90
float shadowx
Definition draw.h:91
float blur
Definition draw.h:91
int width
Definition vid.h:60
int height
Definition vid.h:61
viddef_mode_t mode
currently active video mode
Definition vid.h:73
static vec3_t right
Definition sv_user.c:305
void * dllhandle_t
Definition sys.h:169
qbool Sys_LoadDependency(const char **dllnames, dllhandle_t *handle, const dllfunction_t *fcts)
Definition sys_shared.c:131
void Sys_FreeLibrary(dllhandle_t *handle)
Definition sys_shared.c:245
int32_t Uchar
Definition utf8lib.h:35
cvar_t vid_height
Definition vid_shared.c:137
viddef_t vid
global video state
Definition vid_shared.c:64
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_FreePool(pool)
Definition zone.h:105
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Mem_AllocPool(name, flags, parent)
Definition zone.h:104