1 /* starwars, Copyright (c) 1998-2015 Jamie Zawinski <jwz@jwz.org> and
2 * Claudio Matsuoka <claudio@helllabs.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * Star Wars -- Phosphor meets a well-known scroller from a galaxy far,
15 * Feb 2000 Claudio Matsuoka First version.
16 * Jan 2001 Jamie Zawinski Rewrote large sections to add the ability to
17 * run a subprocess, customization of the font
18 * size and other parameters, etc.
19 * Feb 2001 jepler@inetnebr.com Added anti-aliased lines, and fade-to-black.
20 * Feb 2005 Jamie Zawinski Added texture fonts.
25 * starwars -program 'cat starwars.txt' -columns 25 -no-wrap
30 #endif /* HAVE_CONFIG_H */
40 #define DEFAULTS "*delay: 40000 \n" \
41 "*showFPS: False \n" \
44 "*texFontCacheSize: 300\n" \
45 "*font: " DEF_FONT "\n" \
46 "*textLiteral: " DEF_TEXT "\n" \
47 "*program: xscreensaver-text --cols 0" /* don't wrap */
49 # define release_sws 0
50 # define sws_handle_event xlockmore_no_events
52 #define countof(x) (sizeof((x))/sizeof((*x)))
54 #include "xlockmore.h"
55 #include "textclient.h"
58 #ifdef USE_GL /* whole file */
60 /* Should be in <GL/glext.h> */
61 # ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
62 # define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
64 # ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
65 # define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
69 #define DEF_LINES "125"
70 #define DEF_STEPS "35"
71 #define DEF_SPIN "0.03"
73 #define DEF_COLUMNS "-1"
74 #define DEF_LINE_WRAP "True"
75 #define DEF_ALIGNMENT "Center"
76 #define DEF_SMOOTH "True"
77 #define DEF_THICK "True"
78 #define DEF_FADE "True"
79 #define DEF_TEXTURES "True"
80 #define DEF_DEBUG "False"
82 #define DEF_FONT "-*-utopia-bold-r-normal-*-*-360-*-*-*-*-*-*"
86 #define MAX_THICK_LINES 25
87 #define FONT_WEIGHT 14
90 # define KEEP_ASPECT /* Letterboxing looks dumb on iPhone. */
94 #include "glutstroke.h"
95 #include "glut_roman.h"
96 #define GLUT_FONT (&glutStrokeRoman)
100 GLXContext *glx_context;
102 GLuint text_list, star_list;
103 texture_font_data *texfont;
119 double intra_line_scroll;
121 int line_pixel_width; /* in font units (for wrapping text) */
122 int line_pixel_height; /* in screen units (for computing line thickness) */
123 GLfloat line_thickness;
128 static sws_configuration *scs = NULL;
130 static int max_lines;
131 static int scroll_steps;
132 static float star_spin;
133 static float font_size;
134 static int target_columns;
139 static int textures_p;
141 static char *alignment_str;
142 static int alignment;
144 static XrmOptionDescRec opts[] = {
145 {"-lines", ".lines", XrmoptionSepArg, 0 },
146 {"-steps", ".steps", XrmoptionSepArg, 0 },
147 {"-spin", ".spin", XrmoptionSepArg, 0 },
148 {"-size", ".size", XrmoptionSepArg, 0 },
149 {"-columns", ".columns", XrmoptionSepArg, 0 },
150 /*{"-font", ".font", XrmoptionSepArg, 0 },*/
151 {"-fade", ".fade", XrmoptionNoArg, "True" },
152 {"-no-fade", ".fade", XrmoptionNoArg, "False" },
153 {"-textures", ".textures", XrmoptionNoArg, "True" },
154 {"-smooth", ".smooth", XrmoptionNoArg, "True" },
155 {"-no-smooth", ".smooth", XrmoptionNoArg, "False" },
156 {"-thick", ".thick", XrmoptionNoArg, "True" },
157 {"-no-thick", ".thick", XrmoptionNoArg, "False" },
158 {"-no-textures", ".textures", XrmoptionNoArg, "False" },
159 {"-wrap", ".lineWrap", XrmoptionNoArg, "True" },
160 {"-no-wrap", ".lineWrap", XrmoptionNoArg, "False" },
161 {"-nowrap", ".lineWrap", XrmoptionNoArg, "False" },
162 {"-alignment", ".alignment", XrmoptionSepArg, 0 },
163 {"-left", ".alignment", XrmoptionNoArg, "Left" },
164 {"-right", ".alignment", XrmoptionNoArg, "Right" },
165 {"-center", ".alignment", XrmoptionNoArg, "Center" },
166 {"-debug", ".debug", XrmoptionNoArg, "True" },
169 static argtype vars[] = {
170 {&max_lines, "lines", "Integer", DEF_LINES, t_Int},
171 {&scroll_steps, "steps", "Integer", DEF_STEPS, t_Int},
172 {&star_spin, "spin", "Float", DEF_SPIN, t_Float},
173 {&font_size, "size", "Float", DEF_SIZE, t_Float},
174 {&target_columns, "columns", "Integer", DEF_COLUMNS, t_Int},
175 {&wrap_p, "lineWrap", "Boolean", DEF_LINE_WRAP, t_Bool},
176 {&alignment_str, "alignment", "Alignment", DEF_ALIGNMENT, t_String},
177 {&smooth_p, "smooth", "Boolean", DEF_SMOOTH, t_Bool},
178 {&thick_p, "thick", "Boolean", DEF_THICK, t_Bool},
179 {&fade_p, "fade", "Boolean", DEF_FADE, t_Bool},
180 {&textures_p, "textures", "Boolean", DEF_TEXTURES, t_Bool},
181 {&debug_p, "debug", "Boolean", DEF_DEBUG, t_Bool},
184 ENTRYPOINT ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
188 /* Tabs are bad, mmmkay? */
191 untabify (const char *string)
193 const char *ostring = string;
194 char *result = (char *) malloc ((strlen(string) * 8) + 1);
204 } while (col % TAB_WIDTH);
207 else if (*string == '\r' || *string == '\n')
212 else if (*string == '\010') /* backspace */
214 if (string > ostring)
229 strip (char *s, Bool leading, Bool trailing)
233 while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
238 while (*s2 == ' ' || *s2 == '\t')
250 sw_string_width (sws_configuration *sc, const char *s)
255 texture_string_metrics (sc->texfont, s, &e, 0, 0);
259 return glutStrokeLength (GLUT_FONT, (unsigned char *) s);
264 sw_string_width2 (sws_configuration *sc, const char *s, size_t size)
266 char *s2 = (char *) malloc (size + 1);
269 strncpy (s2, s, size);
272 result = sw_string_width (sc, s2);
279 /* Populates the sc->lines list with as many lines as possible.
282 get_more_lines (sws_configuration *sc)
284 /* wrap anyway, if it's absurdly long. */
285 int wrap_pix = (wrap_p ? sc->line_pixel_width : 10000);
289 int target = sc->buf_size - sc->buf_tail - 2;
291 /* Fill as much as we can into sc->buf.
295 int c = textclient_getc (sc->tc);
298 sc->buf[sc->buf_tail++] = (char) c;
299 sc->buf[sc->buf_tail] = 0;
303 while (sc->total_lines < max_lines)
306 unsigned counter = 0;
308 /* OS X is really slow to calcuate the bounds for a line of text,
311 Really though, the right thing to do is probably to wrap
312 CTLineCreateTruncatedLine, one way or another. */
315 if (next_s >= sc->buf + sc->buf_tail)
321 sw_string_width2 (sc, sc->buf, next_s - sc->buf) >= wrap_pix)
324 counter = 12; /* <-- Adjust to taste. */
328 if (*next_s == '\r' || *next_s == '\n')
337 if (s >= sc->buf + sc->buf_tail)
338 /* Reached end of buffer before end of line. Bail. */
341 /* When checking pixel width, always measure the line from the
342 beginning, or else multi-byte UTF-8 characters, particularly
343 combining diacriticals, aren't measured right. */
345 if (*s == '\r' || *s == '\n' ||
346 (s > sc->buf && sw_string_width2 (sc, sc->buf, s - sc->buf) >= wrap_pix))
350 if (*s == '\r' || *s == '\n')
352 if (*s == '\r' && s[1] == '\n') /* swallow CRLF too */
359 /* We wrapped -- try to back up to the previous word boundary. */
362 while (s2 > sc->buf && *s2 != ' ' && *s2 != '\t')
372 sc->lines[sc->total_lines] = (char *) malloc (L+1);
373 memcpy (sc->lines[sc->total_lines], sc->buf, L);
374 sc->lines[sc->total_lines][L] = 0;
378 /* The GLUT font only has ASCII characters. */
379 char *s1 = utf8_to_latin1 (sc->lines[sc->total_lines], True);
380 free (sc->lines[sc->total_lines]);
381 sc->lines[sc->total_lines] = s1;
385 char *t = sc->lines[sc->total_lines];
386 char *ut = untabify (t);
387 strip (ut, (alignment == 0), 1); /* if centering, strip
388 leading whitespace too */
389 sc->lines[sc->total_lines] = ut;
393 sc->line_widths[sc->total_lines] =
394 sw_string_width(sc, sc->lines[sc->total_lines]);
398 if (sc->buf_tail > (s - sc->buf))
400 int i = sc->buf_tail - (s - sc->buf);
401 memmove (sc->buf, s, i);
403 sc->buf[sc->buf_tail] = 0;
410 sc->buf[sc->buf_tail] = 0;
425 draw_string (sws_configuration *sc, GLfloat x, GLfloat y, const char *s)
428 if (!s || !*s) return;
430 glTranslatef (x, y, 0);
433 print_texture_string (sc->texfont, s);
436 glutStrokeCharacter (GLUT_FONT, *s++);
441 GLfloat h = sc->line_height / sc->font_scale;
442 char **chars = utf8_split (os, 0);
444 char *s2 = (char *) malloc (strlen(s) + 1);
447 if (textures_p) glDisable (GL_TEXTURE_2D);
450 glColor3f (0.2, 0.2, 0.5);
454 for (i = 0; chars[i]; i++)
456 glVertex3f (x + w, y - sc->descent, 0); /* char left */
457 glVertex3f (x + w, y - sc->descent + h, 0);
458 strcat (s2, chars[i]);
459 w = sw_string_width (sc, s2);
463 glVertex3f (x + w, y - sc->descent, 0); /* char right */
464 glVertex3f (x + w, y - sc->descent + h, 0);
466 glVertex3f (x, y - sc->descent + h, 0); /* ascent */
467 glVertex3f (x + w, y - sc->descent + h, 0);
469 glVertex3f (x - sc->char_width, y, 0); /* baseline */
470 glVertex3f (x + sc->char_width + w, y, 0);
472 glVertex3f (x, y - sc->descent, 0); /* descent */
473 glVertex3f (x + w, y - sc->descent, 0);
480 if (textures_p) glEnable (GL_TEXTURE_2D);
486 grid (double width, double height, double xspacing, double yspacing, double z)
489 for (y = 0; y <= height/2; y += yspacing)
492 glVertex3f(-width/2, y, z);
493 glVertex3f( width/2, y, z);
494 glVertex3f(-width/2, -y, z);
495 glVertex3f( width/2, -y, z);
498 for (x = 0; x <= width/2; x += xspacing)
501 glVertex3f( x, -height/2, z);
502 glVertex3f( x, height/2, z);
503 glVertex3f(-x, -height/2, z);
504 glVertex3f(-x, height/2, z);
509 glVertex3f(-width, 0, z);
510 glVertex3f( width, 0, z);
511 glVertex3f(0, -height, z);
512 glVertex3f(0, height, z);
517 box (double width, double height, double depth)
519 glBegin(GL_LINE_LOOP);
520 glVertex3f(-width/2, -height/2, -depth/2);
521 glVertex3f(-width/2, height/2, -depth/2);
522 glVertex3f( width/2, height/2, -depth/2);
523 glVertex3f( width/2, -height/2, -depth/2);
525 glBegin(GL_LINE_LOOP);
526 glVertex3f(-width/2, -height/2, depth/2);
527 glVertex3f(-width/2, height/2, depth/2);
528 glVertex3f( width/2, height/2, depth/2);
529 glVertex3f( width/2, -height/2, depth/2);
531 glBegin(GL_LINE_LOOP);
532 glVertex3f(-width/2, -height/2, -depth/2);
533 glVertex3f(-width/2, -height/2, depth/2);
534 glVertex3f(-width/2, height/2, depth/2);
535 glVertex3f(-width/2, height/2, -depth/2);
537 glBegin(GL_LINE_LOOP);
538 glVertex3f( width/2, -height/2, -depth/2);
539 glVertex3f( width/2, -height/2, depth/2);
540 glVertex3f( width/2, height/2, depth/2);
541 glVertex3f( width/2, height/2, -depth/2);
545 glVertex3f(-width/2, height/2, depth/2);
546 glVertex3f(-width/2, -height/2, -depth/2);
548 glVertex3f( width/2, height/2, depth/2);
549 glVertex3f( width/2, -height/2, -depth/2);
551 glVertex3f(-width/2, -height/2, depth/2);
552 glVertex3f(-width/2, height/2, -depth/2);
554 glVertex3f( width/2, -height/2, depth/2);
555 glVertex3f( width/2, height/2, -depth/2);
560 /* Construct stars (number of stars is dependent on size of screen) */
562 init_stars (ModeInfo *mi, int width, int height)
564 sws_configuration *sc = &scs[MI_SCREEN(mi)];
566 int size = (width > height ? width : height);
567 int nstars = size * size / 320;
570 int steps = max_size / inc;
572 glDeleteLists (sc->star_list, 1);
573 sc->star_list = glGenLists (1);
574 glNewList (sc->star_list, GL_COMPILE);
576 glEnable(GL_POINT_SMOOTH);
578 for (j = 1; j <= steps; j++)
580 glPointSize(inc * j);
582 for (i = 0; i < nstars / steps; i++)
584 glColor3f (0.6 + frand(0.3),
587 glVertex2f (2 * size * (0.5 - frand(1.0)),
588 2 * size * (0.5 - frand(1.0)));
596 /* Window management, etc
599 reshape_sws (ModeInfo *mi, int width, int height)
601 sws_configuration *sc = &scs[MI_SCREEN(mi)];
603 /* Set up matrices for perspective text display
606 GLfloat desired_aspect = (GLfloat) 3/4;
607 int w = mi->xgwa.width;
608 int h = mi->xgwa.height;
610 GLfloat rot = current_device_rotation();
614 int h2 = w * desired_aspect;
615 yoff = (h - h2) / 2; /* Wide window: letterbox at top and bottom. */
616 if (yoff < 0) yoff = 0; /* Tall window: clip off the top. */
621 glViewport (0, yoff, w, h);
623 glMatrixMode (GL_PROJECTION);
626 glMatrixMode (GL_MODELVIEW);
628 gluPerspective (80.0, 1/desired_aspect, 1000, 55000);
629 gluLookAt (0.0, 0.0, 4600.0,
633 /* Horrible kludge to prevent the text from materializing already
634 on screen on iPhone in landscape mode.
636 if ((rot > 45 && rot < 135) ||
637 (rot < -45 && rot > -135))
643 glRotatef (-60.0, 1.0, 0.0, 0.0);
646 glRotatef (60.0, 1.0, 0.0, 0.0);
647 glTranslatef (260, 3200, 0);
648 glScalef (1.85, 1.85, 1);
651 /* The above gives us an arena where the bottom edge of the screen is
652 represented by the line (-2100,-3140,0) - ( 2100,-3140,0). */
654 /* Now let's move the origin to the front of the screen. */
655 glTranslatef (0.0, -3140, 0.0);
657 /* And then let's scale so that the bottom of the screen is 1.0 wide. */
658 glScalef (4200, 4200, 4200);
662 /* Compute the height in pixels of the line at the bottom of the screen. */
664 GLdouble mm[17], pm[17];
666 GLdouble x = 0.5, y1 = 0, z = 0;
667 GLdouble y2 = sc->line_height;
668 GLdouble wx=-1, wy1=-1, wy2=-1, wz=-1;
670 glGetDoublev (GL_MODELVIEW_MATRIX, mm);
671 glGetDoublev (GL_PROJECTION_MATRIX, pm);
672 glGetIntegerv (GL_VIEWPORT, vp);
673 gluProject (x, y1, z, mm, pm, vp, &wx, &wy1, &wz);
674 gluProject (x, y2, z, mm, pm, vp, &wx, &wy2, &wz);
675 sc->line_pixel_height = (wy2 - wy1);
679 /* Compute the best looking line thickness for the bottom line.
682 sc->line_thickness = 1.0;
684 sc->line_thickness = (GLfloat) sc->line_pixel_height / FONT_WEIGHT;
686 if (sc->line_thickness < 1.2)
687 sc->line_thickness = 1.0;
692 gl_init (ModeInfo *mi)
694 sws_configuration *sc = &scs[MI_SCREEN(mi)];
696 glDisable (GL_LIGHTING);
697 glDisable (GL_DEPTH_TEST);
701 glEnable (GL_LINE_SMOOTH);
702 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
703 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
707 sc->text_list = glGenLists (1);
708 glNewList (sc->text_list, GL_COMPILE);
711 sc->star_list = glGenLists (1);
712 glNewList (sc->star_list, GL_COMPILE);
715 sc->line_thickness = 1.0;
720 init_sws (ModeInfo *mi)
724 sws_configuration *sc = 0;
728 sc = &scs[MI_SCREEN(mi)];
730 sc->dpy = MI_DISPLAY(mi);
731 sc = &scs[MI_SCREEN(mi)];
732 /* Unchecked malloc. :( */
733 sc->lines = (char **) calloc (max_lines+1, sizeof(char *));
734 sc->line_widths = (int *) calloc (max_lines+1, sizeof(int));
736 if ((sc->glx_context = init_GL(mi)) != NULL) {
738 reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
739 clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */
741 init_stars (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
747 int cw, ascent, descent;
748 sc->texfont = load_texture_font (MI_DISPLAY(mi), "font");
749 texture_string_metrics (sc->texfont, "n", &e, &ascent, &descent);
752 font_height = ascent + descent;
753 sc->descent = descent;
754 glEnable(GL_ALPHA_TEST);
755 glEnable (GL_TEXTURE_2D);
757 check_gl_error ("loading font");
759 /* "Anistropic filtering helps for quadrilateral-angled textures.
760 A sharper image is accomplished by interpolating and filtering
761 multiple samples from one or more mipmaps to better approximate
762 very distorted textures. This is the next level of filtering
763 after trilinear filtering." */
765 strstr ((char *) glGetString(GL_EXTENSIONS),
766 "GL_EXT_texture_filter_anisotropic"))
768 GLfloat anisotropic = 0.0;
769 glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic);
770 if (anisotropic >= 1.0)
771 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
777 font_height = GLUT_FONT->top - GLUT_FONT->bottom;
778 sc->char_width = glutStrokeWidth (GLUT_FONT, 'z'); /* 'n' seems wide */
782 sc->font_scale = 1.0 / sc->char_width;
785 /* We consider a font that consumes 80 columns to be "18 points".
787 If neither -size nor -columns was specified, default to 60 columns
788 (which is 24 points.)
790 If both were specified, -columns has priority.
796 if (target_columns <= 0 && font_size <= 0)
799 if (target_columns > 0)
800 font_size = base_size * (base_col / (double) target_columns);
801 else if (font_size > 0)
802 target_columns = base_col * (base_size / (double) font_size);
805 sc->line_pixel_width = target_columns * sc->char_width;
807 sc->font_scale /= target_columns;
808 sc->line_height = font_height * sc->font_scale;
810 /* Buffer only a few lines of text.
811 If the buffer is too big, there's a significant delay between
812 when the program launches and when the text appears, which can be
813 irritating for time-sensitive output (clock, current music, etc.)
815 I'd like to buffer only 2 lines, but we need to assume that we
816 could get a whole line of N-byte Unicrud, and if we fill the buffer
817 before hitting the end of the line, we stall.
819 sc->buf_size = target_columns * 2 * 4;
820 if (sc->buf_size < 80) sc->buf_size = 80;
821 sc->buf = (char *) calloc (1, sc->buf_size);
823 sc->total_lines = max_lines-1;
826 star_spin = -star_spin;
828 if (!alignment_str || !*alignment_str ||
829 !strcasecmp(alignment_str, "left"))
831 else if (!strcasecmp(alignment_str, "center") ||
832 !strcasecmp(alignment_str, "middle"))
834 else if (!strcasecmp(alignment_str, "right"))
839 "%s: alignment must be left, center, or right, not \"%s\"\n",
840 progname, alignment_str);
844 sc->tc = textclient_open (sc->dpy);
846 /* one more reshape, after line_height has been computed */
847 reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
852 draw_stars (ModeInfo *mi)
854 sws_configuration *sc = &scs[MI_SCREEN(mi)];
856 glMatrixMode (GL_PROJECTION);
861 glMatrixMode (GL_MODELVIEW);
865 glOrtho (-0.5 * MI_WIDTH(mi), 0.5 * MI_WIDTH(mi),
866 -0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
868 glRotatef (sc->star_theta, 0.0, 0.0, 1.0);
869 if (textures_p) glDisable (GL_TEXTURE_2D);
871 glCallList (sc->star_list);
872 if (textures_p) glEnable (GL_TEXTURE_2D);
876 glMatrixMode (GL_PROJECTION);
881 draw_sws (ModeInfo *mi)
883 sws_configuration *sc = &scs[MI_SCREEN(mi)];
884 /* XtAppContext app = XtDisplayToApplicationContext (sc->dpy);*/
885 Display *dpy = MI_DISPLAY(mi);
886 Window window = MI_WINDOW(mi);
889 if (!sc->glx_context)
892 glDrawBuffer (GL_BACK);
893 glXMakeCurrent (dpy, window, *(sc->glx_context));
895 glClear (GL_COLOR_BUFFER_BIT);
899 glMatrixMode (GL_MODELVIEW);
903 /* Need to do this every time to get device rotation right */
904 reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
911 if (textures_p) glDisable (GL_TEXTURE_2D);
913 glTranslatef (0,-1, 0);
915 glColor3f(1, 0, 0); /* Red line is where text appears */
917 glTranslatef(0, -0.028, 0);
920 glVertex3f(-0.5, 1, 0);
921 glVertex3f( 0.5, 1, 0);
922 glVertex3f(-0.5, -1, 0);
923 glVertex3f( 0.5, -1, 0);
928 glColor3f (0.2, 0.2, 0.2);
929 for (i = 0; i < 16; i++)
932 grid (1, 1, sc->char_width * sc->font_scale, sc->line_height, 0);
933 glTranslatef(0, 1, 0);
935 if (textures_p) glEnable (GL_TEXTURE_2D);
937 check_gl_error ("debug render");
940 /* Scroll to current position */
941 glTranslatef (0.0, sc->intra_line_scroll, 0.0);
943 glColor3f (1.0, 1.0, 0.4);
945 mi->polygon_count = 0;
948 glScalef (sc->font_scale, sc->font_scale, sc->font_scale);
949 for (i = 0; i < sc->total_lines; i++)
951 double fade = (fade_p ? 1.0 * i / sc->total_lines : 1.0);
952 int offscreen_lines = 2;
955 double y = ((sc->total_lines - (i + offscreen_lines) - 1)
958 char *line = sc->lines[i];
962 double xx = x * 1.4; /* a little more to the left */
964 sprintf(n, "%d:", i);
965 glColor3f (1.0, 1.0, 1.0);
966 draw_string (sc, xx / sc->font_scale, y / sc->font_scale, n);
972 if (sc->line_thickness != 1 && !textures_p)
974 int max_thick_lines = MAX_THICK_LINES;
975 GLfloat thinnest_line = 1.0;
976 GLfloat thickest_line = sc->line_thickness;
977 GLfloat range = thickest_line - thinnest_line;
980 int j = sc->total_lines - i - 1;
982 if (j > max_thick_lines)
983 thickness = thinnest_line;
985 thickness = (thinnest_line +
986 (range * ((max_thick_lines - j) /
987 (GLfloat) max_thick_lines)));
989 glLineWidth (thickness);
994 int n = sc->line_widths[i];
995 xoff = 1.0 - (n * sc->font_scale);
1001 glColor3f (fade, fade, 0.5 * fade);
1002 draw_string (sc, (x + xoff) / sc->font_scale, y / sc->font_scale,
1005 mi->polygon_count += strlen (line);
1011 sc->intra_line_scroll += sc->line_height / scroll_steps;
1013 if (sc->intra_line_scroll >= sc->line_height)
1015 sc->intra_line_scroll = 0;
1017 /* Drop the oldest line off the end. */
1019 free (sc->lines[0]);
1021 /* Scroll the contents of the lines array toward 0. */
1022 if (sc->total_lines > 0)
1024 for (i = 1; i < sc->total_lines; i++) {
1025 sc->lines[i-1] = sc->lines[i];
1026 sc->line_widths[i-1] = sc->line_widths[i];
1028 sc->lines[--sc->total_lines] = 0;
1031 /* Bring in new lines at the end. */
1032 get_more_lines (sc);
1034 if (sc->total_lines < max_lines)
1035 /* Oops, we ran out of text... well, insert some blank lines
1036 here so that new text still pulls in from the bottom of
1037 the screen, isntead of just appearing. */
1038 sc->total_lines = max_lines;
1043 if (mi->fps_p) do_fps (mi);
1045 glXSwapBuffers(dpy, window);
1047 sc->star_theta += star_spin;
1051 free_sws (ModeInfo *mi)
1053 sws_configuration *sc = &scs[MI_SCREEN(mi)];
1055 textclient_close (sc->tc);
1057 /* #### there's more to free here */
1062 __extension__ /* don't warn about "string length is greater than the length
1063 ISO C89 compilers are required to support" when including
1064 "starwars.txt" in the defaults... */
1067 XSCREENSAVER_MODULE_2 ("StarWars", starwars, sws)