1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* munch --- munching squares */
3
4 #if 0
5 static const char sccsid[] = "@(#)munch.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
15 *
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
21 *
22 * Tim Showalter <tjs@andrew.cmu.edu>
23 *
24 * Copyright 1997, Tim Showalter
25 * Permission is granted to copy, modify, and use this as long
26 * as this notice remains intact. No warranties are expressed or implied.
27 * CMU Sucks.
28 *
29 * Some code stolen from / This is meant to work with
30 * xscreensaver, Copyright (c) 1992, 1995, 1996
31 * Jamie Zawinski <jwz AT jwz.org>
32 *
33 * Permission to use, copy, modify, distribute, and sell this software and its
34 * documentation for any purpose is hereby granted without fee, provided that
35 * the above copyright notice appear in all copies and that both that
36 * copyright notice and this permission notice appear in supporting
37 * documentation. No representations are made about the suitability of this
38 * software for any purpose. It is provided "as is" without express or
39 * implied warranty.
40 *
41 * Revision History:
42 * 01-Nov-2000: Allocation checks
43 */
44
45 /*-
46 * Munching Squares is this simplistic, silly screen hack (according to
47 * HAKMEM, discovered by Jackson Wright in 1962) where you take Y = X XOR T
48 * and graph it over and over. According to HAKMEM, it takes 5 instructions
49 * of PDP-1 assembly. This is a little more complicated than that, mostly X's
50 * fault, but it does some other random things.
51 * http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item146
52 */
53
54 #ifdef STANDALONE
55 #define MODE_munch
56 #define DEFAULTS "*delay: 5000 \n" \
57 "*cycles: 7 \n" \
58
59 # define free_munch 0
60 # define reshape_munch 0
61 # define munch_handle_event 0
62 #include "xlockmore.h" /* from the xscreensaver distribution */
63 #else /* !STANDALONE */
64 #include "xlock.h" /* from the xlockmore distribution */
65 #endif /* !STANDALONE */
66
67 #ifdef MODE_munch
68
69 ENTRYPOINT ModeSpecOpt munch_opts =
70 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
71
72 #ifdef USE_MODULES
73 ModStruct munch_description =
74 {"munch", "init_munch", "draw_munch", "release_munch",
75 "init_munch", "init_munch", (char *) NULL, &munch_opts,
76 5000, 1, 7, 1, 64, 1.0, "",
77 "Shows munching squares", 0, NULL};
78
79 #endif
80
81 #ifdef DEBUG
82 #include <assert.h>
83 #endif
84
85 /* flags for random things. Must be < log2(random's maximum), incidentally. */
86 #define SHIFT_KX (0x01)
87 #define SHIFT_KT (0x02)
88 #define SHIFT_KY (0x04)
89 #define GRAV (0x08)
90
91 typedef struct {
92 int width, height;
93 int logminwidth;
94 int logmaxwidth;
95 GC gc;
96 int thiswidth;
97 int t;
98 int atX, atY;
99 int kX, kT, kY;
100 int grav;
101 } munchstruct;
102
103 static munchstruct *munches = (munchstruct *) NULL;
104
105 static void
munchBit(ModeInfo * mi,int width,int atX,int atY,int kX,int kT,int kY,int grav)106 munchBit(ModeInfo * mi, int width, /* pixels */
107 int atX, int atY, /* pixels */
108 int kX, int kT, int kY, /* pixels */
109 int grav /* 0 or not */ )
110 {
111 munchstruct *mp = &munches[MI_SCREEN(mi)];
112
113 int x, y;
114 int drawX, drawY;
115
116 #if 0
117 (void) fprintf(stderr, "Doing width %d at %d %d shift %d %d %d grav %d\n",
118 width, atX, atY, kX, kT, kY, grav);
119 #endif
120
121 for (x = 0; x < width; x++) {
122 /* figure out the next point */
123 y = ((x ^ ((mp->t + kT) % width)) + kY) % width;
124
125 drawX = ((x + kX) % width) + atX;
126 drawY = (grav ? y + atY : atY + width - 1 - y);
127
128 /* used to be bugs where it would draw partially offscreen.
129 while that might be a pretty feature, I didn't want it to do
130 that yet. if these trigger, please let me know.
131 */
132 #ifdef DEBUG
133 assert(drawX >= 0 && drawX < MI_WIDTH(mi));
134 assert(drawY >= 0 && drawY < MI_HEIGHT(mi));
135 #endif
136
137 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), mp->gc, drawX, drawY);
138 /* XXX may want to change this to XDrawPoints,
139 but it's fast enough without it for the moment. */
140
141 }
142 }
143
144 /*
145 * dumb way to get # of digits in number. Probably faster than actually
146 * doing a log and a division, maybe.
147 */
148 static int
dumb_log_2(int k)149 dumb_log_2(int k)
150 {
151 int r = -1;
152
153 while (k > 0) {
154 k >>= 1;
155 r++;
156 }
157 return r;
158 }
159
160 static void
free_munch_screen(Display * display,munchstruct * mp)161 free_munch_screen(Display * display, munchstruct * mp)
162 {
163 if (mp == NULL) {
164 return;
165 }
166 if (mp->gc)
167 XFreeGC(display, mp->gc);
168 mp = NULL;
169 }
170
171 ENTRYPOINT void
init_munch(ModeInfo * mi)172 init_munch(ModeInfo * mi)
173 {
174 Display *display = MI_DISPLAY(mi);
175 munchstruct *mp;
176
177 MI_INIT(mi, munches);
178 mp = &munches[MI_SCREEN(mi)];
179
180 if (mp->gc == None) {
181 if ((mp->gc = XCreateGC(display, MI_WINDOW(mi),
182 (unsigned long) 0, (XGCValues *) NULL)) == None)
183 return;
184 }
185 mp->width = MI_WIDTH(mi);
186 mp->height = MI_HEIGHT(mi);
187
188 /* We need a square; limit on screen size? */
189 /* we want a power of 2 for the width or the munch doesn't fill up. */
190 mp->logmaxwidth = (int)
191 dumb_log_2((mp->height < mp->width) ? mp->height : mp->width);
192
193 XSetFunction(display, mp->gc, GXxor);
194
195 mp->logminwidth = MI_CYCLES(mi);
196 if (mp->logminwidth < 2 || MI_IS_ICONIC(mi))
197 mp->logminwidth = 2;
198
199 if (mp->logmaxwidth < mp->logminwidth)
200 mp->logmaxwidth = mp->logminwidth;
201
202 mp->t = 0;
203
204 MI_CLEARWINDOW(mi);
205 }
206
207 ENTRYPOINT void
draw_munch(ModeInfo * mi)208 draw_munch(ModeInfo * mi)
209 {
210 munchstruct *mp;
211
212 if (munches == NULL)
213 return;
214 mp = &munches[MI_SCREEN(mi)];
215 if (mp->gc == None)
216 return;
217
218 MI_IS_DRAWN(mi) = True;
219 if (!mp->t) { /* New one */
220 int randflags = (int) LRAND();
221
222 /* choose size -- power of two */
223 mp->thiswidth = (int) (1 << (mp->logminwidth +
224 (LRAND() % (1 + mp->logmaxwidth - mp->logminwidth))));
225
226 if (MI_NPIXELS(mi) > 2)
227 XSetForeground(MI_DISPLAY(mi), mp->gc,
228 MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
229 else /* Xor'red so WHITE may not be appropriate */
230 XSetForeground(MI_DISPLAY(mi), mp->gc, 1);
231
232 mp->atX = (int) (LRAND() %
233 ((mp->width <= mp->thiswidth) ? 1 : mp->width - mp->thiswidth));
234 mp->atY = (int) (LRAND() %
235 ((mp->height <= mp->thiswidth) ? 1 : mp->height - mp->thiswidth));
236
237 /* wrap-around by these values; no need to %
238 as we end up doing that later anyway */
239 mp->kX = (int) ((randflags & SHIFT_KX) ? LRAND() % mp->thiswidth : 0);
240 mp->kT = (int) ((randflags & SHIFT_KT) ? LRAND() % mp->thiswidth : 0);
241 mp->kY = (int) ((randflags & SHIFT_KY) ? LRAND() % mp->thiswidth : 0);
242
243 /* set the gravity of the munch, or rather,
244 which direction we draw stuff in. */
245 mp->grav = randflags & GRAV;
246 }
247 /* Finally draw this munching square. */
248 munchBit(mi,
249 mp->thiswidth, /* Width, in pixels */
250 /* draw at this location */
251 mp->atX, mp->atY, mp->kX, mp->kT, mp->kY, mp->grav);
252
253 mp->t++;
254 if (mp->t == mp->thiswidth)
255 mp->t = 0;
256 }
257
258 ENTRYPOINT void
release_munch(ModeInfo * mi)259 release_munch(ModeInfo * mi)
260 {
261 if (munches != NULL) {
262 int screen;
263
264 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
265 munchstruct *mp = &munches[screen];
266 free_munch_screen(MI_DISPLAY(mi), mp);
267 }
268 free(munches);
269 munches = (munchstruct *) NULL;
270 }
271 }
272
273 XSCREENSAVER_MODULE ("Munch", munch)
274
275 #endif /* MODE_munch */
276