xenocara/app/xlockmore/modes/matrix.c
2006-11-26 11:07:42 +00:00

784 lines
30 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* matrix --- screensaver inspired by the 1999 sci-fi flick "The Matrix" */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)matrix.c 5.00 2000/11/01 xlockmore";
#endif
/* Matrix-style screensaver
*
* Author: Erik O'Shaughnessy (eriko@xenolab.com) 20 Apr 1999
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Revision History:
* 01-Nov-2000: Allocation checks
* 23-Jul-1999: Unleashed on an unsuspecting world
* 29-Jun-1999: More hacking by Jeremy Buhler (jbuhler@cs.washington.edu)
* - fix memory-related bugs found by xlock maintainer
* - properly reinitialize screen with new size when init()
* is called multiple times
* - reinstate multiple final characters (suggested by
* Joan Touzet)
* - reduce delay to 1 ms (provisionally)
* - decouple pixmap height from screen height, to permit
* less memory use and shorter, more frequent updates
* (for smoother scrolling on slow boxes, but nothing
* will help if the machine is busy. Also restores
* broken display on very small windows).
* - nevertheless, certain display parameters such as the
* interval between column speed updates should depend on
* the screen height -- enforce this at runtime.
* - fix column spacing to use entire window
* - remove redundant size fields from matrix_t and column_t
* structures -- rely on character size and window size
* instead.
* - consistently use PICK_MATRIX() instead of passing
* mp as a parameter whenever the active screen is
* implicitly required.
* 27-Jun-1999: Overhauled by Jeremy Buhler (jbuhler@cs.washington.edu)
* - use screen-to-screen copies as much as possible
* - get by with a single pixmap per column instead of two
* - try to optimize draw_matrix() and new_column() as much
* as humanly possible
* - fixed double-freeing in release_matrix()
* - increased delay to 10 ms to prevent hyperfast scrolling
* - minor cleanups; removed unused or duplicate code/data
* 26-Jun-1999: Tweaks by Jeremy Buhler (jbuhler@cs.washington.edu)
* - Use larger Katakana font with numbers
* - tweak character colors
* - change string and gap distributions for lower screen density
* - Matrix strings end with a fixed character
* - fix scrolling artifacts due to gaps between two column
* pixmaps
* - minor code cleanups to allow future parameterization
* of speed, density
* 09-Jun-1999: Tweaks by Joan Touzet to look more like the original film's
* effects
* 22-Apr-1999: Initial version
*/
#ifdef VMS
#include "vms_x_fix.h"
/*-
* due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
* otherwise caddr_t is not defined correctly
*/
#include <X11/Intrinsic.h>
#endif
#ifdef STANDALONE
#define MODE_matrix
#define PROGCLASS "Matrix"
#define HACK_INIT init_matrix
#define HACK_DRAW draw_matrix
#define matrix_opts xlockmore_opts
#define DEFAULTS "*delay: 1000\n"
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
ModeSpecOpt matrix_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct matrix_description =
{"matrix", "init_matrix", "draw_matrix", "release_matrix",
"refresh_matrix", "change_matrix", (char *) NULL, &matrix_opts,
1000, 1, 1, 1, 64, 1.0, "",
"Shows the Matrix", 0, NULL};
#endif
#ifdef MODE_matrix
#ifndef VMS
#ifndef WIN32
#include <X11/Intrinsic.h>
#endif /* WIN32 */
#endif
/*
* state associated with a single column of the waterfall display
*/
typedef struct {
int yPtr; /* current offset relative to pixmap origin */
Pixmap pixmap;
int strLen; /* remaining length of current string */
int gapLen; /* remaining length of current gap */
Bool endChar; /* is the next char an ending char? */
int speed; /* pixels downward per update */
int nextSpeedUpdate; /* time until next change in speed */
} column_t;
/*
* Matrix display parameters associated with a particular X screen
*/
typedef struct {
column_t *columns; /* columns of the Matrix display */
int num_cols; /* number of columns of Matrix data
* (depends on screen width) */
int charsPerPixmap; /* height of column pixmaps in characters
* (depends on screen height) */
int pixmapHeight; /* height of column pixmaps in pixels
* (depends on screen height) */
int speedUpdateInterval; /* number of characters or spaces that
* must be written to column pixmap before
* the column speed is changed
* (depends on screen height) */
Pixmap kana[2]; /* pixmap containing katakana
* [0] is fg on bg
* [1] is bold on bg */
Pixel fg; /* foreground */
Pixel bg; /* background */
Pixel bold; /* standout foreground color */
} matrix_t;
/* These Katakana font bitmaps were taken from the file 12x24rk.bdf
* distributed with XFree86 3.3.3. The numbers were taken from the file
* 10x20.bdf, since the 12x24rk numbers were rather large compared to
* the other characters.
*/
#define katakana_cell_width 12
#define katakana_cell_height 24
#define katakana_num_cells 65
#define katakana_width 780
#define katakana_height 24
static const unsigned char katakana_bits[] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,
0xff,0xfc,0xff,0xff,0xff,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,
0x7f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xef,0x9f,0xff,0xff,0x9f,0xff,0xfd,0xef,0xff,0xf9,0xcf,0xff,
0xff,0x7f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xfe,0xfb,0xfc,
0xfc,0x9f,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xfc,0xff,0x3f,0xf8,0xcf,0xff,0xe7,0xff,0xff,0xfe,0xff,0xff,0xff,0x03,0x3c,
0xc7,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x9f,0xff,0xff,
0xbf,0xff,0xf9,0xcf,0xff,0xf9,0xcf,0xff,0xff,0x73,0x3e,0xff,0x7b,0xfc,0xfe,
0xfb,0xfc,0xfd,0xff,0xdc,0x9c,0x03,0xfc,0xfc,0x9f,0xff,0xff,0xff,0xff,0xf9,
0x7f,0xfe,0xfb,0xff,0xff,0xdf,0xff,0xff,0xf9,0xff,0x7f,0xf0,0x9f,0xff,0xef,
0xff,0xff,0xfe,0xff,0x9f,0x9f,0x07,0x7c,0xcf,0x9f,0xff,0xff,0xff,0x9f,0xdf,
0xff,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x01,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x1f,0xf8,0xcf,0x9f,0xff,0xff,0x3f,0xff,0xf9,0xdf,0xff,0xf9,0xcf,
0x9f,0xdf,0x67,0x7e,0xff,0x03,0xf8,0xfc,0xfb,0xf9,0xcd,0x0f,0xdc,0x9d,0x07,
0xff,0xfc,0xbf,0xff,0xff,0x1b,0xfc,0xf9,0xff,0x7c,0xf2,0xf9,0xdf,0x80,0xff,
0xff,0xf9,0xff,0xff,0xc3,0x9f,0xff,0xcf,0xff,0xfe,0xfe,0xff,0x3f,0x80,0xff,
0x7f,0xcf,0x93,0xbf,0xff,0xff,0x1f,0x80,0xf9,0x0f,0x9f,0xff,0xf9,0x0f,0xff,
0xf0,0xff,0x3e,0xc0,0x0f,0x3f,0xc0,0x0f,0xff,0xf0,0x01,0xf8,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x05,0xf8,0xcf,0x9d,0xbd,
0xc3,0x3f,0xff,0xf9,0xdf,0xff,0xdd,0xef,0x3f,0x80,0x67,0x7e,0xfe,0x87,0xfd,
0xfc,0xf3,0xfd,0xc1,0x03,0x9f,0x9d,0xff,0xff,0xfc,0xbf,0xff,0xff,0x03,0xf8,
0xef,0xff,0xfc,0xf4,0xf3,0x1f,0x80,0xcf,0xff,0xf9,0x3f,0xf8,0x8f,0x9f,0xff,
0xcf,0x03,0xfc,0xfe,0xff,0x3f,0x80,0xff,0x7f,0xcf,0x87,0x3f,0xff,0xfb,0x3d,
0x80,0xfb,0x0f,0x0f,0xff,0xf8,0x67,0x7e,0xe6,0x7f,0x3e,0xff,0x67,0xfe,0xcf,
0x67,0x7e,0xe6,0xff,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xc1,0xf9,0xe7,0x01,0x38,0xc0,0x3f,0xff,0x81,0xdf,0xff,0x80,
0xef,0x3f,0x80,0x67,0xfe,0xfe,0xff,0xfd,0xfc,0xf7,0xfd,0xc0,0xa1,0xbf,0x99,
0xff,0xff,0xfc,0xbf,0xff,0xff,0xc7,0xfd,0xe1,0xff,0xfc,0xe4,0xfb,0x3f,0xcf,
0xcf,0xdf,0x01,0x01,0xf0,0x9f,0xdf,0xff,0xcf,0x03,0xff,0x0c,0x7f,0xfe,0x9f,
0xff,0x7f,0xcf,0x97,0x3f,0xff,0x03,0xbc,0xcf,0xf3,0x0f,0x67,0x7e,0xf8,0xf3,
0x3c,0xcf,0x3f,0x3e,0xff,0xf3,0xfe,0xcf,0xf3,0x3c,0xcf,0xff,0xfc,0xff,0x7f,
0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xfc,0xe7,0x03,
0x3c,0xf8,0x3f,0xdf,0x80,0x1f,0xfc,0x80,0x67,0xf0,0xdf,0x67,0xfe,0x7f,0xff,
0xfc,0xbc,0xe7,0xfc,0xce,0xbf,0x3f,0x99,0xff,0xff,0xfc,0xbf,0x3f,0xc0,0xff,
0xdd,0xe0,0xff,0xfe,0xee,0xfb,0xff,0xcf,0x87,0x1f,0x00,0x81,0xf1,0xff,0xdf,
0xff,0xcf,0xdf,0xff,0x00,0x01,0xfe,0x9f,0xff,0x7f,0xcf,0x97,0x3f,0xff,0x03,
0xbc,0xcf,0xf7,0x0f,0x67,0x3e,0xf9,0xf3,0x3c,0xcf,0x1f,0x3e,0xff,0xf3,0xff,
0xe7,0xf3,0x3c,0xcf,0xff,0xfc,0xc0,0x7f,0xfe,0xf9,0xff,0xff,0xfb,0xef,0xff,
0xff,0xff,0xbf,0xfc,0x5f,0xfe,0xf3,0xfb,0xfc,0xf9,0x3d,0x10,0x98,0x05,0xfc,
0xde,0x07,0xf0,0xdf,0x67,0xd8,0x3f,0xff,0xfe,0x00,0xe7,0x7c,0xee,0xbf,0x3f,
0x99,0x04,0xf0,0xfc,0x3d,0x38,0xe0,0xff,0x1c,0xe4,0x7f,0xfe,0xce,0xfb,0xfc,
0xcf,0xa7,0x1f,0xf8,0xf9,0x39,0xfe,0xcf,0x7f,0xee,0xdf,0xff,0xa0,0x03,0xfe,
0x9f,0x0c,0x78,0xcf,0x97,0x3f,0x7f,0xf3,0xbc,0xcf,0xe7,0x0b,0xf3,0xfc,0xf9,
0xff,0xfc,0xcf,0x4f,0x3e,0xff,0xf3,0xff,0xe7,0xf3,0x3c,0xcf,0xff,0x3c,0xc0,
0xff,0xfe,0xf9,0xff,0xff,0xf3,0xcf,0xff,0xff,0xff,0xbc,0xcd,0x1f,0xfe,0xf3,
0xfb,0xfc,0xf9,0x01,0x10,0x99,0x81,0x7f,0xce,0x07,0xff,0xdf,0x01,0x90,0xbf,
0xff,0x6e,0x80,0xe7,0x7c,0xe6,0xbf,0x3f,0x99,0x01,0xf0,0xf0,0x01,0xf0,0xff,
0xff,0x3c,0xf3,0x7f,0x7e,0xce,0x7b,0xfc,0xcf,0x37,0xff,0xf9,0xff,0x7c,0xf8,
0xcf,0xff,0xec,0xdf,0x1f,0x9c,0x7f,0xfe,0x9f,0x01,0x78,0xcf,0x97,0x3f,0x3f,
0xf3,0xbc,0xcf,0xe7,0x0b,0xf3,0xfc,0xf9,0xff,0xfc,0xe7,0x67,0x3e,0xf1,0x13,
0xff,0xf3,0x67,0x3e,0xcf,0x03,0x3c,0xce,0x7f,0xbe,0xe9,0xff,0xff,0xf3,0xcf,
0xfe,0xff,0x03,0x3c,0xc9,0x1f,0xff,0xf9,0xfb,0xfc,0xf9,0x01,0xff,0x99,0x9b,
0x7f,0xef,0x33,0xff,0xdf,0x01,0x3e,0x9f,0x7f,0x0e,0xdc,0xe7,0x3e,0xe6,0x3f,
0x38,0xdb,0xb9,0xff,0xe0,0x81,0xff,0xff,0xe7,0xfe,0xf3,0x7f,0x7f,0xde,0x1b,
0xff,0xcf,0x73,0x7f,0xf1,0xff,0xfc,0xf0,0x6f,0xff,0xe0,0xdf,0x1f,0xdc,0x7f,
0xfe,0x9f,0xf1,0x79,0xcf,0x97,0x3f,0xbf,0xf3,0xbc,0xcf,0xe7,0x09,0xf3,0xfc,
0xf9,0x7f,0xfe,0xf1,0x73,0x3e,0xe6,0x63,0xfe,0xf3,0x0f,0x7f,0xc6,0x03,0xfc,
0xef,0x3f,0x3f,0xe0,0xff,0xff,0xf3,0x0f,0xfc,0xff,0x07,0x7c,0xcb,0x9f,0xff,
0xf9,0xfb,0xfc,0xf9,0x3f,0xff,0x9d,0x9f,0x3f,0xef,0x3b,0xff,0xdf,0x67,0x7e,
0xde,0x7f,0x9f,0xcc,0xff,0xbe,0xf4,0x05,0xf8,0xcf,0xbf,0xff,0xc4,0x9f,0xff,
0xff,0x4f,0xfe,0xf9,0x3f,0x7f,0x9e,0x83,0xff,0xcf,0x7b,0x7e,0xe9,0x7f,0xfe,
0xe3,0x6f,0xff,0xf1,0x1f,0x98,0xdd,0x7f,0xfe,0x9f,0xff,0x79,0xcf,0x97,0x37,
0x9f,0xf3,0xbc,0xcf,0xff,0x0d,0xf3,0xfc,0xf9,0x1f,0xff,0xe7,0x73,0xfe,0xcf,
0xf3,0xfc,0xf9,0x67,0xfe,0xc8,0xff,0xfc,0xe1,0x3f,0x3f,0xe0,0x03,0x3e,0xc0,
0x0f,0xfc,0xe7,0xff,0x7c,0xcb,0x9f,0xff,0xf8,0xfb,0xfc,0xf9,0x3f,0xff,0x9d,
0x9f,0xbf,0xe7,0x39,0xff,0xdf,0x67,0x7e,0xce,0x3f,0xff,0xec,0x7f,0x9e,0xf0,
0x81,0xff,0xcf,0xbf,0xff,0xcc,0x9f,0xff,0xff,0x4f,0xff,0xf1,0x3f,0x7f,0x9f,
0xc3,0xff,0xe7,0xf9,0x7e,0xc9,0x7b,0xfe,0xc7,0x67,0xfe,0xf3,0x04,0xf8,0xcd,
0x7f,0x3e,0x80,0xff,0x7c,0xcf,0x97,0x33,0xdf,0xf3,0xbc,0xcf,0xff,0x0c,0xf3,
0xfc,0xf9,0xcf,0xff,0xcf,0x03,0xfc,0xcf,0xf3,0xfc,0xf9,0xf3,0xfc,0xcf,0x7f,
0xfe,0xf1,0x1f,0x3f,0xef,0x03,0x3e,0xc0,0xc1,0x7c,0xe0,0xff,0x7c,0xca,0x9f,
0x7f,0xfa,0xfb,0xfc,0xf9,0x1f,0xff,0x9d,0x9f,0x90,0xf7,0x3d,0xff,0xdf,0x67,
0xfe,0xef,0xbf,0xff,0xe4,0x7f,0xdf,0xf1,0x99,0xff,0xcf,0xbf,0xff,0xdc,0x9f,
0xff,0xff,0x1f,0xff,0xe0,0xbf,0x7f,0xbf,0xfb,0xff,0xe7,0xfd,0x3c,0xd9,0x73,
0xff,0xcf,0xe7,0xfe,0xe7,0xc1,0xff,0xed,0x7f,0x7e,0xc0,0xff,0x7c,0xcf,0x97,
0x3b,0xcf,0xf3,0xfc,0xcf,0xff,0x0e,0x67,0xfe,0xf9,0xe7,0x3f,0xcf,0x7f,0xfe,
0xcf,0xf3,0xfc,0xfc,0xf3,0xfc,0xcf,0x7f,0xfe,0xf9,0x0f,0x3f,0xef,0x9f,0xff,
0xf1,0xc3,0x7e,0xe0,0xff,0xfc,0xee,0x9f,0x3f,0xfb,0xfb,0xfe,0xf9,0x5f,0xff,
0x9d,0x0f,0xd0,0xf7,0x3d,0xff,0xcf,0x67,0xfe,0xe7,0x1f,0xfe,0xf4,0x3f,0xff,
0xf3,0x9f,0xff,0xef,0x9f,0xff,0xfc,0x9f,0xff,0xff,0x1f,0x7f,0xc0,0x9f,0x3f,
0xbf,0xfb,0xff,0xf7,0xff,0x3d,0x99,0x27,0xff,0xff,0xe7,0xfc,0xe3,0xd9,0xff,
0xe5,0x7f,0xff,0xdf,0x7f,0x7e,0xcf,0x97,0x39,0xef,0xf3,0xfc,0xef,0x7f,0x0e,
0x67,0xfe,0xf9,0xf3,0x3f,0xcf,0x7f,0x3e,0xcf,0xf3,0xfc,0xfc,0xf3,0x7c,0xcf,
0x7f,0xfe,0xf9,0x0f,0x3f,0xef,0x9f,0xff,0xf1,0x5f,0xfe,0xe7,0x07,0xfc,0xef,
0x9f,0x9f,0xfb,0x7b,0xfe,0xf9,0x4f,0xff,0x9c,0x00,0xff,0xf3,0xbf,0xff,0xcf,
0x67,0xfe,0xf7,0x5f,0xfe,0xf0,0xbf,0xff,0xf1,0x9f,0xff,0xe7,0x9f,0xff,0xfc,
0x9f,0xff,0xff,0x1f,0x3e,0x88,0xdf,0x3f,0xbf,0xfb,0xff,0xf3,0xff,0xb9,0x99,
0x8f,0xff,0xff,0xf7,0xfc,0xcb,0xdf,0xff,0xf1,0x7f,0xff,0xdf,0x7f,0x7e,0xef,
0x97,0x3d,0xe7,0xf3,0xfc,0xe7,0x7f,0x0f,0x0f,0xff,0xf9,0xf3,0x7f,0xe6,0x7f,
0x7e,0xe6,0x67,0x7e,0xfe,0x67,0x7e,0xe6,0x3f,0xff,0xfd,0x27,0x3f,0xe7,0x9f,
0xff,0xf0,0x5f,0xff,0xe7,0x07,0xfe,0xe7,0xdf,0xdf,0xfb,0x7f,0xfe,0xb9,0x6f,
0xff,0xdc,0xa1,0xff,0xfb,0xbf,0xff,0xcf,0x67,0xfe,0xf3,0xcf,0xfc,0xfc,0x9f,
0xff,0xf5,0x9f,0xff,0xf7,0xdf,0xff,0xfc,0xdf,0xff,0xff,0xdf,0x1e,0x99,0xcf,
0xbf,0xbf,0xfb,0xff,0xfb,0xff,0x99,0xb9,0x9f,0x3f,0xfe,0xf3,0xf9,0xd9,0xdf,
0xff,0xf9,0x7f,0xff,0xdf,0x3f,0xff,0xe7,0x97,0x3c,0xf7,0xf3,0xfc,0xe7,0x3f,
0x0f,0x9f,0x3f,0xc0,0x03,0xfc,0xf0,0x7f,0xfe,0xf0,0x0f,0x7f,0xfe,0x0f,0xff,
0xf0,0x3f,0xff,0xfd,0x37,0xff,0xf7,0x9f,0xff,0xf2,0xdf,0xff,0xe7,0xff,0xfe,
0xf7,0xcf,0xff,0xfb,0x3f,0xcf,0x00,0x67,0xff,0xde,0xbf,0xff,0xf9,0x9f,0x1f,
0xc0,0x67,0xff,0xf9,0xef,0xfd,0xfc,0xdf,0xff,0xfc,0xdf,0xff,0xf3,0xcf,0xff,
0xfc,0xdf,0xdf,0x00,0xcf,0x8c,0x39,0xef,0xbf,0xbf,0xfb,0xff,0xf9,0xff,0xc3,
0xb9,0x3f,0x3f,0xf8,0x33,0xf8,0x9d,0xdf,0xff,0xf9,0x7c,0xff,0xdf,0xbf,0xff,
0xe7,0x93,0x3e,0xf3,0x03,0xfc,0xf7,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9f,0xff,0xfd,0x3f,0xff,0xf3,
0x9f,0x7f,0xf2,0xdf,0xff,0xe7,0xff,0xfe,0xf3,0xef,0xff,0xfb,0x3f,0x1f,0x00,
0x77,0x7f,0xda,0xbf,0xff,0xfc,0xdf,0x3f,0xc0,0x7f,0xbf,0xfc,0xe7,0xf9,0xfc,
0xcf,0xff,0xfe,0xcf,0xff,0xf9,0xef,0xff,0xfc,0xcf,0x1f,0x00,0xef,0xfd,0x39,
0xe7,0x9f,0x3f,0xfb,0xff,0xfd,0xff,0x43,0xb8,0x3f,0xff,0xf1,0x01,0xf8,0xfc,
0xdf,0xff,0xfb,0x01,0xf0,0xdf,0x9f,0xff,0xe7,0x13,0x3e,0xf9,0x03,0xfc,0xf3,
0x8f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x9f,0xff,0xfc,0x3f,0xff,0xfb,0x9f,0x7f,0xf3,0x9f,0xff,0xe7,0xff,
0xfe,0xfb,0xe7,0xff,0xfb,0x9f,0x1f,0xff,0x53,0x7f,0xc3,0xbf,0xff,0xfc,0xcf,
0xff,0xff,0x3f,0x3f,0xfc,0xf3,0xf9,0xfc,0xef,0x7f,0xfe,0xef,0xff,0xf9,0xe7,
0xff,0xfc,0xef,0x1f,0xff,0xe7,0xf9,0xf9,0xf7,0xdf,0x3f,0xfb,0xff,0xfc,0xff,
0xf3,0xf8,0x7f,0xfe,0xe3,0xc1,0xf3,0xfe,0xdf,0xff,0xfb,0x01,0x10,0x80,0xdf,
0xff,0xf7,0x1b,0x3e,0xfd,0xf3,0xff,0xfb,0xcb,0x0f,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfe,0x3f,0xff,
0xf9,0x9f,0x3f,0xf3,0x9f,0xff,0xe7,0xff,0xfe,0xf9,0xf7,0xff,0xfb,0x9f,0xff,
0xff,0x19,0x3f,0xe7,0xbf,0x7f,0xfe,0xef,0xff,0xff,0xbf,0x3f,0xfe,0xf9,0xfb,
0x01,0xe7,0x3f,0xff,0xe7,0xff,0xfc,0xf3,0xff,0xfc,0xe7,0xff,0xff,0xf3,0xf3,
0xf9,0xf3,0xcf,0xff,0xf3,0xf9,0xfe,0xff,0xff,0xf8,0x7f,0xfe,0xc7,0xf9,0x73,
0xfe,0x1f,0xf0,0xfb,0xff,0x1f,0x80,0xcf,0xff,0xf3,0x19,0x3f,0xfc,0xf3,0xff,
0xf9,0xe3,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xe7,0x7f,0xfe,0x3f,0xff,0xfd,0x03,0xb8,0xf1,0x9f,0x1f,0xc0,
0x03,0xfc,0xfc,0xf3,0xff,0xfb,0xcf,0xff,0xff,0x19,0x9f,0xe7,0xbf,0x3f,0xff,
0xe7,0xff,0xff,0x9f,0x7f,0xfe,0xf9,0xff,0x01,0xf7,0x1f,0xff,0xf3,0x7f,0xfe,
0xf3,0xff,0xfc,0xf3,0xff,0xff,0xf9,0xf3,0xf9,0xfb,0xef,0xff,0x03,0x78,0xfe,
0xff,0xff,0xf9,0xff,0xff,0xcf,0xff,0x33,0xff,0x1f,0xf0,0xfb,0xff,0xff,0xff,
0xe7,0xff,0xf8,0x1d,0x3f,0xfe,0xff,0xff,0xfd,0xe3,0x0f,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0x7f,0xff,0x3f,
0xff,0xfc,0x03,0xf8,0xfb,0x9f,0x1f,0x80,0x07,0x7c,0xfc,0xfb,0xff,0xfb,0xe7,
0xff,0xff,0x3c,0x9f,0xff,0xbf,0x9f,0xff,0xf7,0xff,0xff,0xcf,0xff,0xff,0xff,
0xff,0xff,0xff,0x9f,0xff,0xf3,0x3f,0xff,0xf9,0xff,0xfc,0xff,0xff,0xff,0xf9,
0xff,0xf9,0xf9,0xff,0xff,0x07,0x38,0xff,0xff,0xff,0xfd,0xff,0xff,0xdf,0xff,
0x33,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xf3,0xff,0xfc,0xbd,0x7f,0xff,0xff,
0xff,0xfc,0xf3,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f
};
#define PIXMAP_WIDTH katakana_cell_width
#define PICK_MATRIX(mi) (&matrix[MI_SCREEN(mi)])
#define MATRIX_RANDOM(min, max) (NRAND((max) - (min)) + (min))
/*************************************************************************
* CONFIGURABLE DISPLAY OPTIONS
*************************************************************************/
/* Defining RANDOMIZE_COLUMNS causes each column pixmap to be regenerated
* after scrolling off the screen rather than just repeating
* infinitely. This is a better effect but uses more CPU and will
* cause update hesitations (especially on multi-headed machines or
* slower hardware). However, it can be done in relatively little memory
* because the pixmaps can be kept short and regenerated frequently.
*
* Undefining RANDOMIZE_COLUMNS will cause the pixmaps to be generated only
* once, which should save a lot of horsepower for whatever else your machine
* might be doing. However, the tradeoff is that the pixmaps are longer
* to avoid a really boring display.
*/
#define RANDOMIZE_COLUMNS
/*
* Speed at which columns move, in pixels per screen update.
* Must be <= katakana_cell_height; interesting values range
* from one (crawl) to about fifteen (zoom!).
* (Note: the distribution of speeds implemented in new_column()
* is slightly biased against very slow scrolling.)
*/
#define MATRIX_SPEED MATRIX_RANDOM(1, 8)
/*
* Number of characters in each generated string
* (Note: this is not limited by the pixmap size!)
*/
#define MATRIX_STRLEN MATRIX_RANDOM(15, 20)
/*
* Number of character-heights in each generated gap
* (Note: this is not limited by the pixmap size!)
*/
#define MATRIX_GAPLEN MATRIX_RANDOM(2, 6)
/* colors used for Matrix characters */
#define BRIGHTGREEN (28 * MI_NPIXELS(mi) / 64)
#define GREEN (26 * MI_NPIXELS(mi) / 64)
/*************************************************************************/
/*
* state of the Matrix
*/
static matrix_t *matrix = (matrix_t *) NULL;
/* NAME: new_column
*
* FUNCTION: clears and generates a pixmap of "matrix" data
*/
static void new_column(const ModeInfo *mi, column_t *c)
{
matrix_t *mp = PICK_MATRIX(mi);
int currChar;
/*
* clear the pixmap to get rid of previous data or initialize
*/
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), mp->bg);
XFillRectangle(MI_DISPLAY(mi), (Drawable) c->pixmap, MI_GC(mi),
0, 0, PIXMAP_WIDTH, mp->pixmapHeight);
/*
* Write characters into the column pixmap, starting at the
* bottom and moving upwards. Decrement the string length, gap length,
* and next-speed-update timers for the column and reinitialize them
* if necessary.
*/
for (currChar = mp->charsPerPixmap - 1; currChar >= 0; currChar--) {
if (c->nextSpeedUpdate-- == 0) {
c->speed = MATRIX_SPEED;
c->nextSpeedUpdate = mp->speedUpdateInterval;
/* tweak to prevent really slow columns from remaining slow */
if (c->speed <= 2)
c->nextSpeedUpdate /= 2;
}
if (c->gapLen > 0) {
c->gapLen--;
continue;
} else if (c->strLen == 0) {
/*
* generate a gap of random length in the string, followed
* by a random number of characters. Set the endChar flag
* to indicate the end of a new string.
*/
c->gapLen = MATRIX_GAPLEN;
c->strLen = MATRIX_STRLEN;
c->endChar = True;
} else {
Pixmap src;
int kOffset;
if (c->endChar) {
src = mp->kana[1]; /* a bold, non-numeric character */
kOffset = MATRIX_RANDOM(10, katakana_num_cells);
c->endChar = False;
} else { /* inside a string - kana or number */
src = mp->kana[0];
kOffset = MATRIX_RANDOM(0, katakana_num_cells);
}
XCopyArea(MI_DISPLAY(mi), (Drawable) src,
(Drawable) c->pixmap, MI_GC(mi),
kOffset * katakana_cell_width, 0,
katakana_cell_width, katakana_cell_height,
0, currChar * katakana_cell_height);
c->strLen--;
}
}
}
/* NAME: free_matrix
*
* FUNCTION: delete the data associated with a single screen. Be careful
* not to do spurious free()s of nonexistent data, and to nullify all
* freed pointers that might be reused past the end of this call.
*/
static void
free_matrix(Display *display, matrix_t *mp)
{
if (mp->columns != NULL) {
int c;
for (c = 0; c < mp->num_cols; c++) {
if (mp->columns[c].pixmap)
XFreePixmap(display, mp->columns[c].pixmap);
}
free(mp->columns);
mp->columns = (column_t *) NULL;
}
if (mp->kana[0]) {
XFreePixmap(display, mp->kana[0]);
mp->kana[0] = None;
}
if (mp->kana[1]) {
XFreePixmap(display, mp->kana[1]);
mp->kana[1] = None;
}
}
/* NAME: setup_matrix()
*
* FUNCTION: Initialize the Matrix state for the current screen.
* Based on the width and height of the display,
* allocate and initialize column data structures.
*/
static void setup_matrix(const ModeInfo *mi)
{
matrix_t *mp = PICK_MATRIX(mi);
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
int c;
/* screen may have changed size/depth/who-knows-what */
free_matrix(display, mp);
if (MI_NPIXELS(mi) > 2) {
mp->fg = MI_PIXEL(mi, GREEN);
mp->bold = MI_PIXEL(mi, BRIGHTGREEN);
} else
mp->fg = mp->bold = MI_WHITE_PIXEL(mi);
mp->bg = MI_BLACK_PIXEL(mi);
if ((mp->kana[0] = XCreatePixmapFromBitmapData(display, window,
(char *) katakana_bits, katakana_width, katakana_height,
mp->bg, mp->fg, MI_DEPTH(mi))) == None) {
free_matrix(display, mp);
return;
}
if ((mp->kana[1] = XCreatePixmapFromBitmapData(display, window,
(char *) katakana_bits, katakana_width, katakana_height,
mp->bg, mp->bold, MI_DEPTH(mi))) == None) {
free_matrix(display, mp);
return;
}
/*
* Using the width of the kana font, determine how many
* columns can fit across the current screen (with a little
* padding).
*/
mp->num_cols = (int) (MI_WIDTH(mi) / (1.3 * katakana_cell_width));
if ((mp->columns = (column_t *) calloc(mp->num_cols,
sizeof(column_t))) == NULL) {
free_matrix(display, mp);
return;
}
/*
* If we're randomizing columns, keep the column pixmap height small
* to save memory and minimize time for each column update. Otherwise,
* make the height large to maximize variety without updating the pixmaps.
*/
#ifdef RANDOMIZE_COLUMNS
mp->charsPerPixmap = MI_HEIGHT(mi) / (4 * katakana_cell_height);
#else
mp->charsPerPixmap = MI_HEIGHT(mi) / katakana_cell_height;
#endif
if (!mp->charsPerPixmap) /* sanity check for tiny windows */
mp->charsPerPixmap = 1;
mp->pixmapHeight = mp->charsPerPixmap * katakana_cell_height;
for (c = 0; c < mp->num_cols; c++)
if ((mp->columns[c].pixmap = XCreatePixmap(display, window,
PIXMAP_WIDTH, mp->pixmapHeight, MI_DEPTH(mi))) == None) {
free_matrix(display, mp);
return;
}
/* Change the speed of a column after it's covered half the screen */
mp->speedUpdateInterval = MI_HEIGHT(mi) / (2 * katakana_cell_height);
/* initialize the column data */
for (c = 0; c < mp->num_cols; c++) {
column_t *column = &(mp->columns[c]);
column->yPtr = mp->pixmapHeight;
column->nextSpeedUpdate = 0; /* will generate new speed */
column->strLen = 0; /* will generate new string */
new_column(mi, column);
}
}
/* NAME: init_matrix
*
* FUNCTION: allocate space for global matrix array
* initialize colors
* initialize dimensions
* allocate a pair of pixmaps containing character set
* (0 is green on black, 1 is bold on black)
* create columns of "matrix" data
*/
void init_matrix(ModeInfo *mi)
{
if (matrix == NULL) {
if ((matrix = (matrix_t *) calloc(MI_NUM_SCREENS(mi),
sizeof(matrix_t))) == NULL)
return;
}
/* don't want any exposure events from XCopyArea */
XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
MI_CLEARWINDOW(mi);
setup_matrix(mi);
}
/* NAME: draw_matrix
*
* FUNCTION: update the matrix waterfall display
*/
void draw_matrix(ModeInfo *mi)
{
double xDistance;
int i;
matrix_t *mp;
if (matrix == NULL)
return;
mp = PICK_MATRIX(mi);
if (mp->columns == NULL)
return;
MI_IS_DRAWN(mi) = True;
xDistance = (double) MI_WIDTH(mi) / (double) mp->num_cols;
/*
* THEORY OF OPERATION
*
* Screen-to-screen blits occur within the video RAM and are usually
* hardware-accelerated, while pixmap-to-screen blits require DMA
* between main memory and vRAM. To make updates as fast as possible,
* we scroll down the screen contents in each column by <speed> pixels,
* then fill only the top <speed> rows of the column with pixmap data.
*
* There are two tricky bits to this scheme. First, we must keep a
* pointer (yPtr) to the pixmap contents which should be used to
* fill in the top rows of each column. yPtr is decremented on each
* call to draw_matrix(); when it reaches zero, the column's pixmap
* may be redrawn to generate new characters for the column.
*
* Second, the scroll increment corresponding to <speed> need not be a
* multiple of the pixmap height. We must special-case the handling of the
* last decrement that makes yPtr <= 0 to ensure that the last few pixels
* of the old data AND the first few pixels of the new data are both drawn.
* It turns out to be quite reasonable to do the pixmap update inline,
* between drawing the last few old pixels and the first few new pixels.
* Hence, we can achieve smooth scrolling with only one pixmap per column.
*/
for (i = 0; i < mp->num_cols; i++) {
column_t *c = &(mp->columns[i]);
int xOffset = (int) (i * xDistance);
int yDelta = c->speed;
/* screen-screen blit takes care of most of the column */
XCopyArea(MI_DISPLAY(mi), MI_WINDOW(mi),
MI_WINDOW(mi), MI_GC(mi),
xOffset, 0,
PIXMAP_WIDTH, MI_HEIGHT(mi) - yDelta,
xOffset, yDelta);
c->yPtr -= yDelta;
if (c->yPtr <= 0) /* we're about to finish the current pixmap */
{
/* exhaust the pixels in the current pixmap */
XCopyArea(MI_DISPLAY(mi), (Drawable) c->pixmap,
MI_WINDOW(mi), MI_GC(mi),
0, 0,
PIXMAP_WIDTH, yDelta + c->yPtr,
xOffset, -(c->yPtr));
#ifdef RANDOMIZE_COLUMNS
/* regenerate the column pixmap with new text */
new_column(mi, c);
#else
/* speed is normally updated in new_column(), which isn't called,
* so take this opportunity to update the column speed.
*/
c->speed = MATRIX_SPEED;
#endif
/* fill in the remainder of the column from the new pixmap */
XCopyArea(MI_DISPLAY(mi), (Drawable) c->pixmap,
MI_WINDOW(mi), MI_GC(mi),
0, mp->pixmapHeight + c->yPtr,
PIXMAP_WIDTH, -(c->yPtr),
xOffset, 0);
c->yPtr += mp->pixmapHeight;
}
else
{
/* fill in the remainder of the column from the pixmap */
XCopyArea(MI_DISPLAY(mi), (Drawable) c->pixmap,
MI_WINDOW(mi), MI_GC(mi),
0, c->yPtr,
PIXMAP_WIDTH, yDelta,
xOffset, 0);
}
}
}
/* NAME: release_matrix
*
* FUNCTION: frees all allocated resources
*/
void release_matrix(ModeInfo *mi)
{
/* If the matrix exists, free all data associated with all screens.
* free_matrix() does no harm if given nonexistent screens.
*/
if (matrix != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_matrix(MI_DISPLAY(mi), &matrix[screen]);
free(matrix);
matrix = (matrix_t *) NULL;
}
}
/* NAME: refresh_matrix
*
* FUNCTION: refresh the screen
*/
void refresh_matrix(ModeInfo *mi)
{
int c;
matrix_t *mp;
if (matrix == NULL)
return;
mp = PICK_MATRIX(mi);
if (mp->columns == NULL)
return;
/* We simply clear the whole window and restart the scrolling operation.
* In principle, it is possible to restore at least some of the
* column pixmap data to the screen, but it's not worth the trouble.
*/
MI_CLEARWINDOW(mi);
for (c = 0; c < mp->num_cols; c++)
mp->columns[c].yPtr = mp->pixmapHeight;
}
/* NAME: change_matrix
*
* FUNCTION: resets column offsets and speeds and generates new pixmaps
*/
void change_matrix(ModeInfo *mi)
{
int c;
matrix_t *mp;
if (matrix == NULL)
return;
mp = PICK_MATRIX(mi);
if (mp->columns == NULL)
return;
MI_CLEARWINDOW(mi);
for (c = 0; c < mp->num_cols; c++) {
column_t *column = &(mp->columns[c]);
column->yPtr = mp->pixmapHeight;
column->nextSpeedUpdate = 0; /* will generate new speed */
column->strLen = 0; /* will generate new string */
new_column(mi, column);
}
}
#endif /* MODE_matrix */