1 /*
2 glfont: An example of using the SDL_ttf library with OpenGL.
3 Copyright (C) 2001-2019 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 #define TTF_GLFONT_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 static 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 static 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 static 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 = NULL;
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, TTF_GLFONT_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, TTF_GLFONT_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, TTF_GLFONT_USAGE, argv0);
270 return(1);
271 }
272 }
273 argv += i;
274 argc -= i;
275
276 /* Check usage */
277 if (!argv[0]) {
278 fprintf(stderr, TTF_GLFONT_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 }
373 if (text == NULL) {
374 fprintf(stderr, "Couldn't render text: %s\n", SDL_GetError());
375 TTF_CloseFont(font);
376 cleanup(2);
377 }
378 x = (WIDTH - text->w)/2;
379 y = (HEIGHT - text->h)/2;
380 w = text->w;
381 h = text->h;
382 printf("Font is generally %d big, and string is %d big\n",
383 TTF_FontHeight(font), text->h);
384
385 /* Convert the text into an OpenGL texture */
386 glGetError();
387 texture = SDL_GL_LoadTexture(text, texcoord);
388 if ((gl_error = glGetError()) != GL_NO_ERROR) {
389 /* If this failed, the text may exceed texture size limits */
390 printf("Warning: Couldn't create texture: 0x%x\n", gl_error);
391 }
392
393 /* Make texture coordinates easy to understand */
394 texMinX = texcoord[0];
395 texMinY = texcoord[1];
396 texMaxX = texcoord[2];
397 texMaxY = texcoord[3];
398
399 /* We don't need the original text surface anymore */
400 SDL_FreeSurface(text);
401
402 /* Initialize the GL state */
403 glViewport(0, 0, WIDTH, HEIGHT);
404 glMatrixMode(GL_PROJECTION);
405 glLoadIdentity();
406
407 glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);
408
409 glMatrixMode(GL_MODELVIEW);
410 glLoadIdentity();
411
412 glEnable(GL_DEPTH_TEST);
413
414 glDepthFunc(GL_LESS);
415
416 glShadeModel(GL_SMOOTH);
417
418 /* Wait for a keystroke, and blit text on mouse press */
419 done = 0;
420 while (!done) {
421 while (SDL_PollEvent(&event)) {
422 switch (event.type) {
423 case SDL_MOUSEMOTION:
424 x = event.motion.x - w/2;
425 y = event.motion.y - h/2;
426 break;
427
428 case SDL_KEYDOWN:
429 case SDL_QUIT:
430 done = 1;
431 break;
432 default:
433 break;
434 }
435 }
436
437 /* Clear the screen */
438 glClearColor(1.0, 1.0, 1.0, 1.0);
439 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
440
441 /* Draw the spinning cube */
442 glBegin(GL_QUADS);
443
444 glColor3fv(color[0]);
445 glVertex3fv(cube[0]);
446 glColor3fv(color[1]);
447 glVertex3fv(cube[1]);
448 glColor3fv(color[2]);
449 glVertex3fv(cube[2]);
450 glColor3fv(color[3]);
451 glVertex3fv(cube[3]);
452
453 glColor3fv(color[3]);
454 glVertex3fv(cube[3]);
455 glColor3fv(color[4]);
456 glVertex3fv(cube[4]);
457 glColor3fv(color[7]);
458 glVertex3fv(cube[7]);
459 glColor3fv(color[2]);
460 glVertex3fv(cube[2]);
461
462 glColor3fv(color[0]);
463 glVertex3fv(cube[0]);
464 glColor3fv(color[5]);
465 glVertex3fv(cube[5]);
466 glColor3fv(color[6]);
467 glVertex3fv(cube[6]);
468 glColor3fv(color[1]);
469 glVertex3fv(cube[1]);
470
471 glColor3fv(color[5]);
472 glVertex3fv(cube[5]);
473 glColor3fv(color[4]);
474 glVertex3fv(cube[4]);
475 glColor3fv(color[7]);
476 glVertex3fv(cube[7]);
477 glColor3fv(color[6]);
478 glVertex3fv(cube[6]);
479
480 glColor3fv(color[5]);
481 glVertex3fv(cube[5]);
482 glColor3fv(color[0]);
483 glVertex3fv(cube[0]);
484 glColor3fv(color[3]);
485 glVertex3fv(cube[3]);
486 glColor3fv(color[4]);
487 glVertex3fv(cube[4]);
488
489 glColor3fv(color[6]);
490 glVertex3fv(cube[6]);
491 glColor3fv(color[1]);
492 glVertex3fv(cube[1]);
493 glColor3fv(color[2]);
494 glVertex3fv(cube[2]);
495 glColor3fv(color[7]);
496 glVertex3fv(cube[7]);
497
498 glEnd();
499
500 /* Rotate the cube */
501 glMatrixMode(GL_MODELVIEW);
502 glRotatef(5.0, 1.0, 1.0, 1.0);
503
504 /* Show the text on the screen */
505 SDL_GL_Enter2DMode(WIDTH, HEIGHT);
506 glBindTexture(GL_TEXTURE_2D, texture);
507 glBegin(GL_TRIANGLE_STRIP);
508 glTexCoord2f(texMinX, texMinY); glVertex2i(x, y);
509 glTexCoord2f(texMaxX, texMinY); glVertex2i(x+w, y);
510 glTexCoord2f(texMinX, texMaxY); glVertex2i(x, y+h);
511 glTexCoord2f(texMaxX, texMaxY); glVertex2i(x+w, y+h);
512 glEnd();
513 SDL_GL_Leave2DMode();
514
515 /* Swap the buffers so everything is visible */
516 SDL_GL_SwapWindow(window);
517 }
518 SDL_GL_DeleteContext(context);
519 TTF_CloseFont(font);
520 cleanup(0);
521
522 /* Not reached, but fixes compiler warnings */
523 return 0;
524 }
525
526 #else /* HAVE_OPENGL */
527
main(int argc,char * argv[])528 int main(int argc, char *argv[])
529 {
530 printf("No OpenGL support on this system\n");
531 return 1;
532 }
533
534 #endif /* HAVE_OPENGL */
535
536 /* vi: set ts=4 sw=4 expandtab: */
537