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