/* -*- 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 #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 #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 pixels, * then fill only the top 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 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 */