1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* text3d2 --- Shows moving 3D texts */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)text3d.2cc 5.12 2004/03/09 xlockmore";
6
7 #endif
8
9 /* Copyright (c) E. Lassauge, 2004. */
10
11 /*
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * This module is based on a demo of the FTGL graphics library
25 * Copyright Henry Maddocks <henryj AT paradise.net.nz>
26 * http://homepages.paradise.net.nz/henryj/
27 *
28 * My e-mail address is <lassauge AT users.sourceforge.net> (NOSPAM please)
29 * Web site at http://lassauge.free.fr/
30 *
31 * Eric Lassauge (March-09-2004)
32 *
33 * Revision History:
34 *
35 * Eric Lassauge (March-09-2004) Created based on xscreensaver's gltext and
36 * the FTGL library demo:
37 * it uses freetype2 which is more common now.
38 *
39 */
40
41 #define DEF_TEXT "(default)"
42 #define DEF_SPIN "XYZ"
43 #define DEF_WANDER "True"
44 #define DEF_NOSPLIT "False"
45
46 #ifdef STANDALONE
47 #define MODE_text3d2
48 #define DEFAULTS "*delay: 10000 \n" \
49 "*showFPS: False \n" \
50 "*wireframe: False \n" \
51 "*nosplit: " DEF_NOSPLIT "\n" \
52 "*message: " DEF_TEXT "\n"
53
54 #define free_text3d2 0
55 #define text3d2_handle_event 0
56 extern "C"
57 {
58 #include "xlockmore.h" /* from the xscreensaver distribution */
59 /*#include "iostuff.h"*/
60 }
61 #else /* !STANDALONE */
62 #include "xlock.h" /* from the xlockmore distribution */
63 #include "visgl.h"
64 #ifdef HAS_MMOV
65 #undef error
66 #endif
67 #include "iostuff.h"
68 #endif /* !STANDALONE */
69
70 #ifdef MODE_text3d2
71
72 #ifdef FTGL213
73 #include "FTGL/ftgl.h"
74 #else
75 #ifdef __CYGWIN__
76 #include "FTGL/FTGLExtrdFont.h"
77 #include "FTGL/FTGLOutlineFont.h"
78 #else
79 #include "FTGLExtrdFont.h"
80 #include "FTGLOutlineFont.h"
81 #endif
82 #endif
83
84 extern "C"
85 {
86 #include "rotator.h"
87 }
88 #include "text3d2.h"
89 #include <GL/glu.h>
90
91 #include <X11/Xcms.h>
92
93 /* Yes, it's an ugly mix of 'C' and 'C++' functions */
94 #ifndef STANDALONE
95 extern "C" { void init_text3d2(ModeInfo * mi); }
96 extern "C" { void draw_text3d2(ModeInfo * mi); }
97 extern "C" { void change_text3d2(ModeInfo * mi); }
98 extern "C" { void release_text3d2(ModeInfo * mi); }
99 extern "C" { void refresh_text3d2(ModeInfo * mi); }
100 #endif
101
102 /* arial.ttf is not supplied for legal reasons. */
103 /* NT and Windows 3.1 in C:\WINDOWS\SYSTEM\ARIAL.TTF */
104 /* Windows95 in C:\Windows\Fonts\arial.ttf */
105 #ifndef DEF_TTFONT
106 /* Directory of only *.ttf */
107 /* symbol.ttf and wingding.ttf should be excluded or it may core dump */
108 /* can be excluded if gltt is modified see README */
109 #ifdef __CYGWIN__
110 #define DEF_TTFONT "C:\\Windows\\Fonts\\"
111 #else
112 #define DEF_TTFONT "/usr/lib/X11/xlock/fonts/"
113 #endif
114 #endif
115
116 static char *mode_font;
117 static int nosplit;
118 static char *do_spin;
119 static Bool do_wander;
120 static char *fontfile = (char *) NULL;
121
122 /* Manage Option vars */
123
124 static XrmOptionDescRec opts[] =
125 {
126 {(char *) "-ttfont", (char *) ".text3d2.ttfont", XrmoptionSepArg, (caddr_t) NULL},
127 {(char *) "-no_split", (char *) ".text3d2.no_split", XrmoptionNoArg, (caddr_t) "on"},
128 {(char *) "+no_split", (char *) ".text3d2.no_split", XrmoptionNoArg, (caddr_t) "off"},
129 {(char *) "-wander", (char *) ".text3d2.wander", XrmoptionNoArg, (caddr_t) "on"},
130 {(char *) "+wander", (char *) ".text3d2.wander", XrmoptionNoArg, (caddr_t) "off"},
131 {(char *) "-spin", (char *) ".text3d2.spin", XrmoptionSepArg, (caddr_t) NULL},
132 {(char *) "+spin", (char *) ".text3d2.spin", XrmoptionNoArg, (caddr_t) ""},
133 };
134
135 static argtype vars[] =
136 {
137 {(void *) & mode_font, (char *) "ttfont", (char *) "TTFont", (char *) DEF_TTFONT, t_String},
138 {(void *) & nosplit, (char *) "no_split", (char *) "NoSplit", (char *) DEF_NOSPLIT, t_Bool},
139 {(void *) & do_wander, (char *) "wander", (char *) "Wander", (char *) DEF_WANDER, t_Bool},
140 {(void *) & do_spin, (char *) "spin", (char *) "Spin", (char *) DEF_SPIN, t_String},
141 };
142
143 static OptionStruct desc[] =
144 {
145 {(char *) "-ttfont filename", (char *) "Text3d2 TrueType font file name"},
146 {(char *) "-/+no_split", (char *) "Text3d2 words splitting off/on"},
147 {(char *) "-/+wander", (char *) "Text3d2 wander off/on"},
148 {(char *) "-spin name/+spin", (char *) "Text3d2 spin mode"},
149 };
150
151 ENTRYPOINT ModeSpecOpt text3d2_opts =
152 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
153
154 #ifdef USE_MODULES
155 ModStruct text3d2_description =
156 {"text3d2", "init_text3d2", "draw_text3d2", "release_text3d2",
157 "refresh_text3d2", "change_text3d2", (char *) NULL, &text3d2_opts,
158 100000, 1, 10, 1, 64, 1.0, "",
159 "Shows 3D text", 0, NULL};
160 #endif
161
162 static text3d2struct *text3d2 = (text3d2struct *) NULL;
163
164 static GLfloat color[4] = {0.0, 0.0, 0.0, 1.0};
165 static GLfloat light1_ambient[4] = { 1.0, 1.0, 1.0, 1.0 };
166 static GLfloat light2_ambient[4] = { 0.2, 0.2, 0.2, 1.0 };
167
168 /*
169 *-----------------------------------------------------------------------------
170 * Utils.
171 *-----------------------------------------------------------------------------
172 */
173
174 static void
setup_lighting()175 setup_lighting()
176 {
177 // Set up lighting.
178 float light1_diffuse[4] = { 1.0, 0.9, 0.9, 1.0 };
179 float light1_specular[4] = { 1.0, 0.7, 0.7, 1.0 };
180 float light1_position[4] = { -1.0, 1.0, 1.0, 0.0 };
181 glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
182 glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
183 glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
184 glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
185 glEnable(GL_LIGHT1);
186
187 float light2_diffuse[4] = { 0.9, 0.9, 0.9, 1.0 };
188 float light2_specular[4] = { 0.7, 0.7, 0.7, 1.0 };
189 float light2_position[4] = { 1.0, -1.0, -1.0, 0.0 };
190 glLightfv(GL_LIGHT2, GL_AMBIENT, light2_ambient);
191 glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse);
192 glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular);
193 glLightfv(GL_LIGHT2, GL_POSITION, light2_position);
194 glEnable(GL_LIGHT2);
195
196 float front_emission[4] = { 0.3, 0.2, 0.1, 0.0 };
197 float front_ambient[4] = { 0.2, 0.2, 0.2, 0.0 };
198 float front_diffuse[4] = { 0.95, 0.95, 0.8, 0.0 };
199 float front_specular[4] = { 0.6, 0.6, 0.6, 0.0 };
200 glMaterialfv(GL_FRONT, GL_EMISSION, front_emission);
201 glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient);
202 glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse);
203 glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular);
204 glMaterialf(GL_FRONT, GL_SHININESS, 16.0);
205 glColor4fv(front_diffuse);
206
207 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
208 glEnable(GL_CULL_FACE);
209 glColorMaterial(GL_FRONT, GL_DIFFUSE);
210 glEnable(GL_COLOR_MATERIAL);
211
212 glEnable(GL_LIGHTING);
213 glShadeModel(GL_SMOOTH);
214 }
215
216 static int
setup_font(text3d2struct * tp,const char * fontfile)217 setup_font( text3d2struct * tp,
218 const char* fontfile)
219 {
220 if (!tp->wire)
221 tp->font = new FTGLExtrdFont(fontfile);
222 else
223 tp->font = new FTGLOutlineFont(fontfile);
224
225 if( tp->font->Error())
226 {
227 fprintf( stderr, "Failed to open font %s", fontfile);
228 return 0;
229 }
230
231 if( !tp->font->FaceSize( 192))
232 {
233 fprintf( stderr, "Failed to set size");
234 return(0);
235 }
236
237 tp->font->Depth(24);
238
239 tp->font->CharMap(ft_encoding_none);
240
241 return 1;
242 }
243
244 /*
245 *-----------------------------------------------------------------------------
246 *-----------------------------------------------------------------------------
247 * Mode funcs.
248 *-----------------------------------------------------------------------------
249 *-----------------------------------------------------------------------------
250 */
251
252 void
reshape_text3d2(ModeInfo * mi,int width,int height)253 reshape_text3d2(ModeInfo * mi, int width, int height)
254 {
255 text3d2struct *tp = &text3d2[MI_SCREEN(mi)];
256 GLfloat h = (GLfloat) height / (GLfloat) width;
257
258 glViewport(0, 0, tp->WinW = (GLint) width, tp->WinH = (GLint) height);
259
260 glMatrixMode(GL_PROJECTION);
261 glLoadIdentity();
262 gluPerspective (30.0, 1/h, 1.0, 100.0);
263
264 glMatrixMode(GL_MODELVIEW);
265 glMatrixMode(GL_MODELVIEW);
266 glLoadIdentity();
267 gluLookAt( 0.0, 0.0, 30.0,
268 0.0, 0.0, 0.0,
269 0.0, 1.0, 0.0);
270 glClear(GL_COLOR_BUFFER_BIT);
271 }
272
273 /*-------------------------------------------------------------*/
274 static void
gl_init(text3d2struct * tp)275 gl_init (text3d2struct * tp)
276 {
277 glEnable( GL_CULL_FACE);
278 glFrontFace( GL_CCW);
279 glEnable( GL_DEPTH_TEST);
280
281 // Color is used for wire mode only
282 color[0] = ((float) (NRAND(70)) / 100.0) + 0.30;
283 color[1] = ((float) (NRAND(30)) / 100.0) + 0.70;
284 color[2] = color[1] * 0.56;
285
286 }
287
288 /*-------------------------------------------------------------*/
289 static void
draw_text(text3d2struct * tp,Display * display,Window window)290 draw_text(text3d2struct * tp,
291 Display * display,
292 Window window)
293 {
294 int text_length;
295 char *c_text;
296
297 #ifndef STANDALONE
298 if (!nosplit)
299 {
300 text_length = index_dir(tp->words, (char *) " ");
301 if (text_length == 0)
302 text_length = strlen(tp->words);
303 if ((c_text = (char *) malloc(text_length+2)) != NULL)
304 strncpy(c_text, tp->words, text_length);
305 // +2 is because of a bug in FTGL !!
306 c_text[text_length] = 0;
307 c_text[text_length+1] = 0;
308 }
309 else
310 #endif
311 {
312 text_length = strlen(tp->words_start);
313 if ((c_text = (char *) malloc(text_length+2)) != NULL)
314 strncpy(c_text, tp->words_start, text_length);
315 c_text[text_length] = 0;
316 c_text[text_length+1] = 0;
317 }
318
319 // Render text
320 tp->font->Render(c_text);
321
322 //if (!nosplit)
323 free(c_text);
324 }
325
326 /*
327 *-----------------------------------------------------------------------------
328 *-----------------------------------------------------------------------------
329 * Xlock hooks.
330 *-----------------------------------------------------------------------------
331 *-----------------------------------------------------------------------------
332 */
333
334 /*
335 *-----------------------------------------------------------------------------
336 * The display is being taken away from us. Free up malloc'ed
337 * memory and X resources that we've alloc'ed. Only called
338 * once, we must zap everything for every screen.
339 *-----------------------------------------------------------------------------
340 */
341
342 ENTRYPOINT void
release_text3d2(ModeInfo * mi)343 release_text3d2(ModeInfo * mi)
344 {
345 if (text3d2 != NULL)
346 {
347 for (int screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
348 {
349 text3d2struct *tp = &text3d2[screen];
350
351 if (tp->font)
352 delete tp->font;
353 if (tp->rot)
354 free_rotator(tp->rot);
355 }
356 free(text3d2);
357 text3d2 = (text3d2struct *) NULL;
358 }
359 FreeAllGL(mi);
360 }
361
362 /*
363 *-----------------------------------------------------------------------------
364 * Initialize text3d2. Called each time the window changes.
365 *-----------------------------------------------------------------------------
366 */
367
368 ENTRYPOINT void
init_text3d2(ModeInfo * mi)369 init_text3d2(ModeInfo * mi)
370 {
371 text3d2struct *tp;
372
373 if (text3d2 == NULL)
374 {
375 /*MI_INIT(mi, text3d2);*/
376 if ((text3d2 = (text3d2struct *) calloc(MI_NUM_SCREENS(mi),
377 sizeof(text3d2struct))) == NULL)
378 return;
379 }
380 tp = &text3d2[MI_SCREEN(mi)];
381 tp->wire = MI_IS_WIREFRAME(mi);
382 tp->counter = 0;
383
384 #ifdef STANDALONE
385 if ((fontfile = (char *) malloc(strlen(mode_font) + 10)) != NULL)
386 sprintf(fontfile, "%s%s", mode_font, "arial.ttf");
387 #else
388 fontfile = getModeFont(mode_font);
389 #endif
390 if (!fontfile) {
391 MI_CLEARWINDOW(mi);
392 release_text3d2(mi);
393 return;
394 }
395 if (!setup_font(tp,fontfile)) {
396 (void) fprintf(stderr, "%s: unable to open True Type font %s!\n", MI_NAME(mi), fontfile);
397 MI_CLEARWINDOW(mi);
398 release_text3d2(mi);
399 return;
400 }
401 if (MI_IS_DEBUG(mi)) {
402 (void) fprintf(stderr,
403 "%s:\n\tfontfile=%s .\n", MI_NAME(mi), fontfile);
404 }
405
406 /* Do not free fontfile getModeFont handles potential leak */
407 if ((tp->glx_context = init_GL(mi)) != NULL)
408 {
409 if (MI_IS_USE3D(mi)) {
410 // Find out the RGB values out of the left/right colors !
411 XcmsColor search;
412 search.pixel = MI_RIGHT_COLOR(mi);
413 XcmsQueryColor(MI_DISPLAY(mi), MI_COLORMAP(mi), &search, XcmsRGBiFormat);
414 light1_ambient[0] = search.spec.RGBi.red;
415 light1_ambient[1] = search.spec.RGBi.green;
416 light1_ambient[2] = search.spec.RGBi.blue;
417 search.pixel = MI_LEFT_COLOR(mi);
418 XcmsQueryColor(MI_DISPLAY(mi), MI_COLORMAP(mi), &search, XcmsRGBiFormat);
419 light2_ambient[0] = search.spec.RGBi.red;
420 light2_ambient[1] = search.spec.RGBi.green;
421 light2_ambient[2] = search.spec.RGBi.blue;
422 }
423 gl_init(tp);
424 reshape_text3d2(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
425 }
426 else
427 {
428 MI_CLEARWINDOW(mi);
429 }
430
431 { // Manage spin
432 Bool spinx=False, spiny=False, spinz=False;
433 double spin_speed = 1.0;
434 double wander_speed = 0.05;
435 double spin_accel = 1.0;
436
437 char *s = do_spin;
438 while (*s)
439 {
440 if (*s == 'x' || *s == 'X') spinx = True;
441 else if (*s == 'y' || *s == 'Y') spiny = True;
442 else if (*s == 'z' || *s == 'Z') spinz = True;
443 else
444 {
445 (void)fprintf (stderr,
446 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
447 MI_NAME(mi), do_spin);
448 MI_CLEARWINDOW(mi);
449 release_text3d2(mi);
450 return;
451 }
452 s++;
453 }
454
455 tp->rot = make_rotator (spinx ? spin_speed : 0,
456 spiny ? spin_speed : 0,
457 spinz ? spin_speed : 0,
458 spin_accel,
459 do_wander ? wander_speed : 0,
460 False);
461 }
462
463 /* Initialize displayed string */
464 tp->words_start = tp->words = getWords(MI_SCREEN(mi), MI_NUM_SCREENS(mi));
465 if (MI_IS_DEBUG(mi))
466 {
467 (void) fprintf(stderr,
468 "%s words:\n%s\n",
469 MI_NAME(mi), tp->words);
470 }
471 }
472
473 /*
474 *-----------------------------------------------------------------------------
475 * Called by the mainline code periodically to update the display.
476 *-----------------------------------------------------------------------------
477 */
478 ENTRYPOINT void
draw_text3d2(ModeInfo * mi)479 draw_text3d2(ModeInfo * mi)
480 {
481 Display *display = MI_DISPLAY(mi);
482 Window window = MI_WINDOW(mi);
483 text3d2struct *tp;
484
485
486 if (text3d2 == NULL) {
487 return;
488 }
489 tp = &text3d2[MI_SCREEN(mi)];
490
491 if (!tp->glx_context)
492 return;
493
494 MI_IS_DRAWN(mi) = True;
495 tp->counter = tp->counter + 1;
496
497 #ifndef STANDALONE
498 if (tp->counter > (MI_CYCLES(mi) & !nosplit))
499 {
500 int text_length = index_dir(tp->words, (char *) " ");
501
502 /* Every now and then, get a new word */
503 if (text_length == 0)
504 text_length = strlen(tp->words);
505 tp->counter = 0;
506 tp->words += text_length;
507 text_length = strlen(tp->words);
508 if (text_length == 0)
509 {
510 tp->words_start = tp->words =
511 getWords(MI_SCREEN(mi), MI_NUM_SCREENS(mi));
512 }
513 }
514 #endif
515 glShadeModel(GL_SMOOTH);
516
517 glEnable(GL_DEPTH_TEST);
518 glEnable(GL_NORMALIZE);
519 glEnable(GL_CULL_FACE);
520
521 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
522
523 glPushMatrix ();
524
525 glScalef(1.1, 1.1, 1.1);
526
527 {
528 double x, y, z;
529 get_position (tp->rot, &x, &y, &z, 1);
530 glTranslatef((x - 1.0) * 8,
531 (y - 0.5) * 8,
532 (z - 0.5) * 8);
533
534 get_rotation (tp->rot, &x, &y, &z, 1);
535 glRotatef (x * 360, 1.0, 0.0, 0.0);
536 glRotatef (y * 360, 0.0, 1.0, 0.0);
537 glRotatef (z * 360, 0.0, 0.0, 1.0);
538 }
539
540
541 glScalef(0.01, 0.01, 0.01);
542
543 if (!tp->wire)
544 {
545 glDisable( GL_BLEND);
546 setup_lighting();
547 }
548 else
549 glColor4fv (color);
550
551 draw_text(tp, display, window);
552 glPopMatrix ();
553
554 if (MI_IS_FPS(mi)) do_fps (mi);
555
556 glXSwapBuffers(display, window);
557
558 }
559
560 #ifndef STANDALONE
561 ENTRYPOINT void
refresh_text3d2(ModeInfo * mi)562 refresh_text3d2(ModeInfo * mi)
563 {
564 /* Do nothing, it will refresh by itself :) */
565 }
566
567 ENTRYPOINT void
change_text3d2(ModeInfo * mi)568 change_text3d2(ModeInfo * mi)
569 {
570 text3d2struct *tp;
571
572 if (text3d2 == NULL) {
573 return;
574 }
575 tp = &text3d2[MI_SCREEN(mi)];
576
577 if (!tp->glx_context)
578 return;
579 glDrawBuffer(GL_BACK);
580 #ifdef WIN32
581 wglMakeCurrent(hdc, tp->glx_context);
582 #else
583 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tp->glx_context));
584 #endif
585 }
586 #endif
587
588 XSCREENSAVER_MODULE ("Text3d2", text3d2)
589
590 #endif /* MODE_text3d2 */
591