You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1062 lines
						
					
					
						
							29 KiB
						
					
					
				
			
		
		
	
	
							1062 lines
						
					
					
						
							29 KiB
						
					
					
				/* glmatrix, Copyright (c) 2003, 2004 Jamie Zawinski <jwz@jwz.org>
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that
 | 
						|
 * copyright notice and this permission notice appear in supporting
 | 
						|
 * documentation.  No representations are made about the suitability of this
 | 
						|
 * software for any purpose.  It is provided "as is" without express or 
 | 
						|
 * implied warranty.
 | 
						|
 *
 | 
						|
 * GLMatrix -- simulate the text scrolls from the movie "The Matrix".
 | 
						|
 *
 | 
						|
 * This program does a 3D rendering of the dropping characters that
 | 
						|
 * appeared in the title sequences of the movies.  See also `xmatrix'
 | 
						|
 * for a simulation of what the computer monitors actually *in* the
 | 
						|
 * movie did.
 | 
						|
 */
 | 
						|
 | 
						|
#define DEFAULTS	"*delay:	30000         \n" \
 | 
						|
			"*showFPS:      False         \n" \
 | 
						|
			"*wireframe:    False         \n" \
 | 
						|
 | 
						|
# define refresh_matrix 0
 | 
						|
# define release_matrix 0
 | 
						|
#undef countof
 | 
						|
#define countof(x) (sizeof((x))/sizeof((*x)))
 | 
						|
 | 
						|
#undef BELLRAND
 | 
						|
#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
 | 
						|
 | 
						|
#include "wscreensaver-glue.h"
 | 
						|
 | 
						|
#ifdef __GNUC__
 | 
						|
  __extension__  /* don't warn about "string length is greater than the length
 | 
						|
                    ISO C89 compilers are required to support" when including
 | 
						|
                    the following XPM file... */
 | 
						|
#endif
 | 
						|
#include "matrix3.xpm"
 | 
						|
 | 
						|
 | 
						|
#define DEF_SPEED       "1.0"
 | 
						|
#define DEF_DENSITY     "20"
 | 
						|
#define DEF_CLOCK       "False"
 | 
						|
#define DEF_FOG         "True"
 | 
						|
#define DEF_WAVES       "True"
 | 
						|
#define DEF_ROTATE      "True"
 | 
						|
#define DEF_TEXTURE     "True"
 | 
						|
#define DEF_MODE        "Matrix"
 | 
						|
#define DEF_TIMEFMT     " %l%M%p "
 | 
						|
 | 
						|
 | 
						|
#define CHAR_COLS 16
 | 
						|
#define CHAR_ROWS 13
 | 
						|
 | 
						|
static const int matrix_encoding[] = {
 | 
						|
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
 | 
						|
# if 0
 | 
						|
    192, 193, 194, 195, 196, 197, 198, 199,
 | 
						|
    200, 201, 202, 203, 204, 205, 206, 207
 | 
						|
# else
 | 
						|
    160, 161, 162, 163, 164, 165, 166, 167,
 | 
						|
    168, 169, 170, 171, 172, 173, 174, 175
 | 
						|
# endif
 | 
						|
  };
 | 
						|
static const int decimal_encoding[]  = {
 | 
						|
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
 | 
						|
static const int hex_encoding[] = {
 | 
						|
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38 };
 | 
						|
static const int binary_encoding[] = { 16, 17 };
 | 
						|
static const int dna_encoding[]    = { 33, 35, 39, 52 };
 | 
						|
 | 
						|
static const unsigned char char_map[256] = {
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /*   0 */
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /*  16 */
 | 
						|
    0,  1,  2, 96,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  /*  32 */
 | 
						|
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  /*  48 */
 | 
						|
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,  /*  64 */
 | 
						|
   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,  /*  80 */
 | 
						|
   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  /*  96 */
 | 
						|
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,  /* 112 */
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /* 128 */
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /* 144 */
 | 
						|
   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,  /* 160 */
 | 
						|
  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,  /* 176 */
 | 
						|
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  /* 192 */
 | 
						|
  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  /* 208 */
 | 
						|
#if 0
 | 
						|
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  /* 224 */
 | 
						|
  176,177,178,195,180,181,182,183,184,185,186,187,188,189,190,191   /* 240 */
 | 
						|
#else /* see spank_image() */
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /* 224 */
 | 
						|
   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  /* 240 */
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
#define CURSOR_GLYPH 97
 | 
						|
 | 
						|
/* #define DEBUG */
 | 
						|
 | 
						|
#define GRID_SIZE  70     /* width and height of the arena */
 | 
						|
#define GRID_DEPTH 35     /* depth of the arena */
 | 
						|
#define WAVE_SIZE  22     /* periodicity of color (brightness) waves */
 | 
						|
#define SPLASH_RATIO 0.7  /* ratio of GRID_DEPTH where chars hit the screen */
 | 
						|
 | 
						|
static const struct { GLfloat x, y; } nice_views[] = {
 | 
						|
  {  0,     0 },
 | 
						|
  {  0,   -20 },     /* this is a list of viewer rotations that look nice. */
 | 
						|
  {  0,    20 },     /* every now and then we switch to a new one.         */
 | 
						|
  { 25,     0 },     /* (but we only use the first one at start-up.)       */
 | 
						|
  {-25,     0 },
 | 
						|
  { 25,    20 },
 | 
						|
  {-25,    20 },
 | 
						|
  { 25,   -20 },
 | 
						|
  {-25,   -20 },
 | 
						|
 | 
						|
  { 10,     0 },
 | 
						|
  {-10,     0 },
 | 
						|
  {  0,     0 },  /* prefer these */
 | 
						|
  {  0,     0 },
 | 
						|
  {  0,     0 },
 | 
						|
  {  0,     0 },
 | 
						|
  {  0,     0 },
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  GLfloat x, y, z;        /* position of strip */
 | 
						|
  GLfloat dx, dy, dz;     /* velocity of strip */
 | 
						|
 | 
						|
  Bool erasing_p;         /* Whether this strip is on its way out. */
 | 
						|
 | 
						|
  int spinner_glyph;      /* the bottommost glyph -- the feeder */
 | 
						|
  GLfloat spinner_y;      /* where on the strip the bottom glyph is */
 | 
						|
  GLfloat spinner_speed;  /* how fast the bottom glyph drops */
 | 
						|
 | 
						|
  int glyphs[GRID_SIZE];  /* the other glyphs on the strip, which will be
 | 
						|
                             revealed by the dropping spinner.
 | 
						|
                             0 means no glyph; negative means "spinner".
 | 
						|
                             If non-zero, real value is abs(G)-1. */
 | 
						|
 | 
						|
  Bool highlight[GRID_SIZE];
 | 
						|
                          /* some glyphs may be highlighted */
 | 
						|
  
 | 
						|
  int spin_speed;         /* Rotate all spinners every this-many frames */
 | 
						|
  int spin_tick;          /* frame counter */
 | 
						|
 | 
						|
  int wave_position;	  /* Waves of brightness wash down the strip. */
 | 
						|
  int wave_speed;	  /* every this-many frames. */
 | 
						|
  int wave_tick;	  /* frame counter. */
 | 
						|
 | 
						|
} strip;
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  GLXContext *glx_context;
 | 
						|
  Bool button_down_p;
 | 
						|
  GLuint texture;
 | 
						|
  int nstrips;
 | 
						|
  strip *strips;
 | 
						|
  const int *glyph_map;
 | 
						|
  int nglyphs;
 | 
						|
  GLfloat tex_char_width, tex_char_height;
 | 
						|
 | 
						|
  /* auto-tracking direction of view */
 | 
						|
  int last_view, target_view;
 | 
						|
  GLfloat view_x, view_y;
 | 
						|
  int view_steps, view_tick;
 | 
						|
  Bool auto_tracking_p;
 | 
						|
  int track_tick;
 | 
						|
 | 
						|
  int real_char_rows;
 | 
						|
  GLfloat brightness_ramp[WAVE_SIZE];
 | 
						|
 | 
						|
} matrix_configuration;
 | 
						|
 | 
						|
static matrix_configuration *mps = NULL;
 | 
						|
 | 
						|
static GLfloat speed = 1.0;
 | 
						|
static GLfloat density = 20.0;
 | 
						|
static Bool do_clock;
 | 
						|
static char *timefmt;
 | 
						|
static Bool do_fog = 1;
 | 
						|
static Bool do_waves;
 | 
						|
static Bool do_rotate = 1;
 | 
						|
static Bool do_texture = 1;
 | 
						|
static char *mode_str;
 | 
						|
 | 
						|
#if 0
 | 
						|
static XrmOptionDescRec opts[] = {
 | 
						|
  { "-speed",       ".speed",     XrmoptionSepArg, 0 },
 | 
						|
  { "-density",     ".density",   XrmoptionSepArg, 0 },
 | 
						|
  { "-mode",        ".mode",      XrmoptionSepArg, 0 },
 | 
						|
  { "-binary",      ".mode",      XrmoptionNoArg, "binary"      },
 | 
						|
  { "-hexadecimal", ".mode",      XrmoptionNoArg, "hexadecimal" },
 | 
						|
  { "-decimal",     ".mode",      XrmoptionNoArg, "decimal"     },
 | 
						|
  { "-dna",         ".mode",      XrmoptionNoArg, "dna"         },
 | 
						|
  { "-clock",       ".clock",     XrmoptionNoArg, "True"  },
 | 
						|
  { "+clock",       ".clock",     XrmoptionNoArg, "False" },
 | 
						|
  { "-timefmt",     ".timefmt",   XrmoptionSepArg, 0  },
 | 
						|
  { "-fog",         ".fog",       XrmoptionNoArg, "True"  },
 | 
						|
  { "+fog",         ".fog",       XrmoptionNoArg, "False" },
 | 
						|
  { "-waves",       ".waves",     XrmoptionNoArg, "True"  },
 | 
						|
  { "+waves",       ".waves",     XrmoptionNoArg, "False" },
 | 
						|
  { "-rotate",      ".rotate",    XrmoptionNoArg, "True"  },
 | 
						|
  { "+rotate",      ".rotate",    XrmoptionNoArg, "False" },
 | 
						|
  {"-texture",      ".texture",   XrmoptionNoArg, "True"  },
 | 
						|
  {"+texture",      ".texture",   XrmoptionNoArg, "False" },
 | 
						|
};
 | 
						|
 | 
						|
static argtype vars[] = {
 | 
						|
  {&mode_str,   "mode",       "Mode",    DEF_MODE,      t_String},
 | 
						|
  {&speed,      "speed",      "Speed",   DEF_SPEED,     t_Float},
 | 
						|
  {&density,    "density",    "Density", DEF_DENSITY,   t_Float},
 | 
						|
  {&do_clock,   "clock",      "Clock",   DEF_CLOCK,     t_Bool},
 | 
						|
  {&timefmt,    "timefmt",    "Timefmt", DEF_TIMEFMT,   t_String},
 | 
						|
  {&do_fog,     "fog",        "Fog",     DEF_FOG,       t_Bool},
 | 
						|
  {&do_waves,   "waves",      "Waves",   DEF_WAVES,     t_Bool},
 | 
						|
  {&do_rotate,  "rotate",     "Rotate",  DEF_ROTATE,    t_Bool},
 | 
						|
  {&do_texture, "texture",    "Texture", DEF_TEXTURE,   t_Bool},
 | 
						|
};
 | 
						|
 | 
						|
ENTRYPOINT ModeSpecOpt matrix_opts = {countof(opts), opts, countof(vars), vars, NULL};
 | 
						|
#endif
 | 
						|
 | 
						|
/* Re-randomize the state of one strip.
 | 
						|
 */
 | 
						|
static void
 | 
						|
reset_strip (ModeInfo *mi, strip *s)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  int i;
 | 
						|
  Bool time_displayed_p = False;  /* never display time twice in one strip */
 | 
						|
 | 
						|
  memset (s, 0, sizeof(*s));
 | 
						|
  s->x = (GLfloat) (frand(GRID_SIZE) - (GRID_SIZE/2));
 | 
						|
  s->y = (GLfloat) (GRID_SIZE/2 + BELLRAND(0.5));      /* shift top slightly */
 | 
						|
  s->z = (GLfloat) (GRID_DEPTH * 0.2) - frand (GRID_DEPTH * 0.7);
 | 
						|
  s->spinner_y = 0;
 | 
						|
 | 
						|
  s->dx = 0;
 | 
						|
/*  s->dx = ((BELLRAND(0.01) - 0.005) * speed); */
 | 
						|
  s->dy = 0;
 | 
						|
  s->dz = (BELLRAND(0.02) * speed);
 | 
						|
 | 
						|
  s->spinner_speed = (BELLRAND(0.3) * speed);
 | 
						|
 | 
						|
  s->spin_speed = (int) BELLRAND(2.0 / speed) + 1;
 | 
						|
  s->spin_tick  = 0;
 | 
						|
 | 
						|
  s->wave_position = 0;
 | 
						|
  s->wave_speed = (int) BELLRAND(3.0 / speed) + 1;
 | 
						|
  s->wave_tick  = 0;
 | 
						|
 | 
						|
  for (i = 0; i < GRID_SIZE; i++)
 | 
						|
    if (do_clock &&
 | 
						|
        !time_displayed_p &&
 | 
						|
        (i < GRID_SIZE-5) &&   /* display approx. once per 5 strips */
 | 
						|
	!(random() % (GRID_SIZE-5)*5))
 | 
						|
      {
 | 
						|
        unsigned int j;
 | 
						|
	char text[80];
 | 
						|
        time_t now = time ((time_t *) 0);
 | 
						|
        struct tm *tm = localtime (&now);
 | 
						|
	strftime (text, sizeof(text)-1, timefmt, tm);
 | 
						|
 | 
						|
	/* render time into the strip */
 | 
						|
	for (j = 0; j < strlen(text) && i < GRID_SIZE; j++, i++)
 | 
						|
	  {
 | 
						|
	    s->glyphs[i] = char_map [((unsigned char *) text)[j]] + 1;
 | 
						|
	    s->highlight[i] = True;
 | 
						|
	  }
 | 
						|
 | 
						|
        time_displayed_p = True;	
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	int draw_p = (random() % 7);
 | 
						|
	int spin_p = (draw_p && !(random() % 20));
 | 
						|
	int g = (draw_p
 | 
						|
		 ? mp->glyph_map[(random() % mp->nglyphs)] + 1
 | 
						|
		 : 0);
 | 
						|
	if (spin_p) g = -g;
 | 
						|
	s->glyphs[i] = g;
 | 
						|
	s->highlight[i] = False;
 | 
						|
      }
 | 
						|
 | 
						|
  s->spinner_glyph = - (mp->glyph_map[(random() % mp->nglyphs)] + 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Animate the strip one step.  Reset if it has reached the bottom.
 | 
						|
 */
 | 
						|
static void
 | 
						|
tick_strip (ModeInfo *mi, strip *s)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  int i;
 | 
						|
 | 
						|
  if (mp->button_down_p)
 | 
						|
    return;
 | 
						|
 | 
						|
  s->x += s->dx;
 | 
						|
  s->y += s->dy;
 | 
						|
  s->z += s->dz;
 | 
						|
 | 
						|
  if (s->z > GRID_DEPTH * SPLASH_RATIO)  /* splashed into screen */
 | 
						|
    {
 | 
						|
      reset_strip (mi, s);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  s->spinner_y += s->spinner_speed;
 | 
						|
  if (s->spinner_y >= GRID_SIZE)
 | 
						|
    {
 | 
						|
      if (s->erasing_p)
 | 
						|
        {
 | 
						|
          reset_strip (mi, s);
 | 
						|
          return;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          s->erasing_p = True;
 | 
						|
          s->spinner_y = 0;
 | 
						|
          s->spinner_speed /= 2;  /* erase it slower than we drew it */
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  /* Spin the spinners. */
 | 
						|
  s->spin_tick++;
 | 
						|
  if (s->spin_tick > s->spin_speed)
 | 
						|
    {
 | 
						|
      s->spin_tick = 0;
 | 
						|
      s->spinner_glyph = - (mp->glyph_map[(random() % mp->nglyphs)] + 1);
 | 
						|
      for (i = 0; i < GRID_SIZE; i++)
 | 
						|
        if (s->glyphs[i] < 0)
 | 
						|
          {
 | 
						|
            s->glyphs[i] = -(mp->glyph_map[(random() % mp->nglyphs)] + 1);
 | 
						|
            if (! (random() % 800))  /* sometimes they stop spinning */
 | 
						|
              s->glyphs[i] = -s->glyphs[i];
 | 
						|
          }
 | 
						|
    }
 | 
						|
 | 
						|
  /* Move the color (brightness) wave. */
 | 
						|
  s->wave_tick++;
 | 
						|
  if (s->wave_tick > s->wave_speed)
 | 
						|
    {
 | 
						|
      s->wave_tick = 0;
 | 
						|
      s->wave_position++;
 | 
						|
      if (s->wave_position >= WAVE_SIZE)
 | 
						|
        s->wave_position = 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Draw a single character at the given position and brightness.
 | 
						|
 */
 | 
						|
static void
 | 
						|
draw_glyph (ModeInfo *mi, int glyph, Bool highlight,
 | 
						|
            GLfloat x, GLfloat y, GLfloat z,
 | 
						|
            GLfloat brightness)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  int wire = MI_IS_WIREFRAME(mi);
 | 
						|
  GLfloat w = mp->tex_char_width;
 | 
						|
  GLfloat h = mp->tex_char_height;
 | 
						|
  GLfloat cx = 0, cy = 0;
 | 
						|
  GLfloat S = 1;
 | 
						|
  Bool spinner_p = (glyph < 0);
 | 
						|
 | 
						|
  if (glyph == 0) abort();
 | 
						|
  if (glyph < 0) glyph = -glyph;
 | 
						|
 | 
						|
  if (spinner_p)
 | 
						|
    brightness *= 1.5;
 | 
						|
 | 
						|
  if (!do_texture)
 | 
						|
    {
 | 
						|
      S  = 0.8;
 | 
						|
      x += 0.1;
 | 
						|
      y += 0.1;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      int ccx = ((glyph - 1) % CHAR_COLS);
 | 
						|
      int ccy = ((glyph - 1) / CHAR_COLS);
 | 
						|
 | 
						|
      cx = ccx * w;
 | 
						|
      cy = (mp->real_char_rows - ccy - 1) * h;
 | 
						|
 | 
						|
      if (do_fog)
 | 
						|
        {
 | 
						|
          GLfloat depth;
 | 
						|
          depth = (z / GRID_DEPTH) + 0.5;  /* z ratio from back/front      */
 | 
						|
          depth = 0.2 + (depth * 0.8);     /* scale to range [0.2 - 1.0]   */
 | 
						|
          brightness *= depth;             /* so no row goes all black.    */
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  {
 | 
						|
    GLfloat r, g, b, a;
 | 
						|
 | 
						|
    if (highlight)
 | 
						|
      brightness *= 2;
 | 
						|
 | 
						|
    if (!do_texture && !spinner_p)
 | 
						|
      r = b = 0, g = 1;
 | 
						|
    else
 | 
						|
      r = g = b = 1;
 | 
						|
 | 
						|
    a = brightness;
 | 
						|
 | 
						|
    /* If the glyph is very close to the screen (meaning it is very large,
 | 
						|
       and is about to splash into the screen and vanish) then start fading
 | 
						|
       it out, proportional to how close to the glass it is.
 | 
						|
    */
 | 
						|
    if (z > GRID_DEPTH/2)
 | 
						|
      {
 | 
						|
        GLfloat ratio = ((z - GRID_DEPTH/2) /
 | 
						|
                         ((GRID_DEPTH * SPLASH_RATIO) - GRID_DEPTH/2));
 | 
						|
        int i = ratio * WAVE_SIZE;
 | 
						|
 | 
						|
        if (i < 0) i = 0;
 | 
						|
        else if (i >= WAVE_SIZE) i = WAVE_SIZE-1; 
 | 
						|
 | 
						|
        a *= mp->brightness_ramp[i];
 | 
						|
      }
 | 
						|
 | 
						|
    glColor4f (r,g,b,a);
 | 
						|
  }
 | 
						|
 | 
						|
  glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
 | 
						|
  glNormal3f (0, 0, 1);
 | 
						|
  glTexCoord2f (cx,   cy);   glVertex3f (x,   y,   z);
 | 
						|
  glTexCoord2f (cx+w, cy);   glVertex3f (x+S, y,   z);
 | 
						|
  glTexCoord2f (cx+w, cy+h); glVertex3f (x+S, y+S, z);
 | 
						|
  glTexCoord2f (cx,   cy+h); glVertex3f (x,   y+S, z);
 | 
						|
  glEnd ();
 | 
						|
 | 
						|
  if (wire && spinner_p)
 | 
						|
    {
 | 
						|
      glBegin (GL_LINES);
 | 
						|
      glVertex3f (x,   y,   z);
 | 
						|
      glVertex3f (x+S, y+S, z);
 | 
						|
      glVertex3f (x,   y+S, z);
 | 
						|
      glVertex3f (x+S, y,   z);
 | 
						|
      glEnd();
 | 
						|
    }
 | 
						|
 | 
						|
  mi->polygon_count++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Draw all the visible glyphs in the strip.
 | 
						|
 */
 | 
						|
static void
 | 
						|
draw_strip (ModeInfo *mi, strip *s)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  int i;
 | 
						|
  for (i = 0; i < GRID_SIZE; i++)
 | 
						|
    {
 | 
						|
      int g = s->glyphs[i];
 | 
						|
      Bool below_p = (s->spinner_y >= i);
 | 
						|
 | 
						|
      if (s->erasing_p)
 | 
						|
        below_p = !below_p;
 | 
						|
 | 
						|
      if (g && below_p)       /* don't draw cells below the spinner */
 | 
						|
        {
 | 
						|
          GLfloat brightness;
 | 
						|
          if (!do_waves)
 | 
						|
            brightness = 1.0;
 | 
						|
          else
 | 
						|
            {
 | 
						|
              int j = WAVE_SIZE - ((i + (GRID_SIZE - s->wave_position))
 | 
						|
                                   % WAVE_SIZE);
 | 
						|
              brightness = mp->brightness_ramp[j];
 | 
						|
            }
 | 
						|
 | 
						|
          draw_glyph (mi, g, s->highlight[i],
 | 
						|
		      s->x, s->y - i, s->z, brightness);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (!s->erasing_p)
 | 
						|
    draw_glyph (mi, s->spinner_glyph, False,
 | 
						|
		s->x, s->y - s->spinner_y, s->z, 1.0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* qsort comparator for sorting strips by z position */
 | 
						|
static int
 | 
						|
cmp_strips (const void *aa, const void *bb)
 | 
						|
{
 | 
						|
  const strip *a = *(strip **) aa;
 | 
						|
  const strip *b = *(strip **) bb;
 | 
						|
  return ((int) (a->z * 10000) -
 | 
						|
          (int) (b->z * 10000));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Auto-tracking
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
auto_track_init (ModeInfo *mi)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  mp->last_view = 0;
 | 
						|
  mp->target_view = 0;
 | 
						|
  mp->view_x = nice_views[mp->last_view].x;
 | 
						|
  mp->view_y = nice_views[mp->last_view].y;
 | 
						|
  mp->view_steps = 100;
 | 
						|
  mp->view_tick = 0;
 | 
						|
  mp->auto_tracking_p = False;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
auto_track (ModeInfo *mi)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
 | 
						|
  if (! do_rotate)
 | 
						|
    return;
 | 
						|
  if (mp->button_down_p)
 | 
						|
    return;
 | 
						|
 | 
						|
  /* if we're not moving, maybe start moving.  Otherwise, do nothing. */
 | 
						|
  if (! mp->auto_tracking_p)
 | 
						|
    {
 | 
						|
      if (++mp->track_tick < 20/speed) return;
 | 
						|
      mp->track_tick = 0;
 | 
						|
      if (! (random() % 20))
 | 
						|
        mp->auto_tracking_p = True;
 | 
						|
      else
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  {
 | 
						|
    GLfloat ox = nice_views[mp->last_view].x;
 | 
						|
    GLfloat oy = nice_views[mp->last_view].y;
 | 
						|
    GLfloat tx = nice_views[mp->target_view].x;
 | 
						|
    GLfloat ty = nice_views[mp->target_view].y;
 | 
						|
 | 
						|
    /* move from A to B with sinusoidal deltas, so that it doesn't jerk
 | 
						|
       to a stop. */
 | 
						|
    GLfloat th = sin ((M_PI / 2) * (double) mp->view_tick / mp->view_steps);
 | 
						|
 | 
						|
    mp->view_x = (ox + ((tx - ox) * th));
 | 
						|
    mp->view_y = (oy + ((ty - oy) * th));
 | 
						|
    mp->view_tick++;
 | 
						|
 | 
						|
  if (mp->view_tick >= mp->view_steps)
 | 
						|
    {
 | 
						|
      mp->view_tick = 0;
 | 
						|
      mp->view_steps = (350.0 / speed);
 | 
						|
      mp->last_view = mp->target_view;
 | 
						|
      mp->target_view = (random() % (countof(nice_views) - 1)) + 1;
 | 
						|
      mp->auto_tracking_p = False;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Window management, etc
 | 
						|
 */
 | 
						|
ENTRYPOINT void
 | 
						|
reshape_matrix (ModeInfo *mi, int width, int height)
 | 
						|
{
 | 
						|
  GLfloat h = (GLfloat) height / (GLfloat) width;
 | 
						|
 | 
						|
  glViewport (0, 0, (GLint) width, (GLint) height);
 | 
						|
 | 
						|
  glMatrixMode(GL_PROJECTION);
 | 
						|
  glLoadIdentity();
 | 
						|
  gluPerspective (80.0, 1/h, 1.0, 100);
 | 
						|
 | 
						|
  glMatrixMode(GL_MODELVIEW);
 | 
						|
  glLoadIdentity();
 | 
						|
  gluLookAt( 0.0, 0.0, 25.0,
 | 
						|
             0.0, 0.0, 0.0,
 | 
						|
             0.0, 1.0, 0.0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if 0
 | 
						|
ENTRYPOINT Bool
 | 
						|
matrix_handle_event (ModeInfo *mi, XEvent *event)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
 | 
						|
  if (event->xany.type == ButtonPress &&
 | 
						|
      event->xbutton.button == Button1)
 | 
						|
    {
 | 
						|
      mp->button_down_p = True;
 | 
						|
      return True;
 | 
						|
    }
 | 
						|
  else if (event->xany.type == ButtonRelease &&
 | 
						|
           event->xbutton.button == Button1)
 | 
						|
    {
 | 
						|
      mp->button_down_p = False;
 | 
						|
      return True;
 | 
						|
    }
 | 
						|
 | 
						|
  return False;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#if 0
 | 
						|
static Bool
 | 
						|
bigendian (void)
 | 
						|
{
 | 
						|
  union { int i; char c[sizeof(int)]; } u;
 | 
						|
  u.i = 1;
 | 
						|
  return !u.c[0];
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* The image with the characters in it is 512x598, meaning that it needs to
 | 
						|
   be copied into a 512x1024 texture.  But some machines can't handle textures
 | 
						|
   that large...  And it turns out that we aren't using most of the characters
 | 
						|
   in that image anyway, since this program doesn't do anything that makes use
 | 
						|
   of the full range of Latin1 characters.  So... this function tosses out the
 | 
						|
   last 32 of the Latin1 characters, resulting in a 512x506 image, which we
 | 
						|
   can then stuff in a 512x512 texture.  Voila.
 | 
						|
 | 
						|
   If this hack ever grows into something that displays full Latin1 text,
 | 
						|
   well then, Something Else Will Need To Be Done.
 | 
						|
 */
 | 
						|
static void
 | 
						|
spank_image (matrix_configuration *mp, XImage *xi)
 | 
						|
{
 | 
						|
  int ch = xi->height / CHAR_ROWS;
 | 
						|
  int cut = 2;
 | 
						|
  unsigned char *bits = (unsigned char *) xi->data;
 | 
						|
  unsigned char *from, *to, *s, *end;
 | 
						|
  int L = xi->bytes_per_line * ch;
 | 
						|
/*  int i;*/
 | 
						|
 | 
						|
  /* Copy row 12 into 10 (which really means, copy 2 into 0,
 | 
						|
     since texture data is upside down.).
 | 
						|
  */
 | 
						|
  to   = bits + (L * cut);
 | 
						|
  from = bits;
 | 
						|
  end  = from + L;
 | 
						|
  s    = from;
 | 
						|
  while (s < end)
 | 
						|
    *to++ = *s++;
 | 
						|
 | 
						|
  /* Then, pull all the bits down by 2 rows.
 | 
						|
   */
 | 
						|
  to   = bits;
 | 
						|
  from = bits + (L * cut);
 | 
						|
  end  = bits + (L * CHAR_ROWS);
 | 
						|
  s    = from;
 | 
						|
  while (s < end)
 | 
						|
    *to++ = *s++;
 | 
						|
 | 
						|
  /* And clear out the rest, for good measure.
 | 
						|
   */
 | 
						|
  from = bits + (L * (CHAR_ROWS - cut));
 | 
						|
  end  = bits + (L * CHAR_ROWS);
 | 
						|
  s    = from;
 | 
						|
  while (s < end)
 | 
						|
    *s++ = 0;
 | 
						|
 | 
						|
  xi->height -= (cut * ch);
 | 
						|
  mp->real_char_rows -= cut;
 | 
						|
 | 
						|
# if 0
 | 
						|
  /* Finally, pull the map indexes back to match the new bits.
 | 
						|
   */
 | 
						|
  for (i = 0; i < countof(matrix_encoding); i++)
 | 
						|
    if (matrix_encoding[i] > (CHAR_COLS * (CHAR_ROWS - cut)))
 | 
						|
      matrix_encoding[i] -= (cut * CHAR_COLS);
 | 
						|
# endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
load_textures (ModeInfo *mi, Bool flip_p)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  XImage *xi;
 | 
						|
  int x, y;
 | 
						|
  int cw, ch;
 | 
						|
  int orig_w, orig_h;
 | 
						|
 | 
						|
  /* The Matrix XPM is 512x598 -- but GL texture sizes must be powers of 2.
 | 
						|
     So we waste some padding rows to round up.
 | 
						|
   */
 | 
						|
  xi = xpm_to_ximage (matrix3_xpm);
 | 
						|
  orig_w = xi->width;
 | 
						|
  orig_h = xi->height;
 | 
						|
  mp->real_char_rows = CHAR_ROWS;
 | 
						|
  spank_image (mp, xi);
 | 
						|
 | 
						|
  if (xi->height != 512 && xi->height != 1024)
 | 
						|
    {
 | 
						|
      xi->height = (xi->height < 512 ? 512 : 1024);
 | 
						|
      xi->data = realloc (xi->data, xi->height * xi->bytes_per_line);
 | 
						|
      if (!xi->data)
 | 
						|
        {
 | 
						|
          fprintf(stderr, "%s: out of memory\n", progname);
 | 
						|
          exit(1);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (xi->width != 512) abort();
 | 
						|
  if (xi->height != 512 && xi->height != 1024) abort();
 | 
						|
 | 
						|
  /* char size in pixels */
 | 
						|
  cw = orig_w / CHAR_COLS;
 | 
						|
  ch = orig_h / CHAR_ROWS;
 | 
						|
 | 
						|
  /* char size in ratio of final (padded) texture size */
 | 
						|
  mp->tex_char_width  = (GLfloat) cw / xi->width;
 | 
						|
  mp->tex_char_height = (GLfloat) ch / xi->height;
 | 
						|
 | 
						|
  /* Flip each character's bits horizontally -- we could also just do this
 | 
						|
     by reversing the texture coordinates on the quads, but on some systems
 | 
						|
     that slows things down a lot.
 | 
						|
   */
 | 
						|
  if (flip_p)
 | 
						|
    {
 | 
						|
      int xx, col;
 | 
						|
      unsigned long buf[100];
 | 
						|
      for (y = 0; y < xi->height; y++)
 | 
						|
        for (col = 0, xx = 0; col < CHAR_COLS; col++, xx += cw)
 | 
						|
          {
 | 
						|
            for (x = 0; x < cw; x++)
 | 
						|
              buf[x] = XGetPixel (xi, xx+x, y);
 | 
						|
            for (x = 0; x < cw; x++)
 | 
						|
              XPutPixel (xi, xx+x, y, buf[cw-x-1]);
 | 
						|
          }
 | 
						|
    }
 | 
						|
 | 
						|
  /* The pixmap is a color image with no transparency.  Set the texture's
 | 
						|
     alpha to be the green channel, and set the green channel to be 100%.
 | 
						|
   */
 | 
						|
  {
 | 
						|
    int rpos, gpos, bpos, apos;  /* bitfield positions */
 | 
						|
#if 0
 | 
						|
    /* #### Cherub says that the little-endian case must be taken on MacOSX,
 | 
						|
            or else the colors/alpha are the wrong way around.  How can
 | 
						|
            that be the case?
 | 
						|
     */
 | 
						|
    if (bigendian())
 | 
						|
      rpos = 24, gpos = 16, bpos =  8, apos =  0;
 | 
						|
    else
 | 
						|
#endif
 | 
						|
      rpos =  0, gpos =  8, bpos = 16, apos = 24;
 | 
						|
 | 
						|
    for (y = 0; y < xi->height; y++)
 | 
						|
      for (x = 0; x < xi->width; x++)
 | 
						|
        {
 | 
						|
          unsigned long p = XGetPixel (xi, x, y);
 | 
						|
          unsigned char r = (p >> rpos) & 0xFF;
 | 
						|
          unsigned char g = (p >> gpos) & 0xFF;
 | 
						|
          unsigned char b = (p >> bpos) & 0xFF;
 | 
						|
          unsigned char a = g;
 | 
						|
          g = 0xFF;
 | 
						|
          p = (r << rpos) | (g << gpos) | (b << bpos) | (a << apos);
 | 
						|
          XPutPixel (xi, x, y, p);
 | 
						|
        }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Now load the texture into GL.
 | 
						|
   */
 | 
						|
  clear_gl_error();
 | 
						|
  glGenTextures (1, &mp->texture);
 | 
						|
 | 
						|
  glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
 | 
						|
  glPixelStorei (GL_UNPACK_ROW_LENGTH, xi->width);
 | 
						|
  glBindTexture (GL_TEXTURE_2D, mp->texture);
 | 
						|
  check_gl_error ("texture init");
 | 
						|
  glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, xi->width, xi->height, 0, GL_RGBA,
 | 
						|
                GL_UNSIGNED_INT_8_8_8_8_REV, xi->data);
 | 
						|
  {
 | 
						|
    char buf[255];
 | 
						|
    sprintf (buf, "creating %dx%d texture:", xi->width, xi->height);
 | 
						|
    check_gl_error (buf);
 | 
						|
  }
 | 
						|
 | 
						|
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
						|
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
						|
 | 
						|
  /* I'd expect CLAMP to be the thing to do here, but oddly, we get a
 | 
						|
     faint solid green border around the texture if it is *not* REPEAT!
 | 
						|
  */
 | 
						|
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 | 
						|
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 | 
						|
 | 
						|
  glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 | 
						|
  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
 | 
						|
  check_gl_error ("texture param");
 | 
						|
 | 
						|
  XDestroyImage (xi);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ENTRYPOINT void 
 | 
						|
init_matrix (ModeInfo *mi)
 | 
						|
{
 | 
						|
  matrix_configuration *mp;
 | 
						|
  int wire = MI_IS_WIREFRAME(mi);
 | 
						|
  Bool flip_p = 0;
 | 
						|
  int i;
 | 
						|
 | 
						|
  if (wire)
 | 
						|
    do_texture = False;
 | 
						|
 | 
						|
  if (!mps) {
 | 
						|
    mps = (matrix_configuration *)
 | 
						|
      calloc (MI_NUM_SCREENS(mi), sizeof (matrix_configuration));
 | 
						|
    if (!mps) {
 | 
						|
      fprintf(stderr, "%s: out of memory\n", progname);
 | 
						|
      exit(1);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mp = &mps[MI_SCREEN(mi)];
 | 
						|
  mp->glx_context = init_GL(mi);
 | 
						|
 | 
						|
  if (!mode_str || !*mode_str || !strcasecmp(mode_str, "matrix"))
 | 
						|
    {
 | 
						|
      flip_p = 1;
 | 
						|
      mp->glyph_map = matrix_encoding;
 | 
						|
      mp->nglyphs   = countof(matrix_encoding);
 | 
						|
    }
 | 
						|
  else if (!strcasecmp (mode_str, "dna"))
 | 
						|
    {
 | 
						|
      flip_p = 0;
 | 
						|
      mp->glyph_map = dna_encoding;
 | 
						|
      mp->nglyphs   = countof(dna_encoding);
 | 
						|
    }
 | 
						|
  else if (!strcasecmp (mode_str, "bin") ||
 | 
						|
           !strcasecmp (mode_str, "binary"))
 | 
						|
    {
 | 
						|
      flip_p = 0;
 | 
						|
      mp->glyph_map = binary_encoding;
 | 
						|
      mp->nglyphs   = countof(binary_encoding);
 | 
						|
    }
 | 
						|
  else if (!strcasecmp (mode_str, "hex") ||
 | 
						|
           !strcasecmp (mode_str, "hexadecimal"))
 | 
						|
    {
 | 
						|
      flip_p = 0;
 | 
						|
      mp->glyph_map = hex_encoding;
 | 
						|
      mp->nglyphs   = countof(hex_encoding);
 | 
						|
    }
 | 
						|
  else if (!strcasecmp (mode_str, "dec") ||
 | 
						|
           !strcasecmp (mode_str, "decimal"))
 | 
						|
    {
 | 
						|
      flip_p = 0;
 | 
						|
      mp->glyph_map = decimal_encoding;
 | 
						|
      mp->nglyphs   = countof(decimal_encoding);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      fprintf (stderr,
 | 
						|
           "%s: `mode' must be matrix, dna, binary, or hex: not `%s'\n",
 | 
						|
               progname, mode_str);
 | 
						|
      exit (1);
 | 
						|
    }
 | 
						|
 | 
						|
  reshape_matrix (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
 | 
						|
 | 
						|
  glShadeModel(GL_SMOOTH);
 | 
						|
 | 
						|
  glDisable(GL_DEPTH_TEST);
 | 
						|
  glDisable(GL_CULL_FACE);
 | 
						|
  glEnable(GL_NORMALIZE);
 | 
						|
 | 
						|
  if (do_texture)
 | 
						|
    {
 | 
						|
      load_textures (mi, flip_p);
 | 
						|
      glEnable(GL_TEXTURE_2D);
 | 
						|
      glEnable(GL_BLEND);
 | 
						|
 | 
						|
      /* Jeff Epler points out:
 | 
						|
         By using GL_ONE instead of GL_SRC_ONE_MINUS_ALPHA, glyphs are
 | 
						|
         added to each other, so that a bright glyph with a darker one
 | 
						|
         in front is a little brighter than the bright glyph alone.
 | 
						|
       */
 | 
						|
      glBlendFunc (GL_SRC_ALPHA, GL_ONE);
 | 
						|
    }
 | 
						|
 | 
						|
  /* to scale coverage-percent to strips, this number looks about right... */
 | 
						|
  mp->nstrips = (int) (density * 2.2);
 | 
						|
  if      (mp->nstrips < 1)    mp->nstrips = 1;
 | 
						|
  else if (mp->nstrips > 2000) mp->nstrips = 2000;
 | 
						|
 | 
						|
 | 
						|
  mp->strips = calloc (mp->nstrips, sizeof(strip));
 | 
						|
  for (i = 0; i < mp->nstrips; i++)
 | 
						|
    {
 | 
						|
      strip *s = &mp->strips[i];
 | 
						|
      reset_strip (mi, s);
 | 
						|
 | 
						|
      /* If we start all strips from zero at once, then the first few seconds
 | 
						|
         of the animation are much denser than normal.  So instead, set all
 | 
						|
         the initial strips to erase-mode with random starting positions.
 | 
						|
         As these die off at random speeds and are re-created, we'll get a
 | 
						|
         more consistent density. */
 | 
						|
      s->erasing_p = True;
 | 
						|
      s->spinner_y = frand(GRID_SIZE);
 | 
						|
      memset (s->glyphs, 0, sizeof(s->glyphs));  /* no visible glyphs */
 | 
						|
    }
 | 
						|
 | 
						|
  /* Compute the brightness ramp.
 | 
						|
   */
 | 
						|
  for (i = 0; i < WAVE_SIZE; i++)
 | 
						|
    {
 | 
						|
      GLfloat j = ((WAVE_SIZE - i) / (GLfloat) (WAVE_SIZE - 1));
 | 
						|
      j *= (M_PI / 2);       /* j ranges from 0.0 - PI/2  */
 | 
						|
      j = sin (j);           /* j ranges from 0.0 - 1.0   */
 | 
						|
      j = 0.2 + (j * 0.8);   /* j ranges from 0.2 - 1.0   */
 | 
						|
      mp->brightness_ramp[i] = j;
 | 
						|
      /* printf("%2d %8.2f\n", i, j); */
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  auto_track_init (mi);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
 | 
						|
static void
 | 
						|
draw_grid (ModeInfo *mi)
 | 
						|
{
 | 
						|
  if (!MI_IS_WIREFRAME(mi))
 | 
						|
    {
 | 
						|
      glDisable(GL_TEXTURE_2D);
 | 
						|
      glDisable(GL_BLEND);
 | 
						|
    }
 | 
						|
  glPushMatrix();
 | 
						|
 | 
						|
  glColor3f(1, 1, 1);
 | 
						|
  glBegin(GL_LINES);
 | 
						|
  glVertex3f(-GRID_SIZE, 0, 0); glVertex3f(GRID_SIZE, 0, 0);
 | 
						|
  glVertex3f(0, -GRID_SIZE, 0); glVertex3f(0, GRID_SIZE, 0);
 | 
						|
  glEnd();
 | 
						|
  glBegin(GL_LINE_LOOP);
 | 
						|
  glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, 0);
 | 
						|
  glVertex3f(-GRID_SIZE/2,  GRID_SIZE/2, 0);
 | 
						|
  glVertex3f( GRID_SIZE/2,  GRID_SIZE/2, 0);
 | 
						|
  glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, 0);
 | 
						|
  glEnd();
 | 
						|
  glBegin(GL_LINE_LOOP);
 | 
						|
  glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f(-GRID_SIZE/2, GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glEnd();
 | 
						|
  glBegin(GL_LINE_LOOP);
 | 
						|
  glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, -GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glEnd();
 | 
						|
  glBegin(GL_LINES);
 | 
						|
  glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f(-GRID_SIZE/2,  GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f(-GRID_SIZE/2,  GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2,  GRID_SIZE/2, -GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2, -GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glVertex3f( GRID_SIZE/2,  GRID_SIZE/2,  GRID_DEPTH/2);
 | 
						|
  glEnd();
 | 
						|
  glPopMatrix();
 | 
						|
  if (!MI_IS_WIREFRAME(mi))
 | 
						|
    {
 | 
						|
      glEnable(GL_TEXTURE_2D);
 | 
						|
      glEnable(GL_BLEND);
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif /* DEBUG */
 | 
						|
 | 
						|
 | 
						|
ENTRYPOINT void
 | 
						|
draw_matrix (ModeInfo *mi)
 | 
						|
{
 | 
						|
  matrix_configuration *mp = &mps[MI_SCREEN(mi)];
 | 
						|
  int i;
 | 
						|
 | 
						|
  if (!mp->glx_context)
 | 
						|
    return;
 | 
						|
 | 
						|
  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
 | 
						|
 | 
						|
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
						|
 | 
						|
  glPushMatrix ();
 | 
						|
 | 
						|
  if (do_rotate)
 | 
						|
    {
 | 
						|
      glRotatef (mp->view_x, 1, 0, 0);
 | 
						|
      glRotatef (mp->view_y, 0, 1, 0);
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
# if 0
 | 
						|
  glScalef(0.5, 0.5, 0.5);
 | 
						|
# endif
 | 
						|
# if 0
 | 
						|
  glRotatef(-30, 0, 1, 0); 
 | 
						|
# endif
 | 
						|
  draw_grid (mi);
 | 
						|
#endif
 | 
						|
 | 
						|
  mi->polygon_count = 0;
 | 
						|
 | 
						|
  /* Render (and tick) each strip, starting at the back
 | 
						|
     (draw the ones farthest from the camera first, to make
 | 
						|
     the alpha transparency work out right.)
 | 
						|
   */
 | 
						|
  {
 | 
						|
    strip **sorted = malloc (mp->nstrips * sizeof(*sorted));
 | 
						|
    for (i = 0; i < mp->nstrips; i++)
 | 
						|
      sorted[i] = &mp->strips[i];
 | 
						|
    qsort (sorted, i, sizeof(*sorted), cmp_strips);
 | 
						|
 | 
						|
    for (i = 0; i < mp->nstrips; i++)
 | 
						|
      {
 | 
						|
        strip *s = sorted[i];
 | 
						|
        tick_strip (mi, s);
 | 
						|
        draw_strip (mi, s);
 | 
						|
      }
 | 
						|
    free (sorted);
 | 
						|
  }
 | 
						|
 | 
						|
  auto_track (mi);
 | 
						|
 | 
						|
#if 0
 | 
						|
  glBegin(GL_QUADS);
 | 
						|
  glColor3f(1,1,1);
 | 
						|
  glTexCoord2f (0,0);  glVertex3f(-15,-15,0);
 | 
						|
  glTexCoord2f (0,1);  glVertex3f(-15,15,0);
 | 
						|
  glTexCoord2f (1,1);  glVertex3f(15,15,0);
 | 
						|
  glTexCoord2f (1,0);  glVertex3f(15,-15,0);
 | 
						|
  glEnd();
 | 
						|
#endif
 | 
						|
 | 
						|
  glPopMatrix ();
 | 
						|
 | 
						|
  if (mi->fps_p) do_fps (mi);
 | 
						|
  glFinish();
 | 
						|
 | 
						|
  glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
 | 
						|
}
 | 
						|
 | 
						|
WL_EXPORT struct wscreensaver_plugin glmatrix_screensaver = {
 | 
						|
	"GLMatrix",
 | 
						|
	init_matrix,
 | 
						|
	draw_matrix,
 | 
						|
	reshape_matrix
 | 
						|
};
 | 
						|
 |