ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / glx / starwars.c
index d29c37d8818f717784d69382cbc4a8c6227c5250..60f766a72514e576e63a11aa105901f098e0dc79 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * starwars, Copyright (c) 1998-2001 Jamie Zawinski <jwz@jwz.org> and
- * Claudio Matauoka <claudio@helllabs.org>
+ * starwars, Copyright (c) 1998-2001, 2004 Jamie Zawinski <jwz@jwz.org> and
+ * Claudio Matsuoka <claudio@helllabs.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -29,6 +29,8 @@
  *           20010124 jwz       Rewrote large sections to add the ability to
  *                              run a subprocess, customization of the font
  *                              size and other parameters, etc.
+ *           20010224 jepler@mail.inetnebr.com  made the lines be anti-aliased,
+ *                              made the text fade to black at the end.
  */
 
 #include <X11/Intrinsic.h>
@@ -41,20 +43,27 @@ extern XtAppContext app;
 #define HACK_RESHAPE   reshape_sws
 #define sws_opts       xlockmore_opts
 
-#define DEF_PROGRAM    ZIPPY_PROGRAM
-#define DEF_LINES      "500"
+#define DEF_PROGRAM    "(default)"
+#define DEF_LINES      "125"
 #define DEF_STEPS      "35"
 #define DEF_SPIN       "0.03"
 #define DEF_FONT_SIZE  "-1"
 #define DEF_COLUMNS    "-1"
 #define DEF_WRAP       "True"
 #define DEF_ALIGN      "Center"
+#define DEF_SMOOTH     "True"
+#define DEF_THICK      "True"
+#define DEF_FADE       "True"
 
 #define TAB_WIDTH        8
 
 #define BASE_FONT_SIZE    18 /* magic */
 #define BASE_FONT_COLUMNS 80 /* magic */
 
+#define MAX_THICK_LINES   25
+#define FONT_WEIGHT       14
+#define KEEP_ASPECT
+#undef DEBUG
 
 #define DEFAULTS       "*delay:        40000 \n"                    \
                        "*showFPS:      False \n"                    \
@@ -63,6 +72,9 @@ extern XtAppContext app;
                        "*lines:        " DEF_LINES             "\n" \
                        "*spin:         " DEF_SPIN              "\n" \
                        "*steps:        " DEF_STEPS             "\n" \
+                        "*smooth:       " DEF_SMOOTH            "\n" \
+                        "*thick:        " DEF_THICK             "\n" \
+                        "*fade:         " DEF_FADE              "\n" \
                        "*starwars.fontSize: " DEF_FONT_SIZE    "\n" \
                        "*starwars.columns:  " DEF_COLUMNS      "\n" \
                        "*starwars.lineWrap: " DEF_WRAP         "\n" \
@@ -75,11 +87,17 @@ extern XtAppContext app;
 
 #ifdef USE_GL /* whole file */
 
+#include <ctype.h>
 #include <GL/glu.h>
+#include <sys/stat.h>
 #include "glutstroke.h"
 #include "glut_roman.h"
 #define GLUT_FONT (&glutStrokeRoman)
 
+#ifdef HAVE_UNAME
+# include <sys/utsname.h>
+#endif /* HAVE_UNAME */
+
 
 typedef struct {
   GLXContext *glx_context;
@@ -101,6 +119,9 @@ typedef struct {
   double font_scale;
   double intra_line_scroll;
 
+  int line_pixel_height;
+  GLfloat line_thickness;
+
 } sws_configuration;
 
 
@@ -113,33 +134,45 @@ static float star_spin;
 static float font_size;
 static int target_columns;
 static int wrap_p;
+static int smooth_p;
+static int thick_p;
+static int fade_p;
 static char *alignment_str;
 static int alignment;
 
 static XrmOptionDescRec opts[] = {
-  {"-program",   ".starwars.program",  XrmoptionSepArg, (caddr_t) 0 },
-  {"-lines",     ".starwars.lines",    XrmoptionSepArg, (caddr_t) 0 },
-  {"-steps",     ".starwars.steps",    XrmoptionSepArg, (caddr_t) 0 },
-  {"-spin",      ".starwars.spin",     XrmoptionSepArg, (caddr_t) 0 },
-  {"-size",     ".starwars.fontSize", XrmoptionSepArg, (caddr_t) 0 },
-  {"-columns",  ".starwars.columns",  XrmoptionSepArg, (caddr_t) 0 },
-  {"-wrap",     ".starwars.lineWrap", XrmoptionNoArg,  (caddr_t) "True" },
-  {"-no-wrap",  ".starwars.lineWrap", XrmoptionNoArg,  (caddr_t) "False" },
-  {"-nowrap",   ".starwars.lineWrap", XrmoptionNoArg,  (caddr_t) "False" },
-  {"-left",      ".starwars.alignment",XrmoptionNoArg,  (caddr_t) "Left" },
-  {"-right",     ".starwars.alignment",XrmoptionNoArg,  (caddr_t) "Right" },
-  {"-center",    ".starwars.alignment",XrmoptionNoArg,  (caddr_t) "Center" },
+  {"-program",   ".starwars.program",  XrmoptionSepArg, 0 },
+  {"-lines",     ".starwars.lines",    XrmoptionSepArg, 0 },
+  {"-steps",     ".starwars.steps",    XrmoptionSepArg, 0 },
+  {"-spin",      ".starwars.spin",     XrmoptionSepArg, 0 },
+  {"-size",     ".starwars.fontSize", XrmoptionSepArg, 0 },
+  {"-columns",  ".starwars.columns",  XrmoptionSepArg, 0 },
+  {"-smooth",    ".starwars.smooth",   XrmoptionNoArg,  "True" },
+  {"-no-smooth", ".starwars.smooth",   XrmoptionNoArg,  "False" },
+  {"-thick",     ".starwars.thick",    XrmoptionNoArg,  "True" },
+  {"-no-thick",  ".starwars.thick",    XrmoptionNoArg,  "False" },
+  {"-fade",      ".starwars.fade",     XrmoptionNoArg,  "True" },
+  {"-no-fade",   ".starwars.fade",     XrmoptionNoArg,  "False" },
+  {"-wrap",     ".starwars.lineWrap", XrmoptionNoArg,  "True" },
+  {"-no-wrap",  ".starwars.lineWrap", XrmoptionNoArg,  "False" },
+  {"-nowrap",   ".starwars.lineWrap", XrmoptionNoArg,  "False" },
+  {"-left",      ".starwars.alignment",XrmoptionNoArg,  "Left" },
+  {"-right",     ".starwars.alignment",XrmoptionNoArg,  "Right" },
+  {"-center",    ".starwars.alignment",XrmoptionNoArg,  "Center" },
 };
 
 static argtype vars[] = {
-  {(caddr_t *) &program,        "program", "Program", DEF_PROGRAM, t_String},
-  {(caddr_t *) &max_lines,      "lines",   "Integer", DEF_LINES,   t_Int},
-  {(caddr_t *) &scroll_steps,   "steps",   "Integer", DEF_STEPS,   t_Int},
-  {(caddr_t *) &star_spin,      "spin",    "Float",   DEF_SPIN,    t_Float},
-  {(caddr_t *) &font_size,      "fontSize","Float",   DEF_STEPS,   t_Float},
-  {(caddr_t *) &target_columns, "columns", "Integer", DEF_COLUMNS, t_Int},
-  {(caddr_t *) &wrap_p,         "lineWrap","Boolean", DEF_COLUMNS, t_Bool},
-  {(caddr_t *) &alignment_str,  "alignment","Alignment",DEF_ALIGN, t_String},
+  {&program,        "program",   "Program",    DEF_PROGRAM, t_String},
+  {&max_lines,      "lines",     "Integer",    DEF_LINES,   t_Int},
+  {&scroll_steps,   "steps",     "Integer",    DEF_STEPS,   t_Int},
+  {&star_spin,      "spin",      "Float",      DEF_SPIN,    t_Float},
+  {&font_size,      "fontSize",  "Float",      DEF_STEPS,   t_Float},
+  {&target_columns, "columns",   "Integer",    DEF_COLUMNS, t_Int},
+  {&wrap_p,         "lineWrap",  "Boolean",    DEF_COLUMNS, t_Bool},
+  {&alignment_str,  "alignment", "Alignment", DEF_ALIGN,    t_String},
+  {&smooth_p,       "smooth",    "Boolean",   DEF_SMOOTH,   t_Bool},
+  {&thick_p,        "thick",     "Boolean",   DEF_THICK,    t_Bool},
+  {&fade_p,         "fade",      "Boolean",   DEF_FADE,     t_Bool},
 };
 
 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
@@ -151,6 +184,7 @@ ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
 static char *
 untabify (const char *string)
 {
+  const char *ostring = string;
   char *result = (char *) malloc ((strlen(string) * 8) + 1);
   char *out = result;
   int col = 0;
@@ -169,6 +203,11 @@ untabify (const char *string)
           *out++ = *string++;
           col = 0;
         }
+      else if (*string == '\010')    /* backspace */
+        {
+          if (string > ostring)
+            out--, string++;
+        }
       else
         {
           *out++ = *string++;
@@ -176,9 +215,55 @@ untabify (const char *string)
         }
     }
   *out = 0;
+
   return result;
 }
 
+static void
+strip (char *s, Bool leading, Bool trailing)
+{
+  int L = strlen(s);
+  if (trailing)
+    while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
+      s[L--] = 0;
+  if (leading)
+    {
+      char *s2 = s;
+      while (*s2 == ' ' || *s2 == '\t')
+        s2++;
+      if (s == s2)
+        return;
+      while (*s2)
+        *s++ = *s2++;
+      *s = 0;
+    }
+}
+
+
+/* The GLUT font only has ASCII characters in them, so do what we can to
+   convert Latin1 characters to the nearest ASCII equivalent... 
+ */
+static void
+latin1_to_ascii (char *s)
+{
+  unsigned char *us = (unsigned char *) s;
+  const unsigned char ascii[95] = {
+    '!', 'C', '#', '#', 'Y', '|', 'S', '_', 'C', '?', '<', '=', '-', 'R', '_',
+    '?', '?', '2', '3', '\'','u', 'P', '.', ',', '1', 'o', '>', '?', '?', '?',
+    '?', 'A', 'A', 'A', 'A', 'A', 'A', 'E', 'C', 'E', 'E', 'E', 'E', 'I', 'I',
+    'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'x', '0', 'U', 'U', 'U', 'U',
+    'Y', 'p', 'S', 'a', 'a', 'a', 'a', 'a', 'a', 'e', 'c', 'e', 'e', 'e', 'e',
+    'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', '/', 'o', 'u', 'u',
+    'u', 'u', 'y', 'p', 'y' };
+  while (*us)
+    {
+      if (*us >= 161)
+        *us = ascii[*us - 161];
+      else if (*us > 127)
+        *us = '?';
+      us++;
+    }
+}
 
 \f
 /* Subprocess.
@@ -199,8 +284,59 @@ static void
 launch_text_generator (sws_configuration *sc)
 {
   char *oprogram = get_string_resource ("program", "Program");
-  char *program = (char *) malloc (strlen (oprogram) + 10);
+  char *program;
+
+  if (!strcasecmp(oprogram, "(default)"))
+    {
+      oprogram = FORTUNE_PROGRAM;
+
+#if defined(__linux__) && defined(HAVE_UNAME)
+      {
+        static int done_once = 0;
+        if (!done_once)
+          {
+            struct utsname uts;
+            struct stat st;
+            done_once = 1;
+            if (uname (&uts) == 0)
+              {
+                static char cmd[200];
+                char *s;
+                /* strip version at the first non-digit-dash-dot, to
+                   lose any "SMP" crap at the end. */
+                for (s = uts.release; *s; s++)
+                  if (!isdigit(*s) && *s != '.' && *s != '-')
+                    *s = 0;
+                sprintf (cmd, "cat /usr/src/linux-%s/README", uts.release);
+                if (!stat (cmd+4, &st))
+                  oprogram = cmd;
+                else
+                  {
+                    /* kernel source not installed?  try X... */
+                    strcpy (cmd, "cat /usr/X11R6/lib/X11/doc/README");
+                    if (!stat (cmd+4, &st))
+                      oprogram = cmd;
+                  }
+              }
+          }
+      }
+#endif /* __linux__ && HAVE_UNAME */
 
+#ifdef __APPLE__   /* MacOS X + XDarwin */
+      {
+        static int done_once = 0;
+        if (!done_once)
+          {
+            struct stat st;
+            static char *cmd = "cat /usr/X11R6/README";
+            if (!stat (cmd+4, &st))
+              oprogram = cmd;
+          }
+      }
+#endif /* __APPLE__ */
+    }
+
+  program = (char *) malloc (strlen (oprogram) + 10);
   strcpy (program, "( ");
   strcat (program, oprogram);
   strcat (program, " ) 2>&1");
@@ -288,12 +424,17 @@ get_more_lines (sws_configuration *sc)
           return;
         }
 
-      if (*s == '\n' || col > sc->columns)
+      if (*s == '\r' || *s == '\n' || col > sc->columns)
         {
           int L = s - sc->buf;
 
-          if (*s == '\n')
-            *s++ = 0;
+          if (*s == '\r' || *s == '\n')
+            {
+              if (*s == '\r' && s[1] == '\n')  /* swallow CRLF too */
+                *s++ = 0;
+
+              *s++ = 0;
+            }
           else
             {
               /* We wrapped -- try to back up to the previous word boundary. */
@@ -312,10 +453,13 @@ get_more_lines (sws_configuration *sc)
           sc->lines[sc->total_lines] = (char *) malloc (L+1);
           memcpy (sc->lines[sc->total_lines], sc->buf, L);
           sc->lines[sc->total_lines][L] = 0;
+          latin1_to_ascii (sc->lines[sc->total_lines]);
 
           {
             char *t = sc->lines[sc->total_lines];
             char *ut = untabify (t);
+            strip (ut, (alignment == 0), 1); /* if centering, strip
+                                                leading whitespace too */
             sc->lines[sc->total_lines] = ut;
             free (t);
           }
@@ -325,7 +469,7 @@ get_more_lines (sws_configuration *sc)
           if (sc->buf_tail > (s - sc->buf))
             {
               int i = sc->buf_tail - (s - sc->buf);
-              memcpy (sc->buf, s, i);
+              memmove (sc->buf, s, i);
               sc->buf_tail = i;
               sc->buf[sc->buf_tail] = 0;
             }
@@ -355,45 +499,40 @@ draw_string (int x, int y, const char *s)
   if (!s || !*s) return;
   glPushMatrix ();
   glTranslatef (x, y, 0);
+
   while (*s)
     glutStrokeCharacter (GLUT_FONT, *s++);
   glPopMatrix ();
 }
 
 
-#if 0
+#ifdef DEBUG
 static void
 grid (double width, double height, double spacing, double z)
 {
   double x, y;
   for (y = 0; y <= height/2; y += spacing)
     {
-      glBegin(GL_LINE_LOOP);
+      glBegin(GL_LINES);
       glVertex3f(-width/2,  y, z);
       glVertex3f( width/2,  y, z);
-      glEnd();
-      glBegin(GL_LINE_LOOP);
       glVertex3f(-width/2, -y, z);
       glVertex3f( width/2, -y, z);
       glEnd();
     }
   for (x = 0; x <= width/2; x += spacing)
     {
-      glBegin(GL_LINE_LOOP);
+      glBegin(GL_LINES);
       glVertex3f( x, -height/2, z);
       glVertex3f( x,  height/2, z);
-      glEnd();
-      glBegin(GL_LINE_LOOP);
       glVertex3f(-x, -height/2, z);
       glVertex3f(-x,  height/2, z);
       glEnd();
     }
 
-  glBegin(GL_LINE_LOOP);
+  glBegin(GL_LINES);
   glVertex3f(-width, 0, z);
   glVertex3f( width, 0, z);
-  glEnd();
-  glBegin(GL_LINE_LOOP);
   glVertex3f(0, -height, z);
   glVertex3f(0,  height, z);
   glEnd();
@@ -428,55 +567,124 @@ box (double width, double height, double depth)
   glEnd();
 
   glEnd();
-  glBegin(GL_LINE_LOOP);
+  glBegin(GL_LINES);
   glVertex3f(-width/2,   height/2,  depth/2);
   glVertex3f(-width/2,  -height/2, -depth/2);
-  glEnd();
-  glBegin(GL_LINE_LOOP);
+
   glVertex3f( width/2,   height/2,  depth/2);
   glVertex3f( width/2,  -height/2, -depth/2);
-  glEnd();
-  glBegin(GL_LINE_LOOP);
+
   glVertex3f(-width/2,  -height/2,  depth/2);
   glVertex3f(-width/2,   height/2, -depth/2);
-  glEnd();
-  glBegin(GL_LINE_LOOP);
+
   glVertex3f( width/2,  -height/2,  depth/2);
   glVertex3f( width/2,   height/2, -depth/2);
   glEnd();
 }
-#endif /* 0 */
+#endif /* DEBUG */
 
 
-/* Window management, etc
- */
-void
-reshape_sws (ModeInfo *mi, int width, int height)
+/* Construct stars (number of stars is dependent on size of screen) */
+static void
+init_stars (ModeInfo *mi, int width, int height)
 {
   sws_configuration *sc = &scs[MI_SCREEN(mi)];
-  static Bool stars_done = False;
+  int i, j;
+  int nstars = width * height / 320;
+  int max_size = 3;
+  GLfloat inc = 0.5;
+  int steps = max_size / inc;
 
-  glViewport (0, 0, (GLint) width, (GLint) height);
-  if (!stars_done)
+  glDeleteLists (sc->star_list, 1);
+  sc->star_list = glGenLists (1);
+  glNewList (sc->star_list, GL_COMPILE);
+
+  glEnable(GL_POINT_SMOOTH);
+
+  for (j = 1; j <= steps; j++)
     {
-      int i;
-      int nstars = width * height / 320;
-      glDeleteLists (sc->star_list, 1);
-      sc->star_list = glGenLists (1);
-      glNewList (sc->star_list, GL_COMPILE);
+      glPointSize(inc * j);
       glBegin (GL_POINTS);
-      for (i = 0; i < nstars; i++)
+      for (i = 0; i < nstars / steps; i++)
         {
-          GLfloat c = 0.6 + 0.3 * random() / RAND_MAX;
-          glColor3f (c, c, c);
-          glVertex3f (2 * width  * (0.5 - 1.0 * random() / RAND_MAX),
-                      2 * height * (0.5 - 1.0 * random() / RAND_MAX),
-                      0.0);
+          glColor3f (0.6 + frand(0.3),
+                     0.6 + frand(0.3),
+                     0.6 + frand(0.3));
+          glVertex2f (2 * width  * (0.5 - frand(1.0)),
+                      2 * height * (0.5 - frand(1.0)));
         }
       glEnd ();
-      glEndList ();
-      stars_done = True;
     }
+  glEndList ();
+}
+
+
+/* Window management, etc
+ */
+void
+reshape_sws (ModeInfo *mi, int width, int height)
+{
+  sws_configuration *sc = &scs[MI_SCREEN(mi)];
+
+  /* Set up matrices for perspective text display
+   */
+  {
+    GLfloat desired_aspect = (GLfloat) 3/4;
+    int w = mi->xgwa.width;
+    int h = mi->xgwa.height;
+
+#ifdef KEEP_ASPECT
+    h = w * desired_aspect;
+#endif
+
+    glMatrixMode (GL_PROJECTION);
+    glViewport (0, 0, w, h);
+
+    glMatrixMode (GL_MODELVIEW);
+    glLoadIdentity ();
+    gluPerspective (80.0, 1/desired_aspect, 10, 500000);
+    gluLookAt (0.0, 0.0, 4600.0,
+               0.0, 0.0, 0.0,
+               0.0, 1.0, 0.0);
+    glRotatef (-60.0, 1.0, 0.0, 0.0);
+
+    /* The above gives us an arena where the bottom edge of the screen is
+       represented by the line (-2100,-3140,0) - ( 2100,-3140,0). */
+
+    /* Now let's move the origin to the front of the screen. */
+    glTranslatef (0.0, -3140, 0.0);
+
+    /* And then let's scale so that the bottom of the screen is 1.0 wide. */
+    glScalef (4200, 4200, 4200);
+  }
+
+
+  /* Compute the height in pixels of the line at the bottom of the screen. */
+  {
+    GLdouble mm[17], pm[17];
+    GLint vp[5];
+    GLfloat x = 0.5, y1 = 0, z = 0;
+    GLfloat y2 = sc->line_height;
+    GLdouble wx=-1, wy1=-1, wy2=-1, wz=-1;
+
+    glGetDoublev (GL_MODELVIEW_MATRIX, mm);
+    glGetDoublev (GL_PROJECTION_MATRIX, pm);
+    glGetIntegerv (GL_VIEWPORT, vp);
+    gluProject (x, y1, z, mm, pm, vp, &wx, &wy1, &wz);
+    gluProject (x, y2, z, mm, pm, vp, &wx, &wy2, &wz);
+    sc->line_pixel_height = (wy2 - wy1);
+    glLineWidth (1);
+  }
+
+  /* Compute the best looking line thickness for the bottom line.
+   */
+  if (!thick_p)
+    sc->line_thickness = 1.0;
+  else
+    sc->line_thickness = (GLfloat) sc->line_pixel_height / FONT_WEIGHT;
+
+  if (sc->line_thickness < 1.2)
+    sc->line_thickness = 1.0;
 }
 
 
@@ -487,11 +695,17 @@ gl_init (ModeInfo *mi)
 
   program = get_string_resource ("program", "Program");
 
-  glMatrixMode (GL_MODELVIEW);
-
   glDisable (GL_LIGHTING);
   glDisable (GL_DEPTH_TEST);
 
+  if (smooth_p) 
+    {
+      glEnable (GL_LINE_SMOOTH);
+      glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
+      glEnable (GL_BLEND);
+    }
+
   sc->text_list = glGenLists (1);
   glNewList (sc->text_list, GL_COMPILE);
   glEndList ();
@@ -499,6 +713,8 @@ gl_init (ModeInfo *mi)
   sc->star_list = glGenLists (1);
   glNewList (sc->star_list, GL_COMPILE);
   glEndList ();
+
+  sc->line_thickness = 1.0;
 }
 
 
@@ -526,10 +742,10 @@ init_sws (ModeInfo *mi)
   if ((sc->glx_context = init_GL(mi)) != NULL) {
     gl_init(mi);
     reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+    init_stars (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
   }
 
 
-
   font_height = GLUT_FONT->top - GLUT_FONT->bottom;
   sc->font_scale = 1.0 / glutStrokeWidth (GLUT_FONT, 'z');   /* 'n' seems
                                                                 too wide */
@@ -552,7 +768,6 @@ init_sws (ModeInfo *mi)
 
   sc->subproc_relaunch_delay = 2 * 1000;
   sc->total_lines = max_lines-1;
-  launch_text_generator (sc);
 
   if (random() & 1)
     star_spin = -star_spin;
@@ -572,9 +787,40 @@ init_sws (ModeInfo *mi)
                progname, alignment_str);
       exit (1);
     }
+
+  launch_text_generator (sc);
+
+  /* one more reshape, after line_height has been computed */
+  reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
 }
 
 
+static void
+draw_stars (ModeInfo *mi)
+{
+  sws_configuration *sc = &scs[MI_SCREEN(mi)];
+
+  glMatrixMode (GL_PROJECTION);
+  glPushMatrix ();
+  {
+    glLoadIdentity ();
+
+    glMatrixMode (GL_MODELVIEW);
+    glPushMatrix ();
+    {
+      glLoadIdentity ();
+      glOrtho (-0.5 * MI_WIDTH(mi),  0.5 * MI_WIDTH(mi),
+               -0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
+               -100.0, 100.0);
+      glRotatef (sc->star_theta, 0.0, 0.0, 1.0);
+      glCallList (sc->star_list);
+    }
+    glPopMatrix ();
+  }
+  glMatrixMode (GL_PROJECTION);
+  glPopMatrix ();
+}
+
 void
 draw_sws (ModeInfo *mi)
 {
@@ -594,33 +840,20 @@ draw_sws (ModeInfo *mi)
 
   glClear (GL_COLOR_BUFFER_BIT);
 
-  glPushMatrix ();
+  draw_stars (mi);
 
-  glMatrixMode (GL_PROJECTION);
-  glLoadIdentity ();
-  glOrtho (-0.5 * MI_WIDTH(mi),  0.5 * MI_WIDTH(mi),
-           -0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
-           -100.0, 100.0);
-  glRotatef (sc->star_theta, 0.0, 0.0, 1.0);
-  glCallList (sc->star_list);
-
-  glLoadIdentity ();
-  gluPerspective (80.0, 4.0/3.0, 10, 500000);
   glMatrixMode (GL_MODELVIEW);
-  gluLookAt (0.0, 0.0, 4600.0,
-             0.0, 0.0, 0.0,
-             0.0, 1.0, 0.0);
-
-  glRotatef (-60.0, 1.0, 0.0, 0.0);
-
-  /* The above gives us an arena where the bottom edge of the screen is
-     represented by the line (-2100,-3140,0) - ( 2100,-3140,0). */
-
-  /* Now let's move the origin to the front of the screen. */
-  glTranslatef (0.0, -3140, 0.0);
+  glPushMatrix ();
 
-  /* And then let's scale so that the bottom of the screen is 1.0 wide. */
-  glScalef (4200, 4200, 4200);
+#ifdef DEBUG
+  glColor3f (0.4, 0.4, 0.4);
+  glLineWidth (1);
+  glTranslatef(0, 1, 0);
+  box (1, 1, 1);
+  glTranslatef(0, -1, 0);
+  box (1, 1, 1);
+  grid (1, 1, sc->line_height, 0);
+#endif /* DEBUG */
 
   /* Scroll to current position */
   glTranslatef (0.0, sc->intra_line_scroll, 0.0);
@@ -669,19 +902,47 @@ draw_sws (ModeInfo *mi)
                        * sc->line_height);
           double xoff = 0;
           char *line = sc->lines[i];
-#if 0
+#ifdef DEBUG
           char n[20];
           sprintf(n, "%d:", i);
           draw_string (x / sc->font_scale, y / sc->font_scale, n);
-#endif
+#endif /* DEBUG */
           if (!line || !*line)
             continue;
 
+          if (sc->line_thickness != 1)
+            {
+              int max_thick_lines = MAX_THICK_LINES;
+              GLfloat thinnest_line = 1.0;
+              GLfloat thickest_line = sc->line_thickness;
+              GLfloat range = thickest_line - thinnest_line;
+              GLfloat thickness;
+
+              int j = sc->total_lines - i - 1;
+
+              if (j > max_thick_lines)
+                thickness = thinnest_line;
+              else
+                thickness = (thinnest_line +
+                             (range * ((max_thick_lines - j) /
+                                       (GLfloat) max_thick_lines)));
+
+              glLineWidth (thickness);
+            }
+
           if (alignment >= 0)
-            xoff = 1.0 - (glutStrokeLength(GLUT_FONT, line) * sc->font_scale);
+            xoff = 1.0 - (glutStrokeLength(GLUT_FONT,
+                                           (unsigned char *) line)
+                          * sc->font_scale);
           if (alignment == 0)
             xoff /= 2;
 
+          if (fade_p)
+            {
+              double factor = 1.0 * i / sc->total_lines;
+              glColor3f (factor, factor, 0.5 * factor);
+            }
+
           draw_string ((x + xoff) / sc->font_scale, y / sc->font_scale, line);
         }
       glPopMatrix ();