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