Imported wmMatrix-0.2.tar.gz
[dockapps.git] / wmMatrix / matrix.c
blobda2f2a20f4847b9a64f3b3f8ec25ba20428392be
1 /* xscreensaver, Copyright (c) 1999 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
9 * implied warranty.
11 * Matrix -- simulate the text scrolls from the movie "The Matrix".
13 * The movie people distribute their own Windows/Mac screensaver that does
14 * a similar thing, so I wrote one for Unix. However, that version (the
15 * Windows/Mac version at http://www.whatisthematrix.com/) doesn't match my
16 * memory of what the screens in the movie looked like, so my `xmatrix'
17 * does things differently.
20 #include <stdio.h>
21 #include "images/small.xpm"
22 #include "images/medium.xpm"
23 #include "images/large.xpm"
24 #include "images/matrix.xbm"
26 #define CHAR_HEIGHT 4
29 #include "matrix.h"
31 #include "resources.h"
34 extern GC NormalGC;
35 extern GC EraseGC;
36 extern Pixel back_pix, fore_pix;
37 extern int PixmapSize;
38 int CHAR_HEIGHT;
44 static void load_images (m_state *state) {
46 if (state->xgwa.depth > 1) {
48 XpmAttributes xpmattrs;
49 int result;
51 xpmattrs.valuemask = 0;
52 xpmattrs.valuemask |= XpmCloseness;
53 xpmattrs.closeness = 40000;
54 xpmattrs.valuemask |= XpmVisual;
55 xpmattrs.visual = state->xgwa.visual;
56 xpmattrs.valuemask |= XpmDepth;
57 xpmattrs.depth = state->xgwa.depth;
58 xpmattrs.valuemask |= XpmColormap;
59 xpmattrs.colormap = state->xgwa.colormap;
61 if (PixmapSize == 1){
63 CHAR_HEIGHT = 4;
64 result = XpmCreatePixmapFromData (state->dpy, state->window, small,
65 &state->images, 0 /* mask */,
66 &xpmattrs);
67 } else if (PixmapSize == 2){
69 CHAR_HEIGHT = 6;
70 result = XpmCreatePixmapFromData (state->dpy, state->window, medium,
71 &state->images, 0 /* mask */,
72 &xpmattrs);
73 } else {
75 CHAR_HEIGHT = 8;
76 result = XpmCreatePixmapFromData (state->dpy, state->window, large,
77 &state->images, 0 /* mask */,
78 &xpmattrs);
81 if (!state->images || (result != XpmSuccess && result != XpmColorError))
82 state->images = 0;
84 state->image_width = xpmattrs.width;
85 state->image_height = xpmattrs.height;
86 state->nglyphs = state->image_height / CHAR_HEIGHT;
88 } else {
90 state->image_width = matrix_width;
91 state->image_height = matrix_height;
92 state->nglyphs = state->image_height / CHAR_HEIGHT;
94 state->images = XCreatePixmapFromBitmapData (state->dpy, state->window,
95 (char *) matrix_bits,
96 state->image_width, state->image_height,
97 back_pix, fore_pix, state->xgwa.depth);
103 m_state *init_matrix( Display *dpy, Window window ) {
105 m_state *state = (m_state *) calloc (sizeof(*state), 1);
108 state->dpy = dpy;
109 state->window = window;
111 XGetWindowAttributes (dpy, window, &state->xgwa);
112 load_images (state);
114 state->draw_gc = NormalGC;
115 state->erase_gc = EraseGC;
117 state->char_width = state->image_width / 2;
118 state->char_height = CHAR_HEIGHT;
120 state->grid_width = state->xgwa.width / state->char_width;
121 state->grid_height = state->xgwa.height / state->char_height;
122 state->grid_width++;
123 state->grid_height++;
125 state->cells = (m_cell *)calloc (sizeof(m_cell), state->grid_width * state->grid_height);
126 state->feeders = (m_feeder *)calloc (sizeof(m_feeder), state->grid_width);
128 state->density = 40;
130 state->insert_top_p = False;
131 state->insert_bottom_p = True;
134 return state;
139 static void insert_glyph (m_state *state, int glyph, int x, int y) {
141 Bool bottom_feeder_p = (y >= 0);
142 m_cell *from, *to;
144 if (y >= state->grid_height) return;
146 if (bottom_feeder_p) {
148 to = &state->cells[state->grid_width * y + x];
150 } else {
152 for (y = state->grid_height-1; y > 0; y--) {
154 from = &state->cells[state->grid_width * (y-1) + x];
155 to = &state->cells[state->grid_width * y + x];
156 *to = *from;
157 to->changed = True;
160 to = &state->cells[x];
164 to->glyph = glyph;
165 to->changed = True;
167 if (!to->glyph) ;
168 else if (bottom_feeder_p) to->glow = 1 + (random() % 2);
169 else to->glow = 0;
174 static void feed_matrix (m_state *state) {
176 int x;
180 * Update according to current feeders.
182 for (x = 0; x < state->grid_width; x++) {
184 m_feeder *f = &state->feeders[x];
186 if (f->throttle) { /* this is a delay tick, synced to frame. */
188 f->throttle--;
190 } else if (f->remaining > 0) { /* how many items are in the pipe */
192 int g = (random() % state->nglyphs) + 1;
193 insert_glyph (state, g, x, f->y);
194 f->remaining--;
195 if (f->y >= 0) f->y++; /* bottom_feeder_p */
197 } else { /* if pipe is empty, insert spaces */
199 insert_glyph (state, 0, x, f->y);
200 if (f->y >= 0) f->y++; /* bottom_feeder_p */
204 if ((random() % 10) == 0) { /* randomly change throttle speed */
206 f->throttle = ((random() % 5) + (random() % 5));
214 static int densitizer (m_state *state) {
216 /* Horrid kludge that converts percentages (density of screen coverage)
217 to the parameter that actually controls this. I got this mapping
218 empirically, on a 1024x768 screen. Sue me. */
219 if (state->density < 10) return 85;
220 else if (state->density < 15) return 60;
221 else if (state->density < 20) return 45;
222 else if (state->density < 25) return 25;
223 else if (state->density < 30) return 20;
224 else if (state->density < 35) return 15;
225 else if (state->density < 45) return 10;
226 else if (state->density < 50) return 8;
227 else if (state->density < 55) return 7;
228 else if (state->density < 65) return 5;
229 else if (state->density < 80) return 3;
230 else if (state->density < 90) return 2;
231 else return 1;
236 static void hack_matrix (m_state *state) {
238 int x;
240 /* Glow some characters. */
241 if (!state->insert_bottom_p) {
243 int i = random() % (state->grid_width / 2);
244 while (--i > 0) {
246 int x = random() % state->grid_width;
247 int y = random() % state->grid_height;
248 m_cell *cell = &state->cells[state->grid_width * y + x];
249 if (cell->glyph && cell->glow == 0) {
251 cell->glow = random() % 10;
252 cell->changed = True;
258 /* Change some of the feeders. */
259 for (x = 0; x < state->grid_width; x++) {
261 m_feeder *f = &state->feeders[x];
262 Bool bottom_feeder_p;
264 if (f->remaining > 0) /* never change if pipe isn't empty */
265 continue;
267 if ((random() % densitizer(state)) != 0) /* then change N% of the time */
268 continue;
270 f->remaining = 3 + (random() % state->grid_height);
271 f->throttle = ((random() % 5) + (random() % 5));
273 if ((random() % 4) != 0)
274 f->remaining = 0;
276 if (state->insert_top_p && state->insert_bottom_p)
277 bottom_feeder_p = (random() & 1);
278 else
279 bottom_feeder_p = state->insert_bottom_p;
281 if (bottom_feeder_p)
282 f->y = random() % (state->grid_height / 2);
283 else
284 f->y = -1;
289 void draw_matrix (m_state *state, int d) {
291 int x, y;
292 int count = 0;
294 state->density = d;
295 feed_matrix( state );
296 hack_matrix( state );
298 for (y = 0; y < state->grid_height; y++) {
299 for (x = 0; x < state->grid_width; x++) {
301 m_cell *cell = &state->cells[state->grid_width * y + x];
303 if ( cell->glyph ) count++;
305 if ( !cell->changed ) continue;
307 if ( cell->glyph == 0 ) {
309 XFillRectangle( state->dpy, state->window, state->erase_gc,
310 x * state->char_width, y * state->char_height,
311 state->char_width, state->char_height );
312 } else {
314 XCopyArea( state->dpy, state->images, state->window, state->draw_gc,
315 (cell->glow ? state->char_width : 0), (cell->glyph - 1) * state->char_height,
316 state->char_width, state->char_height, x * state->char_width, y * state->char_height );
320 cell->changed = False;
322 if (cell->glow > 0) {
324 cell->glow--;
325 cell->changed = True;
333 #if 0
335 static int i = 0;
336 static int ndens = 0;
337 static int tdens = 0;
338 i++;
339 if (i > 50)
341 int dens = (100.0 *
342 (((double)count) /
343 ((double) (state->grid_width * state->grid_height))));
344 tdens += dens;
345 ndens++;
346 printf ("density: %d%% (%d%%)\n", dens, (tdens / ndens));
347 i = 0;
350 #endif