1 /*
2   showfont:  An example of using the SDL_ttf library with 2D graphics.
3   Copyright (C) 2001-2012 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /* A simple program to test the text rendering feature of the TTF library */
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #ifdef HAVE_ICONV
29 #include <iconv.h>
30 #endif
31 
32 #include "SDL.h"
33 #include "SDL_ttf.h"
34 
35 #define DEFAULT_PTSIZE	18
36 #define DEFAULT_TEXT	"The quick brown fox jumped over the lazy dog"
37 #define NUM_COLORS      256
38 
39 static char *Usage =
40 "Usage: %s [-solid] [-utf8|-unicode] [-b] [-i] [-u] [-s] [-outline size] [-hintlight|-hintmono|-hintnone] [-nokerning] [-fgcol r,g,b] [-bgcol r,g,b] <font>.ttf [ptsize] [text]\n";
41 
cleanup(int exitcode)42 static void cleanup(int exitcode)
43 {
44 	TTF_Quit();
45 	SDL_Quit();
46 	exit(exitcode);
47 }
48 
main(int argc,char * argv[])49 int main(int argc, char *argv[])
50 {
51 	char *argv0 = argv[0];
52 	SDL_Surface *screen;
53 	TTF_Font *font;
54 	SDL_Surface *text, *temp;
55 	int ptsize;
56 	int i, done;
57 	int rdiff, gdiff, bdiff;
58 	SDL_Color colors[NUM_COLORS];
59 	SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
60 	SDL_Color black = { 0x00, 0x00, 0x00, 0 };
61 	SDL_Color *forecol;
62 	SDL_Color *backcol;
63 	SDL_Rect dstrect;
64 	SDL_Event event;
65 	int rendersolid;
66 	int renderstyle;
67 	int outline;
68 	int hinting;
69 	int kerning;
70 	int dump;
71 	enum {
72 		RENDER_LATIN1,
73 		RENDER_UTF8,
74 		RENDER_UNICODE
75 	} rendertype;
76 	char *message, string[128];
77 
78 	/* Look for special execution mode */
79 	dump = 0;
80 	/* Look for special rendering types */
81 	rendersolid = 0;
82 	renderstyle = TTF_STYLE_NORMAL;
83 	rendertype = RENDER_LATIN1;
84 	outline = 0;
85 	hinting = TTF_HINTING_NORMAL;
86 	kerning = 1;
87 	/* Default is black and white */
88 	forecol = &black;
89 	backcol = &white;
90 	for ( i=1; argv[i] && argv[i][0] == '-'; ++i ) {
91 		if ( strcmp(argv[i], "-solid") == 0 ) {
92 			rendersolid = 1;
93 		} else
94 		if ( strcmp(argv[i], "-utf8") == 0 ) {
95 			rendertype = RENDER_UTF8;
96 		} else
97 		if ( strcmp(argv[i], "-unicode") == 0 ) {
98 			rendertype = RENDER_UNICODE;
99 		} else
100 		if ( strcmp(argv[i], "-b") == 0 ) {
101 			renderstyle |= TTF_STYLE_BOLD;
102 		} else
103 		if ( strcmp(argv[i], "-i") == 0 ) {
104 			renderstyle |= TTF_STYLE_ITALIC;
105 		} else
106 		if ( strcmp(argv[i], "-u") == 0 ) {
107 			renderstyle |= TTF_STYLE_UNDERLINE;
108 		} else
109 		if ( strcmp(argv[i], "-s") == 0 ) {
110 			renderstyle |= TTF_STYLE_STRIKETHROUGH;
111 		} else
112 		if ( strcmp(argv[i], "-outline") == 0 ) {
113 			if ( sscanf (argv[++i], "%d", &outline) != 1 ) {
114 				fprintf(stderr, Usage, argv0);
115 				return(1);
116 			}
117 		} else
118 		if ( strcmp(argv[i], "-hintlight") == 0 ) {
119 			hinting = TTF_HINTING_LIGHT;
120 		} else
121 		if ( strcmp(argv[i], "-hintmono") == 0 ) {
122 			hinting = TTF_HINTING_MONO;
123 		} else
124 		if ( strcmp(argv[i], "-hintnone") == 0 ) {
125 			hinting = TTF_HINTING_NONE;
126 		} else
127 		if ( strcmp(argv[i], "-nokerning") == 0 ) {
128 			kerning = 0;
129 		} else
130 		if ( strcmp(argv[i], "-dump") == 0 ) {
131 			dump = 1;
132 		} else
133 		if ( strcmp(argv[i], "-fgcol") == 0 ) {
134 			int r, g, b;
135 			if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) {
136 				fprintf(stderr, Usage, argv0);
137 				return(1);
138 			}
139 			forecol->r = (Uint8)r;
140 			forecol->g = (Uint8)g;
141 			forecol->b = (Uint8)b;
142 		} else
143 		if ( strcmp(argv[i], "-bgcol") == 0 ) {
144 			int r, g, b;
145 			if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) {
146 				fprintf(stderr, Usage, argv0);
147 				return(1);
148 			}
149 			backcol->r = (Uint8)r;
150 			backcol->g = (Uint8)g;
151 			backcol->b = (Uint8)b;
152 		} else {
153 			fprintf(stderr, Usage, argv0);
154 			return(1);
155 		}
156 	}
157 	argv += i;
158 	argc -= i;
159 
160 	/* Check usage */
161 	if ( ! argv[0] ) {
162 		fprintf(stderr, Usage, argv0);
163 		return(1);
164 	}
165 
166 	/* Initialize SDL */
167 	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
168 		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
169 		return(2);
170 	}
171 
172 	/* Initialize the TTF library */
173 	if ( TTF_Init() < 0 ) {
174 		fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError());
175 		SDL_Quit();
176 		return(2);
177 	}
178 
179 	/* Open the font file with the requested point size */
180 	ptsize = 0;
181 	if ( argc > 1 ) {
182 		ptsize = atoi(argv[1]);
183 	}
184 	if ( ptsize == 0 ) {
185 		i = 2;
186 		ptsize = DEFAULT_PTSIZE;
187 	} else {
188 		i = 3;
189 	}
190 	font = TTF_OpenFont(argv[0], ptsize);
191 	if ( font == NULL ) {
192 		fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",
193 					ptsize, argv[0], SDL_GetError());
194 		cleanup(2);
195 	}
196 	TTF_SetFontStyle(font, renderstyle);
197 	TTF_SetFontOutline(font, outline);
198 	TTF_SetFontKerning(font, kerning);
199 	TTF_SetFontHinting(font, hinting);
200 
201 	if( dump ) {
202 		for( i = 48; i < 123; i++ ) {
203 			SDL_Surface* glyph = NULL;
204 
205 			glyph = TTF_RenderGlyph_Shaded( font, i, *forecol, *backcol );
206 
207 			if( glyph ) {
208 				char outname[64];
209 				sprintf( outname, "glyph-%d.bmp", i );
210 				SDL_SaveBMP( glyph, outname );
211 			}
212 
213 		}
214 		cleanup(0);
215 	}
216 
217 	/* Set a 640x480x8 video mode */
218 	screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);
219 	if ( screen == NULL ) {
220 		fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n",
221 							SDL_GetError());
222 		cleanup(2);
223 	}
224 
225 	/* Set a palette that is good for the foreground colored text */
226 	rdiff = backcol->r - forecol->r;
227 	gdiff = backcol->g - forecol->g;
228 	bdiff = backcol->b - forecol->b;
229 	for ( i=0; i<NUM_COLORS; ++i ) {
230 		colors[i].r = forecol->r + (i*rdiff)/4;
231 		colors[i].g = forecol->g + (i*gdiff)/4;
232 		colors[i].b = forecol->b + (i*bdiff)/4;
233 	}
234 	SDL_SetColors(screen, colors, 0, NUM_COLORS);
235 
236 	/* Clear the background to background color */
237 	SDL_FillRect(screen, NULL,
238 			SDL_MapRGB(screen->format, backcol->r, backcol->g, backcol->b));
239 	SDL_UpdateRect(screen, 0, 0, 0, 0);
240 
241 	/* Show which font file we're looking at */
242 	sprintf(string, "Font file: %s", argv[0]);  /* possible overflow */
243 	if ( rendersolid ) {
244 		text = TTF_RenderText_Solid(font, string, *forecol);
245 	} else {
246 		text = TTF_RenderText_Shaded(font, string, *forecol, *backcol);
247 	}
248 	if ( text != NULL ) {
249 		dstrect.x = 4;
250 		dstrect.y = 4;
251 		dstrect.w = text->w;
252 		dstrect.h = text->h;
253 		SDL_BlitSurface(text, NULL, screen, &dstrect);
254 		SDL_FreeSurface(text);
255 	}
256 
257 	/* Render and center the message */
258 	if ( argc > 2 ) {
259 		message = argv[2];
260 	} else {
261 		message = DEFAULT_TEXT;
262 	}
263 	switch (rendertype) {
264 	    case RENDER_LATIN1:
265 		if ( rendersolid ) {
266 			text = TTF_RenderText_Solid(font,message,*forecol);
267 		} else {
268 			text = TTF_RenderText_Shaded(font,message,*forecol,*backcol);
269 		}
270 		break;
271 
272 	    case RENDER_UTF8:
273 		if ( rendersolid ) {
274 			text = TTF_RenderUTF8_Solid(font,message,*forecol);
275 		} else {
276 			text = TTF_RenderUTF8_Shaded(font,message,*forecol,*backcol);
277 		}
278 		break;
279 
280 	    case RENDER_UNICODE:
281 		{
282 			Uint16 unicode_text[BUFSIZ];
283 			int index;
284 #ifdef HAVE_ICONV
285 			/* Use iconv to convert the message into utf-16.
286 			 * "char" and "" are aliases for the local 8-bit encoding */
287 			iconv_t cd;
288 			/*ICONV_CONST*/ char *from_str = message;
289 			char *to_str = (char*)unicode_text;
290 			size_t from_sz = strlen(message) + 1;
291 			size_t to_sz = sizeof(unicode_text);
292 			size_t res;
293 			int i;
294 
295 			if ((cd = iconv_open("UTF-16", "char")) == (iconv_t)-1
296 			    && (cd = iconv_open("UTF-16", "")) == (iconv_t)-1) {
297 				perror("Couldn't open iconv");
298 				exit(1);
299 			}
300 
301 			res = iconv(cd, &from_str, &from_sz, &to_str, &to_sz);
302 			if (res == -1) {
303 				perror("Couldn't use iconv");
304 				exit(1);
305 			}
306 
307 			iconv_close(cd);
308 #else
309 			/* Convert the message from ascii into utf-16.
310 			 * This is unreliable as a test because it always
311 			 * gives the local ordering. */
312 			for (index = 0; message[index]; index++) {
313 				unicode_text[index] = message[index];
314 			}
315 			unicode_text[index] = 0;
316 #endif
317 
318 			if ( rendersolid ) {
319 				text = TTF_RenderUNICODE_Solid(font,
320 					unicode_text, *forecol);
321 			} else {
322 				text = TTF_RenderUNICODE_Shaded(font,
323 					unicode_text, *forecol, *backcol);
324 			}
325 		}
326 		break;
327 	    default:
328 		text = NULL; /* This shouldn't happen */
329 		break;
330 	}
331 	if ( text == NULL ) {
332 		fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError());
333 		TTF_CloseFont(font);
334 		cleanup(2);
335 	}
336 	dstrect.x = (screen->w - text->w)/2;
337 	dstrect.y = (screen->h - text->h)/2;
338 	dstrect.w = text->w;
339 	dstrect.h = text->h;
340 	printf("Font is generally %d big, and string is %hd big\n",
341 						TTF_FontHeight(font), text->h);
342 
343 	/* Blit the text surface */
344 	if ( SDL_BlitSurface(text, NULL, screen, &dstrect) < 0 ) {
345 		fprintf(stderr, "Couldn't blit text to display: %s\n",
346 								SDL_GetError());
347 		TTF_CloseFont(font);
348 		cleanup(2);
349 	}
350 	SDL_UpdateRect(screen, 0, 0, 0, 0);
351 
352 	/* Set the text colorkey and convert to display format */
353 	if ( SDL_SetColorKey(text, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0) < 0 ) {
354 		fprintf(stderr, "Warning: Couldn't set text colorkey: %s\n",
355 								SDL_GetError());
356 	}
357 	temp = SDL_DisplayFormat(text);
358 	if ( temp != NULL ) {
359 		SDL_FreeSurface(text);
360 		text = temp;
361 	}
362 
363 	/* Wait for a keystroke, and blit text on mouse press */
364 	done = 0;
365 	while ( ! done ) {
366 		if ( SDL_WaitEvent(&event) < 0 ) {
367 			fprintf(stderr, "SDL_PullEvent() error: %s\n",
368 								SDL_GetError());
369 			done = 1;
370 			continue;
371 		}
372 		switch (event.type) {
373 			case SDL_MOUSEBUTTONDOWN:
374 				dstrect.x = event.button.x - text->w/2;
375 				dstrect.y = event.button.y - text->h/2;
376 				dstrect.w = text->w;
377 				dstrect.h = text->h;
378 				if ( SDL_BlitSurface(text, NULL, screen,
379 							&dstrect) == 0 ) {
380 					SDL_UpdateRects(screen, 1, &dstrect);
381 				} else {
382 					fprintf(stderr,
383 					"Couldn't blit text to display: %s\n",
384 								SDL_GetError());
385 				}
386 				break;
387 
388 			case SDL_KEYDOWN:
389 			case SDL_QUIT:
390 				done = 1;
391 				break;
392 			default:
393 				break;
394 		}
395 	}
396 	SDL_FreeSurface(text);
397 	TTF_CloseFont(font);
398 	cleanup(0);
399 
400 	/* Not reached, but fixes compiler warnings */
401 	return 0;
402 }
403