http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / slip.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* slip --- lots of slipping blits */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)slip.c        5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1992 by Scott Draves <spot@cs.cmu.edu>
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * 01-Nov-2000: Allocation checks
25  * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
26  * 01-Dec-1995: Patched for VMS <joukj@hrem.stm.tudelft.nl>
27  */
28
29 #ifdef STANDALONE
30 #define MODE_slip
31 #define PROGCLASS "Slip"
32 #define HACK_INIT init_slip
33 #define HACK_DRAW draw_slip
34 #define slip_opts xlockmore_opts
35 #define DEFAULTS "*delay: 50000 \n" \
36  "*count: 35 \n" \
37  "*cycles: 50 \n" \
38  "*ncolors: 200 \n"
39 #include "xlockmore.h"          /* in xscreensaver distribution */
40 #else /* STANDALONE */
41 #include "xlock.h"              /* in xlockmore distribution */
42 #endif /* STANDALONE */
43
44 #ifdef MODE_slip
45
46 ModeSpecOpt slip_opts =
47 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
48
49 #ifdef USE_MODULES
50 ModStruct   slip_description =
51 {"slip", "init_slip", "draw_slip", "release_slip",
52  "init_slip", "init_slip", (char *) NULL, &slip_opts,
53  50000, 35, 50, 1, 64, 1.0, "",
54  "Shows slipping blits", 0, NULL};
55
56 #endif
57
58 typedef struct {
59         int         width, height;
60         int         nblits_remaining;
61         int         blit_width, blit_height;
62         int         mode;
63         int         first_time;
64         int         backwards;
65         short       lasthalf;
66         int         stage;
67         unsigned long r;
68 } slipstruct;
69 static slipstruct *slips = (slipstruct *) NULL;
70
71 static short
72 halfrandom(slipstruct *sp, int mv)
73 {
74         unsigned long r;
75
76         if (sp->lasthalf) {
77                 r = sp->lasthalf;
78                 sp->lasthalf = 0;
79         } else {
80                 r = LRAND();
81                 sp->lasthalf = (short) (r >> 16);
82         }
83         return r % mv;
84 }
85
86 static int
87 erandom(slipstruct *sp, int mv)
88 {
89         int         res;
90
91         if (0 == sp->stage) {
92                 sp->r = LRAND();
93                 sp->stage = 7;
94         }
95         res = (int) (sp->r & 0xf);
96         sp->r = sp->r >> 4;
97         sp->stage--;
98         if (res & 8)
99                 return res & mv;
100         else
101                 return -(res & mv);
102 }
103
104 static void
105 prepare_screen(ModeInfo * mi, slipstruct * sp)
106 {
107
108         Display    *display = MI_DISPLAY(mi);
109         GC          gc = MI_GC(mi);
110         int         i, n, w = sp->width / 20;
111         int         not_solid = halfrandom(sp, 10);
112
113 #ifdef STANDALONE                         /* jwz -- sometimes hack the desktop image! */
114         if (halfrandom(sp, 2) == 0) {
115                 grab_screen_image(DefaultScreenOfDisplay(display),
116                                   MI_WINDOW(mi));
117         }
118 #endif
119
120         sp->backwards = (int) (LRAND() & 1);    /* jwz: go the other way sometimes */
121
122         if (sp->first_time || !halfrandom(sp, 10)) {
123                 MI_CLEARWINDOW(mi);
124                 n = 300;
125         } else {
126                 if (halfrandom(sp, 5))
127                         return;
128                 if (halfrandom(sp, 5))
129                         n = 100;
130                 else
131                         n = 2000;
132         }
133
134         if (MI_NPIXELS(mi) > 2)
135                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
136         else if (halfrandom(sp, 2))
137                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
138         else
139                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
140
141         for (i = 0; i < n; i++) {
142                 int         ww = ((w / 2) + halfrandom(sp, MAX(w, 1)));
143
144                 if (not_solid) {
145                         if (MI_NPIXELS(mi) > 2)
146                                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
147                         else if (halfrandom(sp, 2))
148                                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
149                         else
150                                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
151                 }
152                 XFillRectangle(display, MI_WINDOW(mi), gc,
153                                halfrandom(sp, MAX(sp->width - ww, 1)),
154                                halfrandom(sp, MAX(sp->height - ww, 1)),
155                                ww, ww);
156         }
157         sp->first_time = 0;
158 }
159
160 static int
161 quantize(double d)
162 {
163         int         i = (int) floor(d);
164         double      f = d - i;
165
166         if ((LRAND() & 0xff) < f * 0xff)
167                 i++;
168         return i;
169 }
170
171 void
172 init_slip(ModeInfo * mi)
173 {
174         slipstruct *sp;
175
176         if (slips == NULL) {
177                 if ((slips = (slipstruct *) calloc(MI_NUM_SCREENS(mi),
178                                                sizeof (slipstruct))) == NULL)
179                         return;
180         }
181         sp = &slips[MI_SCREEN(mi)];
182
183         sp->width = MI_WIDTH(mi);
184         sp->height = MI_HEIGHT(mi);
185
186         sp->blit_width = sp->width / 25;
187         sp->blit_height = sp->height / 25;
188         sp->nblits_remaining = 0;
189         sp->mode = 0;
190         sp->first_time = 1;
191
192         /* no "NoExpose" events from XCopyArea wanted */
193         XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
194 }
195
196 void
197 draw_slip(ModeInfo * mi)
198 {
199         Display    *display = MI_DISPLAY(mi);
200         Window      window = MI_WINDOW(mi);
201         GC          gc = MI_GC(mi);
202         int         timer;
203         slipstruct *sp;
204
205         if (slips == NULL)
206                 return;
207         sp = &slips[MI_SCREEN(mi)];
208
209         timer = MI_COUNT(mi) * MI_CYCLES(mi);
210
211         MI_IS_DRAWN(mi) = True;
212
213         while (timer--) {
214                 int         xi = halfrandom(sp, MAX(sp->width - sp->blit_width, 1));
215                 int         yi = halfrandom(sp, MAX(sp->height - sp->blit_height, 1));
216                 double      x, y, dx = 0, dy = 0, t, s1, s2;
217
218                 if (0 == sp->nblits_remaining--) {
219                         static int  lut[] =
220                         {0, 0, 0, 1, 1, 1, 2};
221
222                         prepare_screen(mi, sp);
223                         sp->nblits_remaining = MI_COUNT(mi) *
224                                 (2000 + halfrandom(sp, 1000) + halfrandom(sp, 1000));
225                         if (sp->mode == 2)
226                                 sp->mode = halfrandom(sp, 2);
227                         else
228                                 sp->mode = lut[halfrandom(sp, 7)];
229                 }
230                 x = (2 * xi + sp->blit_width) / (double) sp->width - 1;
231                 y = (2 * yi + sp->blit_height) / (double) sp->height - 1;
232
233                 /* (x,y) is in biunit square */
234                 switch (sp->mode) {
235                         case 0: /* rotor */
236                                 dx = x;
237                                 dy = y;
238
239                                 if (dy < 0) {
240                                         dy += 0.04;
241                                         if (dy > 0)
242                                                 dy = 0.00;
243                                 }
244                                 if (dy > 0) {
245                                         dy -= 0.04;
246                                         if (dy < 0)
247                                                 dy = 0.00;
248                                 }
249                                 t = dx * dx + dy * dy + 1e-10;
250                                 s1 = 2 * dx * dx / t - 1;
251                                 s2 = 2 * dx * dy / t;
252                                 dx = s1 * 5;
253                                 dy = s2 * 5;
254
255                                 if (sp->backwards) {    /* jwz: go the other way sometimes */
256                                         dx = -dx;
257                                         dy = -dy;
258                                 }
259                                 break;
260                         case 1: /* shuffle */
261                                 dx = erandom(sp, 3);
262                                 dy = erandom(sp, 3);
263                                 break;
264                         case 2: /* explode */
265                                 dx = x * 3;
266                                 dy = y * 3;
267                                 break;
268                 }
269                 {
270                         int         qx = xi + quantize(dx), qy = yi + quantize(dy);
271                         int         wrap;
272
273                         if (qx < 0 || qy < 0 ||
274                             qx >= sp->width - sp->blit_width ||
275                             qy >= sp->height - sp->blit_height)
276                                 continue;
277
278 /*-
279 Seems to cause problems using Exceed
280 with PseudoColor
281 X Error of failed request:  BadGC (invalid GC parameter)
282 with TrueColor
283 X Error of failed request:  BadDrawable (invalid Pixmap or Window parameter)
284   Major opcode of failed request:  62 (X_CopyArea)
285  */
286                         XCopyArea(display, window, window, gc, xi, yi,
287                                   sp->blit_width, sp->blit_height,
288                                   qx, qy);
289                         switch (sp->mode) {
290                                 case 0:
291                                         /* wrap */
292                                         wrap = sp->width - (2 * sp->blit_width);
293                                         if (qx > wrap ) {
294                                                 XCopyArea(display, window, window, gc, qx, qy,
295                                                 sp->blit_width, sp->blit_height,
296                                                           qx - wrap, qy);
297                                         }
298                                         if (qx < 2 * sp->blit_width) {
299                                                 XCopyArea(display, window, window, gc, qx, qy,
300                                                 sp->blit_width, sp->blit_height,
301                                                           qx + wrap, qy);
302                                         }
303                                         wrap = sp->height - (2 * sp->blit_height);
304                                         if (qy > wrap) {
305                                                 XCopyArea(display, window, window, gc, qx, qy,
306                                                 sp->blit_width, sp->blit_height,
307                                                           qx, qy - wrap);
308                                         }
309                                         if (qy < 2 * sp->blit_height) {
310                                                 XCopyArea(display, window, window, gc, qx, qy,
311                                                 sp->blit_width, sp->blit_height,
312                                                           qx, qy + wrap);
313                                         }
314                                         break;
315                                 case 1:
316                                 case 2:
317                                         break;
318                         }
319                 }
320         }
321 }
322
323 void
324 release_slip(ModeInfo * mi)
325 {
326         if (slips != NULL) {
327                 (void) free((void *) slips);
328                 slips = (slipstruct *) NULL;
329         }
330 }
331
332 #endif /* MODE_slip */