5c51243688fe8cf8740be80e67fd5ff3ddd45db4
[xscreensaver] / hacks / slip.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  * slip --- lots of blits.
3  */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)slip.c        4.00 97/01/01 xlockmore";
6 #endif
7
8 /* Copyright (c) 1992 by Scott Draves (spot@cs.cmu.edu)
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  * Revision History:
23  * 12-May-97: jwz@jwz.org: turned into a standalone program.
24  * 01-Dec-95: Patched for VMS <joukj@alpha.chem.uva.nl>.
25  */
26
27 #ifdef STANDALONE
28 # define PROGCLASS                                      "Slip"
29 # define HACK_INIT                                      init_slip
30 # define HACK_DRAW                                      draw_slip
31 # define slip_opts                                      xlockmore_opts
32 # define DEFAULTS       "*count:                35    \n"                       \
33                                         "*cycles:               50    \n"                       \
34                                         "*delay:                50000 \n"                       \
35                                         "*ncolors:              200   \n"
36 # include "xlockmore.h"                         /* from the xscreensaver distribution */
37 #else  /* !STANDALONE */
38 # include "xlock.h"                                     /* from the xlockmore distribution */
39 #endif /* !STANDALONE */
40
41 ModeSpecOpt slip_opts = {
42   0, NULL, 0, NULL, NULL };
43
44 typedef struct {
45         int         width, height;
46         int         nblits_remaining;
47         int         blit_width, blit_height;
48         int         mode;
49         int         first_time;
50     int         backwards;
51 } slipstruct;
52 static slipstruct *slips = NULL;
53
54 static short
55 halfrandom(int mv)
56 {
57         static short lasthalf = 0;
58         unsigned long r;
59
60         if (lasthalf) {
61                 r = lasthalf;
62                 lasthalf = 0;
63         } else {
64                 r = LRAND();
65                 lasthalf = r >> 16;
66         }
67         return r % mv;
68 }
69
70 static int
71 erandom(int mv)
72 {
73         static int  stage = 0;
74         static unsigned long r;
75         int         res;
76
77         if (0 == stage) {
78                 r = LRAND();
79                 stage = 7;
80         }
81         res = r & 0xf;
82         r = r >> 4;
83         stage--;
84         if (res & 8)
85                 return res & mv;
86         else
87                 return -(res & mv);
88 }
89
90 static void
91 prepare_screen(ModeInfo * mi, slipstruct * s)
92 {
93
94         Display    *display = MI_DISPLAY(mi);
95         GC          gc = MI_GC(mi);
96         int         i, n, w = s->width / 20;
97         int         not_solid = halfrandom(10);
98
99 #ifdef STANDALONE                         /* jwz -- sometimes hack the desktop image! */
100         if (halfrandom(2) == 0)
101           {
102                 grab_screen_image(DefaultScreenOfDisplay (MI_DISPLAY(mi)),
103                                                   MI_WINDOW(mi));
104                 return;
105           }
106 #endif
107
108         s->backwards = LRAND() & 1;             /* jwz: go the other way sometimes */
109
110         if (s->first_time || (0 == halfrandom(10))) {
111                 XClearWindow(display, MI_WINDOW(mi));
112                 n = 300;
113         } else {
114                 if (halfrandom(5))
115                         return;
116                 if (halfrandom(5))
117                         n = 100;
118                 else
119                         n = 2000;
120         }
121
122         if (MI_NPIXELS(mi) > 2)
123                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(MI_NPIXELS(mi))));
124         else if (halfrandom(2))
125                 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
126         else
127                 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
128
129         for (i = 0; i < n; i++) {
130           int ww = ((w/2) + halfrandom(w));
131                 if (not_solid) {
132                         if (MI_NPIXELS(mi) > 2)
133                                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(MI_NPIXELS(mi))));
134                         else if (halfrandom(2))
135                                 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
136                         else
137                                 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
138                 }
139                 XFillRectangle(display, MI_WINDOW(mi), gc,
140                                halfrandom(s->width - ww),
141                                halfrandom(s->height - ww),
142                                ww, ww);
143         }
144         s->first_time = 0;
145 }
146
147 static int
148 quantize(double d)
149 {
150         int         i = (int) floor(d);
151         double      f = d - i;
152
153         if ((LRAND() & 0xff) < f * 0xff)
154                 i++;
155         return i;
156 }
157
158 void
159 init_slip(ModeInfo * mi)
160 {
161         slipstruct *sp;
162
163         if (slips == NULL) {
164                 if ((slips = (slipstruct *) calloc(MI_NUM_SCREENS(mi),
165                                                sizeof (slipstruct))) == NULL)
166                         return;
167         }
168         sp = &slips[MI_SCREEN(mi)];
169
170         sp->width = MI_WIN_WIDTH(mi);
171         sp->height = MI_WIN_HEIGHT(mi);
172
173         sp->blit_width = sp->width / 25;
174         sp->blit_height = sp->height / 25;
175         sp->nblits_remaining = 0;
176         sp->mode = 0;
177         sp->first_time = 1;
178
179         /* no "NoExpose" events from XCopyArea wanted */
180         XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
181 }
182
183 void
184 draw_slip(ModeInfo * mi)
185 {
186         Display    *display = MI_DISPLAY(mi);
187         Window      window = MI_WINDOW(mi);
188         GC          gc = MI_GC(mi);
189         slipstruct *s = &slips[MI_SCREEN(mi)];
190         int         timer;
191
192         timer = MI_BATCHCOUNT(mi) * MI_CYCLES(mi);
193
194         while (timer--) {
195                 int         xi = halfrandom(s->width - s->blit_width);
196                 int         yi = halfrandom(s->height - s->blit_height);
197                 double      x, y, dx = 0, dy = 0, t, s1, s2;
198
199                 if (0 == s->nblits_remaining--) {
200                         static int lut[] =
201                         {0, 0, 0, 1, 1, 1, 2};
202
203                         prepare_screen(mi, s);
204                         s->nblits_remaining = MI_BATCHCOUNT(mi) *
205                                 (2000 + halfrandom(1000) + halfrandom(1000));
206                         if (s->mode == 2)
207                                 s->mode = halfrandom(2);
208                         else
209                                 s->mode = lut[halfrandom(7)];
210                 }
211                 x = (2 * xi + s->blit_width) / (double) s->width - 1;
212                 y = (2 * yi + s->blit_height) / (double) s->height - 1;
213
214                 /* (x,y) is in biunit square */
215                 switch (s->mode) {
216                         case 0:                                                         /* rotor */
217                                 dx = x;
218                                 dy = y;
219
220                                 if (dy < 0) {
221                                         dy += 0.04;
222                                         if (dy > 0)
223                                                 dy = 0.00;
224                                 }
225                                 if (dy > 0) {
226                                         dy -= 0.04;
227                                         if (dy < 0)
228                                                 dy = 0.00;
229                                 }
230                                 t = dx * dx + dy * dy + 1e-10;
231                                 s1 = 2 * dx * dx / t - 1;
232                                 s2 = 2 * dx * dy / t;
233                                 dx = s1 * 5;
234                                 dy = s2 * 5;
235                                 if (s->backwards) {     /* jwz: go the other way sometimes */
236                                         dx = -dx;
237                                         dy = -dy;
238                                 }
239                                 break;
240                         case 1:                                                         /* shuffle */
241                                 dx = erandom(3);
242                                 dy = erandom(3);
243                                 break;
244                         case 2:                                                         /* explode */
245                                 dx = x * 3;
246                                 dy = y * 3;
247                                 break;
248                 }
249                 {
250                         int         qx = xi + quantize(dx), qy = yi + quantize(dy);
251                         int         wrap;
252
253                         if (qx < 0 || qy < 0 ||
254                             qx >= s->width - s->blit_width ||
255                             qy >= s->height - s->blit_height)
256                                 continue;
257
258                         XCopyArea(display, window, window, gc, xi, yi,
259                                   s->blit_width, s->blit_height,
260                                   qx, qy);
261
262                         switch (s->mode) {
263                                 case 0:
264                                         /* wrap */
265                                         wrap = s->width - (2 * s->blit_width);
266                                         if (qx > wrap)
267                                                 XCopyArea(display, window, window, gc, qx, qy,
268                                                 s->blit_width, s->blit_height,
269                                                           qx - wrap, qy);
270
271                                         if (qx < 2 * s->blit_width)
272                                                 XCopyArea(display, window, window, gc, qx, qy,
273                                                 s->blit_width, s->blit_height,
274                                                           qx + wrap, qy);
275
276                                         wrap = s->height - (2 * s->blit_height);
277                                         if (qy > wrap)
278                                                 XCopyArea(display, window, window, gc, qx, qy,
279                                                 s->blit_width, s->blit_height,
280                                                           qx, qy - wrap);
281
282                                         if (qy < 2 * s->blit_height)
283                                                 XCopyArea(display, window, window, gc, qx, qy,
284                                                 s->blit_width, s->blit_height,
285                                                           qx, qy + wrap);
286                                         break;
287                                 case 1:
288                                 case 2:
289                                         break;
290                         }
291                 }
292         }
293 }
294
295 void
296 release_slip(ModeInfo * mi)
297 {
298         if (slips != NULL) {
299                 (void) free((void *) slips);
300                 slips = NULL;
301         }
302 }