X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fxmatrix.c;h=1a6bebf158c8b857a436e5298e4e20abd6d1ad41;hp=c9f2222fb8c71679b06b711344ef2f36a5b68c71;hb=8eb2873d7054e705c4e83f22d18c40946a9e2529;hpb=a1d41b2aa6e18bf9a49b914a99dda8232c5d7762 diff --git a/hacks/xmatrix.c b/hacks/xmatrix.c index c9f2222f..1a6bebf1 100644 --- a/hacks/xmatrix.c +++ b/hacks/xmatrix.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1999 Jamie Zawinski +/* xscreensaver, Copyright (c) 1999, 2001 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -39,25 +39,6 @@ * * ========================================================== * - * One thing I would like to add (to "-trace" mode) is an intro like at the - * beginning of the movie, where it printed - * - * Call trans opt: received. 2-19-98 13:24:18 REC:Log>_ - * - * then cleared, then - * - * Trace program: running_ - * - * then did the trace. - * - * I was also thinking of sometimes making the screen go blank and say - * "Knock, knock." - * - * However, the problem with both of these ideas is, I made the number images - * by tooling around in GIMP until I got something that looked good (blurring - * and unblurring and enlarging and shrinking and blurring some more...) and I - * couldn't reproduce it if my life depended on it. And to add anything other - * than roman digits/katakana, I'd need to matrixify a whole font... */ #include "screenhack.h" @@ -66,22 +47,31 @@ #ifdef HAVE_XPM # include -# include "images/matrix.xpm" +# include "images/matrix0.xpm" +# include "images/matrix1.xpm" # include "images/matrix2.xpm" +# include "images/matrix0b.xpm" +# include "images/matrix1b.xpm" +# include "images/matrix2b.xpm" #endif -#include "images/matrix.xbm" +#include "images/matrix0.xbm" +#include "images/matrix1.xbm" #include "images/matrix2.xbm" +#include "images/matrix0b.xbm" +#include "images/matrix1b.xbm" +#include "images/matrix2b.xbm" -#define CHAR_ROWS 27 -#define CHAR_COLS 3 -#define FADE_COL 0 -#define PLAIN_COL 1 -#define GLOW_COL 2 +#define CHAR_COLS 16 +#define CHAR_ROWS 13 +#define CHAR_MAPS 3 +#define FADE_MAP 0 +#define PLAIN_MAP 1 +#define GLOW_MAP 2 typedef struct { - unsigned int glyph : 8; int glow : 8; + unsigned int glyph : 9; /* note: 9 bit characters! */ unsigned int changed : 1; unsigned int spinner : 1; } m_cell; @@ -92,6 +82,40 @@ typedef struct { int y; } m_feeder; +#define countof(x) (sizeof(x)/sizeof(*(x))) + +static int matrix_encoding[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207 }; +static int decimal_encoding[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; +static int hex_encoding[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 33, 34, 35, 36, 37, 38 }; +static int binary_encoding[] = { 16, 17 }; +static int dna_encoding[] = { 33, 35, 39, 52 }; +static unsigned char char_map[256] = { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 16 */ + 0, 1, 2, 3, 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 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 128 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 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 */ + 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 */ +}; + +typedef enum { TRACE0, TRACE1, TRACE2, + KNOCK0, KNOCK1, KNOCK2, KNOCK3, + KNOCK4, KNOCK5, KNOCK6, KNOCK7, + MATRIX, DNA, BINARY, HEX } m_mode; + typedef struct { Display *dpy; Window window; @@ -104,24 +128,28 @@ typedef struct { int nspinners; Bool small_p; Bool insert_top_p, insert_bottom_p; - Bool trace_p; + m_mode mode; signed char *tracing; int density; - Pixmap images; + Pixmap images[CHAR_MAPS]; int image_width, image_height; + int nglyphs; + int *glyph_map; } m_state; static void -load_images (m_state *state) +load_images_1 (m_state *state, int which) { #ifdef HAVE_XPM if (!get_boolean_resource ("mono", "Boolean") && state->xgwa.depth > 1) { + + XpmAttributes xpmattrs; int result; xpmattrs.valuemask = 0; @@ -144,35 +172,32 @@ load_images (m_state *state) # endif result = XpmCreatePixmapFromData (state->dpy, state->window, - (state->small_p - ? matrix2_xpm - : matrix_xpm), - &state->images, 0 /* mask */, + (which == 0 ? (state->small_p ? matrix0b_xpm : matrix0_xpm) : + which == 1 ? (state->small_p ? matrix1b_xpm : matrix1_xpm) : + (state->small_p ? matrix2b_xpm : matrix2_xpm)), + &state->images[which], 0 /* mask */, &xpmattrs); if (!state->images || (result != XpmSuccess && result != XpmColorError)) - state->images = 0; + state->images[which] = 0; state->image_width = xpmattrs.width; state->image_height = xpmattrs.height; - state->nglyphs = CHAR_ROWS; } else #endif /* !HAVE_XPM */ { unsigned long fg, bg; - state->image_width = (state->small_p ? matrix2_width : matrix_width); - state->image_height = (state->small_p ? matrix2_height : matrix_height); - state->nglyphs = CHAR_ROWS; - + state->image_width = (state->small_p ? matrix0b_width :matrix0_width); + state->image_height = (state->small_p ? matrix0b_height:matrix0_height); fg = get_pixel_resource("foreground", "Foreground", state->dpy, state->xgwa.colormap); bg = get_pixel_resource("background", "Background", state->dpy, state->xgwa.colormap); - state->images = - XCreatePixmapFromBitmapData (state->dpy, state->window, - (state->small_p - ? (char *) matrix2_bits - : (char *) matrix_bits), + state->images[which] = + XCreatePixmapFromBitmapData (state->dpy, state->window, (char *) + (which == 0 ? (state->small_p ? matrix0b_bits :matrix0_bits) : + which == 1 ? (state->small_p ? matrix1b_bits :matrix1_bits) : + (state->small_p ? matrix2b_bits :matrix2_bits)), state->image_width, state->image_height, bg, fg, state->xgwa.depth); } @@ -180,30 +205,49 @@ load_images (m_state *state) static void -flip_images (m_state *state) +load_images (m_state *state) { - XImage *im = XGetImage (state->dpy, state->images, 0, 0, + load_images_1 (state, 0); + load_images_1 (state, 1); + load_images_1 (state, 2); +} + + +static void +flip_images_1 (m_state *state, int which) +{ + XImage *im = XGetImage (state->dpy, state->images[which], 0, 0, state->image_width, state->image_height, ~0L, (state->xgwa.depth > 1 ? ZPixmap : XYPixmap)); - int x, y, i; - int w = state->image_width / CHAR_COLS; - unsigned long *row = (unsigned long *) malloc (sizeof(*row) * w); + int x, y, xx; + int ww = state->char_width; + unsigned long *row = (unsigned long *) malloc (sizeof(*row) * ww); for (y = 0; y < state->image_height; y++) - for (i = 0; i < CHAR_COLS; i++) - { - for (x = 0; x < w; x++) - row[x] = XGetPixel (im, (i * w) + x, y); - for (x = 0; x < w; x++) - XPutPixel (im, (i * w) + x, y, row[w - x - 1]); - } + { + for (x = 0; x < CHAR_COLS; x++) + { + for (xx = 0; xx < ww; xx++) + row[xx] = XGetPixel (im, (x * ww) + xx, y); + for (xx = 0; xx < ww; xx++) + XPutPixel (im, (x * ww) + xx, y, row[ww - xx - 1]); + } + } - XPutImage (state->dpy, state->images, state->draw_gc, im, 0, 0, 0, 0, + XPutImage (state->dpy, state->images[which], state->draw_gc, im, 0, 0, 0, 0, state->image_width, state->image_height); XDestroyImage (im); free (row); } +static void +flip_images (m_state *state) +{ + flip_images_1 (state, 0); + flip_images_1 (state, 1); + flip_images_1 (state, 2); +} + static void init_spinners (m_state *state) @@ -251,8 +295,9 @@ init_trace (m_state *state) for (i = 0; i < strlen(state->tracing); i++) state->tracing[i] = -state->tracing[i]; - state->nglyphs = 10; - flip_images (state); + + state->glyph_map = decimal_encoding; + state->nglyphs = countof(decimal_encoding); return; @@ -263,7 +308,7 @@ init_trace (m_state *state) if (s) free (s); if (state->tracing) free (state->tracing); state->tracing = 0; - state->trace_p = False; + state->mode = MATRIX; } @@ -271,14 +316,22 @@ static m_state * init_matrix (Display *dpy, Window window) { XGCValues gcv; - char *insert; + char *insert, *mode; m_state *state = (m_state *) calloc (sizeof(*state), 1); + state->dpy = dpy; state->window = window; XGetWindowAttributes (dpy, window, &state->xgwa); - state->small_p = get_boolean_resource ("small", "Boolean"); + { + const char *s = get_string_resource ("small", "Boolean"); + if (s && *s) + state->small_p = get_boolean_resource ("small", "Boolean"); + else + state->small_p = (state->xgwa.width < 300); + } + load_images (state); gcv.foreground = get_pixel_resource("foreground", "Foreground", @@ -299,6 +352,9 @@ init_matrix (Display *dpy, Window window) state->grid_width++; state->grid_height++; + state->glyph_map = matrix_encoding; + state->nglyphs = countof(matrix_encoding); + state->cells = (m_cell *) calloc (sizeof(m_cell), state->grid_width * state->grid_height); state->feeders = (m_feeder *) calloc (sizeof(m_feeder), state->grid_width); @@ -336,11 +392,53 @@ init_matrix (Display *dpy, Window window) if (insert) free (insert); - state->trace_p = get_boolean_resource ("trace", "Trace"); - if (state->trace_p) + mode = get_string_resource ("mode", "Mode"); + if (mode && !strcasecmp(mode, "trace")) + state->mode = TRACE0; + else if (mode && !strcasecmp(mode, "dna")) + state->mode = DNA; + else if (mode && !strcasecmp(mode, "binary")) + state->mode = BINARY; + else if (mode && (!strcasecmp(mode, "hex") || + !strcasecmp(mode, "hexadecimal"))) + state->mode = HEX; + else if (!mode || !*mode || !strcasecmp(mode, "matrix")) + state->mode = MATRIX; + else + { + fprintf (stderr, + "%s: `mode' must be matrix, trace, dna, binary, or hex: not `%s'\n", + progname, mode); + state->mode = MATRIX; + } + + if (state->mode == DNA) + { + state->glyph_map = dna_encoding; + state->nglyphs = countof(dna_encoding); + } + else if (state->mode == BINARY) + { + state->glyph_map = binary_encoding; + state->nglyphs = countof(binary_encoding); + } + else if (state->mode == HEX) + { + state->glyph_map = hex_encoding; + state->nglyphs = countof(hex_encoding); + } + else if (state->mode == HEX) + { + state->glyph_map = hex_encoding; + state->nglyphs = countof(hex_encoding); + } + else if (state->mode == TRACE0) init_trace (state); else - init_spinners (state); + { + flip_images (state); + init_spinners (state); + } return state; } @@ -389,6 +487,14 @@ feed_matrix (m_state *state) { int x; + switch (state->mode) + { + case TRACE2: case MATRIX: case DNA: case BINARY: case HEX: + break; + default: + return; + } + /* Update according to current feeders. */ for (x = 0; x < state->grid_width; x++) { @@ -400,7 +506,7 @@ feed_matrix (m_state *state) } else if (f->remaining > 0) /* how many items are in the pipe */ { - int g = (random() % state->nglyphs) + 1; + int g = state->glyph_map[(random() % state->nglyphs)] + 1; insert_glyph (state, g, x, f->y); f->remaining--; if (f->y >= 0) /* bottom_feeder_p */ @@ -442,11 +548,171 @@ densitizer (m_state *state) } +static void +hack_text (m_state *state) +{ + int i; + int x = 0; + const char *s; + switch (state->mode) + { + case TRACE0: s = "Call trans opt: received.\n" + "2-19-98 13:24:18 REC:Log>_"; break; + case TRACE1: s = "Trace program: running_"; break; + + case KNOCK0: s = "Wake up, Neo..."; break; + case KNOCK1: s = ""; break; + case KNOCK2: s = "The Matrix has you..."; break; + case KNOCK3: s = ""; break; + case KNOCK4: s = "Follow the white rabbit..."; break; + case KNOCK5: s = ""; break; + case KNOCK6: s = "Knock knock, Neo."; break; + case KNOCK7: s = ""; break; + + default: abort(); break; + } + + for (i = 0; i < state->grid_height * state->grid_width; i++) + { + m_cell *cell = &state->cells[i]; + cell->changed = (cell->glyph != 0); + cell->glyph = 0; + } + + if (state->mode == TRACE0 || state->mode == TRACE1) + i = 0; + else + { + int y; + x = ((int)state->grid_width - (int)strlen(s)) / 2; + y = (state->grid_height / 2) - 1; + if (y < 0) y = 0; + if (x < 0) x = 0; + i = (y * state->grid_width) + x; + } + + while (*s) + { + if (*s == '\n') + { + i = ((i / state->grid_width) + 1) * state->grid_width; + x = 0; + } + else + { + m_cell *cell = &state->cells[i]; + if (x < state->grid_width-1) + { + cell->glyph = char_map[(unsigned char) *s] + 1; + if (*s == ' ' || *s == '\t') cell->glyph = 0; + cell->changed = 1; + i++; + } + x++; + } + s++; + } +} + +static void +roll_state (m_state *state) +{ + int delay = 0; + switch (state->mode) + { + case TRACE0: + delay = 3; + state->mode = TRACE1; + break; + + case TRACE1: + delay = 2; + state->mode = TRACE2; + break; + + case TRACE2: + { + Bool any = False; + int i; + for (i = 0; i < strlen(state->tracing); i++) + if (state->tracing[i] < 0) any = True; + + if (!any) + { + XSync (state->dpy, False); + sleep (3); + state->mode = MATRIX; + state->glyph_map = matrix_encoding; + state->nglyphs = countof(matrix_encoding); + flip_images (state); + free (state->tracing); + state->tracing = 0; + } + else if ((random() % 10) == 0) + { + int x = random() % strlen(state->tracing); + if (state->tracing[x] < 0) + state->tracing[x] = -state->tracing[x]; + } + break; + } + + case KNOCK0: delay = 1; state->mode++; break; /* wake */ + case KNOCK1: delay = 4; state->mode++; break; + case KNOCK2: delay = 2; state->mode++; break; /* has */ + case KNOCK3: delay = 4; state->mode++; break; + case KNOCK4: delay = 2; state->mode++; break; /* rabbit */ + case KNOCK5: delay = 4; state->mode++; break; + case KNOCK6: delay = 4; state->mode++; break; /* knock */ + case KNOCK7: + state->mode = MATRIX; + state->glyph_map = matrix_encoding; + state->nglyphs = countof(matrix_encoding); + flip_images (state); + break; + + case MATRIX: + if (! (random() % 5000)) + { + state->mode = KNOCK0; + flip_images (state); + } + break; + + case DNA: case BINARY: case HEX: + break; + + default: + abort(); + break; + } + + if (delay) + { + XSync (state->dpy, False); + sleep (delay); + } +} + + static void hack_matrix (m_state *state) { int x; + switch (state->mode) + { + case TRACE0: case TRACE1: + case KNOCK0: case KNOCK1: case KNOCK2: case KNOCK3: + case KNOCK4: case KNOCK5: case KNOCK6: case KNOCK7: + hack_text (state); + return; + case TRACE2: case MATRIX: case DNA: case BINARY: case HEX: + break; + default: + abort(); break; + } + /* Glow some characters. */ if (!state->insert_bottom_p) { @@ -482,7 +748,7 @@ hack_matrix (m_state *state) if ((random() % 4) != 0) f->remaining = 0; - if (state->trace_p) + if (state->mode == TRACE2) bottom_feeder_p = True; if (state->insert_top_p && state->insert_bottom_p) bottom_feeder_p = (random() & 1); @@ -495,7 +761,7 @@ hack_matrix (m_state *state) f->y = -1; } - if (!state->trace_p && + if (!state->mode == TRACE2 && ! (random() % 500)) init_spinners (state); } @@ -518,17 +784,21 @@ draw_matrix (m_state *state) if (cell->glyph) count++; - if (state->trace_p) + if (state->mode == TRACE2) { int xx = x % strlen(state->tracing); Bool dead_p = state->tracing[xx] > 0; if (y == 0 && x == xx) - cell->glyph = (dead_p ? (state->tracing[xx]-'0'+1) : 0); + cell->glyph = (dead_p + ? state->glyph_map[state->tracing[xx]-'0'] + 1 + : 0); else if (y == 0) cell->glyph = 0; else - cell->glyph = (dead_p ? 0 : (random() % state->nglyphs) + 1); + cell->glyph = (dead_p ? 0 : + (state->glyph_map[(random()%state->nglyphs)] + + 1)); cell->changed = 1; } @@ -543,16 +813,22 @@ draw_matrix (m_state *state) state->char_width, state->char_height); else - XCopyArea (state->dpy, state->images, state->window, state->draw_gc, - ((cell->glow > 0 || cell->spinner) - ? (state->char_width * GLOW_COL) - : (cell->glow == 0 - ? (state->char_width * PLAIN_COL) - : (state->char_width * FADE_COL))), - (cell->glyph - 1) * state->char_height, - state->char_width, state->char_height, - x * state->char_width, - y * state->char_height); + { + int cx = (cell->glyph - 1) % CHAR_COLS; + int cy = (cell->glyph - 1) / CHAR_COLS; + int map = ((cell->glow > 0 || cell->spinner) ? GLOW_MAP : + (cell->glow == 0) ? PLAIN_MAP : + GLOW_MAP); + + XCopyArea (state->dpy, state->images[map], + state->window, state->draw_gc, + cx * state->char_width, + cy * state->char_height, + state->char_width, + state->char_height, + x * state->char_width, + y * state->char_height); + } cell->changed = 0; @@ -571,35 +847,12 @@ draw_matrix (m_state *state) if (cell->spinner) { - cell->glyph = random() % CHAR_ROWS; + cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1); cell->changed = 1; } } - if (state->trace_p) - { - Bool any = False; - int i; - for (i = 0; i < strlen(state->tracing); i++) - if (state->tracing[i] < 0) any = True; - - if (!any) - { - XSync (state->dpy, False); - sleep (3); - state->trace_p = False; - state->nglyphs = CHAR_ROWS; - flip_images (state); - free (state->tracing); - state->tracing = 0; - } - else if ((random() % 10) == 0) - { - int x = random() % strlen(state->tracing); - if (state->tracing[x] < 0) - state->tracing[x] = -state->tracing[x]; - } - } + roll_state (state); #if 0 { @@ -628,10 +881,10 @@ char *progclass = "XMatrix"; char *defaults [] = { ".background: black", ".foreground: green", - "*small: False", + "*small: ", "*delay: 10000", "*insert: both", - "*trace: false", + "*mode: Matrix", "*tracePhone: (212) 555-0690", "*spinners: 5", "*density: 75", @@ -646,8 +899,11 @@ XrmOptionDescRec options [] = { { "-bottom", ".insert", XrmoptionNoArg, "bottom" }, { "-both", ".insert", XrmoptionNoArg, "both" }, { "-density", ".density", XrmoptionSepArg, 0 }, - { "-trace", ".trace", XrmoptionNoArg, "True" }, + { "-trace", ".mode", XrmoptionNoArg, "trace" }, { "-phone", ".tracePhone", XrmoptionSepArg, 0 }, + { "-dna", ".mode", XrmoptionNoArg, "DNA" }, + { "-binary", ".mode", XrmoptionNoArg, "binary" }, + { "-hexadecimal", ".mode", XrmoptionNoArg, "hexadecimal"}, { 0, 0, 0, 0 } };