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 
11 static 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 ================================================================================
32 CVars introduced with the freetype extension
33 ================================================================================
34 */
35 
36 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
37 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"};
38 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!"};
39 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
40 cvar_t r_font_diskcache = {CVAR_SAVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"};
41 cvar_t r_font_compress = {CVAR_SAVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
42 cvar_t r_font_nonpoweroftwo = {CVAR_SAVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
43 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
44 
45 #ifndef DP_FREETYPE_STATIC
46 
47 /*
48 ================================================================================
49 Function definitions. Taken from the freetype2 headers.
50 ================================================================================
51 */
52 
53 
54 FT_EXPORT( FT_Error )
55 (*qFT_Init_FreeType)( FT_Library  *alibrary );
56 FT_EXPORT( FT_Error )
57 (*qFT_Done_FreeType)( FT_Library  library );
58 /*
59 FT_EXPORT( FT_Error )
60 (*qFT_New_Face)( FT_Library   library,
61 		 const char*  filepathname,
62 		 FT_Long      face_index,
63 		 FT_Face     *aface );
64 */
65 FT_EXPORT( FT_Error )
66 (*qFT_New_Memory_Face)( FT_Library      library,
67 			const FT_Byte*  file_base,
68 			FT_Long         file_size,
69 			FT_Long         face_index,
70 			FT_Face        *aface );
71 FT_EXPORT( FT_Error )
72 (*qFT_Done_Face)( FT_Face  face );
73 FT_EXPORT( FT_Error )
74 (*qFT_Select_Size)( FT_Face  face,
75 		    FT_Int   strike_index );
76 FT_EXPORT( FT_Error )
77 (*qFT_Request_Size)( FT_Face          face,
78 		     FT_Size_Request  req );
79 FT_EXPORT( FT_Error )
80 (*qFT_Set_Char_Size)( FT_Face     face,
81 		      FT_F26Dot6  char_width,
82 		      FT_F26Dot6  char_height,
83 		      FT_UInt     horz_resolution,
84 		      FT_UInt     vert_resolution );
85 FT_EXPORT( FT_Error )
86 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
87 			FT_UInt  pixel_width,
88 			FT_UInt  pixel_height );
89 FT_EXPORT( FT_Error )
90 (*qFT_Load_Glyph)( FT_Face   face,
91 		   FT_UInt   glyph_index,
92 		   FT_Int32  load_flags );
93 FT_EXPORT( FT_Error )
94 (*qFT_Load_Char)( FT_Face   face,
95 		  FT_ULong  char_code,
96 		  FT_Int32  load_flags );
97 FT_EXPORT( FT_UInt )
98 (*qFT_Get_Char_Index)( FT_Face   face,
99 		       FT_ULong  charcode );
100 FT_EXPORT( FT_Error )
101 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
102 		     FT_Render_Mode  render_mode );
103 FT_EXPORT( FT_Error )
104 (*qFT_Get_Kerning)( FT_Face     face,
105 		    FT_UInt     left_glyph,
106 		    FT_UInt     right_glyph,
107 		    FT_UInt     kern_mode,
108 		    FT_Vector  *akerning );
109 FT_EXPORT( FT_Error )
110 (*qFT_Attach_Stream)( FT_Face        face,
111 		      FT_Open_Args*  parameters );
112 /*
113 ================================================================================
114 Support for dynamically loading the FreeType2 library
115 ================================================================================
116 */
117 
118 static dllfunction_t ft2funcs[] =
119 {
120 	{"FT_Init_FreeType",		(void **) &qFT_Init_FreeType},
121 	{"FT_Done_FreeType",		(void **) &qFT_Done_FreeType},
122 	//{"FT_New_Face",			(void **) &qFT_New_Face},
123 	{"FT_New_Memory_Face",		(void **) &qFT_New_Memory_Face},
124 	{"FT_Done_Face",		(void **) &qFT_Done_Face},
125 	{"FT_Select_Size",		(void **) &qFT_Select_Size},
126 	{"FT_Request_Size",		(void **) &qFT_Request_Size},
127 	{"FT_Set_Char_Size",		(void **) &qFT_Set_Char_Size},
128 	{"FT_Set_Pixel_Sizes",		(void **) &qFT_Set_Pixel_Sizes},
129 	{"FT_Load_Glyph",		(void **) &qFT_Load_Glyph},
130 	{"FT_Load_Char",		(void **) &qFT_Load_Char},
131 	{"FT_Get_Char_Index",		(void **) &qFT_Get_Char_Index},
132 	{"FT_Render_Glyph",		(void **) &qFT_Render_Glyph},
133 	{"FT_Get_Kerning",		(void **) &qFT_Get_Kerning},
134 	{"FT_Attach_Stream",		(void **) &qFT_Attach_Stream},
135 	{NULL, NULL}
136 };
137 
138 /// Handle for FreeType2 DLL
139 static dllhandle_t ft2_dll = NULL;
140 
141 #else
142 
143 FT_EXPORT( FT_Error )
144 (FT_Init_FreeType)( FT_Library  *alibrary );
145 FT_EXPORT( FT_Error )
146 (FT_Done_FreeType)( FT_Library  library );
147 /*
148 FT_EXPORT( FT_Error )
149 (FT_New_Face)( FT_Library   library,
150 		 const char*  filepathname,
151 		 FT_Long      face_index,
152 		 FT_Face     *aface );
153 */
154 FT_EXPORT( FT_Error )
155 (FT_New_Memory_Face)( FT_Library      library,
156 			const FT_Byte*  file_base,
157 			FT_Long         file_size,
158 			FT_Long         face_index,
159 			FT_Face        *aface );
160 FT_EXPORT( FT_Error )
161 (FT_Done_Face)( FT_Face  face );
162 FT_EXPORT( FT_Error )
163 (FT_Select_Size)( FT_Face  face,
164 		    FT_Int   strike_index );
165 FT_EXPORT( FT_Error )
166 (FT_Request_Size)( FT_Face          face,
167 		     FT_Size_Request  req );
168 FT_EXPORT( FT_Error )
169 (FT_Set_Char_Size)( FT_Face     face,
170 		      FT_F26Dot6  char_width,
171 		      FT_F26Dot6  char_height,
172 		      FT_UInt     horz_resolution,
173 		      FT_UInt     vert_resolution );
174 FT_EXPORT( FT_Error )
175 (FT_Set_Pixel_Sizes)( FT_Face  face,
176 			FT_UInt  pixel_width,
177 			FT_UInt  pixel_height );
178 FT_EXPORT( FT_Error )
179 (FT_Load_Glyph)( FT_Face   face,
180 		   FT_UInt   glyph_index,
181 		   FT_Int32  load_flags );
182 FT_EXPORT( FT_Error )
183 (FT_Load_Char)( FT_Face   face,
184 		  FT_ULong  char_code,
185 		  FT_Int32  load_flags );
186 FT_EXPORT( FT_UInt )
187 (FT_Get_Char_Index)( FT_Face   face,
188 		       FT_ULong  charcode );
189 FT_EXPORT( FT_Error )
190 (FT_Render_Glyph)( FT_GlyphSlot    slot,
191 		     FT_Render_Mode  render_mode );
192 FT_EXPORT( FT_Error )
193 (FT_Get_Kerning)( FT_Face     face,
194 		    FT_UInt     left_glyph,
195 		    FT_UInt     right_glyph,
196 		    FT_UInt     kern_mode,
197 		    FT_Vector  *akerning );
198 FT_EXPORT( FT_Error )
199 (FT_Attach_Stream)( FT_Face        face,
200 		      FT_Open_Args*  parameters );
201 
202 #define qFT_Init_FreeType		FT_Init_FreeType
203 #define qFT_Done_FreeType		FT_Done_FreeType
204 //#define qFT_New_Face			FT_New_Face
205 #define qFT_New_Memory_Face		FT_New_Memory_Face
206 #define qFT_Done_Face			FT_Done_Face
207 #define qFT_Select_Size			FT_Select_Size
208 #define qFT_Request_Size		FT_Request_Size
209 #define qFT_Set_Char_Size		FT_Set_Char_Size
210 #define qFT_Set_Pixel_Sizes		FT_Set_Pixel_Sizes
211 #define qFT_Load_Glyph			FT_Load_Glyph
212 #define qFT_Load_Char			FT_Load_Char
213 #define qFT_Get_Char_Index		FT_Get_Char_Index
214 #define qFT_Render_Glyph		FT_Render_Glyph
215 #define qFT_Get_Kerning			FT_Get_Kerning
216 #define qFT_Attach_Stream		FT_Attach_Stream
217 
218 #endif
219 
220 /// Memory pool for fonts
221 static mempool_t *font_mempool= NULL;
222 
223 /// FreeType library handle
224 static FT_Library font_ft2lib = NULL;
225 
226 #define POSTPROCESS_MAXRADIUS 8
227 typedef struct
228 {
229 	unsigned char *buf, *buf2;
230 	int bufsize, bufwidth, bufheight, bufpitch;
231 	float blur, outline, shadowx, shadowy, shadowz;
232 	int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r;
233 	unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1];
234 	unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1];
235 }
236 font_postprocess_t;
237 static font_postprocess_t pp;
238 
239 typedef struct fontfilecache_s
240 {
241 	unsigned char *buf;
242 	fs_offset_t len;
243 	int refcount;
244 	char path[MAX_QPATH];
245 }
246 fontfilecache_t;
247 #define MAX_FONTFILES 8
248 static fontfilecache_t fontfiles[MAX_FONTFILES];
fontfilecache_LoadFile(const char * path,qboolean quiet,fs_offset_t * filesizepointer)249 static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer)
250 {
251 	int i;
252 	unsigned char *buf;
253 
254 	for(i = 0; i < MAX_FONTFILES; ++i)
255 	{
256 		if(fontfiles[i].refcount > 0)
257 			if(!strcmp(path, fontfiles[i].path))
258 			{
259 				*filesizepointer = fontfiles[i].len;
260 				++fontfiles[i].refcount;
261 				return fontfiles[i].buf;
262 			}
263 	}
264 
265 	buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer);
266 	if(buf)
267 	{
268 		for(i = 0; i < MAX_FONTFILES; ++i)
269 			if(fontfiles[i].refcount <= 0)
270 			{
271 				strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path));
272 				fontfiles[i].len = *filesizepointer;
273 				fontfiles[i].buf = buf;
274 				fontfiles[i].refcount = 1;
275 				return buf;
276 			}
277 	}
278 
279 	return buf;
280 }
fontfilecache_Free(const unsigned char * buf)281 static void fontfilecache_Free(const unsigned char *buf)
282 {
283 	int i;
284 	for(i = 0; i < MAX_FONTFILES; ++i)
285 	{
286 		if(fontfiles[i].refcount > 0)
287 			if(fontfiles[i].buf == buf)
288 			{
289 				if(--fontfiles[i].refcount <= 0)
290 				{
291 					Mem_Free(fontfiles[i].buf);
292 					fontfiles[i].buf = NULL;
293 				}
294 				return;
295 			}
296 	}
297 	// if we get here, it used regular allocation
298 	Mem_Free((void *) buf);
299 }
fontfilecache_FreeAll(void)300 static void fontfilecache_FreeAll(void)
301 {
302 	int i;
303 	for(i = 0; i < MAX_FONTFILES; ++i)
304 	{
305 		if(fontfiles[i].refcount > 0)
306 			Mem_Free(fontfiles[i].buf);
307 		fontfiles[i].buf = NULL;
308 		fontfiles[i].refcount = 0;
309 	}
310 }
311 
312 /*
313 ====================
314 Font_CloseLibrary
315 
316 Unload the FreeType2 DLL
317 ====================
318 */
Font_CloseLibrary(void)319 void Font_CloseLibrary (void)
320 {
321 	fontfilecache_FreeAll();
322 	if (font_mempool)
323 		Mem_FreePool(&font_mempool);
324 	if (font_ft2lib && qFT_Done_FreeType)
325 	{
326 		qFT_Done_FreeType(font_ft2lib);
327 		font_ft2lib = NULL;
328 	}
329 #ifndef DP_FREETYPE_STATIC
330 	Sys_UnloadLibrary (&ft2_dll);
331 #endif
332 	pp.buf = NULL;
333 }
334 
335 /*
336 ====================
337 Font_OpenLibrary
338 
339 Try to load the FreeType2 DLL
340 ====================
341 */
Font_OpenLibrary(void)342 qboolean Font_OpenLibrary (void)
343 {
344 #ifndef DP_FREETYPE_STATIC
345 	const char* dllnames [] =
346 	{
347 #if defined(WIN32)
348 		"libfreetype-6.dll",
349 		"freetype6.dll",
350 #elif defined(MACOSX)
351 		"libfreetype.6.dylib",
352 		"libfreetype.dylib",
353 #else
354 		"libfreetype.so.6",
355 		"libfreetype.so",
356 #endif
357 		NULL
358 	};
359 #endif
360 
361 	if (r_font_disable_freetype.integer)
362 		return false;
363 
364 #ifndef DP_FREETYPE_STATIC
365 	// Already loaded?
366 	if (ft2_dll)
367 		return true;
368 
369 	// Load the DLL
370 	if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs))
371 		return false;
372 #endif
373 	return true;
374 }
375 
376 /*
377 ====================
378 Font_Init
379 
380 Initialize the freetype2 font subsystem
381 ====================
382 */
383 
font_start(void)384 void font_start(void)
385 {
386 	if (!Font_OpenLibrary())
387 		return;
388 
389 	if (qFT_Init_FreeType(&font_ft2lib))
390 	{
391 		Con_Print("ERROR: Failed to initialize the FreeType2 library!\n");
392 		Font_CloseLibrary();
393 		return;
394 	}
395 
396 	font_mempool = Mem_AllocPool("FONT", 0, NULL);
397 	if (!font_mempool)
398 	{
399 		Con_Print("ERROR: Failed to allocate FONT memory pool!\n");
400 		Font_CloseLibrary();
401 		return;
402 	}
403 }
404 
font_shutdown(void)405 void font_shutdown(void)
406 {
407 	int i;
408 	for (i = 0; i < dp_fonts.maxsize; ++i)
409 	{
410 		if (dp_fonts.f[i].ft2)
411 		{
412 			Font_UnloadFont(dp_fonts.f[i].ft2);
413 			dp_fonts.f[i].ft2 = NULL;
414 		}
415 	}
416 	Font_CloseLibrary();
417 }
418 
font_newmap(void)419 void font_newmap(void)
420 {
421 }
422 
Font_Init(void)423 void Font_Init(void)
424 {
425 	Cvar_RegisterVariable(&r_font_nonpoweroftwo);
426 	Cvar_RegisterVariable(&r_font_disable_freetype);
427 	Cvar_RegisterVariable(&r_font_use_alpha_textures);
428 	Cvar_RegisterVariable(&r_font_size_snapping);
429 	Cvar_RegisterVariable(&r_font_kerning);
430 	Cvar_RegisterVariable(&r_font_diskcache);
431 	Cvar_RegisterVariable(&r_font_compress);
432 	Cvar_RegisterVariable(&developer_font);
433 
434 	// let's open it at startup already
435 	Font_OpenLibrary();
436 }
437 
438 /*
439 ================================================================================
440 Implementation of a more or less lazy font loading and rendering code.
441 ================================================================================
442 */
443 
444 #include "ft2_fontdefs.h"
445 
Font_Alloc(void)446 ft2_font_t *Font_Alloc(void)
447 {
448 #ifndef DP_FREETYPE_STATIC
449 	if (!ft2_dll)
450 #else
451 	if (r_font_disable_freetype.integer)
452 #endif
453 		return NULL;
454 	return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
455 }
456 
Font_Attach(ft2_font_t * font,ft2_attachment_t * attachment)457 static qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
458 {
459 	ft2_attachment_t *na;
460 
461 	font->attachmentcount++;
462 	na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount);
463 	if (na == NULL)
464 		return false;
465 	if (font->attachments && font->attachmentcount > 1)
466 	{
467 		memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1));
468 		Mem_Free(font->attachments);
469 	}
470 	memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment));
471 	font->attachments = na;
472 	return true;
473 }
474 
Font_VirtualToRealSize(float sz)475 float Font_VirtualToRealSize(float sz)
476 {
477 	int vh;
478 	//int vw;
479 	int si;
480 	float sn;
481 	if(sz < 0)
482 		return sz;
483 	//vw = ((vid.width > 0) ? vid.width : vid_width.value);
484 	vh = ((vid.height > 0) ? vid.height : vid_height.value);
485 	// now try to scale to our actual size:
486 	sn = sz * vh / vid_conheight.value;
487 	si = (int)sn;
488 	if ( sn - (float)si >= 0.5 )
489 		++si;
490 	return si;
491 }
492 
Font_SnapTo(float val,float snapwidth)493 float Font_SnapTo(float val, float snapwidth)
494 {
495 	return floor(val / snapwidth + 0.5f) * snapwidth;
496 }
497 
498 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
499 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
Font_LoadFont(const char * name,dp_font_t * dpfnt)500 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
501 {
502 	int s, count, i;
503 	ft2_font_t *ft2, *fbfont, *fb;
504 	char vabuf[1024];
505 
506 	ft2 = Font_Alloc();
507 	if (!ft2)
508 	{
509 		dpfnt->ft2 = NULL;
510 		return false;
511 	}
512 
513 	// check if a fallback font has been specified, if it has been, and the
514 	// font fails to load, use the image font as main font
515 	for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
516 	{
517 		if (dpfnt->fallbacks[i][0])
518 			break;
519 	}
520 
521 	if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2))
522 	{
523 		if (i >= MAX_FONT_FALLBACKS)
524 		{
525 			dpfnt->ft2 = NULL;
526 			Mem_Free(ft2);
527 			return false;
528 		}
529 		strlcpy(ft2->name, name, sizeof(ft2->name));
530 		ft2->image_font = true;
531 		ft2->has_kerning = false;
532 	}
533 	else
534 	{
535 		ft2->image_font = false;
536 	}
537 
538 	// attempt to load fallback fonts:
539 	fbfont = ft2;
540 	for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
541 	{
542 		if (!dpfnt->fallbacks[i][0])
543 			break;
544 		if (! (fb = Font_Alloc()) )
545 		{
546 			Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
547 			break;
548 		}
549 
550 		if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
551 		{
552 			if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i])))
553 			if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i])))
554 			if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i])))
555 			if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i])))
556 				Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name);
557 			Mem_Free(fb);
558 			continue;
559 		}
560 		count = 0;
561 		for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
562 		{
563 			if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
564 				++count;
565 		}
566 		if (!count)
567 		{
568 			Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name);
569 			Font_UnloadFont(fb);
570 			Mem_Free(fb);
571 			break;
572 		}
573 		// at least one size of the fallback font loaded successfully
574 		// link it:
575 		fbfont->next = fb;
576 		fbfont = fb;
577 	}
578 
579 	if (fbfont == ft2 && ft2->image_font)
580 	{
581 		// no fallbacks were loaded successfully:
582 		dpfnt->ft2 = NULL;
583 		Mem_Free(ft2);
584 		return false;
585 	}
586 
587 	count = 0;
588 	for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
589 	{
590 		if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
591 			++count;
592 	}
593 	if (!count)
594 	{
595 		// loading failed for every requested size
596 		Font_UnloadFont(ft2);
597 		Mem_Free(ft2);
598 		dpfnt->ft2 = NULL;
599 		return false;
600 	}
601 
602 	//Con_Printf("%i sizes loaded\n", count);
603 	dpfnt->ft2 = ft2;
604 	return true;
605 }
606 
Font_LoadFile(const char * name,int _face,ft2_settings_t * settings,ft2_font_t * font)607 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font)
608 {
609 	size_t namelen;
610 	char filename[MAX_QPATH];
611 	int status;
612 	size_t i;
613 	const unsigned char *data;
614 	fs_offset_t datasize;
615 
616 	memset(font, 0, sizeof(*font));
617 
618 	if (!Font_OpenLibrary())
619 	{
620 		if (!r_font_disable_freetype.integer)
621 		{
622 			Con_Printf("WARNING: can't open load font %s\n"
623 				   "You need the FreeType2 DLL to load font files\n",
624 				   name);
625 		}
626 		return false;
627 	}
628 
629 	font->settings = settings;
630 
631 	namelen = strlen(name);
632 	if (namelen + 5 > sizeof(filename))
633 	{
634 		Con_Printf("WARNING: too long font name. Cannot load this.\n");
635 		return false;
636 	}
637 
638 	// try load direct file
639 	memcpy(filename, name, namelen+1);
640 	data = fontfilecache_LoadFile(filename, false, &datasize);
641 	// try load .ttf
642 	if (!data)
643 	{
644 		memcpy(filename + namelen, ".ttf", 5);
645 		data = fontfilecache_LoadFile(filename, false, &datasize);
646 	}
647 	// try load .otf
648 	if (!data)
649 	{
650 		memcpy(filename + namelen, ".otf", 5);
651 		data = fontfilecache_LoadFile(filename, false, &datasize);
652 	}
653 	// try load .pfb/afm
654 	if (!data)
655 	{
656 		ft2_attachment_t afm;
657 
658 		memcpy(filename + namelen, ".pfb", 5);
659 		data = fontfilecache_LoadFile(filename, false, &datasize);
660 
661 		if (data)
662 		{
663 			memcpy(filename + namelen, ".afm", 5);
664 			afm.data = fontfilecache_LoadFile(filename, false, &afm.size);
665 
666 			if (afm.data)
667 				Font_Attach(font, &afm);
668 		}
669 	}
670 	if (!data)
671 	{
672 		// FS_LoadFile being not-quiet should print an error :)
673 		return false;
674 	}
675 	Con_DPrintf("Loading font %s face %i...\n", filename, _face);
676 
677 	status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
678 	if (status && _face != 0)
679 	{
680 		Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name);
681 		_face = 0;
682 		status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
683 	}
684 	font->data = data;
685 	if (status)
686 	{
687 		Con_Printf("ERROR: can't create face for %s\n"
688 			   "Error %i\n", // TODO: error strings
689 			   name, status);
690 		Font_UnloadFont(font);
691 		return false;
692 	}
693 
694 	// add the attachments
695 	for (i = 0; i < font->attachmentcount; ++i)
696 	{
697 		FT_Open_Args args;
698 		memset(&args, 0, sizeof(args));
699 		args.flags = FT_OPEN_MEMORY;
700 		args.memory_base = (const FT_Byte*)font->attachments[i].data;
701 		args.memory_size = font->attachments[i].size;
702 		if (qFT_Attach_Stream((FT_Face)font->face, &args))
703 			Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name);
704 	}
705 
706 	strlcpy(font->name, name, sizeof(font->name));
707 	font->image_font = false;
708 	font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING);
709 	return true;
710 }
711 
Font_Postprocess_Update(ft2_font_t * fnt,int bpp,int w,int h)712 static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
713 {
714 	int needed, x, y;
715 	float gausstable[2*POSTPROCESS_MAXRADIUS+1];
716 	qboolean need_gauss  = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz);
717 	qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy);
718 	pp.blur = fnt->settings->blur;
719 	pp.outline = fnt->settings->outline;
720 	pp.shadowx = fnt->settings->shadowx;
721 	pp.shadowy = fnt->settings->shadowy;
722 	pp.shadowz = fnt->settings->shadowz;
723 	pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS);
724 	pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS);
725 	pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS);
726 	pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS);
727 	pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS);
728 	pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS);
729 	pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l;
730 	pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r;
731 	pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t;
732 	pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b;
733 	if(need_gauss)
734 	{
735 		float sum = 0;
736 		for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
737 			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));
738 		for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x)
739 			sum += gausstable[POSTPROCESS_MAXRADIUS+x];
740 		for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
741 			pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5);
742 	}
743 	if(need_circle)
744 	{
745 		for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y)
746 			for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x)
747 			{
748 				float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2));
749 				pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5);
750 			}
751 	}
752 	pp.bufwidth = w + pp.padding_l + pp.padding_r;
753 	pp.bufheight = h + pp.padding_t + pp.padding_b;
754 	pp.bufpitch = pp.bufwidth;
755 	needed = pp.bufwidth * pp.bufheight;
756 	if(!pp.buf || pp.bufsize < needed * 2)
757 	{
758 		if(pp.buf)
759 			Mem_Free(pp.buf);
760 		pp.bufsize = needed * 4;
761 		pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize);
762 		pp.buf2 = pp.buf + needed;
763 	}
764 }
765 
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)766 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)
767 {
768 	int x, y;
769 
770 	// calculate gauss table
771 	Font_Postprocess_Update(fnt, bpp, w, h);
772 
773 	if(imagedata)
774 	{
775 		// enlarge buffer
776 		// perform operation, not exceeding the passed padding values,
777 		// but possibly reducing them
778 		*pad_l = min(*pad_l, pp.padding_l);
779 		*pad_r = min(*pad_r, pp.padding_r);
780 		*pad_t = min(*pad_t, pp.padding_t);
781 		*pad_b = min(*pad_b, pp.padding_b);
782 
783 		// outline the font (RGBA only)
784 		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
785 		{
786 			// this is like mplayer subtitle rendering
787 			// bbuffer, bitmap buffer: this is our font
788 			// abuffer, alpha buffer: this is pp.buf
789 			// tmp: this is pp.buf2
790 
791 			// create outline buffer
792 			memset(pp.buf, 0, pp.bufwidth * pp.bufheight);
793 			for(y = -*pad_t; y < h + *pad_b; ++y)
794 				for(x = -*pad_l; x < w + *pad_r; ++x)
795 				{
796 					int x1 = max(-x, -pp.outlinepadding_r);
797 					int y1 = max(-y, -pp.outlinepadding_b);
798 					int x2 = min(pp.outlinepadding_l, w-1-x);
799 					int y2 = min(pp.outlinepadding_t, h-1-y);
800 					int mx, my;
801 					int cur = 0;
802 					int highest = 0;
803 					for(my = y1; my <= y2; ++my)
804 						for(mx = x1; mx <= x2; ++mx)
805 						{
806 							cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)];
807 							if(cur > highest)
808 								highest = cur;
809 						}
810 					pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255;
811 				}
812 
813 			// blur the outline buffer
814 			if(pp.blur > 0 || pp.shadowz != 0)
815 			{
816 				// horizontal blur
817 				for(y = 0; y < pp.bufheight; ++y)
818 					for(x = 0; x < pp.bufwidth; ++x)
819 					{
820 						int x1 = max(-x, -pp.blurpadding_rb);
821 						int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x);
822 						int mx;
823 						int blurred = 0;
824 						for(mx = x1; mx <= x2; ++mx)
825 							blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y];
826 						pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
827 					}
828 
829 				// vertical blur
830 				for(y = 0; y < pp.bufheight; ++y)
831 					for(x = 0; x < pp.bufwidth; ++x)
832 					{
833 						int y1 = max(-y, -pp.blurpadding_rb);
834 						int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y);
835 						int my;
836 						int blurred = 0;
837 						for(my = y1; my <= y2; ++my)
838 							blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)];
839 						pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255;
840 					}
841 			}
842 
843 			// paste the outline below the font
844 			for(y = -*pad_t; y < h + *pad_b; ++y)
845 				for(x = -*pad_l; x < w + *pad_r; ++x)
846 				{
847 					unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)];
848 					if(outlinealpha > 0)
849 					{
850 						unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)];
851 						// a' = 1 - (1 - a1) (1 - a2)
852 						unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha
853 						// c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a'
854 						unsigned char oldfactor     = (255 * (int)oldalpha) / newalpha;
855 						//unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha;
856 						int i;
857 						for(i = 0; i < bpp-1; ++i)
858 						{
859 							unsigned char c = imagedata[x * bpp + pitch * y + i];
860 							c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */;
861 							imagedata[x * bpp + pitch * y + i] = c;
862 						}
863 						imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha;
864 					}
865 					//imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80;
866 				}
867 		}
868 	}
869 	else if(pitch)
870 	{
871 		// perform operation, not exceeding the passed padding values,
872 		// but possibly reducing them
873 		*pad_l = min(*pad_l, pp.padding_l);
874 		*pad_r = min(*pad_r, pp.padding_r);
875 		*pad_t = min(*pad_t, pp.padding_t);
876 		*pad_b = min(*pad_b, pp.padding_b);
877 	}
878 	else
879 	{
880 		// just calculate parameters
881 		*pad_l = pp.padding_l;
882 		*pad_r = pp.padding_r;
883 		*pad_t = pp.padding_t;
884 		*pad_b = pp.padding_b;
885 	}
886 }
887 
888 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
889 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
Font_LoadSize(ft2_font_t * font,float size,qboolean check_only)890 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
891 {
892 	int map_index;
893 	ft2_font_map_t *fmap, temp;
894 	int gpad_l, gpad_r, gpad_t, gpad_b;
895 
896 	if (!(size > 0.001f && size < 1000.0f))
897 		size = 0;
898 
899 	if (!size)
900 		size = 16;
901 	if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
902 		return false;
903 
904 	for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
905 	{
906 		if (!font->font_maps[map_index])
907 			break;
908 		// if a similar size has already been loaded, ignore this one
909 		//abs(font->font_maps[map_index]->size - size) < 4
910 		if (font->font_maps[map_index]->size == size)
911 			return true;
912 	}
913 
914 	if (map_index >= MAX_FONT_SIZES)
915 		return false;
916 
917 	if (check_only) {
918 		FT_Face fontface;
919 		if (font->image_font)
920 			fontface = (FT_Face)font->next->face;
921 		else
922 			fontface = (FT_Face)font->face;
923 		return (Font_SearchSize(font, fontface, size) > 0);
924 	}
925 
926 	Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
927 
928 	memset(&temp, 0, sizeof(temp));
929 	temp.size = size;
930 	temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
931 	if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
932 		temp.glyphSize = CeilPowerOf2(temp.glyphSize);
933 	temp.sfx = (1.0/64.0)/(double)size;
934 	temp.sfy = (1.0/64.0)/(double)size;
935 	temp.intSize = -1; // negative value: LoadMap must search now :)
936 	if (!Font_LoadMap(font, &temp, 0, &fmap))
937 	{
938 		Con_Printf("ERROR: can't load the first character map for %s\n"
939 			   "This is fatal\n",
940 			   font->name);
941 		Font_UnloadFont(font);
942 		return false;
943 	}
944 	font->font_maps[map_index] = temp.next;
945 
946 	fmap->sfx = temp.sfx;
947 	fmap->sfy = temp.sfy;
948 
949 	// load the default kerning vector:
950 	if (font->has_kerning)
951 	{
952 		Uchar l, r;
953 		FT_Vector kernvec;
954 		for (l = 0; l < 256; ++l)
955 		{
956 			for (r = 0; r < 256; ++r)
957 			{
958 				FT_ULong ul, ur;
959 				ul = qFT_Get_Char_Index((FT_Face)font->face, l);
960 				ur = qFT_Get_Char_Index((FT_Face)font->face, r);
961 				if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
962 				{
963 					fmap->kerning.kerning[l][r][0] = 0;
964 					fmap->kerning.kerning[l][r][1] = 0;
965 				}
966 				else
967 				{
968 					fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
969 					fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
970 				}
971 			}
972 		}
973 	}
974 	return true;
975 }
976 
Font_IndexForSize(ft2_font_t * font,float _fsize,float * outw,float * outh)977 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
978 {
979 	int match = -1;
980 	float value = 1000000;
981 	float nval;
982 	int matchsize = -10000;
983 	int m;
984 	float fsize_x, fsize_y;
985 	ft2_font_map_t **maps = font->font_maps;
986 
987 	fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
988 	if(outw && *outw)
989 		fsize_x = *outw * vid.width / vid_conwidth.value;
990 	if(outh && *outh)
991 		fsize_y = *outh * vid.height / vid_conheight.value;
992 
993 	if (fsize_x < 0)
994 	{
995 		if(fsize_y < 0)
996 			fsize_x = fsize_y = 16;
997 		else
998 			fsize_x = fsize_y;
999 	}
1000 	else
1001 	{
1002 		if(fsize_y < 0)
1003 			fsize_y = fsize_x;
1004 	}
1005 
1006 	for (m = 0; m < MAX_FONT_SIZES; ++m)
1007 	{
1008 		if (!maps[m])
1009 			continue;
1010 		// "round up" to the bigger size if two equally-valued matches exist
1011 		nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
1012 		if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
1013 		{
1014 			value = nval;
1015 			match = m;
1016 			matchsize = maps[m]->size;
1017 			if (value == 0) // there is no better match
1018 				break;
1019 		}
1020 	}
1021 	if (value <= r_font_size_snapping.value)
1022 	{
1023 		// do NOT keep the aspect for perfect rendering
1024 		if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
1025 		if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
1026 	}
1027 	return match;
1028 }
1029 
Font_MapForIndex(ft2_font_t * font,int index)1030 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
1031 {
1032 	if (index < 0 || index >= MAX_FONT_SIZES)
1033 		return NULL;
1034 	return font->font_maps[index];
1035 }
1036 
Font_SetSize(ft2_font_t * font,float w,float h)1037 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
1038 {
1039 	if (font->currenth == h &&
1040 	    ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set
1041 	     font->currentw == w)) // same size has been requested
1042 	{
1043 		return true;
1044 	}
1045 	// sorry, but freetype doesn't seem to care about other sizes
1046 	w = (int)w;
1047 	h = (int)h;
1048 	if (font->image_font)
1049 	{
1050 		if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1051 			return false;
1052 	}
1053 	else
1054 	{
1055 		if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72))
1056 			return false;
1057 	}
1058 	font->currentw = w;
1059 	font->currenth = h;
1060 	return true;
1061 }
1062 
Font_GetKerningForMap(ft2_font_t * font,int map_index,float w,float h,Uchar left,Uchar right,float * outx,float * outy)1063 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1064 {
1065 	ft2_font_map_t *fmap;
1066 	if (!font->has_kerning || !r_font_kerning.integer)
1067 		return false;
1068 	if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1069 		return false;
1070 	fmap = font->font_maps[map_index];
1071 	if (!fmap)
1072 		return false;
1073 	if (left < 256 && right < 256)
1074 	{
1075 		//Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
1076 		// quick-kerning, be aware of the size: scale it
1077 		if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
1078 		if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
1079 		return true;
1080 	}
1081 	else
1082 	{
1083 		FT_Vector kernvec;
1084 		FT_ULong ul, ur;
1085 
1086 		//if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
1087 #if 0
1088 		if (!Font_SetSize(font, w, h))
1089 		{
1090 			// this deserves an error message
1091 			Con_Printf("Failed to get kerning for %s\n", font->name);
1092 			return false;
1093 		}
1094 		ul = qFT_Get_Char_Index(font->face, left);
1095 		ur = qFT_Get_Char_Index(font->face, right);
1096 		if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1097 		{
1098 			if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
1099 			if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
1100 			return true;
1101 		}
1102 #endif
1103 		if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
1104 		{
1105 			// this deserves an error message
1106 			Con_Printf("Failed to get kerning for %s\n", font->name);
1107 			return false;
1108 		}
1109 		ul = qFT_Get_Char_Index((FT_Face)font->face, left);
1110 		ur = qFT_Get_Char_Index((FT_Face)font->face, right);
1111 		if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
1112 		{
1113 			if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
1114 			if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
1115 			return true;
1116 		}
1117 		return false;
1118 	}
1119 }
1120 
Font_GetKerningForSize(ft2_font_t * font,float w,float h,Uchar left,Uchar right,float * outx,float * outy)1121 qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
1122 {
1123 	return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
1124 }
1125 
UnloadMapRec(ft2_font_map_t * map)1126 static void UnloadMapRec(ft2_font_map_t *map)
1127 {
1128 	if (map->pic)
1129 	{
1130 		//Draw_FreePic(map->pic); // FIXME: refcounting needed...
1131 		map->pic = NULL;
1132 	}
1133 	if (map->next)
1134 		UnloadMapRec(map->next);
1135 	Mem_Free(map);
1136 }
1137 
Font_UnloadFont(ft2_font_t * font)1138 void Font_UnloadFont(ft2_font_t *font)
1139 {
1140 	int i;
1141 
1142 	// unload fallbacks
1143 	if(font->next)
1144 		Font_UnloadFont(font->next);
1145 
1146 	if (font->attachments && font->attachmentcount)
1147 	{
1148 		for (i = 0; i < (int)font->attachmentcount; ++i) {
1149 			if (font->attachments[i].data)
1150 				fontfilecache_Free(font->attachments[i].data);
1151 		}
1152 		Mem_Free(font->attachments);
1153 		font->attachmentcount = 0;
1154 		font->attachments = NULL;
1155 	}
1156 	for (i = 0; i < MAX_FONT_SIZES; ++i)
1157 	{
1158 		if (font->font_maps[i])
1159 		{
1160 			UnloadMapRec(font->font_maps[i]);
1161 			font->font_maps[i] = NULL;
1162 		}
1163 	}
1164 #ifndef DP_FREETYPE_STATIC
1165 	if (ft2_dll)
1166 #else
1167 	if (!r_font_disable_freetype.integer)
1168 #endif
1169 	{
1170 		if (font->face)
1171 		{
1172 			qFT_Done_Face((FT_Face)font->face);
1173 			font->face = NULL;
1174 		}
1175 	}
1176 	if (font->data) {
1177 	    fontfilecache_Free(font->data);
1178 	    font->data = NULL;
1179 	}
1180 }
1181 
Font_SearchSize(ft2_font_t * font,FT_Face fontface,float size)1182 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
1183 {
1184 	float intSize = size;
1185 	while (1)
1186 	{
1187 		if (!Font_SetSize(font, intSize, intSize))
1188 		{
1189 			Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
1190 			return -1;
1191 		}
1192 		if ((fontface->size->metrics.height>>6) <= size)
1193 			return intSize;
1194 		if (intSize < 2)
1195 		{
1196 			Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
1197 			return -1;
1198 		}
1199 		--intSize;
1200 	}
1201 }
1202 
Font_LoadMap(ft2_font_t * font,ft2_font_map_t * mapstart,Uchar _ch,ft2_font_map_t ** outmap)1203 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
1204 {
1205 	char map_identifier[MAX_QPATH];
1206 	unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
1207 	unsigned char *data = NULL;
1208 	FT_ULong ch, mapch;
1209 	int status;
1210 	int tp;
1211 	FT_Int32 load_flags;
1212 	int gpad_l, gpad_r, gpad_t, gpad_b;
1213 	char vabuf[1024];
1214 
1215 	int pitch;
1216 	int gR, gC; // glyph position: row and column
1217 
1218 	ft2_font_map_t *map, *next;
1219 	ft2_font_t *usefont;
1220 
1221 	FT_Face fontface;
1222 
1223 	int bytesPerPixel = 4; // change the conversion loop too if you change this!
1224 
1225 	if (outmap)
1226 		*outmap = NULL;
1227 
1228 	if (r_font_use_alpha_textures.integer)
1229 		bytesPerPixel = 1;
1230 
1231 	if (font->image_font)
1232 		fontface = (FT_Face)font->next->face;
1233 	else
1234 		fontface = (FT_Face)font->face;
1235 
1236 	switch(font->settings->antialias)
1237 	{
1238 		case 0:
1239 			switch(font->settings->hinting)
1240 			{
1241 				case 0:
1242 					load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1243 					break;
1244 				case 1:
1245 				case 2:
1246 					load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1247 					break;
1248 				default:
1249 				case 3:
1250 					load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
1251 					break;
1252 			}
1253 			break;
1254 		default:
1255 		case 1:
1256 			switch(font->settings->hinting)
1257 			{
1258 				case 0:
1259 					load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1260 					break;
1261 				case 1:
1262 					load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
1263 					break;
1264 				case 2:
1265 					load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
1266 					break;
1267 				default:
1268 				case 3:
1269 					load_flags = FT_LOAD_TARGET_NORMAL;
1270 					break;
1271 			}
1272 			break;
1273 	}
1274 
1275 	//status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
1276 	//if (status)
1277 	if (font->image_font && mapstart->intSize < 0)
1278 		mapstart->intSize = mapstart->size;
1279 	if (mapstart->intSize < 0)
1280 	{
1281 		/*
1282 		mapstart->intSize = mapstart->size;
1283 		while (1)
1284 		{
1285 			if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1286 			{
1287 				Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize);
1288 				return false;
1289 			}
1290 			if ((fontface->size->metrics.height>>6) <= mapstart->size)
1291 				break;
1292 			if (mapstart->intSize < 2)
1293 			{
1294 				Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size);
1295 				return false;
1296 			}
1297 			--mapstart->intSize;
1298 		}
1299 		*/
1300 		if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
1301 			return false;
1302 		Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
1303 	}
1304 
1305 	if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
1306 	{
1307 		Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size);
1308 		return false;
1309 	}
1310 
1311 	map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t));
1312 	if (!map)
1313 	{
1314 		Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name);
1315 		return false;
1316 	}
1317 
1318 	// create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
1319 	dpsnprintf(map_identifier, sizeof(map_identifier),
1320 		"%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
1321 		font->name,
1322 		(double) mapstart->intSize,
1323 		(int) load_flags,
1324 		(double) font->settings->blur,
1325 		(double) font->settings->outline,
1326 		(double) font->settings->shadowx,
1327 		(double) font->settings->shadowy,
1328 		(double) font->settings->shadowz,
1329 		(unsigned) mapidx);
1330 
1331 	// create a cachepic_t from the data now, or reuse an existing one
1332 	map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
1333 	if (developer_font.integer)
1334 	{
1335 		if (!Draw_IsPicLoaded(map->pic))
1336 			Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1337 		else
1338 			Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
1339 	}
1340 
1341 	Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
1342 
1343 	// copy over the information
1344 	map->size = mapstart->size;
1345 	map->intSize = mapstart->intSize;
1346 	map->glyphSize = mapstart->glyphSize;
1347 	map->sfx = mapstart->sfx;
1348 	map->sfy = mapstart->sfy;
1349 
1350 	pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
1351 	if (!Draw_IsPicLoaded(map->pic))
1352 	{
1353 		data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
1354 		if (!data)
1355 		{
1356 			Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
1357 			Mem_Free(map);
1358 			return false;
1359 		}
1360 		// initialize as white texture with zero alpha
1361 		tp = 0;
1362 		while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
1363 		{
1364 			if (bytesPerPixel == 4)
1365 			{
1366 				data[tp++] = 0xFF;
1367 				data[tp++] = 0xFF;
1368 				data[tp++] = 0xFF;
1369 			}
1370 			data[tp++] = 0x00;
1371 		}
1372 	}
1373 
1374 	memset(map->width_of, 0, sizeof(map->width_of));
1375 
1376 	// insert the map
1377 	map->start = mapidx * FONT_CHARS_PER_MAP;
1378 	next = mapstart;
1379 	while(next->next && next->next->start < map->start)
1380 		next = next->next;
1381 	map->next = next->next;
1382 	next->next = map;
1383 
1384 	gR = 0;
1385 	gC = -1;
1386 	for (ch = map->start;
1387 	     ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP;
1388 	     ++ch)
1389 	{
1390 		FT_ULong glyphIndex;
1391 		int w, h, x, y;
1392 		FT_GlyphSlot glyph;
1393 		FT_Bitmap *bmp;
1394 		unsigned char *imagedata = NULL, *dst, *src;
1395 		glyph_slot_t *mapglyph;
1396 		FT_Face face;
1397 		int pad_l, pad_r, pad_t, pad_b;
1398 
1399 		mapch = ch - map->start;
1400 
1401 		if (developer_font.integer)
1402 			Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
1403 
1404 		++gC;
1405 		if (gC >= FONT_CHARS_PER_LINE)
1406 		{
1407 			gC -= FONT_CHARS_PER_LINE;
1408 			++gR;
1409 		}
1410 
1411 		if (data)
1412 		{
1413 			imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
1414 			imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
1415 		}
1416 		//status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
1417 		// we need the glyphIndex
1418 		face = (FT_Face)font->face;
1419 		usefont = NULL;
1420 		if (font->image_font && mapch == ch && img_fontmap[mapch])
1421 		{
1422 			map->glyphs[mapch].image = true;
1423 			continue;
1424 		}
1425 		glyphIndex = qFT_Get_Char_Index(face, ch);
1426 		if (glyphIndex == 0)
1427 		{
1428 			// by convention, 0 is the "missing-glyph"-glyph
1429 			// try to load from a fallback font
1430 			for(usefont = font->next; usefont != NULL; usefont = usefont->next)
1431 			{
1432 				if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize))
1433 					continue;
1434 				// try that glyph
1435 				face = (FT_Face)usefont->face;
1436 				glyphIndex = qFT_Get_Char_Index(face, ch);
1437 				if (glyphIndex == 0)
1438 					continue;
1439 				status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1440 				if (status)
1441 					continue;
1442 				break;
1443 			}
1444 			if (!usefont)
1445 			{
1446 				//Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1447 				// now we let it use the "missing-glyph"-glyph
1448 				face = (FT_Face)font->face;
1449 				glyphIndex = 0;
1450 			}
1451 		}
1452 
1453 		if (!usefont)
1454 		{
1455 			usefont = font;
1456 			face = (FT_Face)font->face;
1457 			status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
1458 			if (status)
1459 			{
1460 				//Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
1461 				Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
1462 				continue;
1463 			}
1464 		}
1465 
1466 		glyph = face->glyph;
1467 		bmp = &glyph->bitmap;
1468 
1469 		w = bmp->width;
1470 		h = bmp->rows;
1471 
1472 		if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) {
1473 			Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h);
1474 			if (w > map->glyphSize)
1475 				w = map->glyphSize - gpad_l - gpad_r;
1476 			if (h > map->glyphSize)
1477 				h = map->glyphSize;
1478 		}
1479 
1480 		if (imagedata)
1481 		{
1482 			switch (bmp->pixel_mode)
1483 			{
1484 			case FT_PIXEL_MODE_MONO:
1485 				if (developer_font.integer)
1486 					Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
1487 				break;
1488 			case FT_PIXEL_MODE_GRAY2:
1489 				if (developer_font.integer)
1490 					Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
1491 				break;
1492 			case FT_PIXEL_MODE_GRAY4:
1493 				if (developer_font.integer)
1494 					Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
1495 				break;
1496 			case FT_PIXEL_MODE_GRAY:
1497 				if (developer_font.integer)
1498 					Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
1499 				break;
1500 			default:
1501 				if (developer_font.integer)
1502 					Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
1503 				Mem_Free(data);
1504 				Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
1505 				return false;
1506 			}
1507 			for (y = 0; y < h; ++y)
1508 			{
1509 				dst = imagedata + y * pitch;
1510 				src = bmp->buffer + y * bmp->pitch;
1511 
1512 				switch (bmp->pixel_mode)
1513 				{
1514 				case FT_PIXEL_MODE_MONO:
1515 					dst += bytesPerPixel - 1; // shift to alpha byte
1516 					for (x = 0; x < bmp->width; x += 8)
1517 					{
1518 						unsigned char c = *src++;
1519 						*dst = 255 * !!((c & 0x80) >> 7); dst += bytesPerPixel;
1520 						*dst = 255 * !!((c & 0x40) >> 6); dst += bytesPerPixel;
1521 						*dst = 255 * !!((c & 0x20) >> 5); dst += bytesPerPixel;
1522 						*dst = 255 * !!((c & 0x10) >> 4); dst += bytesPerPixel;
1523 						*dst = 255 * !!((c & 0x08) >> 3); dst += bytesPerPixel;
1524 						*dst = 255 * !!((c & 0x04) >> 2); dst += bytesPerPixel;
1525 						*dst = 255 * !!((c & 0x02) >> 1); dst += bytesPerPixel;
1526 						*dst = 255 * !!((c & 0x01) >> 0); dst += bytesPerPixel;
1527 					}
1528 					break;
1529 				case FT_PIXEL_MODE_GRAY2:
1530 					dst += bytesPerPixel - 1; // shift to alpha byte
1531 					for (x = 0; x < bmp->width; x += 4)
1532 					{
1533 						unsigned char c = *src++;
1534 						*dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1535 						*dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1536 						*dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1537 						*dst = ( ((c & 0xA0) >> 6) * 0x55 ); c <<= 2; dst += bytesPerPixel;
1538 					}
1539 					break;
1540 				case FT_PIXEL_MODE_GRAY4:
1541 					dst += bytesPerPixel - 1; // shift to alpha byte
1542 					for (x = 0; x < bmp->width; x += 2)
1543 					{
1544 						unsigned char c = *src++;
1545 						*dst = ( ((c & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
1546 						*dst = ( ((c & 0x0F) ) * 0x11); dst += bytesPerPixel;
1547 					}
1548 					break;
1549 				case FT_PIXEL_MODE_GRAY:
1550 					// in this case pitch should equal width
1551 					for (tp = 0; tp < bmp->pitch; ++tp)
1552 						dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
1553 
1554 					//memcpy((void*)dst, (void*)src, bmp->pitch);
1555 					//dst += bmp->pitch;
1556 					break;
1557 				default:
1558 					break;
1559 				}
1560 			}
1561 
1562 			pad_l = gpad_l;
1563 			pad_r = gpad_r;
1564 			pad_t = gpad_t;
1565 			pad_b = gpad_b;
1566 			Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1567 		}
1568 		else
1569 		{
1570 			pad_l = gpad_l;
1571 			pad_r = gpad_r;
1572 			pad_t = gpad_t;
1573 			pad_b = gpad_b;
1574 			Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
1575 		}
1576 
1577 
1578 		// now fill map->glyphs[ch - map->start]
1579 		mapglyph = &map->glyphs[mapch];
1580 
1581 		{
1582 			// old way
1583 			// double advance = (double)glyph->metrics.horiAdvance * map->sfx;
1584 
1585 			double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
1586 			//double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
1587 			double advance = (glyph->advance.x / 64.0) / map->size;
1588 			//double mWidth = (glyph->metrics.width >> 6) / map->size;
1589 			//double mHeight = (glyph->metrics.height >> 6) / map->size;
1590 
1591 			mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1592 			mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
1593 			mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1594 			mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
1595 			//mapglyph->vxmin = bearingX;
1596 			//mapglyph->vxmax = bearingX + mWidth;
1597 			mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size;
1598 			mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask
1599 			//mapglyph->vymin = -bearingY;
1600 			//mapglyph->vymax = mHeight - bearingY;
1601 			mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size;
1602 			mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size;
1603 			//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);
1604 			//mapglyph->advance_x = advance * usefont->size;
1605 			//mapglyph->advance_x = advance;
1606 			mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
1607 			mapglyph->advance_y = 0;
1608 
1609 			if (developer_font.integer)
1610 			{
1611 				Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
1612 				Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
1613 				if (ch >= 32 && ch <= 128)
1614 					Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
1615 				Con_DPrintf("glyphinfo:   Vertex info:\n");
1616 				Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
1617 				Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
1618 				Con_DPrintf("glyphinfo:   Texture info:\n");
1619 				Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
1620 				Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
1621 				Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
1622 			}
1623 		}
1624 		map->glyphs[mapch].image = false;
1625 	}
1626 
1627 	if (!Draw_IsPicLoaded(map->pic))
1628 	{
1629 		int w = map->glyphSize * FONT_CHARS_PER_LINE;
1630 		int h = map->glyphSize * FONT_CHAR_LINES;
1631 		// update the pic returned by Draw_CachePic_Flags earlier to contain our texture
1632 		Draw_NewPic(map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0));
1633 
1634 		if (r_font_diskcache.integer >= 1)
1635 		{
1636 			// swap to BGRA for tga writing...
1637 			int s = w * h;
1638 			int x;
1639 			int b;
1640 			for (x = 0;x < s;x++)
1641 			{
1642 				b = data[x*4+0];
1643 				data[x*4+0] = data[x*4+2];
1644 				data[x*4+2] = b;
1645 			}
1646 			Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data);
1647 #ifndef USE_GLES2
1648 			if (r_font_compress.integer && qglGetCompressedTexImageARB && Draw_IsPicLoaded(map->pic))
1649 				R_SaveTextureDDSFile(Draw_GetPicTexture(map->pic), va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
1650 #endif
1651 		}
1652 	}
1653 
1654 	if(data)
1655 		Mem_Free(data);
1656 
1657 	if (!Draw_IsPicLoaded(map->pic))
1658 	{
1659 		// if the first try isn't successful, keep it with a broken texture
1660 		// otherwise we retry to load it every single frame where ft2 rendering is used
1661 		// this would be bad...
1662 		// only `data' must be freed
1663 		Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n",
1664 			   font->name, mapstart->size, mapidx);
1665 		return false;
1666 	}
1667 	if (outmap)
1668 		*outmap = map;
1669 	return true;
1670 }
1671 
Font_LoadMapForIndex(ft2_font_t * font,int map_index,Uchar _ch,ft2_font_map_t ** outmap)1672 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
1673 {
1674 	if (map_index < 0 || map_index >= MAX_FONT_SIZES)
1675 		return false;
1676 	// the first map must have been loaded already
1677 	if (!font->font_maps[map_index])
1678 		return false;
1679 	return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap);
1680 }
1681 
FontMap_FindForChar(ft2_font_map_t * start,Uchar ch)1682 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
1683 {
1684 	while (start && start->start + FONT_CHARS_PER_MAP <= ch)
1685 		start = start->next;
1686 	if (start && start->start > ch)
1687 		return NULL;
1688 	return start;
1689 }
1690