1 /*
2 *	SDL Graphics Extension
3 *	Text/TrueType font functions
4 *
5 *	Started 990815
6 *
7 *	License: LGPL v2+ (see the file LICENSE)
8 *	(c)1999-2003 Anders Lindstr�m
9 *
10 *	Uses the excellent FreeType 2 library, available at:
11 *	http://www.freetype.org/
12 */
13 
14 /*********************************************************************
15  *  This library is free software; you can redistribute it and/or    *
16  *  modify it under the terms of the GNU Library General Public      *
17  *  License as published by the Free Software Foundation; either     *
18  *  version 2 of the License, or (at your option) any later version. *
19  *********************************************************************/
20 
21 /*
22 *  Most of this code is taken from the SDL ttf lib by Sam Lantinga
23 *  <slouken@devolution.com>
24 */
25 
26 
27 #include "SDL.h"
28 #include "SDL_endian.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <math.h>
33 #include "sge_surface.h"
34 #include "sge_primitives.h"
35 #include "sge_tt_text.h"
36 #include "sge_textpp.h"
37 
38 #ifndef _SGE_NOTTF
39 #include <freetype/freetype.h>
40 #include <freetype/ftoutln.h>
41 #include <freetype/ttnameid.h>
42 #include <freetype/internal/ftobjs.h>
43 
44 /* The structure used to hold glyph information (cached) */
45 struct glyph {
46 	int stored;
47 	FT_UInt index;
48 	//FT_Bitmap bitmap;
49 	FT_Bitmap pixmap;
50 	int minx;
51 	int maxx;
52 	int miny;
53 	int maxy;
54 	int yoffset;
55 	int advance;
56 	Uint16 cached;
57 };
58 
59 /* the truetype font structure */
60 struct _sge_TTFont{
61 	FT_Face face;
62 
63 	/* Font metrics */
64 	int height;
65 	int ascent;
66 	int descent;
67 	int lineskip;
68 
69 	/* The font style */
70 	Uint8 style;
71 
72 	/* Extra width in glyph bounds for text styles */
73 	int glyph_overhang;
74 	float glyph_italics;
75 
76 	/* Information in the font for underlining */
77 	int underline_offset;
78 	int underline_height;
79 
80 	/* For now, support Latin-1 character set caching */
81 	glyph *current;
82 	glyph cache[256];
83 	glyph scratch;
84 
85 	/* We are responsible for closing the font stream */
86 	SDL_RWops *src;
87 	int freesrc;
88 	FT_Open_Args args;
89 
90 	/* For non-scalable formats, we must remember which font index size */
91 	int font_size_family;
92 };
93 
94 
95 /* FIXME: Right now we assume the gray-scale renderer Freetype is using
96    supports 256 shades of gray, but we should instead key off of num_grays
97    in the result FT_Bitmap after the FT_Render_Glyph() call. */
98 #define NUM_GRAYS       256
99 
100 /* Handy routines for converting from fixed point */
101 #define FT_FLOOR(X)	((X & -64) / 64)
102 #define FT_CEIL(X)	(((X + 63) & -64) / 64)
103 
104 #define CACHED_METRICS	0x10
105 #define CACHED_BITMAP	0x01
106 #define CACHED_PIXMAP	0x02
107 
108 /* Fix a problem with older version of Freetype */
109 #ifndef FT_OPEN_STREAM
110 	#define FT_OPEN_STREAM ft_open_stream
111 #endif
112 
113 /* The FreeType font engine/library */
114 static FT_Library _sge_library;
115 static int _sge_TTF_initialized = 0;
116 static int _sge_TTF_byteswapped = 0;
117 
118 Uint8 _sge_TTF_AA=1;     //Rendering mode: 0-OFF, 1-AA, 2-Alpha
119 
120 
121 /**********************************************************************************/
122 /**                          Open/misc font functions                            **/
123 /**********************************************************************************/
124 
125 //==================================================================================
126 // Turns TTF AntiAliasing On/Off or alpha (nice but slow) (Default: On)
127 //==================================================================================
sge_TTF_AAOff(void)128 void sge_TTF_AAOff(void)
129 {
130 	_sge_TTF_AA=0;
131 }
sge_TTF_AAOn(void)132 void sge_TTF_AAOn(void)
133 {
134 	_sge_TTF_AA=1;
135 }
sge_TTF_AA_Alpha(void)136 void sge_TTF_AA_Alpha(void)
137 {
138 	_sge_TTF_AA=2;
139 }
140 
141 
142 //==================================================================================
143 // Control UNICODE byteswapping (default: no => swapped=0)
144 //==================================================================================
145 /* This function tells the library whether UNICODE text is generally
146    byteswapped.  A UNICODE BOM character at the beginning of a string
147    will override this setting for that string.
148  */
sge_TTF_ByteSwappedUNICODE(int swapped)149 void sge_TTF_ByteSwappedUNICODE(int swapped)
150 {
151 	_sge_TTF_byteswapped = swapped;
152 }
153 
154 
155 //==================================================================================
156 // Closes the ttf engine, done by exit
157 //==================================================================================
sge_TTF_Quit(void)158 void sge_TTF_Quit(void)
159 {
160 	if ( _sge_TTF_initialized ) {
161 		FT_Done_FreeType( _sge_library );
162 	}
163 	_sge_TTF_initialized = 0;
164 }
165 
166 
167 //==================================================================================
168 // Starts the ttf engine, must be called first
169 //==================================================================================
sge_TTF_Init(void)170 int sge_TTF_Init(void)
171 {
172 	FT_Error error;
173 
174 	if( _sge_TTF_initialized )
175 		return 0;
176 
177 	error = FT_Init_FreeType( &_sge_library );
178 	if ( error ) {
179 		SDL_SetError("SGE - Couldn't init FreeType engine");
180 		return(-1);
181 	} else {
182 		_sge_TTF_initialized = 1;
183 	}
184 	atexit(sge_TTF_Quit); //dont't trust the user...
185 	return 0;
186 }
187 
188 
189 //==================================================================================
190 // Some helper functions
191 //==================================================================================
Flush_Glyph(glyph * glyph)192 void Flush_Glyph(glyph *glyph)
193 {
194 	glyph->stored = 0;
195 	glyph->index = 0;
196 	//if( glyph->bitmap.buffer ) {
197 	//	free( glyph->bitmap.buffer );
198 	//	glyph->bitmap.buffer = 0;
199 	//}
200 	if( glyph->pixmap.buffer ) {
201 		free( glyph->pixmap.buffer );
202 		glyph->pixmap.buffer = 0;
203 	}
204 	glyph->cached = 0;
205 }
206 
Flush_Cache(sge_TTFont * font)207 void Flush_Cache(sge_TTFont *font)
208 {
209 	int i;
210 	int size = sizeof( font->cache ) / sizeof( font->cache[0] );
211 
212 	for( i = 0; i < size; ++i ) {
213 		if( font->cache[i].cached ) {
214 			Flush_Glyph( &font->cache[i] );
215 		}
216 
217 	}
218 	if( font->scratch.cached ) {
219 		Flush_Glyph( &font->scratch );
220 	}
221 }
222 
223 
224 //==================================================================================
225 // Remove font from memory
226 //==================================================================================
sge_TTF_CloseFont(sge_TTFont * font)227 void sge_TTF_CloseFont(sge_TTFont *font)
228 {
229 	Flush_Cache( font );
230 
231 	if ( font->face )
232 		FT_Done_Face( font->face );
233 	if ( font->args.stream )
234 		free( font->args.stream );
235 	if ( font->freesrc )
236 		SDL_RWclose( font->src );
237 
238 	free( font );
239 }
240 
241 
242 //==================================================================================
243 // Seek and read stream (internal)
244 //==================================================================================
RWread(FT_Stream stream,unsigned long offset,unsigned char * buffer,unsigned long count)245 unsigned long RWread(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count)
246 {
247 	SDL_RWops *src;
248 
249 	src = (SDL_RWops *)stream->descriptor.pointer;
250 	SDL_RWseek( src, (int)offset, SEEK_SET );
251 	return SDL_RWread( src, buffer, 1, (int)count );
252 }
253 
254 
255 //==================================================================================
256 // Open the TT font sream and returns the font
257 //==================================================================================
sge_TTF_OpenFontIndexRW(SDL_RWops * src,int freesrc,int ptsize,long index,int xdpi,int ydpi)258 sge_TTFont *sge_TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index, int xdpi, int ydpi)
259 {
260 	sge_TTFont *font;
261 	FT_Error error;
262 	FT_Face face;
263 	FT_Fixed scale;
264 	FT_Stream stream;
265 	int position;
266 
267 	if( !_sge_TTF_initialized){
268 		SDL_SetError("SGE - Freetype not initialized");
269 		return NULL;
270 	}
271 
272 	/* Check to make sure we can seek in this stream */
273 	position = SDL_RWtell(src);
274 	if ( position < 0 ) {
275 		SDL_SetError("SGE - Can't seek in font stream");
276 		return NULL;
277 	}
278 
279 	font = (sge_TTFont *)malloc(sizeof(*font));
280 	if ( font == NULL ) {
281 		SDL_SetError("SGE - Out of memory");
282 		return(NULL);
283 	}
284 	memset(font, 0, sizeof(*font));
285 
286 	font->src = src;
287 	font->freesrc = freesrc;
288 
289 	stream = (FT_Stream)malloc(sizeof(*stream));
290 	if ( stream == NULL ) {
291 		SDL_SetError("SGE - Out of memory");
292 		sge_TTF_CloseFont( font );
293 		return NULL;
294 	}
295 	memset(stream, 0, sizeof(*stream));
296 
297 	stream->memory = _sge_library->memory;
298 	stream->read = RWread;
299 	stream->descriptor.pointer = src;
300 	stream->pos = (unsigned long)position;
301 	SDL_RWseek(src, 0, SEEK_END);
302 	stream->size = (unsigned long)(SDL_RWtell(src) - position);
303 	SDL_RWseek(src, position, SEEK_SET);
304 
305 	font->args.flags = FT_OPEN_STREAM;
306 	font->args.stream = stream;
307 
308 	/* Open the font stream and create ancillary data */
309 	error = FT_Open_Face( _sge_library, &font->args, index, &font->face );
310 	if ( error ) {
311 		SDL_SetError("SGE - Couldn't open font face");
312 		sge_TTF_CloseFont( font );
313 		return NULL;
314 	}
315 	face = font->face;
316 
317 	/* Handle scalable font face (global metrics) */
318 	if ( FT_IS_SCALABLE(face) ) {
319 
320 		/* Set the character size and use DPI in arguments */
321 		error = FT_Set_Char_Size( font->face, 0, ptsize * 64, xdpi, ydpi );
322 		if( error ) {
323 			SDL_SetError("SGE - Couldn't set font size");
324 			sge_TTF_CloseFont( font );
325 			return NULL;
326 		}
327 
328 		/* Get the scalable font metrics for this font */
329 		scale = face->size->metrics.y_scale;
330 		font->ascent  = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
331 		font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
332 		font->height  = font->ascent - font->descent + /* baseline */ 1;
333 		font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
334 		font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
335 		font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
336 	} else {
337 		/* Non-scalable font face.  ptsize determines which family
338 		 * or series of fonts to grab from the non-scalable format.
339 		 * It is not the point size of the font.
340 		 * */
341 		if ( ptsize >= font->face->num_fixed_sizes )
342 			ptsize = font->face->num_fixed_sizes - 1;
343 
344 		font->font_size_family = ptsize;
345 		error = FT_Set_Pixel_Sizes( face, face->available_sizes[ptsize].height, face->available_sizes[ptsize].width );
346 
347 		/* With non-scalale fonts, Freetype2 likes to fill many of the
348 		 * font metrics with the value of 0.  The size of the
349 		 * non-scalable fonts must be determined differently
350 		 * or sometimes cannot be determined.
351 		 * */
352 	  	font->ascent = face->available_sizes[ptsize].height;
353 	  	font->descent = 0;
354 	  	font->height = face->available_sizes[ptsize].height;
355 	  	font->lineskip = FT_CEIL(font->ascent);
356 	  	font->underline_offset = FT_FLOOR(face->underline_position);
357 	  	font->underline_height = FT_FLOOR(face->underline_thickness);
358 	}
359 
360 	if ( font->underline_height < 1 )
361 		font->underline_height = 1;
362 
363 	/* Set the default font style */
364 	font->style = SGE_TTF_NORMAL;
365 	font->glyph_overhang = face->size->metrics.y_ppem / 10;
366 	/* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
367 	font->glyph_italics = 0.207f;
368 	font->glyph_italics *= font->height;
369 
370 	return font;
371 }
372 
sge_TTF_OpenFontRW(SDL_RWops * src,int freesrc,int ptsize,int xdpi,int ydpi)373 sge_TTFont *sge_TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize, int xdpi, int ydpi)
374 {
375 	return sge_TTF_OpenFontIndexRW(src, freesrc, ptsize, 0, xdpi, ydpi);
376 }
377 
sge_TTF_OpenFontIndex(const char * file,int ptsize,long index,int xdpi,int ydpi)378 sge_TTFont *sge_TTF_OpenFontIndex( const char *file, int ptsize, long index, int xdpi, int ydpi)
379 {
380 	return sge_TTF_OpenFontIndexRW(SDL_RWFromFile(file, "rb"), 1, ptsize, index, xdpi, ydpi);
381 }
382 
sge_TTF_OpenFont(const char * file,int ptsize)383 sge_TTFont *sge_TTF_OpenFont(const char *file, int ptsize)
384 {
385 	return sge_TTF_OpenFontIndex(file, ptsize, 0, 96, 96);
386 }
387 
388 
389 //==================================================================================
390 // Load a glyph
391 //==================================================================================
Load_Glyph(sge_TTFont * font,Uint16 ch,glyph * cached,int want)392 FT_Error Load_Glyph(sge_TTFont *font, Uint16 ch, glyph *cached, int want )
393 {
394 	FT_Face face;
395 	FT_Error error;
396 	FT_GlyphSlot glyph;
397 	FT_Glyph_Metrics* metrics;
398 	FT_Outline* outline;
399 
400 	if ( !font || !font->face ) {
401 		return FT_Err_Invalid_Handle;
402 	}
403 
404 	face = font->face;
405 
406 	/* Load the glyph */
407 	if ( ! cached->index ) {
408 		cached->index = FT_Get_Char_Index( face, ch );
409 	}
410 	error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
411 	if( error ) {
412 		return error;
413 	}
414 
415 	/* Get our glyph shortcuts */
416 	glyph = face->glyph;
417 	metrics = &glyph->metrics;
418 	outline = &glyph->outline;
419 
420 	/* Get the glyph metrics if desired */
421 	if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
422 		if ( FT_IS_SCALABLE( face ) ) {
423 			/* Get the bounding box */
424 			cached->minx = FT_FLOOR(metrics->horiBearingX);
425 			cached->maxx = cached->minx + FT_CEIL(metrics->width);
426 			cached->maxy = FT_FLOOR(metrics->horiBearingY);
427 			cached->miny = cached->maxy - FT_CEIL(metrics->height);
428 			cached->yoffset = font->ascent - cached->maxy;
429 			cached->advance = FT_CEIL(metrics->horiAdvance);
430 		} else {
431 			/* Get the bounding box for non-scalable format.
432 			 * Again, freetype2 fills in many of the font metrics
433 			 * with the value of 0, so some of the values we
434 			 * need must be calculated differently with certain
435 			 * assumptions about non-scalable formats.
436 			 * */
437 			cached->minx = FT_FLOOR(metrics->horiBearingX);
438 			cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
439 			cached->maxy = FT_FLOOR(metrics->horiBearingY);
440 			cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
441 			cached->yoffset = 0;
442 			cached->advance = FT_CEIL(metrics->horiAdvance);
443 		}
444 
445 		/* Adjust for bold and italic text */
446 		if ( font->style & SGE_TTF_BOLD ) {
447 			cached->maxx += font->glyph_overhang;
448 		}
449 		if ( font->style & SGE_TTF_ITALIC ) {
450 			cached->maxx += (int)ceil(font->glyph_italics);
451 		}
452 		cached->stored |= CACHED_METRICS;
453 	}
454 
455 	if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
456 	     ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
457 		//int mono = (want & CACHED_BITMAP);
458 		int i;
459 		FT_Bitmap* src;
460 		FT_Bitmap* dst;
461 
462 		/* Handle the italic style */
463 		if( font->style & SGE_TTF_ITALIC ) {
464 			FT_Matrix shear;
465 
466 			shear.xx = 1 << 16;
467 			shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
468 			shear.yx = 0;
469 			shear.yy = 1 << 16;
470 
471 			FT_Outline_Transform( outline, &shear );
472 		}
473 
474 		/* Render the glyph */
475 		//if ( mono ) {
476 		//	error = FT_Render_Glyph( glyph, ft_render_mode_mono );
477 		//} else {
478 			error = FT_Render_Glyph( glyph, ft_render_mode_normal );
479 		//}
480 		if( error ) {
481 			return error;
482 		}
483 
484 		/* Copy over information to cache */
485 		src = &glyph->bitmap;
486 		//if ( mono ) {
487 		//	dst = &cached->bitmap;
488 		//} else {
489 			dst = &cached->pixmap;
490 		//}
491 		memcpy( dst, src, sizeof( *dst ) );
492 
493 		/* FT_Render_Glyph() and .fon fonts always generate a
494 		 * two-color (black and white) glyphslot surface, even
495 		 * when rendered in ft_render_mode_normal.  This is probably
496 		 * a freetype2 bug because it is inconsistent with the
497 		 * freetype2 documentation under FT_Render_Mode section.
498 		 * */
499 		if ( !FT_IS_SCALABLE(face) ) {
500 			dst->pitch *= 8;
501 		}
502 
503 		/* Adjust for bold and italic text */
504 		if( font->style & SGE_TTF_BOLD ) {
505 			int bump = font->glyph_overhang;
506 			dst->pitch += bump;
507 			dst->width += bump;
508 		}
509 		if( font->style & SGE_TTF_ITALIC ) {
510 			int bump = (int)ceil(font->glyph_italics);
511 			dst->pitch += bump;
512 			dst->width += bump;
513 		}
514 
515 		if( dst->rows != 0 ) {
516 			dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows );
517 			if( !dst->buffer ) {
518 				return FT_Err_Out_Of_Memory;
519 			}
520 			memset( dst->buffer, 0, dst->pitch * dst->rows );
521 
522 			for( i = 0; i < src->rows; i++ ) {
523 				int soffset = i * src->pitch;
524 				int doffset = i * dst->pitch;
525 				/*if ( mono ) {
526 					unsigned char *srcp = src->buffer + soffset;
527 					unsigned char *dstp = dst->buffer + doffset;
528 					int j;
529 					for ( j = 0; j < src->width; j += 8 ) {
530 						unsigned char ch = *srcp++;
531 						*dstp++ = (ch&0x80) >> 7;
532 						ch <<= 1;
533 						*dstp++ = (ch&0x80) >> 7;
534 						ch <<= 1;
535 						*dstp++ = (ch&0x80) >> 7;
536 						ch <<= 1;
537 						*dstp++ = (ch&0x80) >> 7;
538 						ch <<= 1;
539 						*dstp++ = (ch&0x80) >> 7;
540 						ch <<= 1;
541 						*dstp++ = (ch&0x80) >> 7;
542 						ch <<= 1;
543 						*dstp++ = (ch&0x80) >> 7;
544 						ch <<= 1;
545 						*dstp++ = (ch&0x80) >> 7;
546 					}
547 				} else */if ( !FT_IS_SCALABLE(face) ) {
548 					/* This special case wouldn't
549 					 * be here if the FT_Render_Glyph()
550 					 * function wasn't buggy when it tried
551 					 * to render a .fon font with 256
552 					 * shades of gray.  Instead, it
553 					 * returns a black and white surface
554 					 * and we have to translate it back
555 					 * to a 256 gray shaded surface.
556 					 * */
557 					unsigned char *srcp = src->buffer + soffset;
558 					unsigned char *dstp = dst->buffer + doffset;
559 					unsigned char ch;
560 					int j, k;
561 					for ( j = 0; j < src->width; j += 8) {
562 						ch = *srcp++;
563 						for (k = 0; k < 8; ++k) {
564 							if ((ch&0x80) >> 7) {
565 								*dstp++ = NUM_GRAYS - 1;
566 							} else {
567 								*dstp++ = 0x00;
568 							}
569 							ch <<= 1;
570 						}
571 					}
572 				} else {
573 					memcpy(dst->buffer+doffset,
574 				    	   src->buffer+soffset, src->pitch);
575 				}
576 			}
577 		}
578 
579 		/* Handle the bold style */
580 		if ( font->style & SGE_TTF_BOLD ) {
581 			int row;
582 			int col;
583 			int offset;
584 			int pixel;
585 			Uint8* pixmap;
586 
587 			/* The pixmap is a little hard, we have to add and clamp */
588 			for( row = dst->rows - 1; row >= 0; --row ) {
589 				pixmap = (Uint8*) dst->buffer + row * dst->pitch;
590 				for( offset=1; offset <= font->glyph_overhang; ++offset ) {
591 					for( col = dst->width - 1; col > 0; --col ) {
592 						pixel = (pixmap[col] + pixmap[col-1]);
593 						if( pixel > NUM_GRAYS - 1 ) {
594 							pixel = NUM_GRAYS - 1;
595 						}
596 						pixmap[col] = (Uint8) pixel;
597 					}
598 				}
599 			}
600 		}
601 
602 		/* Mark that we rendered this format */
603 		//if ( mono ) {
604 		//	cached->stored |= CACHED_BITMAP;
605 		//} else {
606 			cached->stored |= CACHED_PIXMAP;
607 		//}
608 	}
609 
610 	/* We're done, mark this glyph cached */
611 	cached->cached = ch;
612 
613 	return 0;
614 }
615 
616 
617 //==================================================================================
618 // Find glyph
619 //==================================================================================
Find_Glyph(sge_TTFont * font,Uint16 ch,int want)620 FT_Error Find_Glyph(sge_TTFont *font, Uint16 ch, int want)
621 {
622 	int retval = 0;
623 
624 	if( ch < 256 ) {
625 		font->current = &font->cache[ch];
626 	} else {
627 		if ( font->scratch.cached != ch ) {
628 			Flush_Glyph( &font->scratch );
629 		}
630 		font->current = &font->scratch;
631 	}
632 	if ( (font->current->stored & want) != want ) {
633 		retval = Load_Glyph( font, ch, font->current, want );
634 	}
635 	return retval;
636 }
637 
638 
639 //==================================================================================
640 // Change the size of font
641 //==================================================================================
sge_TTF_SetFontSizeDPI(sge_TTFont * font,int ptsize,int xdpi,int ydpi)642 int sge_TTF_SetFontSizeDPI(sge_TTFont *font, int ptsize, int xdpi, int ydpi)
643 {
644 	FT_Error error;
645 	FT_Fixed scale;
646 	FT_Face face;
647 
648 	face = font->face;
649 	Flush_Cache(font);
650 
651 	if ( FT_IS_SCALABLE(face) ) {
652 
653 		/* Set the character size */
654 		error = FT_Set_Char_Size( font->face, 0, ptsize * 64, xdpi, ydpi );
655 		if( error ) {
656 			sge_SetError("SGE - Couldn't set font size");
657 			sge_TTF_CloseFont( font );
658 			return -1;
659 		}
660 
661 		/* Get the scalable font metrics for this font */
662 		scale = face->size->metrics.y_scale;
663 		font->ascent  = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
664 		font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
665 		font->height  = font->ascent - font->descent + /* baseline */ 1;
666 		font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
667 		font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
668 		font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
669 
670 	} else {
671 		/* Non-scalable font case.  ptsize determines which family
672 		 * or series of fonts to grab from the non-scalable format.
673 		 * It is not the point size of the font.
674 		 * */
675 		if ( ptsize >= font->face->num_fixed_sizes )
676 			ptsize = font->face->num_fixed_sizes - 1;
677 
678 		font->font_size_family = ptsize;
679 		error = FT_Set_Pixel_Sizes( face, face->available_sizes[ptsize].height, face->available_sizes[ptsize].width );
680 
681 		/* With non-scalale fonts, Freetype2 likes to fill many of the
682 		 * font metrics with the value of 0.  The size of the
683 		 * non-scalable fonts must be determined differently
684 		 * or sometimes cannot be determined.
685 		 * */
686 	  	font->ascent = face->available_sizes[ptsize].height;
687 	  	font->descent = 0;
688 	  	font->height = face->available_sizes[ptsize].height;
689 	  	font->lineskip = FT_CEIL(font->ascent);
690 	  	font->underline_offset = FT_FLOOR(face->underline_position);
691 		font->underline_height = FT_FLOOR(face->underline_thickness);
692 	}
693 
694 	if ( font->underline_height < 1 ) {
695 		font->underline_height = 1;
696 	}
697 
698 	/* Set the default font style */
699 	//font->style = SGE_TTF_NORMAL;
700 	font->glyph_overhang = face->size->metrics.y_ppem / 10;
701 	/* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
702 	font->glyph_italics = 0.207f;
703 	font->glyph_italics *= font->height;
704 
705 	return 0;
706 }
707 
sge_TTF_SetFontSize(sge_TTFont * font,int ptsize)708 int sge_TTF_SetFontSize(sge_TTFont *font, int ptsize)
709 {
710 	return sge_TTF_SetFontSizeDPI(font, ptsize, 96 ,96);
711 }
712 
713 
714 //==================================================================================
715 // Get font geometrics
716 //==================================================================================
sge_TTF_FontHeight(sge_TTFont * font)717 int sge_TTF_FontHeight(sge_TTFont *font)
718 {
719 	return(font->height);
720 }
sge_TTF_FontAscent(sge_TTFont * font)721 int sge_TTF_FontAscent(sge_TTFont *font)
722 {
723 	return(font->ascent);
724 }
sge_TTF_FontDescent(sge_TTFont * font)725 int sge_TTF_FontDescent(sge_TTFont *font)
726 {
727 	return(font->descent);
728 }
sge_TTF_FontLineSkip(sge_TTFont * font)729 int sge_TTF_FontLineSkip(sge_TTFont *font)
730 {
731 	return(font->lineskip);
732 }
sge_TTF_FontFaces(sge_TTFont * font)733 long sge_TTF_FontFaces(sge_TTFont *font)
734 {
735 	return(font->face->num_faces);
736 }
sge_TTF_FontFaceIsFixedWidth(sge_TTFont * font)737 int sge_TTF_FontFaceIsFixedWidth(sge_TTFont *font)
738 {
739 	return(FT_IS_FIXED_WIDTH(font->face));
740 }
sge_TTF_FontFaceFamilyName(sge_TTFont * font)741 char *sge_TTF_FontFaceFamilyName(sge_TTFont *font)
742 {
743 	return(font->face->family_name);
744 }
sge_TTF_FontFaceStyleName(sge_TTFont * font)745 char *sge_TTF_FontFaceStyleName(sge_TTFont *font)
746 {
747 	return(font->face->style_name);
748 }
sge_TTF_GlyphMetrics(sge_TTFont * font,Uint16 ch,int * minx,int * maxx,int * miny,int * maxy,int * advance)749 int sge_TTF_GlyphMetrics(sge_TTFont *font, Uint16 ch, int* minx, int* maxx, int* miny, int* maxy, int* advance)
750 {
751 	FT_Error error;
752 
753 	error = Find_Glyph(font, ch, CACHED_METRICS);
754 
755 	if ( error ) {
756 		return -1;
757 	}
758 
759 	if ( minx ) {
760 		*minx = font->current->minx;
761 	}
762 	if ( maxx ) {
763 		*maxx = font->current->maxx;
764 	}
765 	if ( miny ) {
766 		*miny = font->current->miny;
767 	}
768 	if ( maxy ) {
769 		*maxy = font->current->maxy;
770 	}
771 	if ( advance ) {
772 		*advance = font->current->advance;
773 	}
774 	return 0;
775 }
776 
777 
778 //==================================================================================
779 // Set font style
780 //==================================================================================
sge_TTF_SetFontStyle(sge_TTFont * font,Uint8 style)781 void sge_TTF_SetFontStyle(sge_TTFont *font, Uint8 style)
782 {
783 	font->style = style;
784 	Flush_Cache(font);
785 }
786 
787 
788 //==================================================================================
789 // Get font style
790 //==================================================================================
sge_TTF_GetFontStyle(sge_TTFont * font)791 Uint8 sge_TTF_GetFontStyle(sge_TTFont *font)
792 {
793 	return(font->style);
794 }
795 #endif /* _SGE_NOTTF */
796 
797 
798 //==================================================================================
799 // Convert the Latin-1 text to UNICODE
800 //==================================================================================
ASCII_to_UNICODE(Uint16 * unicode,const char * text,int len)801 Uint16 *ASCII_to_UNICODE(Uint16 *unicode, const char *text, int len)
802 {
803 	int i;
804 
805 	for ( i=0; i < len; ++i ) {
806 		unicode[i] = ((const unsigned char *)text)[i];
807 	}
808 	unicode[i] = 0;
809 
810 	return unicode;
811 }
812 
sge_Latin1_Uni(const char * text)813 Uint16 *sge_Latin1_Uni(const char *text)
814 {
815 	Uint16 *unicode_text;
816 	int i, unicode_len;
817 
818 	/* Copy the Latin-1 text to a UNICODE text buffer */
819 	unicode_len = strlen(text);
820 	unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
821 	if ( unicode_text == NULL ) {
822 		SDL_SetError("SGE - Out of memory");
823 		return(NULL);
824 	}
825 	for ( i=0; i < unicode_len; ++i ) {
826 		unicode_text[i] = ((const unsigned char *)text)[i];
827 	}
828 	unicode_text[i] = 0;
829 
830 	return(unicode_text);
831 }
832 
833 //==================================================================================
834 // Convert the UTF-8 text to UNICODE
835 //==================================================================================
UTF8_to_UNICODE(Uint16 * unicode,const char * utf8,int len)836 Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
837 {
838 	int i, j;
839 	Uint16 ch;
840 
841 	for ( i=0, j=0; i < len; ++i, ++j ) {
842 		ch = ((const unsigned char *)utf8)[i];
843 		if ( ch >= 0xF0 ) {
844 			ch  =  (Uint16)(utf8[i]&0x07) << 18;
845 			ch |=  (Uint16)(utf8[++i]&0x3F) << 12;
846 			ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
847 			ch |=  (Uint16)(utf8[++i]&0x3F);
848 		} else
849 		if ( ch >= 0xE0 ) {
850 			ch  =  (Uint16)(utf8[i]&0x3F) << 12;
851 			ch |=  (Uint16)(utf8[++i]&0x3F) << 6;
852 			ch |=  (Uint16)(utf8[++i]&0x3F);
853 		} else
854 		if ( ch >= 0xC0 ) {
855 			ch  =  (Uint16)(utf8[i]&0x3F) << 6;
856 			ch |=  (Uint16)(utf8[++i]&0x3F);
857 		}
858 		unicode[j] = ch;
859 	}
860 	unicode[j] = 0;
861 
862 	return unicode;
863 }
864 
sge_UTF8_Uni(const char * text)865 Uint16 *sge_UTF8_Uni(const char *text)
866 {
867 	Uint16 *unicode_text;
868 	int unicode_len;
869 
870 	/* Copy the UTF-8 text to a UNICODE text buffer */
871 	unicode_len = strlen(text);
872 	unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
873 	if ( unicode_text == NULL ) {
874 		SDL_SetError("SGE - Out of memory");
875 		return(NULL);
876 	}
877 
878 	return UTF8_to_UNICODE(unicode_text, text, unicode_len);
879 }
880 
881 #ifndef _SGE_NOTTF
882 //==================================================================================
883 // Get the width of the text with the given font
884 //==================================================================================
sge_TTF_TextSizeUNI(sge_TTFont * font,const Uint16 * text)885 SDL_Rect sge_TTF_TextSizeUNI(sge_TTFont *font, const Uint16 *text)
886 {
887 	SDL_Rect ret; ret.x=0; ret.y=0, ret.w=0, ret.h=0;
888 	const Uint16 *ch;
889 	int swapped;
890 	int x, z;
891 	int minx, maxx;
892 	int miny, maxy;
893 	glyph *glyph;
894 	FT_Error error;
895 
896 	/* Initialize everything to 0 */
897 	if ( ! _sge_TTF_initialized ) {
898 		return ret;
899 	}
900 
901 	minx = miny = 0;
902 	maxx = maxy = 0;
903 	swapped = _sge_TTF_byteswapped;
904 
905 	/* Load each character and sum it's bounding box */
906 	x= 0;
907 	for ( ch=text; *ch; ++ch ) {
908 		Uint16 c = *ch;
909 		if ( c == UNICODE_BOM_NATIVE ) {
910 			swapped = 0;
911 			if ( text == ch ) {
912 				++text;
913 			}
914 			continue;
915 		}
916 		if ( c == UNICODE_BOM_SWAPPED ) {
917 			swapped = 1;
918 			if ( text == ch ) {
919 				++text;
920 			}
921 			continue;
922 		}
923 		if ( swapped ) {
924 			c = SDL_Swap16(c);
925 		}
926 
927 		error = Find_Glyph(font, c, CACHED_METRICS);
928 		if ( error ) {
929 			return ret;
930 		}
931 		glyph = font->current;
932 
933 		if ( (ch == text) && (glyph->minx < 0) ) {
934 			/* Fixes the texture wrapping bug when the first letter
935 			 * has a negative minx value or horibearing value.  The entire
936 			 * bounding box must be adjusted to be bigger so the entire
937 			 * letter can fit without any texture corruption or wrapping.
938 			 *
939 			 * Effects: First enlarges bounding box.
940 			 * Second, xstart has to start ahead of its normal spot in the
941 			 * negative direction of the negative minx value.
942 			 * (pushes everything to the right).
943 			 *
944 			 * This will make the memory copy of the glyph bitmap data
945 			 * work out correctly.
946 			 * */
947 			z -= glyph->minx;
948 		}
949 
950 		z = x + glyph->minx;
951 		if ( minx > z ) {
952 			minx = z;
953 		}
954 		if ( font->style & SGE_TTF_BOLD ) {
955 			x += font->glyph_overhang;
956 		}
957 		if ( glyph->advance > glyph->maxx ) {
958 			z = x + glyph->advance;
959 		} else {
960 			z = x + glyph->maxx;
961 		}
962 		if ( maxx < z ) {
963 			maxx = z;
964 		}
965 		x += glyph->advance;
966 
967 		if ( glyph->miny < miny ) {
968 			miny = glyph->miny;
969 		}
970 		if ( glyph->maxy > maxy ) {
971 			maxy = glyph->maxy;
972 		}
973 	}
974 
975 	/* Fill the bounds rectangle */
976 	ret.w = (maxx - minx);
977 	//ret.h = (maxy - miny); /* This is correct, but breaks many applications */
978 	ret.h = font->height;
979 
980 	return ret;
981 }
982 
sge_TTF_TextSize(sge_TTFont * font,char * text)983 SDL_Rect sge_TTF_TextSize(sge_TTFont *font, char *text)
984 {
985 	SDL_Rect ret; ret.x=ret.y=ret.w=ret.y=0;
986 	Uint16 *unicode_text;
987 	int unicode_len;
988 
989 	/* Copy the Latin-1 text to a UNICODE text buffer */
990 	unicode_len = strlen(text);
991 	unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
992 	if ( unicode_text == NULL ) {
993 		SDL_SetError("SGE - Out of memory");
994 		return ret;
995 	}
996 	ASCII_to_UNICODE(unicode_text, text, unicode_len);
997 
998 	/* Render the new text */
999 	ret = sge_TTF_TextSizeUNI(font, unicode_text);
1000 
1001 	/* Free the text buffer and return */
1002 	free(unicode_text);
1003 
1004 	return ret;
1005 }
1006 
1007 
1008 
1009 /**********************************************************************************/
1010 /**                           TTF output functions                               **/
1011 /**********************************************************************************/
1012 
1013 //==================================================================================
1014 // TT Render (unicode)
1015 // Returns an 8bit or 32bit(8/8/8/8-alpha) surface with TT text
1016 //==================================================================================
sge_TTF_Render(sge_TTFont * font,const Uint16 * text,SDL_Color fg,SDL_Color bg,int alpha_level)1017 SDL_Surface *sge_TTF_Render(sge_TTFont *font,const Uint16 *text, SDL_Color fg, SDL_Color bg, int alpha_level)
1018 {
1019 	int xstart, width;
1020 	int w, h;
1021 	SDL_Surface *textbuf;
1022 	SDL_Palette *palette;
1023 	int index;
1024 	int rdiff, gdiff, bdiff;
1025 	int swapped;
1026 	const Uint16 *ch;
1027 	Uint8 *src, *dst;
1028 	Uint32 *dst32;
1029 	Uint32 alpha=0;
1030 	Uint32 pixel=0;
1031 	Uint32 Rmask=0, Gmask=0, Bmask=0, Amask=0;
1032 	int row, col;
1033 	FT_Error error;
1034 
1035 	/* Get the dimensions of the text surface */
1036 	SDL_Rect ret=sge_TTF_TextSizeUNI(font, text);
1037 	w=ret.w; h=ret.h;
1038 	if ( !w ) {
1039 		SDL_SetError("SGE - Text has zero width");
1040 		return(NULL);
1041 	}
1042 
1043 	/* Create the target surface */
1044 	width = w;
1045 	if(_sge_TTF_AA!=2) /* Allocate an 8-bit pixmap */
1046 		textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
1047 	else{ /* Allocate an 32-bit alpha pixmap */
1048 		if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
1049 			Rmask = 0x000000FF;
1050 			Gmask = 0x0000FF00;
1051 			Bmask = 0x00FF0000;
1052 			Amask = 0xFF000000;
1053 		} else {
1054 			Rmask = 0xFF000000;
1055 			Gmask = 0x00FF0000;
1056 			Bmask = 0x0000FF00;
1057 			Amask = 0x000000FF;
1058 		}
1059 		textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask);
1060 	}
1061 
1062 	if ( textbuf == NULL ) {
1063 		SDL_SetError("SGE - Out of memory");
1064 		return(NULL);
1065 	}
1066 
1067 
1068 	/* Setup our colors */
1069 	switch(_sge_TTF_AA){
1070 
1071 		case 0:{  /* No fancy antialiasing or alpha component */
1072 			palette = textbuf->format->palette;
1073 
1074 			palette->colors[0].r = bg.r;
1075 			palette->colors[0].g = bg.g;
1076 			palette->colors[0].b = bg.b;
1077 			palette->colors[1].r = fg.r;
1078 			palette->colors[1].g = fg.g;
1079 			palette->colors[1].b = fg.b;
1080 		}
1081 		break;
1082 
1083 		case 1:{  /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
1084 			palette = textbuf->format->palette;
1085 
1086 			rdiff = fg.r - bg.r;
1087 			gdiff = fg.g - bg.g;
1088 			bdiff = fg.b - bg.b;
1089 			for ( index=0; index< NUM_GRAYS; ++index ) {
1090 				palette->colors[index].r = bg.r + (index*rdiff)/(NUM_GRAYS-1);
1091 				palette->colors[index].g = bg.g + (index*gdiff)/(NUM_GRAYS-1);
1092 				palette->colors[index].b = bg.b + (index*bdiff)/(NUM_GRAYS-1);
1093 			}
1094 		}
1095 		break;
1096 
1097 		case 2:{  /* Alpha component magic */
1098 			sge_ClearSurface(textbuf, SDL_MapRGBA(textbuf->format, bg.r,bg.g,bg.b,SDL_ALPHA_TRANSPARENT));
1099 			//pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
1100 			pixel = (fg.b<<16)|(fg.g<<8)|fg.r;
1101 		}
1102 		break;
1103 	}
1104 
1105 
1106 	/* Load and render each character */
1107 	xstart = 0;
1108 	swapped = _sge_TTF_byteswapped;
1109 	for ( ch=text; *ch; ++ch ) {
1110 		Uint16 c = *ch;
1111 		if ( c == UNICODE_BOM_NATIVE ) {
1112 			swapped = 0;
1113 			if ( text == ch ) {
1114 				++text;
1115 			}
1116 			continue;
1117 		}
1118 		if ( c == UNICODE_BOM_SWAPPED ) {
1119 			swapped = 1;
1120 			if ( text == ch ) {
1121 				++text;
1122 			}
1123 			continue;
1124 		}
1125 		if ( swapped ) {
1126 			c = SDL_Swap16(c);
1127 		}
1128 
1129 		error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP);
1130 
1131 		if ( ! error ) {
1132 			/* Compensate for wrap around bug with negative minx's */
1133 			if ( (ch == text) && (font->current->minx < 0) ) {
1134 				xstart -= font->current->minx;
1135 			}
1136 
1137 			w = font->current->pixmap.width;
1138 			for ( row = 0; row < font->current->pixmap.rows; ++row ) {
1139 				/* Make sure we don't go over the limit */
1140 				if ( row+font->current->yoffset >= textbuf->h )
1141 					continue;
1142 
1143 				dst = (Uint8 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch + xstart + font->current->minx;
1144 
1145 				switch(_sge_TTF_AA){
1146 
1147 					case 0:{  /* Normal */
1148 						src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
1149 						for ( col=w; col>0; --col ) {
1150 							*dst++ |= (*src++<NUM_GRAYS/2)? 0:1;
1151 						}
1152 					}
1153 					break;
1154 					case 1:{  /* Antialiasing */
1155 						src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
1156 						for ( col=w; col>0; --col ) {
1157 							*dst++ |= *src++;
1158 						}
1159 					}
1160 					break;
1161 
1162 					case 2:{  /* Alpha */
1163 						src = (Uint8*) (font->current->pixmap.buffer + font->current->pixmap.pitch * row);
1164 						dst32 = (Uint32 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch/4 + xstart + font->current->minx;
1165 						if( alpha_level == SDL_ALPHA_OPAQUE ){
1166 							for ( col=w; col>0; --col ) {
1167 								alpha = *src++;
1168 								*dst32++ |= pixel | (alpha << 24);
1169 							}
1170 						}else{
1171 							//We need to scale the alpha value
1172 							//Thanks mabi!
1173 							for ( col=w; col>0; --col ) {
1174 								alpha = (*src++) * alpha_level/255;
1175 								*dst32++ |= pixel | (alpha << 24);
1176 							}
1177 						}
1178 					}
1179 					break;
1180 				}
1181 			}
1182 
1183 			xstart += font->current->advance;
1184 			if ( font->style & SGE_TTF_BOLD ) {
1185 				xstart += font->glyph_overhang;
1186 			}
1187 		}
1188 	}
1189 
1190 	/* Handle the underline style */
1191 	if ( font->style & SGE_TTF_UNDERLINE ) {
1192 		int row_offset;
1193 
1194 		row_offset = font->ascent - font->underline_offset - 1;
1195 		if ( row_offset > textbuf->h ) {
1196 			row_offset = (textbuf->h-1) - font->underline_height;
1197 		}
1198 
1199 		if(_sge_TTF_AA==0){
1200 			dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
1201 			for ( row=font->underline_height; row>0; --row ) {
1202 				memset(dst, 1, textbuf->w );
1203 				dst += textbuf->pitch;
1204 			}
1205 		}else if(_sge_TTF_AA==1){
1206 			dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
1207 			for ( row=font->underline_height; row>0; --row ) {
1208 				memset(dst, NUM_GRAYS - 1, textbuf->w );
1209 				dst += textbuf->pitch;
1210 			}
1211 		}else{
1212 			//pixel |= Amask;
1213 			pixel |= (alpha_level << 24);
1214 			dst32 = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4;
1215 			for ( row=font->underline_height; row>0; --row ) {
1216 				for ( col=0; col < textbuf->w; ++col ) {
1217 					dst32[col] = pixel;
1218 				}
1219 				dst32 += textbuf->pitch/4;
1220 			}
1221 		}
1222 	}
1223 	return(textbuf);
1224 }
1225 
sge_TTF_RenderUNICODE(sge_TTFont * font,const Uint16 * text,SDL_Color fg,SDL_Color bg)1226 SDL_Surface *sge_TTF_RenderUNICODE(sge_TTFont *font,const Uint16 *text, SDL_Color fg, SDL_Color bg)
1227 {
1228 	return sge_TTF_Render(font, text, fg, bg, SDL_ALPHA_OPAQUE);
1229 }
1230 
1231 //==================================================================================
1232 // Renders the Unicode string to TrueType on surface, with the color fcolor.
1233 // bcolor is the target color for the antialiasing.
1234 // Alpha sets the transparency of the text (255-solid, 0-max).
1235 //==================================================================================
sge_tt_textout_UNI(SDL_Surface * Surface,sge_TTFont * font,const Uint16 * uni,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)1236 SDL_Rect sge_tt_textout_UNI(SDL_Surface *Surface, sge_TTFont *font, const Uint16 *uni, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
1237 {
1238 	SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
1239 
1240 	SDL_Color temp;
1241 	SDL_Surface *text;
1242 
1243 	text=sge_TTF_Render(font,uni,sge_GetRGB(Surface,fcolor),sge_GetRGB(Surface,bcolor), Alpha);
1244 	if(text==NULL){return ret;}
1245 
1246  	/* Align the surface text to the baseline */
1247 	Uint16 ascent=font->ascent;
1248 
1249 	temp=sge_GetRGB(Surface,bcolor);
1250 	sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,temp.r,temp.g,temp.b),Alpha);
1251 	sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
1252 
1253 	ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
1254 
1255 	SDL_FreeSurface(text);
1256 	return ret;
1257 }
1258 
1259 
1260 //==================================================================================
1261 // Renders the Unicode string to TrueType on surface, with the color fcolor.
1262 // bcolor is the target color for the antialiasing.
1263 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
1264 //==================================================================================
sge_tt_textout_UNI(SDL_Surface * Surface,sge_TTFont * font,const Uint16 * uni,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha)1265 SDL_Rect sge_tt_textout_UNI(SDL_Surface *Surface, sge_TTFont *font, const Uint16 *uni, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
1266 {
1267 	SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
1268 	SDL_Surface *text;
1269 
1270 	text=sge_TTF_Render(font,uni,sge_FillPaletteEntry(fR,fG,fB),sge_FillPaletteEntry(bR,bG,bB), Alpha);
1271 	if(text==NULL){return ret;}
1272 
1273 	/* Align the surface text to the baseline */
1274 	Uint16 ascent=font->ascent;
1275 
1276 	sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,bR,bG,bB),Alpha);
1277 
1278 	sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
1279 
1280 	ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
1281 
1282 	SDL_FreeSurface(text);
1283 	return ret;
1284 }
1285 
1286 
1287 //==================================================================================
1288 // Renders the Latin-1 string to TrueType on surface, with the color fcolor.
1289 // bcolor is the target color for the antialiasing.
1290 // Alpha sets the transparency of the text (0-solid, 255-max).
1291 //==================================================================================
sge_tt_textout(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)1292 SDL_Rect sge_tt_textout(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
1293 {
1294 	SDL_Rect ret;
1295 	Uint16 *uni;
1296 
1297 	uni=sge_Latin1_Uni(string);
1298 
1299 	ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
1300 	free(uni);
1301 
1302 	return ret;
1303 }
1304 
1305 //==================================================================================
1306 // Renders the Latin-1 string to TrueType on surface, with the color fcolor.
1307 // bcolor is the target color for the antialiasing.
1308 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
1309 //==================================================================================
sge_tt_textout(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha)1310 SDL_Rect sge_tt_textout(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
1311 {
1312 	SDL_Rect ret;
1313 	Uint16 *uni;
1314 
1315 	uni=sge_Latin1_Uni(string);
1316 
1317 	ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
1318 	free(uni);
1319 
1320 	return ret;
1321 }
1322 
1323 
1324 //==================================================================================
1325 // Renders the UTF-8 string to TrueType on surface, with the color fcolor.
1326 // bcolor is the target color for the antialiasing.
1327 // Alpha sets the transparency of the text (0-solid, 255-max).
1328 //==================================================================================
sge_tt_textout_UTF8(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)1329 SDL_Rect sge_tt_textout_UTF8(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
1330 {
1331 	SDL_Rect ret;
1332 	Uint16 *uni;
1333 
1334 	uni=sge_UTF8_Uni(string);
1335 
1336 	ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
1337 	free(uni);
1338 
1339 	return ret;
1340 }
1341 
1342 //==================================================================================
1343 // Renders the UTF-8 string to TrueType on surface, with the color fcolor.
1344 // bcolor is the target color for the antialiasing.
1345 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
1346 //==================================================================================
sge_tt_textout_UTF8(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha)1347 SDL_Rect sge_tt_textout_UTF8(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
1348 {
1349 	SDL_Rect ret;
1350 	Uint16 *uni;
1351 
1352 	uni=sge_UTF8_Uni(string);
1353 
1354 	ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
1355 	free(uni);
1356 
1357 	return ret;
1358 }
1359 
1360 
1361 //==================================================================================
1362 // Renders the formatet Latin-1 string to TrueType on surface, with the color fcolor.
1363 // bcolor is the target color for the antialiasing.
1364 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB ONLY)
1365 // * just like printf(char *format,...) *
1366 //==================================================================================
sge_tt_textoutf(SDL_Surface * Surface,sge_TTFont * font,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha,char * format,...)1367 SDL_Rect sge_tt_textoutf(SDL_Surface *Surface, sge_TTFont *font, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha ,char *format,...)
1368 {
1369 	char buf[256];
1370 
1371 	va_list ap;
1372 
1373 	#ifdef __WIN32__
1374 	va_start((va_list*)ap, format); //Stupid win32 crosscompiler
1375 	#else
1376 	va_start(ap, format);
1377 	#endif
1378 
1379 	vsprintf(buf, format, ap);
1380 	va_end(ap);
1381 
1382 	return sge_tt_textout(Surface, font, buf, x,y, fR,fG,fB, bR,bG,bB, Alpha);
1383 }
1384 
1385 
1386 
1387 
1388 /**********************************************************************************/
1389 /**                          TTF 'input' functions                               **/
1390 /**********************************************************************************/
1391 
1392 // The old code that once lurked here has been replaced by shiny new code that uses
1393 // the text classes.
1394 
sge_tt_input(SDL_Surface * screen,sge_TTFont * font,char * string,Uint8 flags,int pos,int len,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha)1395 int sge_tt_input(SDL_Surface *screen, sge_TTFont *font, char *string, Uint8 flags,int pos, int len, Sint16 x,Sint16 y, Uint8 fR,Uint8 fG,Uint8 fB, Uint8 bR,Uint8 bG,Uint8 bB, int Alpha)
1396 {
1397 	if( pos==0 && len>0 )
1398 		string[0] = '\0';
1399 
1400 	sge_TextSurface text(screen, string, x, y-sge_TTF_FontAscent(font));
1401 	text.set_ttFont(font, fR,fG,fB, bR, bG, bB);
1402 	text.show_cursor(true);
1403 	text.set_alpha(Alpha);
1404 	text.max_chars(len-1);
1405 
1406 	int ret = sge_text_input(&text, flags);
1407 
1408 	strncpy( string, text.get_string(false).c_str(), sizeof(char)*len );
1409 	return ret;
1410 }
1411 
sge_tt_input_UNI(SDL_Surface * screen,sge_TTFont * font,Uint16 * string,Uint8 flags,int pos,int len,Sint16 x,Sint16 y,Uint8 fR,Uint8 fG,Uint8 fB,Uint8 bR,Uint8 bG,Uint8 bB,int Alpha)1412 int sge_tt_input_UNI(SDL_Surface *screen, sge_TTFont *font, Uint16 *string, Uint8 flags, int pos, int len, Sint16 x,Sint16 y, Uint8 fR,Uint8 fG,Uint8 fB, Uint8 bR,Uint8 bG,Uint8 bB, int Alpha)
1413 {
1414 	sge_TextSurface text(screen, "", x, y-sge_TTF_FontAscent(font));
1415 
1416 	if( pos!=0 )
1417 		text.change_uctext(string);
1418 
1419 	text.set_ttFont(font, fR,fG,fB, bR, bG, bB);
1420 	text.show_cursor(true);
1421 	text.set_alpha(Alpha);
1422 	text.max_chars(len-1);
1423 
1424 	int ret = sge_text_input(&text, flags);
1425 
1426 	Uint16 *tmp = text.get_ucstring(false);
1427 
1428 	strncpy( (char*)string, (char*)tmp, sizeof(Uint16)*len );
1429 
1430 	delete[] tmp;
1431 
1432 	return ret;
1433 }
1434 
sge_tt_input_UNI(SDL_Surface * screen,sge_TTFont * font,Uint16 * string,Uint8 flags,int pos,int len,Sint16 x,Sint16 y,Uint32 fcol,Uint32 bcol,int Alpha)1435 int sge_tt_input_UNI(SDL_Surface *screen, sge_TTFont *font, Uint16 *string, Uint8 flags, int pos,int len, Sint16 x,Sint16 y, Uint32 fcol,Uint32 bcol, int Alpha)
1436 {
1437 	Uint8 fr,fg,fb, br,bg,bb;
1438 
1439 	SDL_GetRGB(fcol, screen->format, &fr, &fg, &fb);
1440 	SDL_GetRGB(bcol, screen->format, &br, &bg, &bb);
1441 
1442 	return sge_tt_input_UNI(screen, font, string, flags, pos,len, x,y, fr,fg,fb, br,bg,bb, Alpha);
1443 }
1444 
1445 
sge_tt_input(SDL_Surface * screen,sge_TTFont * font,char * string,Uint8 flags,int pos,int len,Sint16 x,Sint16 y,Uint32 fcol,Uint32 bcol,int Alpha)1446 int sge_tt_input(SDL_Surface *screen, sge_TTFont *font, char *string, Uint8 flags, int pos,int len, Sint16 x,Sint16 y, Uint32 fcol,Uint32 bcol, int Alpha)
1447 {
1448 	Uint8 fr,fg,fb, br,bg,bb;
1449 
1450 	SDL_GetRGB(fcol, screen->format, &fr, &fg, &fb);
1451 	SDL_GetRGB(bcol, screen->format, &br, &bg, &bb);
1452 
1453 	return sge_tt_input(screen, font, string, flags, pos,len, x,y, fr,fg,fb, br,bg,bb, Alpha);
1454 }
1455 
1456 #endif /* _SGE_NOTTF */
1457