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-2001 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 <stdlib.h>
29 #include <memory.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
37 #ifndef _SGE_NOTTF
38 #include <ft2build.h>
39 #include FT_FREETYPE_H
40 #include FT_OUTLINE_H
41 #include FT_TRUETYPE_IDS_H
42
43 /* The structure used to hold glyph information (cached) */
44 struct glyph {
45 int stored;
46 FT_UInt index;
47 //FT_Bitmap bitmap;
48 FT_Bitmap pixmap;
49 int minx;
50 int maxx;
51 int miny;
52 int maxy;
53 int yoffset;
54 int advance;
55 Uint16 cached;
56 };
57
58 /* the truetype font structure */
59 struct _sge_TTFont{
60 FT_Face face;
61
62 /* Font metrics */
63 int height;
64 int ascent;
65 int descent;
66 int lineskip;
67
68 /* The font style */
69 Uint8 style;
70
71 /* Extra width in glyph bounds for text styles */
72 int glyph_overhang;
73 float glyph_italics;
74
75 /* Information in the font for underlining */
76 int underline_offset;
77 int underline_height;
78
79 /* For now, support Latin-1 character set caching */
80 glyph *current;
81 glyph cache[256];
82 glyph scratch;
83 };
84
85
86 /* Macro to convert a character to a Unicode value -- assume already Unicode */
87 //Should really make a proper convert algorithm someday
88 #define UNICODE(c) c
89
90 /* FIXME: Right now we assume the gray-scale renderer Freetype is using
91 supports 256 shades of gray, but we should instead key off of num_grays
92 in the result FT_Bitmap after the FT_Render_Glyph() call. */
93 #define NUM_GRAYS 256
94
95 /* Handy routines for converting from fixed point */
96 #define FT_FLOOR(X) ((X & -64) / 64)
97 #define FT_CEIL(X) (((X + 63) & -64) / 64)
98
99 #define CACHED_METRICS 0x10
100 #define CACHED_BITMAP 0x01
101 #define CACHED_PIXMAP 0x02
102
103 /* The FreeType font engine/library */
104 static FT_Library _sge_library;
105 static int _sge_TTF_initialized = 0;
106
107 Uint8 _sge_TTF_AA=1; //Rendering mode: 0-OFF, 1-AA, 2-Alpha
108
109
110 /**********************************************************************************/
111 /** Open/misc font functions **/
112 /**********************************************************************************/
113
114 //==================================================================================
115 // Turns TTF AntiAliasing On/Off or alpha (nice but slow) (Default: On)
116 //==================================================================================
sge_TTF_AAOff(void)117 void sge_TTF_AAOff(void)
118 {
119 _sge_TTF_AA=0;
120 }
sge_TTF_AAOn(void)121 void sge_TTF_AAOn(void)
122 {
123 _sge_TTF_AA=1;
124 }
sge_TTF_AA_Alpha(void)125 void sge_TTF_AA_Alpha(void)
126 {
127 _sge_TTF_AA=2;
128 }
129
130
131 //==================================================================================
132 // Closes the ttf engine, done by exit
133 //==================================================================================
sge_TTF_Quit(void)134 void sge_TTF_Quit(void)
135 {
136 if ( _sge_TTF_initialized ) {
137 FT_Done_FreeType( _sge_library );
138 }
139 _sge_TTF_initialized = 0;
140 }
141
142
143 //==================================================================================
144 // Starts the ttf engine, must be called first
145 //==================================================================================
sge_TTF_Init(void)146 int sge_TTF_Init(void)
147 {
148 FT_Error error;
149
150 error = FT_Init_FreeType( &_sge_library );
151 if ( error ) {
152 SDL_SetError("SGE - Couldn't init FreeType engine");
153 return(-1);
154 } else {
155 _sge_TTF_initialized = 1;
156 }
157 atexit(sge_TTF_Quit); //dont't trust the user...
158 return(0);
159 }
160
161
162 //==================================================================================
163 // Some helper functions
164 //==================================================================================
Flush_Glyph(glyph * glyph)165 void Flush_Glyph(glyph *glyph)
166 {
167 glyph->stored = 0;
168 glyph->index = 0;
169 //if( glyph->bitmap.buffer ) {
170 // free( glyph->bitmap.buffer );
171 // glyph->bitmap.buffer = 0;
172 //}
173 if( glyph->pixmap.buffer ) {
174 free( glyph->pixmap.buffer );
175 glyph->pixmap.buffer = 0;
176 }
177 glyph->cached = 0;
178 }
179
Flush_Cache(sge_TTFont * font)180 void Flush_Cache(sge_TTFont *font)
181 {
182 int i;
183 int size = sizeof( font->cache ) / sizeof( font->cache[0] );
184
185 for( i = 0; i < size; ++i ) {
186 if( font->cache[i].cached ) {
187 Flush_Glyph( &font->cache[i] );
188 }
189
190 }
191 if( font->scratch.cached ) {
192 Flush_Glyph( &font->scratch );
193 }
194 }
195
196
197 //==================================================================================
198 // Remove font from memory
199 //==================================================================================
sge_TTF_CloseFont(sge_TTFont * font)200 void sge_TTF_CloseFont(sge_TTFont *font)
201 {
202 Flush_Cache( font );
203 FT_Done_Face( font->face );
204 free( font );
205 }
206
207
208 //==================================================================================
209 // Open the TT font file and returns the font with pt size
210 //==================================================================================
sge_TTF_OpenFont(const char * file,int ptsize)211 sge_TTFont *sge_TTF_OpenFont(const char *file, int ptsize)
212 {
213 sge_TTFont *font;
214 FT_Error error;
215 FT_Face face;
216 FT_Fixed scale;
217
218 font = (sge_TTFont *)malloc(sizeof(*font));
219 if ( font == NULL ) {
220 SDL_SetError("SGE - Out of memory");
221 return(NULL);
222 }
223 memset(font, 0, sizeof(*font));
224
225 /* Open the font and create ancillary data */
226 error = FT_New_Face( _sge_library, file, 0, &font->face );
227 if ( error ) {
228 sge_SetError("SGE - Couldn't load font file: %s",file);
229 free(font);
230 return(NULL);
231 }
232 face = font->face;
233
234 /* Make sure that our font face is scalable (global metrics) */
235 if ( ! FT_IS_SCALABLE(face) ) {
236 sge_SetError("SGE - Font face is not scalable: %s",file);
237 sge_TTF_CloseFont( font );
238 return NULL;
239 }
240
241 /* Set the character size and use 96 DPI */
242 error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 96, 96 );
243 //error = FT_Set_Pixel_Sizes( font->face, 0, ptsize );
244 if( error ) {
245 sge_SetError("SGE - Couldn't set font size: %s",file);
246 sge_TTF_CloseFont( font );
247 return NULL;
248 }
249
250 /* Get the scalable font metrics for this font */
251 scale = face->size->metrics.y_scale;
252 font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
253 font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
254 font->height = font->ascent - font->descent + /* baseline */ 1;
255 font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
256 font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
257 font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
258 if ( font->underline_height < 1 ) {
259 font->underline_height = 1;
260 }
261
262 /* Set the default font style */
263 font->style = SGE_TTF_NORMAL;
264 font->glyph_overhang = face->size->metrics.y_ppem / 10;
265 /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
266 font->glyph_italics = 0.207f;
267 font->glyph_italics *= font->height;
268
269 return font;
270 }
271
272
273 //==================================================================================
274 // Load a glyph
275 //==================================================================================
Load_Glyph(sge_TTFont * font,Uint16 ch,glyph * cached,int want)276 FT_Error Load_Glyph(sge_TTFont *font, Uint16 ch, glyph *cached, int want )
277 {
278 FT_Face face;
279 FT_Error error;
280 FT_GlyphSlot glyph;
281 FT_Glyph_Metrics* metrics;
282 FT_Outline* outline;
283
284 //assert( font );
285 //assert( font->face );
286
287 face = font->face;
288
289 /* Load the glyph */
290 if ( ! cached->index ) {
291 cached->index = FT_Get_Char_Index( face, ch );
292 }
293 error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
294 if( error ) {
295 return error;
296 }
297
298 /* Get our glyph shortcuts */
299 glyph = face->glyph;
300 metrics = &glyph->metrics;
301 outline = &glyph->outline;
302
303 /* Get the glyph metrics if desired */
304 if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
305 /* Get the bounding box */
306 cached->minx = FT_FLOOR(metrics->horiBearingX);
307 cached->maxx = cached->minx + FT_CEIL(metrics->width);
308 cached->maxy = FT_FLOOR(metrics->horiBearingY);
309 cached->miny = cached->maxy - FT_CEIL(metrics->height);
310 cached->yoffset = font->ascent - cached->maxy;
311 cached->advance = FT_CEIL(metrics->horiAdvance);
312
313 /* Adjust for bold and italic text */
314 if ( font->style & SGE_TTF_BOLD ) {
315 cached->maxx += font->glyph_overhang;
316 }
317 if ( font->style & SGE_TTF_ITALIC ) {
318 cached->maxx += (int)ceil(font->glyph_italics);
319 }
320 cached->stored |= CACHED_METRICS;
321 }
322
323 if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
324 ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
325 //int mono = (want & CACHED_BITMAP);
326 int i;
327 FT_Bitmap* src;
328 FT_Bitmap* dst;
329
330 /* Handle the italic style */
331 if( font->style & SGE_TTF_ITALIC ) {
332 FT_Matrix shear;
333
334 shear.xx = 1 << 16;
335 shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
336 shear.yx = 0;
337 shear.yy = 1 << 16;
338
339 FT_Outline_Transform( outline, &shear );
340 }
341
342 /* Render the glyph */
343 //if ( mono ) {
344 // error = FT_Render_Glyph( glyph, ft_render_mode_mono );
345 //} else {
346 error = FT_Render_Glyph( glyph, ft_render_mode_normal );
347 //}
348 if( error ) {
349 return error;
350 }
351
352 /* Copy over information to cache */
353 src = &glyph->bitmap;
354 //if ( mono ) {
355 // dst = &cached->bitmap;
356 //} else {
357 dst = &cached->pixmap;
358 //}
359 memcpy( dst, src, sizeof( *dst ) );
360 //if ( mono ) {
361 // dst->pitch *= 8;
362 //}
363
364 /* Adjust for bold and italic text */
365 if( font->style & SGE_TTF_BOLD ) {
366 int bump = font->glyph_overhang;
367 dst->pitch += bump;
368 dst->width += bump;
369 }
370 if( font->style & SGE_TTF_ITALIC ) {
371 int bump = (int)ceil(font->glyph_italics);
372 dst->pitch += bump;
373 dst->width += bump;
374 }
375
376 dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows );
377 if( !dst->buffer ) {
378 return FT_Err_Out_Of_Memory;
379 }
380 memset( dst->buffer, 0, dst->pitch * dst->rows );
381
382 for( i = 0; i < src->rows; i++ ) {
383 int soffset = i * src->pitch;
384 int doffset = i * dst->pitch;
385 /*if ( mono ) {
386 unsigned char *srcp = src->buffer + soffset;
387 unsigned char *dstp = dst->buffer + doffset;
388 int j;
389 for ( j = 0; j < src->width; j += 8 ) {
390 unsigned char ch = *srcp++;
391 *dstp++ = (ch&0x80) >> 7;
392 ch <<= 1;
393 *dstp++ = (ch&0x80) >> 7;
394 ch <<= 1;
395 *dstp++ = (ch&0x80) >> 7;
396 ch <<= 1;
397 *dstp++ = (ch&0x80) >> 7;
398 ch <<= 1;
399 *dstp++ = (ch&0x80) >> 7;
400 ch <<= 1;
401 *dstp++ = (ch&0x80) >> 7;
402 ch <<= 1;
403 *dstp++ = (ch&0x80) >> 7;
404 ch <<= 1;
405 *dstp++ = (ch&0x80) >> 7;
406 }
407 } else {*/
408 memcpy(dst->buffer+doffset,
409 src->buffer+soffset, src->pitch);
410 //}
411 }
412
413 /* Handle the bold style */
414 if ( font->style & SGE_TTF_BOLD ) {
415 int row;
416 int col;
417 int offset;
418 int pixel;
419 Uint8* pixmap;
420
421 /* The pixmap is a little hard, we have to add and clamp */
422 for( row = dst->rows - 1; row >= 0; --row ) {
423 pixmap = (Uint8*) dst->buffer + row * dst->pitch;
424 for( offset=1; offset <= font->glyph_overhang; ++offset ) {
425 for( col = dst->width - 1; col > 0; --col ) {
426 pixel = (pixmap[col] + pixmap[col-1]);
427 if( pixel > NUM_GRAYS - 1 ) {
428 pixel = NUM_GRAYS - 1;
429 }
430 pixmap[col] = (Uint8) pixel;
431 }
432 }
433 }
434 }
435
436 /* Mark that we rendered this format */
437 //if ( mono ) {
438 // cached->stored |= CACHED_BITMAP;
439 //} else {
440 cached->stored |= CACHED_PIXMAP;
441 //}
442 }
443
444 /* We're done, mark this glyph cached */
445 cached->cached = ch;
446
447 return 0;
448 }
449
450
451 //==================================================================================
452 // Find glyph
453 //==================================================================================
Find_Glyph(sge_TTFont * font,Uint16 ch,int want)454 FT_Error Find_Glyph(sge_TTFont *font, Uint16 ch, int want)
455 {
456 int retval = 0;
457
458 if( ch < 256 ) {
459 font->current = &font->cache[ch];
460 } else {
461 if ( font->scratch.cached != ch ) {
462 Flush_Glyph( &font->scratch );
463 }
464 font->current = &font->scratch;
465 }
466 if ( (font->current->stored & want) != want ) {
467 retval = Load_Glyph( font, ch, font->current, want );
468 }
469 return retval;
470 }
471
472
473 //==================================================================================
474 // Change the size of font
475 //==================================================================================
sge_TTF_SetFontSize(sge_TTFont * font,int ptsize)476 int sge_TTF_SetFontSize(sge_TTFont *font, int ptsize)
477 {
478 FT_Error error;
479 FT_Fixed scale;
480 FT_Face face;
481
482 /* Set the character size and use 96 DPI */
483 error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 96, 96 );
484 //error = FT_Set_Pixel_Sizes( font->face, 0, ptsize );
485 if( error ) {
486 sge_SetError("SGE - Couldn't set font size");
487 sge_TTF_CloseFont( font );
488 return -1;
489 }
490
491 Flush_Cache(font);
492 face = font->face;
493
494 /* Get the scalable font metrics for this font */
495 scale = face->size->metrics.y_scale;
496 font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
497 font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
498 font->height = font->ascent - font->descent + /* baseline */ 1;
499 font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
500 font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
501 font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
502 if ( font->underline_height < 1 ) {
503 font->underline_height = 1;
504 }
505
506 /* Set the default font style */
507 //font->style = SGE_TTF_NORMAL;
508 font->glyph_overhang = face->size->metrics.y_ppem / 10;
509 /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
510 font->glyph_italics = 0.207f;
511 font->glyph_italics *= font->height;
512
513 return 0;
514 }
515
516
517 //==================================================================================
518 // Get font geometrics
519 //==================================================================================
sge_TTF_FontHeight(sge_TTFont * font)520 int sge_TTF_FontHeight(sge_TTFont *font)
521 {
522 return(font->height);
523 }
sge_TTF_FontAscent(sge_TTFont * font)524 int sge_TTF_FontAscent(sge_TTFont *font)
525 {
526 return(font->ascent);
527 }
sge_TTF_FontDescent(sge_TTFont * font)528 int sge_TTF_FontDescent(sge_TTFont *font)
529 {
530 return(font->descent);
531 }
sge_TTF_FontLineSkip(sge_TTFont * font)532 int sge_TTF_FontLineSkip(sge_TTFont *font)
533 {
534 return(font->lineskip);
535 }
sge_TTF_GlyphMetrics(sge_TTFont * font,Uint16 ch,int * minx,int * maxx,int * miny,int * maxy,int * advance)536 int sge_TTF_GlyphMetrics(sge_TTFont *font, Uint16 ch, int* minx, int* maxx, int* miny, int* maxy, int* advance)
537 {
538 FT_Error error;
539
540 error = Find_Glyph(font, ch, CACHED_METRICS);
541
542 if ( error ) {
543 return -1;
544 }
545
546 if ( minx ) {
547 *minx = font->current->minx;
548 }
549 if ( maxx ) {
550 *maxx = font->current->maxx;
551 }
552 if ( miny ) {
553 *miny = font->current->miny;
554 }
555 if ( maxy ) {
556 *maxy = font->current->maxy;
557 }
558 if ( advance ) {
559 *advance = font->current->advance;
560 }
561 return 0;
562 }
563
564
565 //==================================================================================
566 // Set font style
567 //==================================================================================
sge_TTF_SetFontStyle(sge_TTFont * font,Uint8 style)568 void sge_TTF_SetFontStyle(sge_TTFont *font, Uint8 style)
569 {
570 font->style = style;
571 Flush_Cache(font);
572 }
573
574
575 //==================================================================================
576 // Get font style
577 //==================================================================================
sge_TTF_GetFontStyle(sge_TTFont * font)578 Uint8 sge_TTF_GetFontStyle(sge_TTFont *font)
579 {
580 return(font->style);
581 }
582 #endif /* _SGE_NOTTF */
583
584
585 //==================================================================================
586 // Convert the Latin-1 text to UNICODE
587 //==================================================================================
ASCII_to_UNICODE(Uint16 * unicode,const char * text,int len)588 Uint16 *ASCII_to_UNICODE(Uint16 *unicode, const char *text, int len)
589 {
590 int i;
591
592 for ( i=0; i < len; ++i ) {
593 unicode[i] = ((const unsigned char *)text)[i];
594 }
595 unicode[i] = 0;
596
597 return unicode;
598 }
599
sge_Latin1_Uni(const char * text)600 Uint16 *sge_Latin1_Uni(const char *text)
601 {
602 Uint16 *unicode_text;
603 int i, unicode_len;
604
605 /* Copy the Latin-1 text to a UNICODE text buffer */
606 unicode_len = strlen(text);
607 unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
608 if ( unicode_text == NULL ) {
609 SDL_SetError("SGE - Out of memory");
610 return(NULL);
611 }
612 for ( i=0; i < unicode_len; ++i ) {
613 unicode_text[i] = ((const unsigned char *)text)[i];
614 }
615 unicode_text[i] = 0;
616
617 return(unicode_text);
618 }
619
620 //==================================================================================
621 // Convert the UTF-8 text to UNICODE
622 //==================================================================================
UTF8_to_UNICODE(Uint16 * unicode,const char * utf8,int len)623 Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
624 {
625 int i, j;
626 Uint16 ch;
627
628 for ( i=0, j=0; i < len; ++i, ++j ) {
629 ch = ((const unsigned char *)utf8)[i];
630 if ( ch >= 0xF0 ) {
631 ch = (Uint16)(utf8[i]&0x07) << 18;
632 ch |= (Uint16)(utf8[++i]&0x3F) << 12;
633 ch |= (Uint16)(utf8[++i]&0x3F) << 6;
634 ch |= (Uint16)(utf8[++i]&0x3F);
635 } else
636 if ( ch >= 0xE0 ) {
637 ch = (Uint16)(utf8[i]&0x3F) << 12;
638 ch |= (Uint16)(utf8[++i]&0x3F) << 6;
639 ch |= (Uint16)(utf8[++i]&0x3F);
640 } else
641 if ( ch >= 0xC0 ) {
642 ch = (Uint16)(utf8[i]&0x3F) << 6;
643 ch |= (Uint16)(utf8[++i]&0x3F);
644 }
645 unicode[j] = ch;
646 }
647 unicode[j] = 0;
648
649 return unicode;
650 }
651
sge_UTF8_Uni(const char * text)652 Uint16 *sge_UTF8_Uni(const char *text)
653 {
654 Uint16 *unicode_text;
655 int unicode_len;
656
657 /* Copy the UTF-8 text to a UNICODE text buffer */
658 unicode_len = strlen(text);
659 unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
660 if ( unicode_text == NULL ) {
661 SDL_SetError("SGE - Out of memory");
662 return(NULL);
663 }
664
665 return UTF8_to_UNICODE(unicode_text, text, unicode_len);
666 }
667
668 #ifndef _SGE_NOTTF
669 //==================================================================================
670 // Get the width of the text with the given font
671 //==================================================================================
sge_TTF_TextSizeUNI(sge_TTFont * font,const Uint16 * text)672 SDL_Rect sge_TTF_TextSizeUNI(sge_TTFont *font, const Uint16 *text)
673 {
674 SDL_Rect ret; ret.x=0; ret.y=0, ret.w=0, ret.h=0;
675 const Uint16 *ch;
676 int x, z;
677 int minx, maxx;
678 int miny, maxy;
679 glyph *glyph;
680 FT_Error error;
681
682 /* Initialize everything to 0 */
683 if ( ! _sge_TTF_initialized ) {
684 return ret;
685 }
686
687 minx = miny = 0;
688 maxx = maxy = 0;
689
690 /* Load each character and sum it's bounding box */
691 x= 0;
692 for ( ch=text; *ch; ++ch ) {
693 error = Find_Glyph(font, *ch, CACHED_METRICS);
694 if ( error ) {
695 return ret;
696 }
697 glyph = font->current;
698
699 z = x + glyph->minx;
700 if ( minx > z ) {
701 minx = z;
702 }
703 if ( font->style & SGE_TTF_BOLD ) {
704 x += font->glyph_overhang;
705 }
706 if ( glyph->advance > glyph->maxx ) {
707 z = x + glyph->advance;
708 } else {
709 z = x + glyph->maxx;
710 }
711 if ( maxx < z ) {
712 maxx = z;
713 }
714 x += glyph->advance;
715
716 if ( glyph->miny < miny ) {
717 miny = glyph->miny;
718 }
719 if ( glyph->maxy > maxy ) {
720 maxy = glyph->maxy;
721 }
722 }
723
724 /* Fill the bounds rectangle */
725 ret.w = (maxx - minx);
726 //ret.h = (maxy - miny); /* This is correct, but breaks many applications */
727 ret.h = font->height;
728
729 return ret;
730 }
731
sge_TTF_TextSize(sge_TTFont * font,const char * text,int a_iMaxLength)732 SDL_Rect sge_TTF_TextSize(sge_TTFont *font, const char *text, int a_iMaxLength)
733 {
734 SDL_Rect ret; ret.x=ret.y=ret.w=ret.y=0;
735 Uint16 *unicode_text;
736 int unicode_len;
737
738 /* Copy the Latin-1 text to a UNICODE text buffer */
739 unicode_len = strlen(text);
740 if ( unicode_len > a_iMaxLength
741 && a_iMaxLength>=0 )
742 {
743 unicode_len = a_iMaxLength;
744 }
745 unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
746 if ( unicode_text == NULL ) {
747 SDL_SetError("SGE - Out of memory");
748 return ret;
749 }
750 ASCII_to_UNICODE( unicode_text, text, unicode_len );
751
752 /* Render the new text */
753 ret = sge_TTF_TextSizeUNI(font, unicode_text);
754
755 /* Free the text buffer and return */
756 free(unicode_text);
757
758 return ret;
759 }
760
761
762
763 /**********************************************************************************/
764 /** TTF output functions **/
765 /**********************************************************************************/
766
767 //==================================================================================
768 // TT Render (unicode)
769 // Returns an 8bit or 32bit(8/8/8/8-alpha) surface with TT text
770 //==================================================================================
sge_TTF_RenderUNICODE(sge_TTFont * font,const Uint16 * text,SDL_Color fg,SDL_Color bg)771 SDL_Surface *sge_TTF_RenderUNICODE(sge_TTFont *font,const Uint16 *text, SDL_Color fg, SDL_Color bg)
772 {
773 int xstart, width;
774 int w, h;
775 SDL_Surface *textbuf;
776 SDL_Palette *palette;
777 int index;
778 int rdiff, gdiff, bdiff;
779 const Uint16 *ch;
780 Uint8 *src, *dst;
781 Uint32 *dst32;
782 Uint32 alpha=0;
783 Uint32 pixel=0;
784 Uint32 Rmask=0, Gmask=0, Bmask=0, Amask=0;
785 int row, col;
786 FT_Error error;
787
788 /* Get the dimensions of the text surface */
789 SDL_Rect ret=sge_TTF_TextSizeUNI(font, text);
790 w=ret.w; h=ret.h;
791 if ( !w ) {
792 SDL_SetError("SGE - Text has zero width");
793 return(NULL);
794 }
795
796 /* Create the target surface */
797 width = w;
798 if(_sge_TTF_AA!=2) /* Allocate an 8-bit pixmap */
799 textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
800 else{ /* Allocate an 32-bit alpha pixmap */
801 if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
802 Rmask = 0x000000FF;
803 Gmask = 0x0000FF00;
804 Bmask = 0x00FF0000;
805 Amask = 0xFF000000;
806 } else {
807 Rmask = 0xFF000000;
808 Gmask = 0x00FF0000;
809 Bmask = 0x0000FF00;
810 Amask = 0x000000FF;
811 }
812 textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask);
813 }
814
815 if ( textbuf == NULL ) {
816 SDL_SetError("SGE - Out of memory");
817 return(NULL);
818 }
819
820
821 /* Setup our colors */
822 switch(_sge_TTF_AA){
823
824 case 0:{ /* No fancy antialiasing or alpha component */
825 palette = textbuf->format->palette;
826
827 palette->colors[0].r = bg.r;
828 palette->colors[0].g = bg.g;
829 palette->colors[0].b = bg.b;
830 palette->colors[1].r = fg.r;
831 palette->colors[1].g = fg.g;
832 palette->colors[1].b = fg.b;
833 }
834 break;
835
836 case 1:{ /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
837 palette = textbuf->format->palette;
838
839 rdiff = fg.r - bg.r;
840 gdiff = fg.g - bg.g;
841 bdiff = fg.b - bg.b;
842 for ( index=0; index< NUM_GRAYS; ++index ) {
843 palette->colors[index].r = bg.r + (index*rdiff)/(NUM_GRAYS-1);
844 palette->colors[index].g = bg.g + (index*gdiff)/(NUM_GRAYS-1);
845 palette->colors[index].b = bg.b + (index*bdiff)/(NUM_GRAYS-1);
846 }
847 }
848 break;
849
850 case 2:{ /* Alpha component magic */
851 sge_ClearSurface(textbuf, SDL_MapRGBA(textbuf->format, bg.r,bg.g,bg.b,SDL_ALPHA_TRANSPARENT));
852 //pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
853 pixel = (fg.b<<16)|(fg.g<<8)|fg.r;
854 }
855 break;
856 }
857
858
859 /* Load and render each character */
860 xstart = 0;
861 for ( ch=text; *ch; ++ch ) {
862 error = Find_Glyph(font, *ch, CACHED_METRICS|CACHED_PIXMAP);
863
864 if ( ! error ) {
865 w = font->current->pixmap.width;
866 src = (Uint8 *)font->current->pixmap.buffer;
867 for ( row = 0; row < font->current->pixmap.rows; ++row ) {
868 dst = (Uint8 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch + xstart + font->current->minx;
869
870 switch(_sge_TTF_AA){
871
872 case 0:{ /* Normal */
873 src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
874 for ( col=w; col>0; --col ) {
875 *dst++ |= (*src++<NUM_GRAYS/2)? 0:1;
876 }
877 }
878 break;
879 case 1:{ /* Antialiasing */
880 src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
881 for ( col=w; col>0; --col ) {
882 *dst++ |= *src++;
883 }
884 }
885 break;
886
887 case 2:{ /* Alpha */
888 dst32 = (Uint32 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch/4 + xstart + font->current->minx;
889 for ( col=w; col>0; --col ) {
890 alpha = *src++;
891 *dst32++ |= pixel | (alpha << 24);
892 }
893 }
894 break;
895 }
896 }
897
898 xstart += font->current->advance;
899 if ( font->style & SGE_TTF_BOLD ) {
900 xstart += font->glyph_overhang;
901 }
902 }
903 }
904
905 /* Handle the underline style */
906 if ( font->style & SGE_TTF_UNDERLINE ) {
907 int row_offset;
908
909 row_offset = font->ascent - font->underline_offset - 1;
910 if ( row_offset > textbuf->h ) {
911 row_offset = (textbuf->h-1) - font->underline_height;
912 }
913
914 if(_sge_TTF_AA==0){
915 dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
916 for ( row=font->underline_height; row>0; --row ) {
917 memset(dst, 1, textbuf->w );
918 dst += textbuf->pitch;
919 }
920 }else if(_sge_TTF_AA==1){
921 dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
922 for ( row=font->underline_height; row>0; --row ) {
923 memset(dst, NUM_GRAYS - 1, textbuf->w );
924 dst += textbuf->pitch;
925 }
926 }else{
927 pixel |= Amask;
928 dst32 = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4;
929 for ( row=font->underline_height; row>0; --row ) {
930 for ( col=0; col < textbuf->w; ++col ) {
931 dst32[col] = pixel;
932 }
933 dst32 += textbuf->pitch/4;
934 }
935 }
936 }
937 return(textbuf);
938 }
939
940
941 //==================================================================================
942 // Renders the Unicode string to TrueType on surface, with the color fcolor.
943 // bcolor is the target color for the antialiasing.
944 // Alpha sets the transparency of the text (255-solid, 0-max).
945 //==================================================================================
sge_tt_textout_UNI(SDL_Surface * Surface,sge_TTFont * font,const Uint16 * uni,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)946 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)
947 {
948 SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
949
950 SDL_Color temp;
951 SDL_Surface *text;
952
953 text=sge_TTF_RenderUNICODE(font,uni,sge_GetRGB(Surface,fcolor),sge_GetRGB(Surface,bcolor));
954 if(text==NULL){return ret;}
955
956 /* Align the surface text to the baseline */
957 Uint16 ascent=font->ascent;
958
959 temp=sge_GetRGB(Surface,bcolor);
960 sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,temp.r,temp.g,temp.b),Alpha);
961 sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
962
963 ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
964
965 SDL_FreeSurface(text);
966 return ret;
967 }
968
969
970 //==================================================================================
971 // Renders the Unicode string to TrueType on surface, with the color fcolor.
972 // bcolor is the target color for the antialiasing.
973 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
974 //==================================================================================
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)975 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)
976 {
977 SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
978 SDL_Surface *text;
979
980 text=sge_TTF_RenderUNICODE(font,uni,sge_FillPaletteEntry(fR,fG,fB),sge_FillPaletteEntry(bR,bG,bB));
981 if(text==NULL){return ret;}
982
983 /* Align the surface text to the baseline */
984 Uint16 ascent=font->ascent;
985
986 sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,bR,bG,bB),Alpha);
987
988 sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
989
990 ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
991
992 SDL_FreeSurface(text);
993 return ret;
994 }
995
996
997 //==================================================================================
998 // Renders the Latin-1 string to TrueType on surface, with the color fcolor.
999 // bcolor is the target color for the antialiasing.
1000 // Alpha sets the transparency of the text (0-solid, 255-max).
1001 //==================================================================================
sge_tt_textout(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)1002 SDL_Rect sge_tt_textout(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
1003 {
1004 SDL_Rect ret;
1005 Uint16 *uni;
1006
1007 uni=sge_Latin1_Uni(string);
1008
1009 ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
1010 free(uni);
1011
1012 return ret;
1013 }
1014
1015 //==================================================================================
1016 // Renders the Latin-1 string to TrueType on surface, with the color fcolor.
1017 // bcolor is the target color for the antialiasing.
1018 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
1019 //==================================================================================
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)1020 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)
1021 {
1022 SDL_Rect ret;
1023 Uint16 *uni;
1024
1025 uni=sge_Latin1_Uni(string);
1026
1027 ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
1028 free(uni);
1029
1030 return ret;
1031 }
1032
1033
1034 //==================================================================================
1035 // Renders the UTF-8 string to TrueType on surface, with the color fcolor.
1036 // bcolor is the target color for the antialiasing.
1037 // Alpha sets the transparency of the text (0-solid, 255-max).
1038 //==================================================================================
sge_tt_textout_UTF8(SDL_Surface * Surface,sge_TTFont * font,const char * string,Sint16 x,Sint16 y,Uint32 fcolor,Uint32 bcolor,int Alpha)1039 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)
1040 {
1041 SDL_Rect ret;
1042 Uint16 *uni;
1043
1044 uni=sge_UTF8_Uni(string);
1045
1046 ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
1047 free(uni);
1048
1049 return ret;
1050 }
1051
1052 //==================================================================================
1053 // Renders the UTF-8 string to TrueType on surface, with the color fcolor.
1054 // bcolor is the target color for the antialiasing.
1055 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
1056 //==================================================================================
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)1057 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)
1058 {
1059 SDL_Rect ret;
1060 Uint16 *uni;
1061
1062 uni=sge_UTF8_Uni(string);
1063
1064 ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
1065 free(uni);
1066
1067 return ret;
1068 }
1069
1070
1071 //==================================================================================
1072 // Renders the formatet Latin-1 string to TrueType on surface, with the color fcolor.
1073 // bcolor is the target color for the antialiasing.
1074 // Alpha sets the transparency of the text (0-solid, 255-max). (RGB ONLY)
1075 // * just like printf(char *format,...) *
1076 //==================================================================================
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,const char * format,...)1077 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 ,const char *format,...)
1078 {
1079 char buf[256];
1080
1081 va_list ap;
1082
1083 #ifdef __WIN32__
1084 va_start((va_list*)ap, format); //Stupid win32 crosscompiler
1085 #else
1086 va_start(ap, format);
1087 #endif
1088
1089 vsprintf(buf, format, ap);
1090 va_end(ap);
1091
1092 return sge_tt_textout(Surface, font, buf, x,y, fR,fG,fB, bR,bG,bB, Alpha);
1093 }
1094
1095
1096
1097
1098 /**********************************************************************************/
1099 /** TTF 'input' functions **/
1100 /**********************************************************************************/
1101
1102 // First some internel functions for TTF input
1103
1104 //==================================================================================
1105 // Fast update function for TTF input
1106 //
1107 // type=0 - in ret smaller then out ret
1108 // type=1 - in ret bigger then out ret
1109 // type=3 - safe
1110 //==================================================================================
fast_update(SDL_Surface * Surface,SDL_Surface * buffer,SDL_Rect ret,int type,sge_TTFont * font,Uint16 * string,Sint16 x,Sint16 y,Uint32 fcol,Uint32 bcol,int Alpha)1111 SDL_Rect fast_update(SDL_Surface *Surface,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol,int Alpha)
1112 {
1113 if(type==0){
1114 sge_Update_OFF();
1115 sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
1116 ret=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
1117 sge_Update_ON();
1118 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1119 }
1120 else if(type==1){
1121 SDL_Rect temp;
1122
1123 sge_Update_OFF();
1124 sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
1125 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
1126 sge_Update_ON();
1127 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1128 ret=temp;
1129 }
1130 else{
1131 SDL_Rect temp;
1132
1133 sge_Update_OFF();
1134 sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
1135 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
1136 sge_Update_ON();
1137 if(ret.w>=temp.w){
1138 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1139 }
1140 else{
1141 sge_UpdateRect(Surface, temp.x, temp.y, temp.w, temp.h);
1142 }
1143 ret=temp;
1144 }
1145 return ret;
1146 }
1147
1148 //==================================================================================
1149 // Update function for TTF input that preserve background
1150 //
1151 // type=0 - in ret smaller then out ret
1152 // type=1 - in ret bigger then out ret
1153 // type=3 - safe
1154 //==================================================================================
nice_update(SDL_Surface * Surface,SDL_Surface * buffer,SDL_Rect ret,int type,sge_TTFont * font,Uint16 * string,Sint16 x,Sint16 y,Uint32 fcol,Uint32 bcol,int Alpha)1155 SDL_Rect nice_update(SDL_Surface *Surface,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha)
1156 {
1157 if(type==0){
1158 sge_Update_OFF();
1159 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1160 ret=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1161 sge_Update_ON();
1162 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1163 }
1164 else if(type==1){
1165 SDL_Rect temp;
1166
1167 sge_Update_OFF();
1168 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1169 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1170 sge_Update_ON();
1171 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1172 ret=temp;
1173 }
1174 else{
1175 SDL_Rect temp;
1176
1177 sge_Update_OFF();
1178 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1179 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1180 sge_Update_ON();
1181 if(ret.w>=temp.w){
1182 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1183 }
1184 else{
1185 sge_UpdateRect(Surface, temp.x, temp.y, temp.w, temp.h);
1186 }
1187 ret=temp;
1188 }
1189
1190 return ret;
1191 }
1192 #endif /* _SGE_NOTTF */
1193
1194
1195 //==================================================================================
1196 // Handle keyrepeats
1197 //==================================================================================
keyrepeat(SDL_Event * event,int wait)1198 int keyrepeat(SDL_Event *event, int wait)
1199 {
1200 int keydown=1,c=0,ret=0;
1201 SDL_Event ev;
1202
1203 do{
1204 if(SDL_PollEvent(&ev)==1){
1205 if(ev.type==SDL_QUIT){ret=-1;keydown=0;}
1206 if(ev.type==SDL_KEYUP || ev.type==SDL_KEYDOWN){ //Keyrepeat cancelled
1207 keydown=0;
1208 if(ev.type==SDL_KEYDOWN){
1209 SDL_PeepEvents(&ev,1, SDL_ADDEVENT, 0); //Return the newly pressed key to the event queue
1210 }
1211 }
1212 }
1213 SDL_Delay(10);
1214 c++;
1215 if(c>wait && keydown==1){ //trigers keyrepeat
1216 ret=1;
1217 SDL_PeepEvents(event,1, SDL_ADDEVENT, 0); //Return the old key to the event queue
1218 keydown=0;
1219 }
1220 }while(keydown==1);
1221
1222 return ret;
1223 }
1224
1225
1226 //==================================================================================
1227 // Insert a element
1228 //==================================================================================
insert_char(Uint16 * string,Uint16 ch,int pos,int max)1229 void insert_char(Uint16 *string, Uint16 ch, int pos, int max)
1230 {
1231 if(pos>max || pos<0){return;}
1232 else if(pos==max){string[pos]=ch;}
1233 else{
1234 for(int i=max; i>=pos; i--){
1235 string[i+1]=string[i];
1236 }
1237 string[pos]=ch;
1238 }
1239 }
1240
1241
1242 //==================================================================================
1243 // Delete a element
1244 //==================================================================================
delete_char(Uint16 * string,int pos,int max)1245 void delete_char(Uint16 *string, int pos, int max)
1246 {
1247 if(pos>max || pos<0){return;}
1248 else if(pos==max){string[pos]=0;}
1249 else{
1250 for(int i=pos; i<=max-1; i++){
1251 string[i]=string[i+1];
1252 }
1253 string[max]=0;
1254 }
1255 }
1256
1257
1258 #ifndef _SGE_NOTTF
1259 // These functions handle keyboard input and shows the result on screen. The text
1260 // can be edited with [Backspace], [Delete], [Left arrow] and [Right arrow].
1261 // Text input is terminated when [Return] or [Enter] is pressed, or if a quit event
1262 // is recived.
1263 // The sge_tt_input functions puts the result in 'string'.
1264 //
1265 // Flags: SGE_IBG - Keeps background, else bye bye background
1266 // SGE_IDEL - Delete text on exit
1267 // SGE_INOKR - No keyrepeat
1268 // (use OR | to give more than one)
1269 //
1270 // If you want a 'default' text you can copy it to string before call and set pos to
1271 // the first empty element in string - ex. "Hello" => pos=5. If not - zero.
1272 // len is the max numbers of chars editable - ex. if you set the default text to "100"
1273 // and only want 3 digits out, set len to 3. string should have atleast len+1 elements
1274 // allocated
1275 // This is *not* a fast, optimized function - but it gets the job done...
1276
1277 // Return:
1278 // Zero or above - the lenght of the string
1279 // -1 recieved a quit event (the lenght is lost)
1280 // -2 invalid indata
1281 // -3 out of memory
1282
1283 //==================================================================================
1284 // Text input UNICODE (the core)
1285 //==================================================================================
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)1286 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)
1287 {
1288 if(len<pos || pos<0 || len<0){return -2;}
1289
1290 Uint16 cur=124;//The charactar for the cursor - '|'
1291 int max; //The strings size
1292
1293 /* Set update function */
1294 SDL_Rect (*_update)(SDL_Surface *screen,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha);
1295 SDL_Surface *buffer;
1296
1297 if(flags&SGE_FLAG1){ /* Keep background? */
1298 _update=nice_update;
1299 buffer=SDL_DisplayFormat(screen); /* Fixme: Yum! Memory! */
1300 if(buffer==NULL){SDL_SetError("SGE - Out of memory");return -3;}
1301 }
1302 else{ /* nope */
1303 _update=fast_update;
1304 buffer=NULL;
1305 Alpha=0;
1306 }
1307
1308 SDL_Rect ret;
1309
1310 max=pos;
1311 string[pos+1]=0;
1312
1313 SDL_EnableUNICODE(1);
1314
1315 /* Init cursor */
1316 string[pos]=cur;
1317 ret=sge_tt_textout_UNI(screen,font,string, x,y, fcol, bcol, Alpha);
1318
1319 SDL_Event event;
1320 int quit=0;
1321 do{
1322 /* Check events */
1323 SDL_WaitEvent(&event);
1324 if(event.type==SDL_QUIT){quit=-1;}
1325 else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_ESCAPE){quit=1;}
1326 else if(event.type==SDL_KEYDOWN && (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER)){quit=1;}
1327 else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_BACKSPACE){
1328 if(pos>0){
1329 /* Delete char cursor-1 */
1330 delete_char(string,pos-1,max); pos--; max--;
1331
1332 ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
1333
1334 /* Handle keyrepeat */
1335 if(!(flags&SGE_FLAG3))
1336 if(keyrepeat(&event, 20)==-1){quit=-1;}
1337 }
1338 }
1339 else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_RIGHT){
1340 if(pos!=max && pos!=len){
1341 /* Move cursor right */
1342 delete_char(string,pos,max);pos++;
1343 insert_char(string,cur,pos,max);
1344
1345 ret=_update(screen,buffer,ret,3,font,string, x,y, fcol, bcol, Alpha);
1346
1347 /* Handle keyrepeat */
1348 if(!(flags&SGE_FLAG3))
1349 if(keyrepeat(&event, 20)==-1){quit=-1;}
1350 }
1351 }
1352 else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_LEFT){
1353 if(pos>0){
1354 /* Move cursor left */
1355 delete_char(string,pos,max);pos--;
1356 insert_char(string,cur,pos,max);
1357
1358 ret=_update(screen,buffer,ret,3,font,string, x,y, fcol, bcol, Alpha);
1359
1360 /* Handle keyrepeat */
1361 if(!(flags&SGE_FLAG3))
1362 if(keyrepeat(&event, 20)==-1){quit=-1;}
1363 }
1364 }
1365 else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_DELETE){
1366 /* Delete char cursor+1 */
1367 if(pos!=max && pos!=len){
1368 delete_char(string,pos+1,max);max--;
1369
1370 ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
1371
1372 /* Handle keyrepeat */
1373 if(!(flags&SGE_FLAG3))
1374 if(keyrepeat(&event, 20)==-1){quit=-1;}
1375 }
1376 }
1377 else if(event.type==SDL_KEYDOWN && event.key.keysym.unicode!=0){
1378 /* Insert new char */
1379 if(max!=len){
1380 max++;
1381 insert_char(string, event.key.keysym.unicode, pos,max); pos++;
1382
1383 ret=_update(screen,buffer,ret,0,font,string, x,y, fcol, bcol, Alpha);
1384
1385 /* Handle keyrepeat */
1386 if(!(flags&SGE_FLAG3))
1387 if(keyrepeat(&event, 40)==-1){quit=-1;}
1388 }
1389 }
1390 }while(quit==0);
1391
1392 /* Remove the cursor from string */
1393 delete_char(string,pos,max);
1394
1395 if(flags&SGE_FLAG2){ //Remove the text
1396 if(flags&SGE_FLAG1){
1397 sge_Blit(buffer,screen, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1398 sge_UpdateRect(screen, ret.x, ret.y, ret.w, ret.h);
1399 }
1400 else{
1401 sge_FilledRect(screen,ret.x, ret.y, ret.x+ret.w, ret.y+ret.h,bcol);
1402 }
1403 }
1404 else{ //Draw text without cursor
1405 ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
1406 }
1407
1408
1409 if(flags&SGE_FLAG1){SDL_FreeSurface(buffer);}
1410
1411 if(quit==-1){return -1;} //Waaa! The user killed me!
1412 return max;
1413 }
1414
1415
1416
1417
CReadline(SDL_Surface * a_poScreen,sge_TTFont * a_poFont,char * a_pcString,int a_iPos,int a_iLen,int a_x,int a_y,int a_w,Uint32 a_iFCol,Uint32 a_iBCol,int a_iAlpha)1418 CReadline::CReadline( SDL_Surface *a_poScreen, sge_TTFont *a_poFont,
1419 char *a_pcString, int a_iPos, int a_iLen,
1420 int a_x, int a_y, int a_w, Uint32 a_iFCol, Uint32 a_iBCol, int a_iAlpha )
1421 {
1422 m_iResult = 0;
1423 m_poScreen = a_poScreen;
1424 m_poFont = a_poFont;
1425 m_piString = 0;
1426 m_iLen = -1;
1427 w = a_w;
1428 x = a_x;
1429 y = a_y;
1430
1431 SDL_EnableUNICODE(1);
1432
1433 // Create background copy.
1434
1435 m_oWorkArea.x = x;
1436 m_oWorkArea.y = y - sge_TTF_FontAscent(m_poFont);
1437 m_oWorkArea.w = w;
1438 m_oWorkArea.h = sge_TTF_FontHeight(a_poFont);
1439
1440 m_poBackground = sge_copy_surface( a_poScreen, m_oWorkArea.x, m_oWorkArea.y, m_oWorkArea.w, m_oWorkArea.h );
1441
1442 Restart( a_pcString, a_iPos, a_iLen, a_iFCol, a_iBCol, a_iAlpha );
1443 }
1444
1445
Restart(char * a_pcString,int a_iPos,int a_iLen,Uint32 a_iFCol,Uint32 a_iBCol,int a_iAlpha)1446 void CReadline::Restart( char *a_pcString, int a_iPos, int a_iLen,
1447 Uint32 a_iFCol, Uint32 a_iBCol, int a_iAlpha )
1448 {
1449 if ( NULL == m_piString
1450 || m_iLen <= a_iLen )
1451 {
1452 if ( m_piString ) delete[] m_piString;
1453 m_iLen = a_iLen;
1454 m_piString = new Uint16[a_iLen+2];
1455 }
1456
1457 m_iResult = 0;
1458
1459 m_pcLatin1String = a_pcString;
1460 m_iPos = a_iPos;
1461 m_iFCol = a_iFCol;
1462 m_iBCol = a_iBCol;
1463 m_iAlpha = a_iAlpha;
1464
1465 // Convert the original string into an unicode string
1466
1467 int i;
1468 for(i=0; i<m_iPos; i++)
1469 {
1470 m_piString[i]=(unsigned char)m_pcLatin1String[i];
1471 }
1472 m_piString[m_iPos]=0;
1473
1474 // Insert the cursor at the end
1475
1476 m_iCursor = 124; // '|' character
1477 m_iMax=m_iPos;
1478 m_piString[m_iPos+1]=0;
1479 m_piString[m_iPos]=m_iCursor;
1480 Redraw();
1481 SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY/2, SDL_DEFAULT_REPEAT_INTERVAL/2 );
1482 }
1483
1484
~CReadline()1485 CReadline::~CReadline()
1486 {
1487 delete[] m_piString;
1488 SDL_FreeSurface( m_poBackground );
1489 m_poBackground = NULL;
1490
1491 SDL_EnableKeyRepeat( 0, 0 );
1492 }
1493
1494
1495 /** Returns the current state of the line input.
1496 \retval -1 A quit event was encountered.
1497 \retval -2 Escape was pressed
1498 \retval 0 Input is in progress.
1499 \retval 1 Input has finished.
1500 */
GetResult()1501 int CReadline::GetResult()
1502 {
1503 if ( m_iResult == 0 )
1504 {
1505 return m_iResult;
1506 }
1507
1508 SDL_EnableKeyRepeat( 0, 0 );
1509
1510 sge_Blit( m_poBackground, m_poScreen, m_oUpdateRect.x, m_oUpdateRect.y,
1511 m_oUpdateRect.x, m_oUpdateRect.y, m_oUpdateRect.w, m_oUpdateRect.h);
1512 sge_UpdateRect(m_poScreen, m_oUpdateRect.x, m_oUpdateRect.y, m_oUpdateRect.w, m_oUpdateRect.h);
1513
1514 if ( m_iResult < 0 )
1515 {
1516 return m_iResult;
1517 }
1518
1519 delete_char( m_piString, m_iPos, m_iMax );
1520
1521 memset( m_pcLatin1String, 0, sizeof(char)*(m_iPos+1) );
1522 for( int i=0; i<=m_iMax; i++)
1523 {
1524 m_pcLatin1String[i] = (char)m_piString[i];
1525 }
1526
1527 insert_char( m_piString, m_iCursor, m_iPos, m_iMax );
1528
1529 return 1;
1530 }
1531
1532
1533
1534
1535 /** Internal method for redrawing the string. */
Update(int a_iCode)1536 void CReadline::Update( int a_iCode )
1537 {
1538 //m_oUpdateRect = nice_update( m_poScreen, m_poBackground, m_oUpdateRect, a_iCode, m_poFont, m_piString,
1539 // x, y, m_iFCol, m_iBCol, m_iAlpha );
1540
1541 SDL_Rect oOldClipRect;
1542 SDL_GetClipRect( m_poScreen, &oOldClipRect );
1543 SDL_SetClipRect( m_poScreen, &m_oWorkArea );
1544
1545 sge_Blit( m_poBackground, m_poScreen, 0, 0, m_oWorkArea.x, m_oWorkArea.y, m_oWorkArea.w, m_oWorkArea.h );
1546 sge_tt_textout_UNI( m_poScreen, m_poFont, m_piString, x, y, m_iFCol, m_iBCol, m_iAlpha );
1547 sge_UpdateRect( m_poScreen, m_oWorkArea.x, m_oWorkArea.y, m_oWorkArea.w, m_oWorkArea.h );
1548
1549 SDL_SetClipRect( m_poScreen, &oOldClipRect );
1550 }
1551
1552
Redraw()1553 void CReadline::Redraw()
1554 {
1555 m_oUpdateRect = sge_tt_textout_UNI( m_poScreen, m_poFont, m_piString, x, y, m_iFCol, m_iBCol, m_iAlpha );
1556 sge_UpdateRect( m_poScreen, m_oWorkArea.x, m_oWorkArea.y, m_oWorkArea.w, m_oWorkArea.h );
1557 }
1558
1559
Clear()1560 void CReadline::Clear()
1561 {
1562 sge_Blit( m_poBackground, m_poScreen, 0, 0, m_oWorkArea.x, m_oWorkArea.y, m_oWorkArea.w, m_oWorkArea.h );
1563 }
1564
1565
1566 /** Runs the event queue until the input is finished.
1567 \see GetResult
1568 */
Execute()1569 int CReadline::Execute()
1570 {
1571 int iRetval;
1572 SDL_Event e;
1573 while ( 1 )
1574 {
1575 SDL_WaitEvent( &e );
1576 HandleKeyEvent( e );
1577 iRetval = GetResult();
1578 if ( iRetval )
1579 break;
1580 }
1581
1582 return iRetval;
1583 }
1584
1585
1586
HandleKeyEvent(SDL_Event & a_roEvent)1587 void CReadline::HandleKeyEvent( SDL_Event& a_roEvent )
1588 {
1589 if(a_roEvent.type==SDL_QUIT)
1590 {
1591 m_iResult = -1;
1592 return;
1593 }
1594
1595 if ( a_roEvent.type != SDL_KEYDOWN )
1596 {
1597 return;
1598 }
1599
1600 if( a_roEvent.key.keysym.sym==SDLK_ESCAPE )
1601 {
1602 m_iResult = -2;
1603 return;
1604 }
1605
1606 if ( a_roEvent.key.keysym.sym==SDLK_RETURN
1607 || a_roEvent.key.keysym.sym==SDLK_KP_ENTER )
1608 {
1609 m_iResult = 1;
1610 return;
1611 }
1612
1613 if( a_roEvent.key.keysym.sym==SDLK_BACKSPACE )
1614 {
1615 if ( m_iPos == 0 )
1616 {
1617 return;
1618 }
1619 /* Delete char cursor-1 */
1620 delete_char(m_piString,m_iPos-1,m_iMax);
1621 m_iPos--;
1622 m_iMax--;
1623 Update( 1 );
1624 return;
1625 }
1626
1627 if( a_roEvent.key.keysym.sym==SDLK_RIGHT
1628 && m_iPos!=m_iMax && m_iPos!=m_iLen )
1629 {
1630 /* Move cursor right */
1631 delete_char(m_piString,m_iPos,m_iMax);
1632 m_iPos++;
1633 insert_char(m_piString,m_iCursor,m_iPos,m_iMax);
1634 Update( 3 );
1635 return;
1636 }
1637
1638 if ( a_roEvent.key.keysym.sym==SDLK_LEFT
1639 && m_iPos>0 )
1640 {
1641 /* Move cursor left */
1642 delete_char(m_piString,m_iPos,m_iMax);
1643 m_iPos--;
1644 insert_char(m_piString,m_iCursor,m_iPos,m_iMax);
1645 Update( 3 );
1646 return;
1647 }
1648
1649 if( a_roEvent.key.keysym.sym==SDLK_DELETE )
1650 {
1651 if ( m_iPos!=m_iMax && m_iPos!=m_iLen )
1652 {
1653 delete_char(m_piString,m_iPos+1,m_iMax);
1654 m_iMax--;
1655 Update( 1 );
1656 }
1657 return;
1658 }
1659
1660 if( a_roEvent.key.keysym.unicode!=0
1661 && a_roEvent.key.keysym.unicode >=32
1662 && a_roEvent.key.keysym.unicode <=255
1663 && m_iMax != m_iLen )
1664 {
1665 m_iMax++;
1666 insert_char(m_piString, a_roEvent.key.keysym.unicode, m_iPos, m_iMax);
1667 m_iPos++;
1668 Update( 0 );
1669 }
1670 }
1671
1672
1673 /*
1674 SDL_Rect CReadline::NiceUpdate( SDL_Surface *Surface,SDL_Surface *buffer,
1675 SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y,
1676 Uint32 fcol, Uint32 bcol, int Alpha )
1677 {
1678 if(type==0){
1679 sge_Update_OFF();
1680 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1681 ret=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1682 sge_Update_ON();
1683 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1684 }
1685 else if(type==1){
1686 SDL_Rect temp;
1687
1688 sge_Update_OFF();
1689 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1690 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1691 sge_Update_ON();
1692 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1693 ret=temp;
1694 }
1695 else{
1696 SDL_Rect temp;
1697
1698 sge_Update_OFF();
1699 sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
1700 temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
1701 sge_Update_ON();
1702 if(ret.w>=temp.w){
1703 sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
1704 }
1705 else{
1706 sge_UpdateRect(Surface, temp.x, temp.y, temp.w, temp.h);
1707 }
1708 ret=temp;
1709 }
1710
1711 return ret;
1712 }
1713 */
1714
1715
1716
1717
1718
1719 //==================================================================================
1720 // Text input UNICODE (RGB)
1721 //==================================================================================
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)1722 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)
1723 {
1724 return sge_tt_input_UNI(screen,font,string,flags,pos,len,x,y,SDL_MapRGB(screen->format, fR,fG,fB),SDL_MapRGB(screen->format, bR,bG,bB),Alpha);
1725 }
1726
1727
1728 //==================================================================================
1729 // Text input Latin1
1730 //
1731 // Will fail miserable if ret<0!
1732 //==================================================================================
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)1733 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)
1734 {
1735 if(len<pos || pos<0 || len<0){return -2;}
1736
1737 #ifndef __GNUC__
1738 Uint16 *uni=new Uint16[len+2]; //ANSI C++
1739 #else
1740 Uint16 uni[len+2];
1741 #endif
1742
1743 int ret;
1744
1745 int i;
1746 if(pos!=0){
1747 for(i=0; i<pos; i++){ //Convert Latin1 => Uni
1748 uni[i]=(unsigned char)string[i];
1749 }
1750 }
1751 uni[pos]=0;
1752
1753 ret=sge_tt_input_UNI(screen,font,uni,flags,pos,len,x,y,fcol,bcol,Alpha);
1754
1755 memset(string,0,sizeof(char)*(pos+1));
1756 if(ret>0){
1757 for( i=0; i<=ret; i++){ //Convert Uni => Latin1
1758 string[i] = (char)uni[i];
1759 }
1760 }
1761
1762 #ifndef __GNUC__
1763 delete[] uni;
1764 #endif
1765
1766 return ret;
1767 }
1768
1769
1770 //==================================================================================
1771 // Text input Latin1 (RGB)
1772 //==================================================================================
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)1773 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)
1774 {
1775 return sge_tt_input(screen,font,string,flags,pos,len,x,y,SDL_MapRGB(screen->format, fR,fG,fB),SDL_MapRGB(screen->format, bR,bG,bB),Alpha);
1776 }
1777 #endif /* _SGE_NOTTF */
1778