2 * starwars, Copyright (c) 1998-2007 Jamie Zawinski <jwz@jwz.org> and
3 * Claudio Matsuoka <claudio@helllabs.org>
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
13 * Star Wars -- Phosphor meets a well-known scroller from a galaxy far,
16 * Feb 2000 Claudio Matsuoka First version.
17 * Jan 2001 Jamie Zawinski Rewrote large sections to add the ability to
18 * run a subprocess, customization of the font
19 * size and other parameters, etc.
20 * Feb 2001 jepler@inetnebr.com Added anti-aliased lines, and fade-to-black.
21 * Feb 2005 Jamie Zawinski Added texture fonts.
26 * starwars -program 'cat starwars.txt' -columns 25 -no-wrap -texture
31 #endif /* HAVE_CONFIG_H */
41 # include <sys/utsname.h>
42 #endif /* HAVE_UNAME */
45 # include <X11/Intrinsic.h>
49 #define DEFAULTS "*delay: 40000 \n" \
50 "*showFPS: False \n" \
52 "*font: " DEF_FONT "\n"
54 # define refresh_sws 0
55 # define sws_handle_event 0
57 #define countof(x) (sizeof((x))/sizeof((*x)))
59 #include "xlockmore.h"
61 #ifdef USE_GL /* whole file */
63 /* Should be in <GL/glext.h> */
64 # ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
65 # define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
67 # ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
68 # define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
72 #define DEF_PROGRAM "xscreensaver-text --cols 0" /* don't wrap */
73 #define DEF_LINES "125"
74 #define DEF_STEPS "35"
75 #define DEF_SPIN "0.03"
76 #define DEF_FONT_SIZE "-1"
77 #define DEF_COLUMNS "-1"
78 #define DEF_WRAP "True"
79 #define DEF_ALIGN "Center"
80 #define DEF_SMOOTH "True"
81 #define DEF_THICK "True"
82 #define DEF_FADE "True"
83 #define DEF_TEXTURES "True"
84 #define DEF_DEBUG "False"
86 /* Utopia 800 needs 64 512x512 textures (4096x4096 bitmap).
87 Utopia 720 needs 16 512x512 textures (2048x2048 bitmap).
88 Utopia 480 needs 16 512x512 textures (2048x2048 bitmap).
89 Utopia 400 needs 4 512x512 textures (1024x1024 bitmap).
90 Utopia 180 needs 1 512x512 texture.
91 Times 240 needs 1 512x512 texture.
93 #define DEF_FONT "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-iso8859-1"
97 #define MAX_THICK_LINES 25
98 #define FONT_WEIGHT 14
102 #include "glutstroke.h"
103 #include "glut_roman.h"
104 #define GLUT_FONT (&glutStrokeRoman)
108 GLXContext *glx_context;
110 GLuint text_list, star_list;
111 texture_font_data *texfont;
116 XtIntervalId pipe_timer;
117 Time subproc_relaunch_delay;
130 double intra_line_scroll;
132 int line_pixel_width; /* in font units (for wrapping text) */
133 int line_pixel_height; /* in screen units (for computing line thickness) */
134 GLfloat line_thickness;
139 static sws_configuration *scs = NULL;
141 static char *program;
142 static int max_lines;
143 static int scroll_steps;
144 static float star_spin;
145 static float font_size;
146 static int target_columns;
151 static int textures_p;
153 static char *alignment_str;
154 static int alignment;
156 static XrmOptionDescRec opts[] = {
157 {"-program", ".program", XrmoptionSepArg, 0 },
158 {"-lines", ".lines", XrmoptionSepArg, 0 },
159 {"-steps", ".steps", XrmoptionSepArg, 0 },
160 {"-spin", ".spin", XrmoptionSepArg, 0 },
161 {"-size", ".fontSize", XrmoptionSepArg, 0 },
162 {"-columns", ".columns", XrmoptionSepArg, 0 },
163 /*{"-font", ".font", XrmoptionSepArg, 0 },*/
164 {"-fade", ".fade", XrmoptionNoArg, "True" },
165 {"-no-fade", ".fade", XrmoptionNoArg, "False" },
166 {"-textures", ".textures", XrmoptionNoArg, "True" },
167 {"-smooth", ".smooth", XrmoptionNoArg, "True" },
168 {"-no-smooth", ".smooth", XrmoptionNoArg, "False" },
169 {"-thick", ".thick", XrmoptionNoArg, "True" },
170 {"-no-thick", ".thick", XrmoptionNoArg, "False" },
171 {"-no-textures", ".textures", XrmoptionNoArg, "False" },
172 {"-wrap", ".lineWrap", XrmoptionNoArg, "True" },
173 {"-no-wrap", ".lineWrap", XrmoptionNoArg, "False" },
174 {"-nowrap", ".lineWrap", XrmoptionNoArg, "False" },
175 {"-alignment", ".alignment", XrmoptionSepArg, 0 },
176 {"-left", ".alignment", XrmoptionNoArg, "Left" },
177 {"-right", ".alignment", XrmoptionNoArg, "Right" },
178 {"-center", ".alignment", XrmoptionNoArg, "Center" },
179 {"-debug", ".debug", XrmoptionNoArg, "True" },
182 static argtype vars[] = {
183 {&program, "program", "Program", DEF_PROGRAM, t_String},
184 {&max_lines, "lines", "Integer", DEF_LINES, t_Int},
185 {&scroll_steps, "steps", "Integer", DEF_STEPS, t_Int},
186 {&star_spin, "spin", "Float", DEF_SPIN, t_Float},
187 {&font_size, "fontSize", "Float", DEF_FONT_SIZE, t_Float},
188 {&target_columns, "columns", "Integer", DEF_COLUMNS, t_Int},
189 {&wrap_p, "lineWrap", "Boolean", DEF_WRAP, t_Bool},
190 {&alignment_str, "alignment", "Alignment", DEF_ALIGN, t_String},
191 {&smooth_p, "smooth", "Boolean", DEF_SMOOTH, t_Bool},
192 {&thick_p, "thick", "Boolean", DEF_THICK, t_Bool},
193 {&fade_p, "fade", "Boolean", DEF_FADE, t_Bool},
194 {&textures_p, "textures", "Boolean", DEF_TEXTURES, t_Bool},
195 {&debug_p, "debug", "Boolean", DEF_DEBUG, t_Bool},
198 ENTRYPOINT ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
202 /* Tabs are bad, mmmkay? */
205 untabify (const char *string)
207 const char *ostring = string;
208 char *result = (char *) malloc ((strlen(string) * 8) + 1);
218 } while (col % TAB_WIDTH);
221 else if (*string == '\r' || *string == '\n')
226 else if (*string == '\010') /* backspace */
228 if (string > ostring)
243 strip (char *s, Bool leading, Bool trailing)
247 while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
252 while (*s2 == ' ' || *s2 == '\t')
263 /* The GLUT font only has ASCII characters in them, so do what we can to
264 convert Latin1 characters to the nearest ASCII equivalent...
267 latin1_to_ascii (char *s)
269 unsigned char *us = (unsigned char *) s;
270 const unsigned char ascii[95] = {
271 '!', 'C', '#', '#', 'Y', '|', 'S', '_', 'C', '?', '<', '=', '-', 'R', '_',
272 '?', '?', '2', '3', '\'','u', 'P', '.', ',', '1', 'o', '>', '?', '?', '?',
273 '?', 'A', 'A', 'A', 'A', 'A', 'A', 'E', 'C', 'E', 'E', 'E', 'E', 'I', 'I',
274 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'x', '0', 'U', 'U', 'U', 'U',
275 'Y', 'p', 'S', 'a', 'a', 'a', 'a', 'a', 'a', 'e', 'c', 'e', 'e', 'e', 'e',
276 'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', '/', 'o', 'u', 'u',
277 'u', 'u', 'y', 'p', 'y' };
281 *us = ascii[*us - 161];
290 (This bit mostly cribbed from phosphor.c)
293 static void drain_input (sws_configuration *sc);
296 subproc_cb (XtPointer closure, int *source, XtInputId *id)
298 sws_configuration *sc = (sws_configuration *) closure;
304 launch_text_generator (sws_configuration *sc)
306 XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
307 char *oprogram = get_string_resource (sc->dpy, "program", "Program");
308 char *program = (char *) malloc (strlen (oprogram) + 10);
309 strcpy (program, "( ");
310 strcat (program, oprogram);
311 strcat (program, " ) 2>&1");
313 if ((sc->pipe = popen (program, "r")))
316 XtAppAddInput (app, fileno (sc->pipe),
317 (XtPointer) (XtInputReadMask | XtInputExceptMask),
318 subproc_cb, (XtPointer) sc);
328 relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
330 sws_configuration *sc = (sws_configuration *) closure;
331 if (!sc->pipe_timer) abort();
333 launch_text_generator (sc);
337 /* When the subprocess has generated some output, this reads as much as it
338 can into sc->buf at sc->buf_tail.
341 drain_input (sws_configuration *sc)
343 XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
344 if (sc->buf_tail < sc->buf_size - 2)
346 int target = sc->buf_size - sc->buf_tail - 2;
348 ? read (fileno (sc->pipe),
349 (void *) (sc->buf + sc->buf_tail),
355 sc->buf[sc->buf_tail] = 0;
361 XtRemoveInput (sc->pipe_id);
367 /* If the process didn't print a terminating newline, add one. */
368 if (sc->buf_tail > 1 &&
369 sc->buf[sc->buf_tail-1] != '\n')
371 sc->buf[sc->buf_tail++] = '\n';
372 sc->buf[sc->buf_tail] = 0;
375 /* Then add one more, just for giggles. */
376 sc->buf[sc->buf_tail++] = '\n';
377 sc->buf[sc->buf_tail] = 0;
379 /* Set up a timer to re-launch the subproc in a bit. */
380 sc->pipe_timer = XtAppAddTimeOut (app, sc->subproc_relaunch_delay,
381 relaunch_generator_timer,
389 string_width (sws_configuration *sc, const char *s)
392 return texture_string_width (sc->texfont, s, 0);
394 return glutStrokeLength (GLUT_FONT, (unsigned char *) s);
398 char_width (sws_configuration *sc, char c)
403 return string_width (sc, s);
407 /* Populates the sc->lines list with as many lines as are currently in
408 sc->buf (which was filled by drain_input().
411 get_more_lines (sws_configuration *sc)
413 /* wrap anyway, if it's absurdly long. */
414 int wrap_pix = (wrap_p ? sc->line_pixel_width : 10000);
420 while (sc->total_lines < max_lines)
424 if (s >= sc->buf + sc->buf_tail)
425 /* Reached end of buffer before end of line. Bail. */
428 cw = char_width (sc, *s);
430 if (*s == '\r' || *s == '\n' ||
431 col_pix + cw >= wrap_pix)
435 if (*s == '\r' || *s == '\n')
437 if (*s == '\r' && s[1] == '\n') /* swallow CRLF too */
444 /* We wrapped -- try to back up to the previous word boundary. */
447 while (s2 > sc->buf && *s2 != ' ' && *s2 != '\t')
457 sc->lines[sc->total_lines] = (char *) malloc (L+1);
458 memcpy (sc->lines[sc->total_lines], sc->buf, L);
459 sc->lines[sc->total_lines][L] = 0;
462 latin1_to_ascii (sc->lines[sc->total_lines]);
465 char *t = sc->lines[sc->total_lines];
466 char *ut = untabify (t);
467 strip (ut, (alignment == 0), 1); /* if centering, strip
468 leading whitespace too */
469 sc->lines[sc->total_lines] = ut;
475 if (sc->buf_tail > (s - sc->buf))
477 int i = sc->buf_tail - (s - sc->buf);
478 memmove (sc->buf, s, i);
480 sc->buf[sc->buf_tail] = 0;
487 sc->buf[sc->buf_tail] = 0;
498 int tab_pix = TAB_WIDTH * sc->char_width;
499 col = TAB_WIDTH * ((col / TAB_WIDTH) + 1);
500 col_pix = tab_pix * ((col / tab_pix) + 1);
509 draw_string (sws_configuration *sc, GLfloat x, GLfloat y, const char *s)
512 if (!s || !*s) return;
514 glTranslatef (x, y, 0);
517 print_texture_string (sc->texfont, s);
520 glutStrokeCharacter (GLUT_FONT, *s++);
526 GLfloat h = sc->line_height / sc->font_scale;
530 if (textures_p) glDisable (GL_TEXTURE_2D);
532 glColor3f (0.4, 0.4, 0.4);
534 glTranslatef (x, y, 0);
538 w = string_width (sc, c);
539 glBegin (GL_LINE_LOOP);
540 glVertex3f (0, 0, 0);
541 glVertex3f (w, 0, 0);
542 glVertex3f (w, h, 0);
543 glVertex3f (0, h, 0);
545 glTranslatef (w, 0, 0);
548 if (textures_p) glEnable (GL_TEXTURE_2D);
554 grid (double width, double height, double xspacing, double yspacing, double z)
557 for (y = 0; y <= height/2; y += yspacing)
560 glVertex3f(-width/2, y, z);
561 glVertex3f( width/2, y, z);
562 glVertex3f(-width/2, -y, z);
563 glVertex3f( width/2, -y, z);
566 for (x = 0; x <= width/2; x += xspacing)
569 glVertex3f( x, -height/2, z);
570 glVertex3f( x, height/2, z);
571 glVertex3f(-x, -height/2, z);
572 glVertex3f(-x, height/2, z);
577 glVertex3f(-width, 0, z);
578 glVertex3f( width, 0, z);
579 glVertex3f(0, -height, z);
580 glVertex3f(0, height, z);
585 box (double width, double height, double depth)
587 glBegin(GL_LINE_LOOP);
588 glVertex3f(-width/2, -height/2, -depth/2);
589 glVertex3f(-width/2, height/2, -depth/2);
590 glVertex3f( width/2, height/2, -depth/2);
591 glVertex3f( width/2, -height/2, -depth/2);
593 glBegin(GL_LINE_LOOP);
594 glVertex3f(-width/2, -height/2, depth/2);
595 glVertex3f(-width/2, height/2, depth/2);
596 glVertex3f( width/2, height/2, depth/2);
597 glVertex3f( width/2, -height/2, depth/2);
599 glBegin(GL_LINE_LOOP);
600 glVertex3f(-width/2, -height/2, -depth/2);
601 glVertex3f(-width/2, -height/2, depth/2);
602 glVertex3f(-width/2, height/2, depth/2);
603 glVertex3f(-width/2, height/2, -depth/2);
605 glBegin(GL_LINE_LOOP);
606 glVertex3f( width/2, -height/2, -depth/2);
607 glVertex3f( width/2, -height/2, depth/2);
608 glVertex3f( width/2, height/2, depth/2);
609 glVertex3f( width/2, height/2, -depth/2);
613 glVertex3f(-width/2, height/2, depth/2);
614 glVertex3f(-width/2, -height/2, -depth/2);
616 glVertex3f( width/2, height/2, depth/2);
617 glVertex3f( width/2, -height/2, -depth/2);
619 glVertex3f(-width/2, -height/2, depth/2);
620 glVertex3f(-width/2, height/2, -depth/2);
622 glVertex3f( width/2, -height/2, depth/2);
623 glVertex3f( width/2, height/2, -depth/2);
628 /* Construct stars (number of stars is dependent on size of screen) */
630 init_stars (ModeInfo *mi, int width, int height)
632 sws_configuration *sc = &scs[MI_SCREEN(mi)];
634 int size = (width > height ? width : height);
635 int nstars = size * size / 320;
638 int steps = max_size / inc;
640 glDeleteLists (sc->star_list, 1);
641 sc->star_list = glGenLists (1);
642 glNewList (sc->star_list, GL_COMPILE);
644 glEnable(GL_POINT_SMOOTH);
646 for (j = 1; j <= steps; j++)
648 glPointSize(inc * j);
650 for (i = 0; i < nstars / steps; i++)
652 glColor3f (0.6 + frand(0.3),
655 glVertex2f (2 * size * (0.5 - frand(1.0)),
656 2 * size * (0.5 - frand(1.0)));
664 /* Window management, etc
667 reshape_sws (ModeInfo *mi, int width, int height)
669 sws_configuration *sc = &scs[MI_SCREEN(mi)];
671 /* Set up matrices for perspective text display
674 GLfloat desired_aspect = (GLfloat) 3/4;
675 int w = mi->xgwa.width;
676 int h = mi->xgwa.height;
681 int h2 = w * desired_aspect;
682 yoff = (h - h2) / 2; /* Wide window: letterbox at top and bottom. */
683 if (yoff < 0) yoff = 0; /* Tall window: clip off the top. */
688 glMatrixMode (GL_PROJECTION);
689 glViewport (0, yoff, w, h);
691 glMatrixMode (GL_MODELVIEW);
693 gluPerspective (80.0, 1/desired_aspect, 1000, 55000);
694 gluLookAt (0.0, 0.0, 4600.0,
697 glRotatef (-60.0, 1.0, 0.0, 0.0);
700 glRotatef (60.0, 1.0, 0.0, 0.0);
701 glTranslatef (260, 3200, 0);
702 glScalef (1.85, 1.85, 1);
705 /* The above gives us an arena where the bottom edge of the screen is
706 represented by the line (-2100,-3140,0) - ( 2100,-3140,0). */
708 /* Now let's move the origin to the front of the screen. */
709 glTranslatef (0.0, -3140, 0.0);
711 /* And then let's scale so that the bottom of the screen is 1.0 wide. */
712 glScalef (4200, 4200, 4200);
716 /* Compute the height in pixels of the line at the bottom of the screen. */
718 GLdouble mm[17], pm[17];
720 GLfloat x = 0.5, y1 = 0, z = 0;
721 GLfloat y2 = sc->line_height;
722 GLdouble wx=-1, wy1=-1, wy2=-1, wz=-1;
724 glGetDoublev (GL_MODELVIEW_MATRIX, mm);
725 glGetDoublev (GL_PROJECTION_MATRIX, pm);
726 glGetIntegerv (GL_VIEWPORT, vp);
727 gluProject (x, y1, z, mm, pm, vp, &wx, &wy1, &wz);
728 gluProject (x, y2, z, mm, pm, vp, &wx, &wy2, &wz);
729 sc->line_pixel_height = (wy2 - wy1);
733 /* Compute the best looking line thickness for the bottom line.
736 sc->line_thickness = 1.0;
738 sc->line_thickness = (GLfloat) sc->line_pixel_height / FONT_WEIGHT;
740 if (sc->line_thickness < 1.2)
741 sc->line_thickness = 1.0;
746 gl_init (ModeInfo *mi)
748 sws_configuration *sc = &scs[MI_SCREEN(mi)];
750 program = get_string_resource (mi->dpy, "program", "Program");
752 glDisable (GL_LIGHTING);
753 glDisable (GL_DEPTH_TEST);
757 glEnable (GL_LINE_SMOOTH);
758 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
759 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
763 sc->text_list = glGenLists (1);
764 glNewList (sc->text_list, GL_COMPILE);
767 sc->star_list = glGenLists (1);
768 glNewList (sc->star_list, GL_COMPILE);
771 sc->line_thickness = 1.0;
776 init_sws (ModeInfo *mi)
780 sws_configuration *sc = 0;
783 scs = (sws_configuration *)
784 calloc (MI_NUM_SCREENS(mi), sizeof (sws_configuration));
786 fprintf(stderr, "%s: out of memory\n", progname);
791 sc = &scs[MI_SCREEN(mi)];
793 sc->dpy = MI_DISPLAY(mi);
794 sc = &scs[MI_SCREEN(mi)];
795 sc->lines = (char **) calloc (max_lines+1, sizeof(char *));
797 if ((sc->glx_context = init_GL(mi)) != NULL) {
799 reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
800 init_stars (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
806 sc->texfont = load_texture_font (MI_DISPLAY(mi), "font");
807 cw = texture_string_width (sc->texfont, "n", &lh);
810 glEnable(GL_ALPHA_TEST);
811 glEnable (GL_TEXTURE_2D);
813 check_gl_error ("loading font");
815 /* "Anistropic filtering helps for quadrilateral-angled textures.
816 A sharper image is accomplished by interpolating and filtering
817 multiple samples from one or more mipmaps to better approximate
818 very distorted textures. This is the next level of filtering
819 after trilinear filtering." */
821 strstr ((char *) glGetString(GL_EXTENSIONS),
822 "GL_EXT_texture_filter_anisotropic"))
824 GLfloat anisotropic = 0.0;
825 glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic);
826 if (anisotropic >= 1.0)
827 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
833 font_height = GLUT_FONT->top - GLUT_FONT->bottom;
834 sc->char_width = glutStrokeWidth (GLUT_FONT, 'z'); /* 'n' seems wide */
837 sc->font_scale = 1.0 / sc->char_width;
840 /* We consider a font that consumes 80 columns to be "18 points".
842 If neither -size nor -columns was specified, default to 60 columns
843 (which is 24 points.)
845 If both were specified, -columns has priority.
851 if (target_columns <= 0 && font_size <= 0)
854 if (target_columns > 0)
855 font_size = base_size * (base_col / (double) target_columns);
856 else if (font_size > 0)
857 target_columns = base_col * (base_size / (double) font_size);
860 sc->line_pixel_width = target_columns * sc->char_width;
862 sc->font_scale /= target_columns;
863 sc->line_height = font_height * sc->font_scale;
866 /* Buffer only two lines of text.
867 If the buffer is too big, there's a significant delay between
868 when the program launches and when the text appears, which can be
869 irritating for time-sensitive output (clock, current music, etc.)
871 sc->buf_size = target_columns * 2;
872 if (sc->buf_size < 80) sc->buf_size = 80;
873 sc->buf = (char *) calloc (1, sc->buf_size);
875 sc->subproc_relaunch_delay = 2 * 1000; /* 2 seconds */
876 sc->total_lines = max_lines-1;
879 star_spin = -star_spin;
881 if (!alignment_str || !*alignment_str ||
882 !strcasecmp(alignment_str, "left"))
884 else if (!strcasecmp(alignment_str, "center") ||
885 !strcasecmp(alignment_str, "middle"))
887 else if (!strcasecmp(alignment_str, "right"))
892 "%s: alignment must be left, center, or right, not \"%s\"\n",
893 progname, alignment_str);
897 launch_text_generator (sc);
899 /* one more reshape, after line_height has been computed */
900 reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
905 draw_stars (ModeInfo *mi)
907 sws_configuration *sc = &scs[MI_SCREEN(mi)];
909 glMatrixMode (GL_PROJECTION);
914 glMatrixMode (GL_MODELVIEW);
918 glOrtho (-0.5 * MI_WIDTH(mi), 0.5 * MI_WIDTH(mi),
919 -0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
921 glRotatef (sc->star_theta, 0.0, 0.0, 1.0);
922 if (textures_p) glDisable (GL_TEXTURE_2D);
923 glCallList (sc->star_list);
924 if (textures_p) glEnable (GL_TEXTURE_2D);
928 glMatrixMode (GL_PROJECTION);
933 draw_sws (ModeInfo *mi)
935 sws_configuration *sc = &scs[MI_SCREEN(mi)];
936 /* XtAppContext app = XtDisplayToApplicationContext (sc->dpy);*/
937 Display *dpy = MI_DISPLAY(mi);
938 Window window = MI_WINDOW(mi);
941 if (!sc->glx_context)
945 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
946 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
949 glDrawBuffer (GL_BACK);
950 glXMakeCurrent (dpy, window, *(sc->glx_context));
952 glClear (GL_COLOR_BUFFER_BIT);
956 glMatrixMode (GL_MODELVIEW);
963 if (textures_p) glDisable (GL_TEXTURE_2D);
965 glColor3f (0.4, 0.4, 0.4);
966 glTranslatef (0,-1, 0);
967 for (i = 0; i < 16; i++)
970 grid (1, 1, sc->char_width * sc->font_scale, sc->line_height, 0);
971 glTranslatef(0, 1, 0);
973 if (textures_p) glEnable (GL_TEXTURE_2D);
977 /* Scroll to current position */
978 glTranslatef (0.0, sc->intra_line_scroll, 0.0);
980 glColor3f (1.0, 1.0, 0.4);
981 glCallList (sc->text_list);
982 mi->polygon_count = sc->polygon_count;
984 sc->intra_line_scroll += sc->line_height / scroll_steps;
986 if (sc->intra_line_scroll >= sc->line_height)
988 sc->intra_line_scroll = 0;
990 /* Drop the oldest line off the end. */
994 /* Scroll the contents of the lines array toward 0. */
995 if (sc->total_lines > 0)
997 for (i = 1; i < sc->total_lines; i++)
998 sc->lines[i-1] = sc->lines[i];
999 sc->lines[--sc->total_lines] = 0;
1002 /* Bring in new lines at the end. */
1003 get_more_lines (sc);
1005 if (sc->total_lines < max_lines)
1006 /* Oops, we ran out of text... well, insert some blank lines
1007 here so that new text still pulls in from the bottom of
1008 the screen, isntead of just appearing. */
1009 sc->total_lines = max_lines;
1011 glDeleteLists (sc->text_list, 1);
1012 sc->text_list = glGenLists (1);
1013 glNewList (sc->text_list, GL_COMPILE);
1014 sc->polygon_count = 0;
1016 glScalef (sc->font_scale, sc->font_scale, sc->font_scale);
1017 for (i = 0; i < sc->total_lines; i++)
1019 double fade = (fade_p ? 1.0 * i / sc->total_lines : 1.0);
1020 int offscreen_lines = 2;
1023 double y = ((sc->total_lines - (i + offscreen_lines) - 1)
1026 char *line = sc->lines[i];
1030 double xx = x * 1.4; /* a little more to the left */
1032 sprintf(n, "%d:", i);
1033 draw_string (sc, xx / sc->font_scale, y / sc->font_scale, n);
1036 if (!line || !*line)
1039 if (sc->line_thickness != 1 && !textures_p)
1041 int max_thick_lines = MAX_THICK_LINES;
1042 GLfloat thinnest_line = 1.0;
1043 GLfloat thickest_line = sc->line_thickness;
1044 GLfloat range = thickest_line - thinnest_line;
1047 int j = sc->total_lines - i - 1;
1049 if (j > max_thick_lines)
1050 thickness = thinnest_line;
1052 thickness = (thinnest_line +
1053 (range * ((max_thick_lines - j) /
1054 (GLfloat) max_thick_lines)));
1056 glLineWidth (thickness);
1061 int n = string_width (sc, line);
1062 xoff = 1.0 - (n * sc->font_scale);
1068 glColor3f (fade, fade, 0.5 * fade);
1069 draw_string (sc, (x + xoff) / sc->font_scale, y / sc->font_scale,
1072 sc->polygon_count += strlen (line);
1080 if (mi->fps_p) do_fps (mi);
1082 glXSwapBuffers(dpy, window);
1084 sc->star_theta += star_spin;
1088 release_sws (ModeInfo *mi)
1092 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1093 sws_configuration *sc = &scs[screen];
1095 XtRemoveInput (sc->pipe_id);
1099 XtRemoveTimeOut (sc->pipe_timer);
1101 /* #### there's more to free here */
1110 XSCREENSAVER_MODULE_2 ("StarWars", starwars, sws)