http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[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 DEFAULTS       "*delay: 50000 \n" \
31                                         "*count: 35 \n" \
32                                         "*cycles: 50 \n" \
33                                         "*ncolors: 200 \n"
34 # define refresh_slip 0
35 # define slip_handle_event 0
36 # include "xlockmore.h"         /* in xscreensaver distribution */
37 #else /* STANDALONE */
38 # include "xlock.h"             /* in xlockmore distribution */
39 #endif /* STANDALONE */
40
41 #ifdef MODE_slip
42
43 ENTRYPOINT ModeSpecOpt slip_opts =
44 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
45
46 #ifdef USE_MODULES
47 ModStruct   slip_description =
48 {"slip", "init_slip", "draw_slip", "release_slip",
49  "init_slip", "init_slip", (char *) NULL, &slip_opts,
50  50000, 35, 50, 1, 64, 1.0, "",
51  "Shows slipping blits", 0, NULL};
52
53 #endif
54
55 typedef struct {
56         int         width, height;
57         int         nblits_remaining;
58         int         blit_width, blit_height;
59         int         mode;
60         int         first_time;
61         int         backwards;
62         short       lasthalf;
63         int         stage;
64         unsigned long r;
65     Bool image_loading_p;
66 } slipstruct;
67 static slipstruct *slips = (slipstruct *) NULL;
68
69 static short
70 halfrandom(slipstruct *sp, int mv)
71 {
72         unsigned long r;
73
74         if (sp->lasthalf) {
75                 r = sp->lasthalf;
76                 sp->lasthalf = 0;
77         } else {
78                 r = LRAND();
79                 sp->lasthalf = (short) (r >> 16);
80         }
81         return r % mv;
82 }
83
84 static int
85 erandom(slipstruct *sp, int mv)
86 {
87         int         res;
88
89         if (0 == sp->stage) {
90                 sp->r = LRAND();
91                 sp->stage = 7;
92         }
93         res = (int) (sp->r & 0xf);
94         sp->r = sp->r >> 4;
95         sp->stage--;
96         if (res & 8)
97                 return res & mv;
98         else
99                 return -(res & mv);
100 }
101
102 #ifdef STANDALONE
103 static void
104 image_loaded_cb (Screen *screen, Window w, Drawable d,
105                  const char *name, XRectangle *geom,
106                  void *closure)
107 {
108   ModeInfo *mi = (ModeInfo *) closure;
109   slipstruct *sp = &slips[MI_SCREEN(mi)];
110   Display *dpy = DisplayOfScreen (screen);
111   XCopyArea (dpy, d, w, mi->gc, 0, 0,
112              sp->width, sp->height, 0, 0);
113   XFreePixmap (dpy, d);
114   sp->image_loading_p = False;
115 }
116 #endif /* STANDALONE */
117
118 static void
119 prepare_screen(ModeInfo * mi, slipstruct * sp)
120 {
121
122         Display    *display = MI_DISPLAY(mi);
123         GC          gc = MI_GC(mi);
124         int         i, n, w = sp->width / 20;
125         int         not_solid = halfrandom(sp, 10);
126
127         sp->backwards = (int) (LRAND() & 1);    /* jwz: go the other way sometimes */
128
129         if (sp->first_time || !halfrandom(sp, 10)) {
130                 MI_CLEARWINDOW(mi);
131                 n = 300;
132         } else {
133                 if (halfrandom(sp, 5))
134                         return;
135                 if (halfrandom(sp, 5))
136                         n = 100;
137                 else
138                         n = 2000;
139         }
140
141         if (MI_NPIXELS(mi) > 2)
142                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
143         else if (halfrandom(sp, 2))
144                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
145         else
146                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
147
148         for (i = 0; i < n; i++) {
149                 int         ww = ((w / 2) + halfrandom(sp, MAX(w, 1)));
150
151                 if (not_solid) {
152                         if (MI_NPIXELS(mi) > 2)
153                                 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
154                         else if (halfrandom(sp, 2))
155                                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
156                         else
157                                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
158                 }
159                 XFillRectangle(display, MI_WINDOW(mi), gc,
160                                halfrandom(sp, MAX(sp->width - ww, 1)),
161                                halfrandom(sp, MAX(sp->height - ww, 1)),
162                                ww, ww);
163         }
164         sp->first_time = 0;
165
166
167 #ifdef STANDALONE                         /* jwz -- sometimes hack the desktop image! */
168         if (!sp->image_loading_p &&
169         (1||halfrandom(sp, 2) == 0)) {
170       /* Load it into a pixmap so that the "Loading" message and checkerboard
171          don't show up on the window -- we keep running while the image is
172          in progress... */
173       Pixmap p = XCreatePixmap (MI_DISPLAY(mi), MI_WINDOW(mi),
174                                 sp->width, sp->height, mi->xgwa.depth);
175       sp->image_loading_p = True;
176       load_image_async (ScreenOfDisplay (MI_DISPLAY(mi), 0/*####MI_SCREEN(mi)*/),
177                         MI_WINDOW(mi), p, image_loaded_cb, mi);
178         }
179 #endif
180 }
181
182 static int
183 quantize(double d)
184 {
185         int         i = (int) floor(d);
186         double      f = d - i;
187
188         if ((LRAND() & 0xff) < f * 0xff)
189                 i++;
190         return i;
191 }
192
193 ENTRYPOINT void
194 reshape_slip (ModeInfo * mi, int w, int h)
195 {
196   slipstruct *sp = &slips[MI_SCREEN(mi)];
197   sp->width = w;
198   sp->height = h;
199   sp->blit_width = sp->width / 25;
200   sp->blit_height = sp->height / 25;
201
202   sp->mode = 0;
203   sp->nblits_remaining = 0;
204 }
205
206 ENTRYPOINT void
207 init_slip (ModeInfo * mi)
208 {
209         slipstruct *sp;
210
211         if (slips == NULL) {
212                 if ((slips = (slipstruct *) calloc(MI_NUM_SCREENS(mi),
213                                                sizeof (slipstruct))) == NULL)
214                         return;
215         }
216         sp = &slips[MI_SCREEN(mi)];
217
218         sp->nblits_remaining = 0;
219         sp->mode = 0;
220         sp->first_time = 1;
221
222         /* no "NoExpose" events from XCopyArea wanted */
223         XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
224
225     reshape_slip (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
226 }
227
228 ENTRYPOINT void
229 draw_slip (ModeInfo * mi)
230 {
231         Display    *display = MI_DISPLAY(mi);
232         Window      window = MI_WINDOW(mi);
233         GC          gc = MI_GC(mi);
234         int         timer;
235         slipstruct *sp;
236
237         if (slips == NULL)
238                 return;
239         sp = &slips[MI_SCREEN(mi)];
240
241         timer = MI_COUNT(mi) * MI_CYCLES(mi);
242
243         MI_IS_DRAWN(mi) = True;
244
245         while (timer--) {
246                 int         xi = halfrandom(sp, MAX(sp->width - sp->blit_width, 1));
247                 int         yi = halfrandom(sp, MAX(sp->height - sp->blit_height, 1));
248                 double      x, y, dx = 0, dy = 0, t, s1, s2;
249
250                 if (0 == sp->nblits_remaining--) {
251                         static const int lut[] = {0, 0, 0, 1, 1, 1, 2};
252
253                         prepare_screen(mi, sp);
254                         sp->nblits_remaining = MI_COUNT(mi) *
255                                 (2000 + halfrandom(sp, 1000) + halfrandom(sp, 1000));
256                         if (sp->mode == 2)
257                                 sp->mode = halfrandom(sp, 2);
258                         else
259                                 sp->mode = lut[halfrandom(sp, 7)];
260                 }
261                 x = (2 * xi + sp->blit_width) / (double) sp->width - 1;
262                 y = (2 * yi + sp->blit_height) / (double) sp->height - 1;
263
264                 /* (x,y) is in biunit square */
265                 switch (sp->mode) {
266                         case 0: /* rotor */
267                                 dx = x;
268                                 dy = y;
269
270                                 if (dy < 0) {
271                                         dy += 0.04;
272                                         if (dy > 0)
273                                                 dy = 0.00;
274                                 }
275                                 if (dy > 0) {
276                                         dy -= 0.04;
277                                         if (dy < 0)
278                                                 dy = 0.00;
279                                 }
280                                 t = dx * dx + dy * dy + 1e-10;
281                                 s1 = 2 * dx * dx / t - 1;
282                                 s2 = 2 * dx * dy / t;
283                                 dx = s1 * 5;
284                                 dy = s2 * 5;
285
286                                 if (sp->backwards) {    /* jwz: go the other way sometimes */
287                                         dx = -dx;
288                                         dy = -dy;
289                                 }
290                                 break;
291                         case 1: /* shuffle */
292                                 dx = erandom(sp, 3);
293                                 dy = erandom(sp, 3);
294                                 break;
295                         case 2: /* explode */
296                                 dx = x * 3;
297                                 dy = y * 3;
298                                 break;
299                 }
300                 {
301                         int         qx = xi + quantize(dx), qy = yi + quantize(dy);
302                         int         wrap;
303
304                         if (qx < 0 || qy < 0 ||
305                             qx >= sp->width - sp->blit_width ||
306                             qy >= sp->height - sp->blit_height)
307                                 continue;
308
309 /*-
310 Seems to cause problems using Exceed
311 with PseudoColor
312 X Error of failed request:  BadGC (invalid GC parameter)
313 with TrueColor
314 X Error of failed request:  BadDrawable (invalid Pixmap or Window parameter)
315   Major opcode of failed request:  62 (X_CopyArea)
316  */
317                         XCopyArea(display, window, window, gc, xi, yi,
318                                   sp->blit_width, sp->blit_height,
319                                   qx, qy);
320                         switch (sp->mode) {
321                                 case 0:
322                                         /* wrap */
323                                         wrap = sp->width - (2 * sp->blit_width);
324                                         if (qx > wrap ) {
325                                                 XCopyArea(display, window, window, gc, qx, qy,
326                                                 sp->blit_width, sp->blit_height,
327                                                           qx - wrap, qy);
328                                         }
329                                         if (qx < 2 * sp->blit_width) {
330                                                 XCopyArea(display, window, window, gc, qx, qy,
331                                                 sp->blit_width, sp->blit_height,
332                                                           qx + wrap, qy);
333                                         }
334                                         wrap = sp->height - (2 * sp->blit_height);
335                                         if (qy > wrap) {
336                                                 XCopyArea(display, window, window, gc, qx, qy,
337                                                 sp->blit_width, sp->blit_height,
338                                                           qx, qy - wrap);
339                                         }
340                                         if (qy < 2 * sp->blit_height) {
341                                                 XCopyArea(display, window, window, gc, qx, qy,
342                                                 sp->blit_width, sp->blit_height,
343                                                           qx, qy + wrap);
344                                         }
345                                         break;
346                                 case 1:
347                                 case 2:
348                                         break;
349                         }
350                 }
351         }
352 }
353
354 ENTRYPOINT void
355 release_slip (ModeInfo * mi)
356 {
357         if (slips != NULL) {
358                 (void) free((void *) slips);
359                 slips = (slipstruct *) NULL;
360         }
361 }
362
363 XSCREENSAVER_MODULE ("Slip", slip)
364
365 #endif /* MODE_slip */