source: trunk/third/xscreensaver/hacks/munch.c @ 12203

Revision 12203, 7.4 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12202, which included commits to RCS files with non-trunk default branches.
Line 
1/* munch.c
2 * A munching squares implementation for X
3 * Tim Showalter <tjs@andrew.cmu.edu>
4 *
5 * Copyright 1997, Tim Showalter
6 * Permission is granted to copy, modify, and use this as long
7 * as this notice remains intact.  No warranties are expressed or implied.
8 * CMU Sucks.
9 *
10 * Some code stolen from / This is meant to work with
11 * xscreensaver, Copyright (c) 1992, 1995, 1996
12 * Jamie Zawinski <jwz@jwz.org>
13 *
14 * Permission to use, copy, modify, distribute, and sell this software and its
15 * documentation for any purpose is hereby granted without fee, provided that
16 * the above copyright notice appear in all copies and that both that
17 * copyright notice and this permission notice appear in supporting
18 * documentation.  No representations are made about the suitability of this
19 * software for any purpose.  It is provided "as is" without express or
20 * implied warranty.
21 */
22
23/* Munching Squares is this simplistic, silly screen hack (according
24   to HAKMEM, discovered by Jackson Wright in 1962) where you take
25   Y = X XOR T and graph it over and over.  According to HAKMEM, it
26   takes 5 instructions of PDP-1 assembly.  This is a little more
27   complicated than that, mostly X's fault, but it does some other
28   random things.
29
30   http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item146
31 */
32
33#include <math.h>
34/*#include <assert.h>*/
35#include "screenhack.h"
36
37/* flags for random things.  Must be < log2(random's maximum), incidentially.
38 */
39#define SHIFT_KX (0x01)
40#define SHIFT_KT (0x02)
41#define SHIFT_KY (0x04)
42#define GRAV     (0x08)
43
44char *progclass = "Munch";
45
46char *defaults [] = {
47    ".background:       black",
48    ".foreground:       white",
49    "*delay:            5000",
50    "*hold:             100000",
51    "*clear:            50",
52    "*logminwidth:      7",
53    "*shift:            True",
54    "*xor:              True",
55    0
56};
57
58XrmOptionDescRec options [] = {
59    { "-delay",         ".delay",       XrmoptionSepArg, 0 },
60    { "-hold",          ".hold",        XrmoptionSepArg, 0 },
61    { "-clear",         ".clear",       XrmoptionSepArg, "true" },
62    { "-shift",         ".shift",       XrmoptionNoArg, "true" },
63    { "-no-shift",      ".shift",       XrmoptionNoArg, "false" },
64    { "-logminwidth",   ".logminwidth", XrmoptionSepArg, 0 },
65    { "-xor",           ".xor",         XrmoptionNoArg, "true" },
66    { "-no-xor",        ".xor",         XrmoptionNoArg, "false" },
67    { 0, 0, 0, 0 }
68};
69
70
71static GC gc;
72/* only configurable things right now */
73static int delay, hold, clear, logminwidth, shiftk, xor;
74
75static void munchOnce (Display* dpy, Window w,
76                       int width, /* pixels */
77                       int atX, int atY, /* pixels */
78                       int kX, int kT, int kY, /* pixels */
79                       int grav /* 0 or not */) {
80
81    int x, y, t;
82    static Colormap cmap;
83    XWindowAttributes xgwa;
84    XColor fgc;
85    int drawX, drawY;
86
87    /*
88    fprintf(stderr,"Doing width %d at %d %d shift %d %d %d grav %d\n",
89            width, atX, atY, kX, kT, kY, grav);
90            */
91   
92    XGetWindowAttributes (dpy, w, &xgwa);
93
94    if (!mono_p) {
95        /* XXX there are probably bugs with this. */
96        cmap = xgwa.colormap;
97   
98        fgc.red = random() % 65535;
99        fgc.green = random() % 65535;
100        fgc.blue = random() % 65535;
101   
102        if (XAllocColor(dpy, cmap, &fgc)) {
103            XSetForeground(dpy, gc, fgc.pixel);
104        }
105    }
106   
107    /* Finally draw this munching square. */
108    for(t = 0; t < width; t++) {
109        for(x = 0; x < width; x++) {
110            /* figure out the next point */
111            y = ((x ^ ((t + kT) % width)) + kY) % width;
112
113            drawX = ((x + kX) % width) + atX;
114            drawY = (grav ? y + atY : atY + width - 1 - y);
115
116            /* used to be bugs where it would draw partially offscreen.
117               while that might be a pretty feature, I didn't want it to do
118               that yet.  if these trigger, please let me know.
119               */
120/*          assert(drawX >= 0 && drawX < xgwa.width);
121            assert(drawY >= 0 && drawY < xgwa.height);
122*/
123
124            XDrawPoint(dpy, w, gc, drawX, drawY);
125            /* XXX may want to change this to XDrawPoints,
126               but it's fast enough without it for the moment. */
127           
128        }
129       
130        /* we've drawn one pass' worth of points.  let the server catch up
131           or this won't be interesting to watch at all.  we call this here
132           in the hopes of having one whole sequence of dots appear at the
133           same time (one for each value of x, surprisingly enough)
134           */
135        XSync(dpy, False);
136        screenhack_handle_events (dpy);
137        if (delay) usleep(delay);
138    }
139}
140
141/*
142 * dumb way to get # of digits in number.  Probably faster than actually
143 * doing a log and a division, maybe.
144 */
145static int dumb_log_2(int k) {
146    int r = -1;
147    while (k > 0) {
148        k >>= 1; r++;
149    }
150    return r;
151}
152
153/* This parses arguments, initializes the window, etc., and finally starts
154 * calling munchOnce ad infinitum.
155 */
156void
157screenhack (dpy, w) Display *dpy; Window w;
158{
159    int logmaxwidth;
160    int maxwidth;
161    XWindowAttributes xgwa;
162    Colormap cmap;
163    XGCValues gcv;
164    int n = 0;  /* number of squares before we have to clear */
165    int randflags;
166    int thiswidth;
167   
168    /* get the dimensions of the window */
169    XGetWindowAttributes (dpy, w, &xgwa);
170   
171    /* We need a square; limit on screen size? */
172    /* we want a power of 2 for the width or the munch doesn't fill up.
173     */
174    logmaxwidth = (int)
175        dumb_log_2(xgwa.height < xgwa.width ? xgwa.height : xgwa.width);
176
177    maxwidth = 1 << logmaxwidth;
178
179    if (logmaxwidth < logminwidth) {
180        /* off-by-one error here?  Anyone running on < 640x480? */
181        fprintf(stderr, "munch: screen too small; use -logminwidth\n");
182        fprintf(stderr, "\t(width is %d; log is %d; log must be at least "
183                "%d)\n",
184                (xgwa.height < xgwa.width ? xgwa.height : xgwa.width),
185                logmaxwidth, logminwidth);
186        exit(0);
187    }
188   
189    /* create the gc */
190    cmap = xgwa.colormap;
191    gcv.foreground= get_pixel_resource("foreground","Foreground",
192                                       dpy, cmap);
193    gcv.background= get_pixel_resource("background","Background",
194                                       dpy, cmap);
195   
196    gc = XCreateGC(dpy, w, GCForeground|GCBackground, &gcv);
197   
198    delay = get_integer_resource ("delay", "Integer");
199    if (delay < 0) delay = 0;
200   
201    hold = get_integer_resource ("hold", "Integer");
202    if (hold < 0) hold = 0;
203   
204    clear = get_integer_resource ("clear", "Integer");
205    if (clear < 0) clear = 0;
206
207    logminwidth = get_integer_resource ("logminwidth", "Integer");
208    if (logminwidth < 2) logminwidth = 2;
209
210    shiftk = get_boolean_resource("shift", "Boolean");
211
212    xor = get_boolean_resource("xor", "Boolean");
213
214    /* always draw xor on mono. */
215    if (mono_p || xor) {
216        XSetFunction(dpy, gc, GXxor);
217    }
218
219    for(;;) {
220        /* saves some calls to random.  big deal */
221        randflags = random();
222
223        /* choose size -- power of two */
224        thiswidth = 1 << (logminwidth +
225                          (random() % (1 + logmaxwidth - logminwidth)));
226
227        munchOnce(dpy, w,
228                  thiswidth, /* Width, in pixels */
229                 
230                  /* draw at this location */
231                  (random() % (xgwa.width <= thiswidth ? 1
232                               : xgwa.width - thiswidth)),
233                  (random() % (xgwa.height <= thiswidth ? 1
234                               : xgwa.width - thiswidth)),
235                 
236                  /* wrap-around by these values; no need to %
237                     as we end up doing that later anyway*/
238                  ((shiftk && (randflags & SHIFT_KX))
239                   ? (random() % thiswidth) : 0),
240                  ((shiftk && (randflags & SHIFT_KT))
241                   ? (random() % thiswidth) : 0),
242                  ((shiftk && (randflags & SHIFT_KY))
243                   ? (random() % thiswidth) : 0),
244                 
245                  /* set the gravity of the munch, or rather,
246                     which direction we draw stuff in. */
247                  (randflags & GRAV)
248                  );
249       
250        screenhack_handle_events (dpy);
251        if (hold) usleep(hold);
252       
253        if (clear && ++n >= clear) {
254            XClearWindow(dpy, w);
255            n = 0;
256        }
257    }
258}
Note: See TracBrowser for help on using the repository browser.