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"
50 #ifdef USE_GL /* whole file */
53 # include <sys/utsname.h>
54 #endif /* HAVE_UNAME */
58 #include "glutstroke.h"
59 #include "glut_roman.h"
60 #define GLUT_FONT (&glutStrokeRoman)
64 GLXContext *glx_context;
66 GLfloat rotx, roty, rotz; /* current object rotation */
67 GLfloat dx, dy, dz; /* current rotational velocity */
68 GLfloat ddx, ddy, ddz; /* current rotational acceleration */
69 GLfloat d_max; /* max velocity */
77 Bool spin_x, spin_y, spin_z;
82 static text_configuration *tps = NULL;
84 static char *text_fmt;
86 static Bool do_wander;
88 static XrmOptionDescRec opts[] = {
89 { "-text", ".text", XrmoptionSepArg, 0 },
90 { "-spin", ".spin", XrmoptionSepArg, 0 },
91 { "+spin", ".spin", XrmoptionNoArg, "" },
92 { "-wander", ".wander", XrmoptionNoArg, "True" },
93 { "+wander", ".wander", XrmoptionNoArg, "False" }
96 static argtype vars[] = {
97 {(caddr_t *) &text_fmt, "text", "Text", DEF_TEXT, t_String},
98 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String},
99 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
102 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
105 /* Window management, etc
108 reshape_text (ModeInfo *mi, int width, int height)
110 GLfloat h = (GLfloat) height / (GLfloat) width;
112 glViewport (0, 0, (GLint) width, (GLint) height);
114 glMatrixMode(GL_PROJECTION);
117 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
118 gluLookAt( 0.0, 0.0, 15.0,
121 glMatrixMode(GL_MODELVIEW);
123 glTranslatef(0.0, 0.0, -15.0);
125 glClear(GL_COLOR_BUFFER_BIT);
130 gl_init (ModeInfo *mi)
132 text_configuration *tp = &tps[MI_SCREEN(mi)];
133 int wire = MI_IS_WIREFRAME(mi);
135 static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
139 glLightfv(GL_LIGHT0, GL_POSITION, pos);
140 glEnable(GL_CULL_FACE);
141 glEnable(GL_LIGHTING);
143 glEnable(GL_DEPTH_TEST);
146 tp->text_list = glGenLists (1);
147 glNewList (tp->text_list, GL_COMPILE);
152 /* lifted from lament.c */
153 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
154 #define RANDSIGN() ((random() & 1) ? 1 : -1)
157 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
172 if (ppos < 0) abort();
173 if (ppos > 1.0) abort();
174 *pos = (*pos > 0 ? ppos : -ppos);
180 if (*v > max_v || *v < -max_v)
184 /* If it stops, start it going in the other direction. */
191 /* keep going in the same direction */
206 /* Alter direction of rotational acceleration randomly. */
207 if (! (random() % 120))
210 /* Change acceleration very occasionally. */
211 if (! (random() % 200))
215 else if (random() & 1)
224 parse_text (ModeInfo *mi)
226 text_configuration *tp = &tps[MI_SCREEN(mi)];
228 if (tp->text) free (tp->text);
230 if (!text_fmt || !*text_fmt || !strcmp(text_fmt, "(default)"))
235 if (uname (&uts) < 0)
237 tp->text = strdup("uname() failed");
242 if ((s = strchr(uts.nodename, '.')))
244 tp->text = (char *) malloc(strlen(uts.nodename) +
245 strlen(uts.sysname) +
246 strlen(uts.version) +
247 strlen(uts.release) + 10);
249 sprintf(tp->text, "%s\n%s %s.%s",
250 uts.nodename, uts.sysname, uts.version, uts.release);
252 sprintf(tp->text, "%s\n%s %s",
253 uts.nodename, uts.sysname, uts.release);
256 # else /* !HAVE_UNAME */
258 tp->text = strdup(getenv("SYS$NODE"));
260 tp->text = strdup("* *\n* * *\nxscreensaver\n* * *\n* *");
262 # endif /* !HAVE_UNAME */
264 else if (!strchr (text_fmt, '%'))
266 tp->text = strdup (text_fmt);
270 time_t now = time ((time_t *) 0);
271 struct tm *tm = localtime (&now);
272 int L = strlen(text_fmt) + 100;
273 tp->text = (char *) malloc (L);
275 strftime (tp->text, L-1, text_fmt, tm);
277 sprintf (tp->text, "strftime error:\n%s", text_fmt);
283 init_text (ModeInfo *mi)
285 text_configuration *tp;
288 tps = (text_configuration *)
289 calloc (MI_NUM_SCREENS(mi), sizeof (text_configuration));
291 fprintf(stderr, "%s: out of memory\n", progname);
295 tp = &tps[MI_SCREEN(mi)];
298 tp = &tps[MI_SCREEN(mi)];
300 if ((tp->glx_context = init_GL(mi)) != NULL) {
302 reshape_text (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
305 tp->rotx = frand(1.0) * RANDSIGN();
306 tp->roty = frand(1.0) * RANDSIGN();
307 tp->rotz = frand(1.0) * RANDSIGN();
309 /* bell curve from 0-6 degrees, avg 3 */
310 tp->dx = (frand(1) + frand(1) + frand(1)) / (360/2);
311 tp->dy = (frand(1) + frand(1) + frand(1)) / (360/2);
312 tp->dz = (frand(1) + frand(1) + frand(1)) / (360/2);
314 tp->d_max = tp->dx * 2;
316 tp->ddx = 0.00006 + frand(0.00003);
317 tp->ddy = 0.00006 + frand(0.00003);
318 tp->ddz = 0.00006 + frand(0.00003);
322 tp->colors = (XColor *) calloc(tp->ncolors, sizeof(XColor));
323 make_smooth_colormap (0, 0, 0,
324 tp->colors, &tp->ncolors,
333 if (*s == 'x' || *s == 'X') tp->spin_x = 1;
334 else if (*s == 'y' || *s == 'Y') tp->spin_y = 1;
335 else if (*s == 'z' || *s == 'Z') tp->spin_z = 1;
339 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
351 unit_tube (Bool wire)
354 int faces = TUBE_FACES;
355 GLfloat step = M_PI * 2 / faces;
364 glBegin(wire ? GL_LINES : GL_QUAD_STRIP);
366 glBegin(wire ? GL_LINES : GL_QUADS);
369 for (i = 0, th = 0; i <= faces; i++)
371 GLfloat x = cos (th);
372 GLfloat y = sin (th);
374 glVertex3f(x, 0.0, y);
375 glVertex3f(x, 1.0, y);
381 glVertex3f(x, 1.0, y);
382 glVertex3f(x, 0.0, y);
389 for (z = 0; z <= 1; z++)
391 glFrontFace(z == 0 ? GL_CCW : GL_CW);
392 glNormal3f(0, (z == 0 ? -1 : 1), 0);
393 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
394 if (! wire) glVertex3f(0, z, 0);
395 for (i = 0, th = 0; i <= faces; i++)
397 GLfloat x = cos (th);
398 GLfloat y = sin (th);
408 tube (GLfloat x1, GLfloat y1, GLfloat z1,
409 GLfloat x2, GLfloat y2, GLfloat z2,
410 GLfloat diameter, GLfloat cap_size,
413 GLfloat length, angle, a, b, c;
415 if (diameter <= 0) abort();
421 length = sqrt (a*a + b*b + c*c);
422 angle = acos (a / length);
425 glTranslatef(x1, y1, z1);
426 glScalef (length, length, length);
428 if (c == 0 && b == 0)
429 glRotatef (angle / (M_PI / 180), 0, 1, 0);
431 glRotatef (angle / (M_PI / 180), 0, -c, b);
433 glRotatef (-90, 0, 0, 1);
434 glScalef (diameter/length, 1, diameter/length);
436 /* extend the endpoints of the tube by the cap size in both directions */
439 GLfloat c = cap_size/length;
440 glTranslatef (0, -c, 0);
441 glScalef (1, 1+c+c, 1);
451 fill_character (GLUTstrokeFont font, int c, Bool wire)
453 GLfloat tube_width = 10;
455 const StrokeCharRec *ch;
456 const StrokeRec *stroke;
457 const CoordRec *coord;
458 StrokeFontPtr fontinfo;
461 fontinfo = (StrokeFontPtr) font;
463 if (c < 0 || c >= fontinfo->num_chars)
465 ch = &(fontinfo->ch[c]);
469 for (i = ch->num_strokes, stroke = ch->stroke;
470 i > 0; i--, stroke++) {
471 for (j = stroke->num_coords, coord = stroke->coord;
474 if (j != stroke->num_coords)
476 coord->x, coord->y, 0,
484 return (int) (ch->right + tube_width/2);
491 text_extents (const char *string, int *wP, int *hP)
493 const char *s, *start;
494 int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
501 if (*s == '\n' || *s == 0)
506 w += glutStrokeWidth(GLUT_FONT, *start);
511 if (w > *wP) *wP = w;
525 fill_string (const char *string, Bool wire)
527 const char *s, *start;
528 int line_height = GLUT_FONT->top - GLUT_FONT->bottom;
530 GLfloat x = 0, y = 0;
534 lines = text_extents (string, &ow, &oh);
536 y = oh / 2 - line_height;
541 if (*s == '\n' || *s == 0)
545 const char *lstart = start;
546 const char *lend = s;
548 /* strip off whitespace at beginning and end of line
549 (since we're centering.) */
550 while (lend > lstart && isspace(lend[-1]))
552 while (lstart < lend && isspace(*lstart))
555 for (s2 = lstart; s2 < lend; s2++)
556 line_w += glutStrokeWidth (GLUT_FONT, *s2);
558 x = (-ow/2) + ((ow-line_w)/2);
559 for (s2 = lstart; s2 < lend; s2++)
562 glTranslatef(x, y, 0);
563 off = fill_character (GLUT_FONT, *s2, wire);
580 draw_text (ModeInfo *mi)
582 text_configuration *tp = &tps[MI_SCREEN(mi)];
583 Display *dpy = MI_DISPLAY(mi);
584 Window window = MI_WINDOW(mi);
585 int wire = MI_IS_WIREFRAME(mi);
587 static GLfloat color[4] = {0.0, 0.0, 0.0, 1.0};
588 static GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
590 if (!tp->glx_context)
593 if (strchr (text_fmt, '%'))
595 static time_t last_update = -1;
596 time_t now = time ((time_t *) 0);
597 if (now != last_update) /* do it once a second */
602 glShadeModel(GL_SMOOTH);
604 glEnable(GL_DEPTH_TEST);
605 glEnable(GL_NORMALIZE);
606 glEnable(GL_CULL_FACE);
608 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
612 glScalef(1.1, 1.1, 1.1);
619 static int frame = 0;
621 # define SINOID(SCALE,SIZE) \
622 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
624 x = SINOID(0.031, 9.0);
625 y = SINOID(0.023, 9.0);
626 z = SINOID(0.017, 9.0);
628 glTranslatef(x, y, z);
631 if (tp->spin_x || tp->spin_y || tp->spin_z)
636 if (x < 0) x = 1 - (x + 1);
637 if (y < 0) y = 1 - (y + 1);
638 if (z < 0) z = 1 - (z + 1);
640 if (tp->spin_x) glRotatef(x * 360, 1.0, 0.0, 0.0);
641 if (tp->spin_y) glRotatef(y * 360, 0.0, 1.0, 0.0);
642 if (tp->spin_z) glRotatef(z * 360, 0.0, 0.0, 1.0);
644 rotate(&tp->rotx, &tp->dx, &tp->ddx, tp->d_max);
645 rotate(&tp->roty, &tp->dy, &tp->ddy, tp->d_max);
646 rotate(&tp->rotz, &tp->dz, &tp->ddz, tp->d_max);
652 color[0] = tp->colors[tp->ccolor].red / 65536.0;
653 color[1] = tp->colors[tp->ccolor].green / 65536.0;
654 color[2] = tp->colors[tp->ccolor].blue / 65536.0;
656 if (tp->ccolor >= tp->ncolors) tp->ccolor = 0;
658 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
660 glScalef(0.01, 0.01, 0.01);
662 fill_string(tp->text, wire);
666 if (mi->fps_p) do_fps (mi);
669 glXSwapBuffers(dpy, window);