1 /* gltext, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
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
12 #include <X11/Intrinsic.h>
14 extern XtAppContext app;
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
22 #define DEF_TEXT "(default)"
23 #define DEF_SPIN "XYZ"
24 #define DEF_WANDER "True"
26 #define DEFAULTS "*delay: 10000 \n" \
27 "*showFPS: False \n" \
28 "*wireframe: False \n" \
29 "*spin: " DEF_SPIN "\n" \
30 "*wander: " DEF_WANDER "\n" \
31 "*text: " DEF_TEXT "\n"
34 #define SMOOTH_TUBE /* whether to have smooth or faceted tubes */
37 # define TUBE_FACES 12 /* how densely to render tubes */
44 #define countof(x) (sizeof((x))/sizeof((*x)))
46 #include "xlockmore.h"
51 #ifdef USE_GL /* whole file */
54 # include <sys/utsname.h>
55 #endif /* HAVE_UNAME */
59 #include "glutstroke.h"
60 #include "glut_roman.h"
61 #define GLUT_FONT (&glutStrokeRoman)
65 GLXContext *glx_context;
67 GLfloat rotx, roty, rotz; /* current object rotation */
68 GLfloat dx, dy, dz; /* current rotational velocity */
69 GLfloat ddx, ddy, ddz; /* current rotational acceleration */
70 GLfloat d_max; /* max velocity */
78 Bool spin_x, spin_y, spin_z;
83 static text_configuration *tps = NULL;
85 static char *text_fmt;
87 static Bool do_wander;
89 static XrmOptionDescRec opts[] = {
90 { "-text", ".text", XrmoptionSepArg, 0 },
91 { "-spin", ".spin", XrmoptionSepArg, 0 },
92 { "+spin", ".spin", XrmoptionNoArg, "False" },
93 { "-wander", ".wander", XrmoptionNoArg, "True" },
94 { "+wander", ".wander", XrmoptionNoArg, "False" }
97 static argtype vars[] = {
98 {(caddr_t *) &text_fmt, "text", "Text", DEF_TEXT, t_String},
99 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String},
100 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
103 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
106 /* Window management, etc
109 reshape_text (ModeInfo *mi, int width, int height)
111 GLfloat h = (GLfloat) height / (GLfloat) width;
113 glViewport (0, 0, (GLint) width, (GLint) height);
115 glMatrixMode(GL_PROJECTION);
118 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
119 gluLookAt( 0.0, 0.0, 15.0,
122 glMatrixMode(GL_MODELVIEW);
124 glTranslatef(0.0, 0.0, -15.0);
126 glClear(GL_COLOR_BUFFER_BIT);
131 gl_init (ModeInfo *mi)
133 text_configuration *tp = &tps[MI_SCREEN(mi)];
134 int wire = MI_IS_WIREFRAME(mi);
136 static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
140 glLightfv(GL_LIGHT0, GL_POSITION, pos);
141 glEnable(GL_CULL_FACE);
142 glEnable(GL_LIGHTING);
144 glEnable(GL_DEPTH_TEST);
147 tp->text_list = glGenLists (1);
148 glNewList (tp->text_list, GL_COMPILE);
153 /* lifted from lament.c */
154 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
155 #define RANDSIGN() ((random() & 1) ? 1 : -1)
158 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
173 if (ppos < 0) abort();
174 if (ppos > 1.0) abort();
175 *pos = (*pos > 0 ? ppos : -ppos);
181 if (*v > max_v || *v < -max_v)
185 /* If it stops, start it going in the other direction. */
192 /* keep going in the same direction */
207 /* Alter direction of rotational acceleration randomly. */
208 if (! (random() % 120))
211 /* Change acceleration very occasionally. */
212 if (! (random() % 200))
216 else if (random() & 1)
225 parse_text (ModeInfo *mi)
227 text_configuration *tp = &tps[MI_SCREEN(mi)];
229 if (tp->text) free (tp->text);
231 if (!text_fmt || !*text_fmt || !strcmp(text_fmt, "(default)"))
236 if (uname (&uts) < 0)
238 tp->text = strdup("uname() failed");
243 if ((s = strchr(uts.nodename, '.')))
245 tp->text = (char *) malloc(strlen(uts.nodename) +
246 strlen(uts.sysname) +
247 strlen(uts.version) +
248 strlen(uts.release) + 10);
250 sprintf(tp->text, "%s\n%s %s.%s",
251 uts.nodename, uts.sysname, uts.version, uts.release);
253 sprintf(tp->text, "%s\n%s %s",
254 uts.nodename, uts.sysname, uts.release);
257 # else /* !HAVE_UNAME */
259 tp->text = strdup(getenv("SYS$NODE"));
261 tp->text = strdup("* *\n* * *\nxscreensaver\n* * *\n* *");
263 # endif /* !HAVE_UNAME */
265 else if (!strchr (text_fmt, '%'))
267 tp->text = strdup (text_fmt);
271 time_t now = time ((time_t *) 0);
272 struct tm *tm = localtime (&now);
273 int L = strlen(text_fmt) + 100;
274 tp->text = (char *) malloc (L);
276 strftime (tp->text, L-1, text_fmt, tm);
278 sprintf (tp->text, "strftime error:\n%s", text_fmt);
284 init_text (ModeInfo *mi)
286 text_configuration *tp;
289 tps = (text_configuration *)
290 calloc (MI_NUM_SCREENS(mi), sizeof (text_configuration));
292 fprintf(stderr, "%s: out of memory\n", progname);
296 tp = &tps[MI_SCREEN(mi)];
299 tp = &tps[MI_SCREEN(mi)];
301 if ((tp->glx_context = init_GL(mi)) != NULL) {
303 reshape_text (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
306 tp->rotx = frand(1.0) * RANDSIGN();
307 tp->roty = frand(1.0) * RANDSIGN();
308 tp->rotz = frand(1.0) * RANDSIGN();
310 /* bell curve from 0-6 degrees, avg 3 */
311 tp->dx = (frand(1) + frand(1) + frand(1)) / (360/2);
312 tp->dy = (frand(1) + frand(1) + frand(1)) / (360/2);
313 tp->dz = (frand(1) + frand(1) + frand(1)) / (360/2);
315 tp->d_max = tp->dx * 2;
317 tp->ddx = 0.00006 + frand(0.00003);
318 tp->ddy = 0.00006 + frand(0.00003);
319 tp->ddz = 0.00006 + frand(0.00003);
323 tp->colors = (XColor *) calloc(tp->ncolors, sizeof(XColor));
324 make_smooth_colormap (0, 0, 0,
325 tp->colors, &tp->ncolors,
334 if (*s == 'x' || *s == 'X') tp->spin_x = 1;
335 else if (*s == 'y' || *s == 'Y') tp->spin_y = 1;
336 else if (*s == 'z' || *s == 'Z') tp->spin_z = 1;
340 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
352 fill_character (GLUTstrokeFont font, int c, Bool wire)
354 GLfloat tube_width = 10;
356 const StrokeCharRec *ch;
357 const StrokeRec *stroke;
358 const CoordRec *coord;
359 StrokeFontPtr fontinfo;
362 fontinfo = (StrokeFontPtr) font;
364 if (c < 0 || c >= fontinfo->num_chars)
366 ch = &(fontinfo->ch[c]);
370 for (i = ch->num_strokes, stroke = ch->stroke;
371 i > 0; i--, stroke++) {
372 for (j = stroke->num_coords, coord = stroke->coord;
380 if (j != stroke->num_coords)
382 coord->x, coord->y, 0,
385 TUBE_FACES, smooth, wire);
390 return (int) (ch->right + tube_width/2);
397 text_extents (const char *string, int *wP, int *hP)
399 const char *s, *start;
400 int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
407 if (*s == '\n' || *s == 0)
412 w += glutStrokeWidth(GLUT_FONT, *start);
417 if (w > *wP) *wP = w;
431 fill_string (const char *string, Bool wire)
433 const char *s, *start;
434 int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
436 GLfloat x = 0, y = 0;
440 lines = text_extents (string, &ow, &oh);
442 y = oh / 2 - line_height;
447 if (*s == '\n' || *s == 0)
451 const char *lstart = start;
452 const char *lend = s;
454 /* strip off whitespace at beginning and end of line
455 (since we're centering.) */
456 while (lend > lstart && isspace(lend[-1]))
458 while (lstart < lend && isspace(*lstart))
461 for (s2 = lstart; s2 < lend; s2++)
462 line_w += glutStrokeWidth (GLUT_FONT, *s2);
464 x = (-ow/2) + ((ow-line_w)/2);
465 for (s2 = lstart; s2 < lend; s2++)
468 glTranslatef(x, y, 0);
469 off = fill_character (GLUT_FONT, *s2, wire);
486 draw_text (ModeInfo *mi)
488 text_configuration *tp = &tps[MI_SCREEN(mi)];
489 Display *dpy = MI_DISPLAY(mi);
490 Window window = MI_WINDOW(mi);
491 int wire = MI_IS_WIREFRAME(mi);
493 static GLfloat color[4] = {0.0, 0.0, 0.0, 1.0};
494 static GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
496 if (!tp->glx_context)
499 if (strchr (text_fmt, '%'))
501 static time_t last_update = -1;
502 time_t now = time ((time_t *) 0);
503 if (now != last_update) /* do it once a second */
508 glShadeModel(GL_SMOOTH);
510 glEnable(GL_DEPTH_TEST);
511 glEnable(GL_NORMALIZE);
512 glEnable(GL_CULL_FACE);
514 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
518 glScalef(1.1, 1.1, 1.1);
525 static int frame = 0;
527 # define SINOID(SCALE,SIZE) \
528 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
530 x = SINOID(0.031, 9.0);
531 y = SINOID(0.023, 9.0);
532 z = SINOID(0.017, 9.0);
534 glTranslatef(x, y, z);
537 if (tp->spin_x || tp->spin_y || tp->spin_z)
542 if (x < 0) x = 1 - (x + 1);
543 if (y < 0) y = 1 - (y + 1);
544 if (z < 0) z = 1 - (z + 1);
546 if (tp->spin_x) glRotatef(x * 360, 1.0, 0.0, 0.0);
547 if (tp->spin_y) glRotatef(y * 360, 0.0, 1.0, 0.0);
548 if (tp->spin_z) glRotatef(z * 360, 0.0, 0.0, 1.0);
550 rotate(&tp->rotx, &tp->dx, &tp->ddx, tp->d_max);
551 rotate(&tp->roty, &tp->dy, &tp->ddy, tp->d_max);
552 rotate(&tp->rotz, &tp->dz, &tp->ddz, tp->d_max);
558 color[0] = tp->colors[tp->ccolor].red / 65536.0;
559 color[1] = tp->colors[tp->ccolor].green / 65536.0;
560 color[2] = tp->colors[tp->ccolor].blue / 65536.0;
562 if (tp->ccolor >= tp->ncolors) tp->ccolor = 0;
564 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
566 glScalef(0.01, 0.01, 0.01);
568 fill_string(tp->text, wire);
572 if (mi->fps_p) do_fps (mi);
575 glXSwapBuffers(dpy, window);