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