1 /*
2 glfont: An example of using the SDL_ttf library with OpenGL.
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 #include "SDL.h"
29 #include "SDL_ttf.h"
30
31 #ifdef HAVE_OPENGL
32
33 #include "SDL_opengl.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 [-utf8|-unicode] [-b] [-i] [-u] [-fgcol r,g,b] [-bgcol r,g,b] \
41 <font>.ttf [ptsize] [text]\n";
42
SDL_GL_Enter2DMode()43 void SDL_GL_Enter2DMode()
44 {
45 SDL_Surface *screen = SDL_GetVideoSurface();
46
47 /* Note, there may be other things you need to change,
48 depending on how you have your OpenGL state set up.
49 */
50 glPushAttrib(GL_ENABLE_BIT);
51 glDisable(GL_DEPTH_TEST);
52 glDisable(GL_CULL_FACE);
53 glEnable(GL_TEXTURE_2D);
54
55 /* This allows alpha blending of 2D textures with the scene */
56 glEnable(GL_BLEND);
57 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
58
59 glViewport(0, 0, screen->w, screen->h);
60
61 glMatrixMode(GL_PROJECTION);
62 glPushMatrix();
63 glLoadIdentity();
64
65 glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0);
66
67 glMatrixMode(GL_MODELVIEW);
68 glPushMatrix();
69 glLoadIdentity();
70
71 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
72 }
73
SDL_GL_Leave2DMode()74 void SDL_GL_Leave2DMode()
75 {
76 glMatrixMode(GL_MODELVIEW);
77 glPopMatrix();
78
79 glMatrixMode(GL_PROJECTION);
80 glPopMatrix();
81
82 glPopAttrib();
83 }
84
85 /* Quick utility function for texture creation */
power_of_two(int input)86 static int power_of_two(int input)
87 {
88 int value = 1;
89
90 while ( value < input ) {
91 value <<= 1;
92 }
93 return value;
94 }
95
SDL_GL_LoadTexture(SDL_Surface * surface,GLfloat * texcoord)96 GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord)
97 {
98 GLuint texture;
99 int w, h;
100 SDL_Surface *image;
101 SDL_Rect area;
102 Uint32 saved_flags;
103 Uint8 saved_alpha;
104
105 /* Use the surface width and height expanded to powers of 2 */
106 w = power_of_two(surface->w);
107 h = power_of_two(surface->h);
108 texcoord[0] = 0.0f; /* Min X */
109 texcoord[1] = 0.0f; /* Min Y */
110 texcoord[2] = (GLfloat)surface->w / w; /* Max X */
111 texcoord[3] = (GLfloat)surface->h / h; /* Max Y */
112
113 image = SDL_CreateRGBSurface(
114 SDL_SWSURFACE,
115 w, h,
116 32,
117 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
118 0x000000FF,
119 0x0000FF00,
120 0x00FF0000,
121 0xFF000000
122 #else
123 0xFF000000,
124 0x00FF0000,
125 0x0000FF00,
126 0x000000FF
127 #endif
128 );
129 if ( image == NULL ) {
130 return 0;
131 }
132
133 /* Save the alpha blending attributes */
134 saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
135 #if SDL_VERSION_ATLEAST(1, 3, 0)
136 SDL_GetSurfaceAlphaMod(surface, &saved_alpha);
137 SDL_SetSurfaceAlphaMod(surface, 0xFF);
138 #else
139 saved_alpha = surface->format->alpha;
140 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
141 SDL_SetAlpha(surface, 0, 0);
142 }
143 #endif
144
145 /* Copy the surface into the GL texture image */
146 area.x = 0;
147 area.y = 0;
148 area.w = surface->w;
149 area.h = surface->h;
150 SDL_BlitSurface(surface, &area, image, &area);
151
152 /* Restore the alpha blending attributes */
153 #if SDL_VERSION_ATLEAST(1, 3, 0)
154 SDL_SetSurfaceAlphaMod(surface, saved_alpha);
155 #else
156 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
157 SDL_SetAlpha(surface, saved_flags, saved_alpha);
158 }
159 #endif
160
161 /* Create an OpenGL texture for the image */
162 glGenTextures(1, &texture);
163 glBindTexture(GL_TEXTURE_2D, texture);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
166 glTexImage2D(GL_TEXTURE_2D,
167 0,
168 GL_RGBA,
169 w, h,
170 0,
171 GL_RGBA,
172 GL_UNSIGNED_BYTE,
173 image->pixels);
174 SDL_FreeSurface(image); /* No longer needed */
175
176 return texture;
177 }
178
cleanup(int exitcode)179 static void cleanup(int exitcode)
180 {
181 TTF_Quit();
182 SDL_Quit();
183 exit(exitcode);
184 }
185
main(int argc,char * argv[])186 int main(int argc, char *argv[])
187 {
188 char *argv0 = argv[0];
189 SDL_Surface *screen;
190 TTF_Font *font;
191 SDL_Surface *text;
192 int ptsize;
193 int i, done;
194 SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
195 SDL_Color black = { 0x00, 0x00, 0x00, 0 };
196 SDL_Color *forecol;
197 SDL_Color *backcol;
198 GLenum gl_error;
199 GLuint texture;
200 int x, y, w, h;
201 GLfloat texcoord[4];
202 GLfloat texMinX, texMinY;
203 GLfloat texMaxX, texMaxY;
204 float color[8][3]= {{ 1.0, 1.0, 0.0},
205 { 1.0, 0.0, 0.0},
206 { 0.0, 0.0, 0.0},
207 { 0.0, 1.0, 0.0},
208 { 0.0, 1.0, 1.0},
209 { 1.0, 1.0, 1.0},
210 { 1.0, 0.0, 1.0},
211 { 0.0, 0.0, 1.0}};
212 float cube[8][3]= {{ 0.5, 0.5, -0.5},
213 { 0.5, -0.5, -0.5},
214 {-0.5, -0.5, -0.5},
215 {-0.5, 0.5, -0.5},
216 {-0.5, 0.5, 0.5},
217 { 0.5, 0.5, 0.5},
218 { 0.5, -0.5, 0.5},
219 {-0.5, -0.5, 0.5}};
220 SDL_Event event;
221 int renderstyle;
222 int dump;
223 enum {
224 RENDER_LATIN1,
225 RENDER_UTF8,
226 RENDER_UNICODE
227 } rendertype;
228 char *message;
229
230 /* Look for special execution mode */
231 dump = 0;
232 /* Look for special rendering types */
233 renderstyle = TTF_STYLE_NORMAL;
234 rendertype = RENDER_LATIN1;
235 /* Default is black and white */
236 forecol = &black;
237 backcol = &white;
238 for ( i=1; argv[i] && argv[i][0] == '-'; ++i ) {
239 if ( strcmp(argv[i], "-utf8") == 0 ) {
240 rendertype = RENDER_UTF8;
241 } else
242 if ( strcmp(argv[i], "-unicode") == 0 ) {
243 rendertype = RENDER_UNICODE;
244 } else
245 if ( strcmp(argv[i], "-b") == 0 ) {
246 renderstyle |= TTF_STYLE_BOLD;
247 } else
248 if ( strcmp(argv[i], "-i") == 0 ) {
249 renderstyle |= TTF_STYLE_ITALIC;
250 } else
251 if ( strcmp(argv[i], "-u") == 0 ) {
252 renderstyle |= TTF_STYLE_UNDERLINE;
253 } else
254 if ( strcmp(argv[i], "-dump") == 0 ) {
255 dump = 1;
256 } else
257 if ( strcmp(argv[i], "-fgcol") == 0 ) {
258 int r, g, b;
259 if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) {
260 fprintf(stderr, Usage, argv0);
261 return(1);
262 }
263 forecol->r = (Uint8)r;
264 forecol->g = (Uint8)g;
265 forecol->b = (Uint8)b;
266 } else
267 if ( strcmp(argv[i], "-bgcol") == 0 ) {
268 int r, g, b;
269 if ( sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3 ) {
270 fprintf(stderr, Usage, argv0);
271 return(1);
272 }
273 backcol->r = (Uint8)r;
274 backcol->g = (Uint8)g;
275 backcol->b = (Uint8)b;
276 } else {
277 fprintf(stderr, Usage, argv0);
278 return(1);
279 }
280 }
281 argv += i;
282 argc -= i;
283
284 /* Check usage */
285 if ( ! argv[0] ) {
286 fprintf(stderr, Usage, argv0);
287 return(1);
288 }
289
290 /* Initialize SDL */
291 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
292 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
293 return(2);
294 }
295
296 /* Initialize the TTF library */
297 if ( TTF_Init() < 0 ) {
298 fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError());
299 SDL_Quit();
300 return(2);
301 }
302
303 /* Open the font file with the requested point size */
304 ptsize = 0;
305 if ( argc > 1 ) {
306 ptsize = atoi(argv[1]);
307 }
308 if ( ptsize == 0 ) {
309 i = 2;
310 ptsize = DEFAULT_PTSIZE;
311 } else {
312 i = 3;
313 }
314 font = TTF_OpenFont(argv[0], ptsize);
315 if ( font == NULL ) {
316 fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",
317 ptsize, argv[0], SDL_GetError());
318 cleanup(2);
319 }
320 TTF_SetFontStyle(font, renderstyle);
321
322 if( dump ) {
323 for( i = 48; i < 123; i++ ) {
324 SDL_Surface* glyph = NULL;
325
326 glyph = TTF_RenderGlyph_Shaded( font, i, *forecol, *backcol );
327
328 if( glyph ) {
329 char outname[64];
330 sprintf( outname, "glyph-%d.bmp", i );
331 SDL_SaveBMP( glyph, outname );
332 }
333
334 }
335 cleanup(0);
336 }
337
338 /* Set a 640x480 video mode */
339 screen = SDL_SetVideoMode(640, 480, 0, SDL_OPENGL);
340 if ( screen == NULL ) {
341 fprintf(stderr, "Couldn't set 640x480 OpenGL mode: %s\n",
342 SDL_GetError());
343 cleanup(2);
344 }
345
346 /* Render and center the message */
347 if ( argc > 2 ) {
348 message = argv[2];
349 } else {
350 message = DEFAULT_TEXT;
351 }
352 switch (rendertype) {
353 case RENDER_LATIN1:
354 text = TTF_RenderText_Blended(font, message, *forecol);
355 break;
356
357 case RENDER_UTF8:
358 text = TTF_RenderUTF8_Blended(font, message, *forecol);
359 break;
360
361 case RENDER_UNICODE:
362 {
363 /* This doesn't actually work because you can't pass
364 UNICODE text in via command line, AFAIK, but...
365 */
366 Uint16 unicode_text[BUFSIZ];
367 int index;
368 for ( index = 0; (message[0] || message[1]); ++index ) {
369 unicode_text[index] = ((Uint8 *)message)[0];
370 unicode_text[index] <<= 8;
371 unicode_text[index] |= ((Uint8 *)message)[1];
372 message += 2;
373 }
374 text = TTF_RenderUNICODE_Blended(font,
375 unicode_text, *forecol);
376 }
377 break;
378 default:
379 text = NULL; /* This shouldn't happen */
380 break;
381 }
382 if ( text == NULL ) {
383 fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError());
384 TTF_CloseFont(font);
385 cleanup(2);
386 }
387 x = (screen->w - text->w)/2;
388 y = (screen->h - text->h)/2;
389 w = text->w;
390 h = text->h;
391 printf("Font is generally %d big, and string is %hd big\n",
392 TTF_FontHeight(font), text->h);
393
394 /* Convert the text into an OpenGL texture */
395 glGetError();
396 texture = SDL_GL_LoadTexture(text, texcoord);
397 if ( (gl_error = glGetError()) != GL_NO_ERROR ) {
398 /* If this failed, the text may exceed texture size limits */
399 printf("Warning: Couldn't create texture: 0x%x\n", gl_error);
400 }
401
402 /* Make texture coordinates easy to understand */
403 texMinX = texcoord[0];
404 texMinY = texcoord[1];
405 texMaxX = texcoord[2];
406 texMaxY = texcoord[3];
407
408 /* We don't need the original text surface anymore */
409 SDL_FreeSurface(text);
410
411 /* Initialize the GL state */
412 glViewport( 0, 0, screen->w, screen->h );
413 glMatrixMode( GL_PROJECTION );
414 glLoadIdentity( );
415
416 glOrtho( -2.0, 2.0, -2.0, 2.0, -20.0, 20.0 );
417
418 glMatrixMode( GL_MODELVIEW );
419 glLoadIdentity( );
420
421 glEnable(GL_DEPTH_TEST);
422
423 glDepthFunc(GL_LESS);
424
425 glShadeModel(GL_SMOOTH);
426
427 /* Wait for a keystroke, and blit text on mouse press */
428 done = 0;
429 while ( ! done ) {
430 while ( SDL_PollEvent(&event) ) {
431 switch (event.type) {
432 case SDL_MOUSEMOTION:
433 x = event.motion.x - w/2;
434 y = event.motion.y - h/2;
435 break;
436
437 case SDL_KEYDOWN:
438 case SDL_QUIT:
439 done = 1;
440 break;
441 default:
442 break;
443 }
444 }
445
446 /* Clear the screen */
447 glClearColor(1.0, 1.0, 1.0, 1.0);
448 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
449
450 /* Draw the spinning cube */
451 glBegin( GL_QUADS );
452
453 glColor3fv(color[0]);
454 glVertex3fv(cube[0]);
455 glColor3fv(color[1]);
456 glVertex3fv(cube[1]);
457 glColor3fv(color[2]);
458 glVertex3fv(cube[2]);
459 glColor3fv(color[3]);
460 glVertex3fv(cube[3]);
461
462 glColor3fv(color[3]);
463 glVertex3fv(cube[3]);
464 glColor3fv(color[4]);
465 glVertex3fv(cube[4]);
466 glColor3fv(color[7]);
467 glVertex3fv(cube[7]);
468 glColor3fv(color[2]);
469 glVertex3fv(cube[2]);
470
471 glColor3fv(color[0]);
472 glVertex3fv(cube[0]);
473 glColor3fv(color[5]);
474 glVertex3fv(cube[5]);
475 glColor3fv(color[6]);
476 glVertex3fv(cube[6]);
477 glColor3fv(color[1]);
478 glVertex3fv(cube[1]);
479
480 glColor3fv(color[5]);
481 glVertex3fv(cube[5]);
482 glColor3fv(color[4]);
483 glVertex3fv(cube[4]);
484 glColor3fv(color[7]);
485 glVertex3fv(cube[7]);
486 glColor3fv(color[6]);
487 glVertex3fv(cube[6]);
488
489 glColor3fv(color[5]);
490 glVertex3fv(cube[5]);
491 glColor3fv(color[0]);
492 glVertex3fv(cube[0]);
493 glColor3fv(color[3]);
494 glVertex3fv(cube[3]);
495 glColor3fv(color[4]);
496 glVertex3fv(cube[4]);
497
498 glColor3fv(color[6]);
499 glVertex3fv(cube[6]);
500 glColor3fv(color[1]);
501 glVertex3fv(cube[1]);
502 glColor3fv(color[2]);
503 glVertex3fv(cube[2]);
504 glColor3fv(color[7]);
505 glVertex3fv(cube[7]);
506 glEnd( );
507
508 /* Rotate the cube */
509 glMatrixMode(GL_MODELVIEW);
510 glRotatef(5.0, 1.0, 1.0, 1.0);
511
512 /* Show the text on the screen */
513 SDL_GL_Enter2DMode();
514 glBindTexture(GL_TEXTURE_2D, texture);
515 glBegin(GL_TRIANGLE_STRIP);
516 glTexCoord2f(texMinX, texMinY); glVertex2i(x, y );
517 glTexCoord2f(texMaxX, texMinY); glVertex2i(x+w, y );
518 glTexCoord2f(texMinX, texMaxY); glVertex2i(x, y+h);
519 glTexCoord2f(texMaxX, texMaxY); glVertex2i(x+w, y+h);
520 glEnd();
521 SDL_GL_Leave2DMode();
522
523 /* Swap the buffers so everything is visible */
524 SDL_GL_SwapBuffers( );
525 }
526 TTF_CloseFont(font);
527 cleanup(0);
528
529 /* Not reached, but fixes compiler warnings */
530 return 0;
531 }
532
533 #else /* HAVE_OPENGL */
534
main(int argc,char * argv[])535 int main(int argc, char *argv[])
536 {
537 printf("No OpenGL support on this system\n");
538 return 1;
539 }
540
541 #endif /* HAVE_OPENGL */
542