http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.29.tar.gz
[xscreensaver] / hacks / glx / gltext.c
1 /* gltext, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include <X11/Intrinsic.h>
13
14 extern XtAppContext app;
15
16 #define PROGCLASS       "GLText"
17 #define HACK_INIT       init_text
18 #define HACK_DRAW       draw_text
19 #define HACK_RESHAPE    reshape_text
20 #define sws_opts        xlockmore_opts
21
22 #define DEF_TEXT        "(default)"
23
24 #define DEFAULTS        "*delay:        10000     \n" \
25                         "*showFPS:      False     \n" \
26                         "*wireframe:    False     \n" \
27                         "*text:       " DEF_TEXT "\n"
28
29 #undef countof
30 #define countof(x) (sizeof((x))/sizeof((*x)))
31
32 #include "xlockmore.h"
33 #include "colors.h"
34
35 #ifdef USE_GL /* whole file */
36
37 #ifdef HAVE_UNAME
38 # include <sys/utsname.h>
39 #endif /* HAVE_UNAME */
40
41
42 #include <GL/glu.h>
43 #include "glutstroke.h"
44 #include "glut_roman.h"
45 #define GLUT_FONT (&glutStrokeRoman)
46
47
48 typedef struct {
49   GLXContext *glx_context;
50
51   GLfloat rotx, roty, rotz;        /* current object rotation */
52   GLfloat dx, dy, dz;              /* current rotational velocity */
53   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
54   GLfloat d_max;                   /* max velocity */
55
56   GLuint text_list;
57
58   int ncolors;
59   XColor *colors;
60   int ccolor;
61
62 } text_configuration;
63
64 static text_configuration *tps = NULL;
65
66 static char *text;
67
68 static XrmOptionDescRec opts[] = {
69   { "-text",   ".text",   XrmoptionSepArg, 0 }
70 };
71
72 static argtype vars[] = {
73   {(caddr_t *) &text, "text", "Text", DEF_TEXT, t_String},
74 };
75
76 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
77
78
79 /* Window management, etc
80  */
81 void
82 reshape_text (ModeInfo *mi, int width, int height)
83 {
84   GLfloat h = (GLfloat) height / (GLfloat) width;
85
86   glViewport (0, 0, (GLint) width, (GLint) height);
87
88   glMatrixMode(GL_PROJECTION);
89   glLoadIdentity();
90
91   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
92   gluLookAt( 0.0, 0.0, 15.0,
93              0.0, 0.0, 0.0,
94              0.0, 1.0, 0.0);
95   glMatrixMode(GL_MODELVIEW);
96   glLoadIdentity();
97   glTranslatef(0.0, 0.0, -15.0);
98
99   glClear(GL_COLOR_BUFFER_BIT);
100 }
101
102
103 static void
104 gl_init (ModeInfo *mi)
105 {
106   text_configuration *tp = &tps[MI_SCREEN(mi)];
107   int wire = MI_IS_WIREFRAME(mi);
108
109   static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
110
111   if (!wire)
112     {
113       glLightfv(GL_LIGHT0, GL_POSITION, pos);
114       glEnable(GL_CULL_FACE);
115       glEnable(GL_LIGHTING);
116       glEnable(GL_LIGHT0);
117       glEnable(GL_DEPTH_TEST);
118     }
119
120   tp->text_list = glGenLists (1);
121   glNewList (tp->text_list, GL_COMPILE);
122   glEndList ();
123 }
124
125
126 /* lifted from lament.c */
127 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
128 #define RANDSIGN() ((random() & 1) ? 1 : -1)
129
130 static void
131 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
132 {
133   double ppos = *pos;
134
135   /* tick position */
136   if (ppos < 0)
137     ppos = -(ppos + *v);
138   else
139     ppos += *v;
140
141   if (ppos > 1.0)
142     ppos -= 1.0;
143   else if (ppos < 0)
144     ppos += 1.0;
145
146   if (ppos < 0) abort();
147   if (ppos > 1.0) abort();
148   *pos = (*pos > 0 ? ppos : -ppos);
149
150   /* accelerate */
151   *v += *dv;
152
153   /* clamp velocity */
154   if (*v > max_v || *v < -max_v)
155     {
156       *dv = -*dv;
157     }
158   /* If it stops, start it going in the other direction. */
159   else if (*v < 0)
160     {
161       if (random() % 4)
162         {
163           *v = 0;
164
165           /* keep going in the same direction */
166           if (random() % 2)
167             *dv = 0;
168           else if (*dv < 0)
169             *dv = -*dv;
170         }
171       else
172         {
173           /* reverse gears */
174           *v = -*v;
175           *dv = -*dv;
176           *pos = -*pos;
177         }
178     }
179
180   /* Alter direction of rotational acceleration randomly. */
181   if (! (random() % 120))
182     *dv = -*dv;
183
184   /* Change acceleration very occasionally. */
185   if (! (random() % 200))
186     {
187       if (*dv == 0)
188         *dv = 0.00001;
189       else if (random() & 1)
190         *dv *= 1.2;
191       else
192         *dv *= 0.8;
193     }
194 }
195
196
197 void 
198 init_text (ModeInfo *mi)
199 {
200   text_configuration *tp;
201
202   if (!tps) {
203     tps = (text_configuration *)
204       calloc (MI_NUM_SCREENS(mi), sizeof (text_configuration));
205     if (!tps) {
206       fprintf(stderr, "%s: out of memory\n", progname);
207       exit(1);
208     }
209
210     tp = &tps[MI_SCREEN(mi)];
211   }
212
213   tp = &tps[MI_SCREEN(mi)];
214
215   if ((tp->glx_context = init_GL(mi)) != NULL) {
216     gl_init(mi);
217     reshape_text (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
218   }
219
220   tp->rotx = frand(1.0) * RANDSIGN();
221   tp->roty = frand(1.0) * RANDSIGN();
222   tp->rotz = frand(1.0) * RANDSIGN();
223
224   /* bell curve from 0-6 degrees, avg 3 */
225   tp->dx = (frand(1) + frand(1) + frand(1)) / (360/2);
226   tp->dy = (frand(1) + frand(1) + frand(1)) / (360/2);
227   tp->dz = (frand(1) + frand(1) + frand(1)) / (360/2);
228
229   tp->d_max = tp->dx * 2;
230
231   tp->ddx = 0.00006 + frand(0.00003);
232   tp->ddy = 0.00006 + frand(0.00003);
233   tp->ddz = 0.00006 + frand(0.00003);
234
235   tp->ddx = 0.00001;
236   tp->ddy = 0.00001;
237   tp->ddz = 0.00001;
238
239   if (!text || !*text || !strcmp(text, "(default)"))
240     {
241 # ifdef HAVE_UNAME
242       struct utsname uts;
243
244       if (uname (&uts) < 0)
245         {
246           text = strdup("uname() failed");
247         }
248       else
249         {
250           char *s;
251           if ((s = strchr(uts.nodename, '.')))
252             *s = 0;
253           text = (char *) malloc(strlen(uts.nodename) +
254                                  strlen(uts.sysname) +
255                                  strlen(uts.version) +
256                                  strlen(uts.release) + 10);
257 #  ifdef _AIX
258           sprintf(text, "%s\n%s %s.%s",
259                   uts.nodename, uts.sysname, uts.version, uts.release);
260 #  else  /* !_AIX */
261           sprintf(text, "%s\n%s %s",
262                   uts.nodename, uts.sysname, uts.release);
263 #  endif /* !_AIX */
264         }
265 # else  /* !HAVE_UNAME */
266 #  ifdef VMS
267       text = strdup(getenv("SYS$NODE"));
268 #  else
269       text = strdup("*  *\n*  *  *\nxscreensaver\n*  *  *\n*  *");
270 #  endif
271 # endif /* !HAVE_UNAME */
272     }
273
274
275   tp->ncolors = 255;
276   tp->colors = (XColor *) calloc(tp->ncolors, sizeof(XColor));
277   make_smooth_colormap (0, 0, 0,
278                         tp->colors, &tp->ncolors,
279                         False, 0, False);
280 }
281
282
283 static void
284 unit_tube (Bool wire)
285 {
286   int i;
287   GLfloat d3 = 0.2075;
288
289   glPushMatrix();
290
291   if (!wire)
292     glShadeModel(GL_SMOOTH);
293
294   glFrontFace(GL_CCW);
295
296   for (i = 0; i < 8; i++)
297     {
298       glNormal3f(1, 0, 0);
299       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
300       glVertex3f(0.5, 0.0, -d3); glVertex3f(0.5, 1.0, -d3);
301       glVertex3f(0.5, 1.0,  d3); glVertex3f(0.5, 0.0,  d3);
302       glEnd();
303       glRotatef(45, 0, 1, 0);
304     }
305
306   if (! wire)
307     {
308       glNormal3f(0, -1, 0);
309       glBegin(GL_TRIANGLE_FAN);
310       glVertex3f(0, 0, 0);
311       glVertex3f(-d3,  0, -0.5); glVertex3f( d3,  0, -0.5);
312       glVertex3f( 0.5, 0, -d3);  glVertex3f( 0.5, 0,  d3);
313       glVertex3f( d3,  0,  0.5); glVertex3f(-d3,  0,  0.5);
314       glVertex3f(-0.5, 0,  d3);  glVertex3f(-0.5, 0, -d3);
315       glVertex3f(-d3,  0, -0.5); glVertex3f( d3,  0, -0.5);
316
317       glEnd();
318
319       glTranslatef(0, 1, 0);
320
321       glNormal3f(0, 1, 0);
322       glBegin(GL_TRIANGLE_FAN);
323       glVertex3f(0, 0, 0);
324       glVertex3f(-0.5, 0, -d3);  glVertex3f(-0.5, 0,  d3); 
325       glVertex3f(-d3,  0,  0.5); glVertex3f( d3,  0,  0.5); 
326       glVertex3f( 0.5, 0,  d3);  glVertex3f( 0.5, 0, -d3); 
327       glVertex3f( d3,  0, -0.5); glVertex3f(-d3,  0, -0.5); 
328       glVertex3f(-0.5, 0, -d3);  glVertex3f(-0.5, 0,  d3); 
329       glEnd();
330     }
331
332   glPopMatrix();
333 }
334
335
336 static void
337 tube (GLfloat x1, GLfloat y1, 
338       GLfloat x2, GLfloat y2,
339       GLfloat z,
340       GLfloat diameter,
341       Bool wire)
342 {
343   GLfloat length, rot;
344
345   if (y1 == y2) y2 += 0.01;  /* waah... */
346
347   length = sqrt(((x2-x1)*(x2-x1)) +
348                 ((y2-y1)*(y2-y1)));
349
350   rot = (acos((x2-x1)/length)
351          / (M_PI / 180));
352
353   if (rot < 0 || rot > 180) abort();
354   if (y1 <= y2) rot = -rot;
355
356   rot = 180-rot;
357
358   if (diameter < 0) abort();
359   if (length < 0) abort();
360
361   glPushMatrix();
362
363   glTranslatef(x1, y1, z);
364   glRotatef(rot+90, 0, 0, 1);
365   glTranslatef(0, -diameter/8, 0);
366   glScalef (diameter, length+diameter/4, diameter);
367   unit_tube (wire);
368   glPopMatrix();
369   
370 }
371
372
373
374 static int
375 fill_character (GLUTstrokeFont font, int c, Bool wire)
376 {
377   int tube_width = 20;
378
379   const StrokeCharRec *ch;
380   const StrokeRec *stroke;
381   const CoordRec *coord;
382   StrokeFontPtr fontinfo;
383   int i, j;
384
385   fontinfo = (StrokeFontPtr) font;
386
387   if (c < 0 || c >= fontinfo->num_chars)
388     return 0;
389   ch = &(fontinfo->ch[c]);
390   if (ch)
391     {
392       GLfloat lx, ly;
393       for (i = ch->num_strokes, stroke = ch->stroke;
394            i > 0; i--, stroke++) {
395         for (j = stroke->num_coords, coord = stroke->coord;
396              j > 0; j--, coord++)
397           {
398             if (j != stroke->num_coords)
399               tube (lx, ly, coord->x, coord->y, 0, tube_width, wire);
400             lx = coord->x;
401             ly = coord->y;
402           }
403       }
404       return (int) (ch->right + tube_width/2);
405     }
406   return 0;
407 }
408
409
410 static int
411 text_extents (const char *string, int *wP, int *hP)
412 {
413   const char *s, *start;
414   int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
415   int lines = 0;
416   *wP = 0;
417   *hP = 0;
418   start = string;
419   s = start;
420   while (1)
421     if (*s == '\n' || *s == 0)
422       {
423         int w = 0;
424         while (start < s)
425           {
426             w += glutStrokeWidth(GLUT_FONT, *start);
427             start++;
428           }
429         start = s+1;
430
431         if (w > *wP) *wP = w;
432         *hP += line_height;
433         s++;
434         lines++;
435         if (*s == 0) break;
436       }
437     else
438       s++;
439
440   return lines;
441 }
442
443
444 static void
445 fill_string (const char *string, Bool wire)
446 {
447   const char *s, *start;
448   int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
449   int off;
450   GLfloat x = 0, y = 0;
451   int lines;
452
453   int ow, oh;
454   lines = text_extents (string, &ow, &oh);
455
456   y = oh / 2 - line_height;
457
458   start = string;
459   s = start;
460   while (1)
461     if (*s == '\n' || *s == 0)
462       {
463         int line_w = 0;
464         const char *s2;
465
466         for (s2 = start; s2 < s; s2++)
467           line_w += glutStrokeWidth (GLUT_FONT, *s2);
468
469         x = (-ow/2) + ((ow-line_w)/2);
470         while (start < s)
471           {
472             glPushMatrix();
473             glTranslatef(x, y, 0);
474             off = fill_character (GLUT_FONT, *start, wire);
475             x += off;
476             glPopMatrix();
477             start++;
478           }
479         start = s+1;
480
481         y -= line_height;
482         s++;
483         if (*s == 0) break;
484       }
485     else
486       s++;
487 }
488
489
490 void
491 draw_text (ModeInfo *mi)
492 {
493   text_configuration *tp = &tps[MI_SCREEN(mi)];
494   Display *dpy = MI_DISPLAY(mi);
495   Window window = MI_WINDOW(mi);
496   int wire = MI_IS_WIREFRAME(mi);
497
498   static GLfloat color[4] = {0.0, 0.0, 0.0, 1.0};
499   static GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
500
501   if (!tp->glx_context)
502     return;
503
504   glShadeModel(GL_SMOOTH);
505
506   glEnable(GL_DEPTH_TEST);
507   glEnable(GL_NORMALIZE);
508   glEnable(GL_CULL_FACE);
509
510   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
511
512   glPushMatrix ();
513
514   glScalef(1.1, 1.1, 1.1);
515
516   {
517     static int frame = 0;
518     GLfloat x, y, z;
519
520 #   define SINOID(SCALE,SIZE) \
521       ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
522     x = SINOID(0.031, 9.0);
523     y = SINOID(0.023, 9.0);
524     z = SINOID(0.017, 9.0);
525     frame++;
526     glTranslatef(x, y, z);
527
528     x = tp->rotx;
529     y = tp->roty;
530     z = tp->rotz;
531     if (x < 0) x = 1 - (x + 1);
532     if (y < 0) y = 1 - (y + 1);
533     if (z < 0) z = 1 - (z + 1);
534
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     rotate(&tp->rotx, &tp->dx, &tp->ddx, tp->d_max);
540     rotate(&tp->roty, &tp->dy, &tp->ddy, tp->d_max);
541     rotate(&tp->rotz, &tp->dz, &tp->ddz, tp->d_max);
542   }
543
544   glColor4fv (white);
545
546   color[0] = tp->colors[tp->ccolor].red   / 65536.0;
547   color[1] = tp->colors[tp->ccolor].green / 65536.0;
548   color[2] = tp->colors[tp->ccolor].blue  / 65536.0;
549   tp->ccolor++;
550   if (tp->ccolor >= tp->ncolors) tp->ccolor = 0;
551
552   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
553
554   glScalef(0.01, 0.01, 0.01);
555   fill_string(text, wire);
556
557   glPopMatrix ();
558
559   if (mi->fps_p) do_fps (mi);
560   glFinish();
561
562   glXSwapBuffers(dpy, window);
563 }
564
565 #endif /* USE_GL */