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