ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / moire2.c
1 /* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include "screenhack.h"
13 #include <X11/Xutil.h>
14
15 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
16 # include "xdbe.h"
17 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
18
19 static int ncolors;
20 static XColor *colors = 0;
21 static int fg_pixel, bg_pixel;
22 static Pixmap p0 = 0, p1 = 0, p2 = 0, p3 = 0;
23 static GC copy_gc = 0, erase_gc = 0, window_gc = 0;
24 static int width, height, size;
25 static int x1, x2, y1, y2, x3, y3;
26 static int dx1, dx2, dx3, dy1, dy2, dy3;
27 static int othickness, thickness;
28 static Bool do_three;
29 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
30 XdbeBackBuffer back_buf = 0;
31 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
32
33 static void
34 init_moire2 (Display *dpy, Window window)
35 {
36   XWindowAttributes xgwa;
37   XGetWindowAttributes (dpy, window, &xgwa);
38
39   othickness = get_integer_resource("thickness", "Thickness");
40
41   if (mono_p)
42     ncolors = 2;
43   else
44     ncolors = get_integer_resource ("colors", "Colors");
45   if (ncolors < 2) ncolors = 2;
46   if (ncolors <= 2) mono_p = True;
47
48   if (mono_p)
49     colors = 0;
50   else
51     colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
52
53   if (mono_p)
54     ;
55   else
56     make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
57                           True, 0, True);
58
59   bg_pixel = get_pixel_resource("background", "Background", dpy,
60                                 xgwa.colormap);
61   fg_pixel = get_pixel_resource("foreground", "Foreground", dpy,
62                                 xgwa.colormap);
63
64 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
65   back_buf = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
66 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
67 }
68
69
70 static void
71 reset_moire2 (Display *dpy, Window window)
72 {
73   GC gc;
74   XWindowAttributes xgwa;
75   XGCValues gcv;
76   Bool xor;
77   XGetWindowAttributes (dpy, window, &xgwa);
78
79   do_three = (0 == (random() % 3));
80
81   width = xgwa.width;
82   height = xgwa.height;
83   size = width > height ? width : height;
84
85   if (p0) XFreePixmap(dpy, p0);
86   if (p1) XFreePixmap(dpy, p1);
87   if (p2) XFreePixmap(dpy, p2);
88   if (p3) XFreePixmap(dpy, p3);
89
90   p0 = XCreatePixmap(dpy, window, width, height, 1);
91   p1 = XCreatePixmap(dpy, window, width*2, height*2, 1);
92   p2 = XCreatePixmap(dpy, window, width*2, height*2, 1);
93   if (do_three)
94     p3 = XCreatePixmap(dpy, window, width*2, height*2, 1);
95   else
96     p3 = 0;
97
98   thickness = (othickness > 0 ? othickness : (1 + (random() % 4)));
99
100   gcv.foreground = 0;
101   gcv.line_width = (thickness == 1 ? 0 : thickness);
102   gc = XCreateGC (dpy, p1, GCForeground|GCLineWidth, &gcv);
103
104   XFillRectangle(dpy, p1, gc, 0, 0, width*2, height*2);
105   XFillRectangle(dpy, p2, gc, 0, 0, width*2, height*2);
106   if (do_three)
107     XFillRectangle(dpy, p3, gc, 0, 0, width*2, height*2);
108
109   XSetForeground(dpy, gc, 1);
110
111   xor = (do_three || (thickness == 1) || (random() & 1));
112
113   {
114     int i, ii, maxx, maxy;
115
116 #define FROB(P) do { \
117     maxx = (size*4); \
118     maxy = (size*4); \
119     if (0 == (random() % 5)) { \
120         float f = 1.0 + frand(0.05); \
121         if (random() & 1) maxx *= f; \
122         else maxy *= f; \
123       } \
124     ii = (thickness + 1 + (xor ? 0 : 1) + (random() % (4 * thickness)));  \
125     for (i = 0; i < (size*2); i += ii)  \
126       XDrawArc(dpy, (P), gc, i-size, i-size, maxx-i-i, maxy-i-i, 0, 360*64); \
127     if (0 == (random() % 5)) \
128       { \
129         XSetFunction(dpy, gc, GXxor); \
130         XFillRectangle(dpy, (P), gc, 0, 0, width*2, height*2); \
131         XSetFunction(dpy, gc, GXcopy); \
132       } \
133     } while(0)
134
135     FROB(p1);
136     FROB(p2);
137     if (do_three)
138       FROB(p3);
139 #undef FROB
140   }
141
142   XFreeGC(dpy, gc);
143
144   if (copy_gc) XFreeGC(dpy, copy_gc);
145   gcv.function = (xor ? GXxor : GXor);
146   gcv.foreground = 1;
147   gcv.background = 0;
148
149   copy_gc = XCreateGC (dpy, p0, GCFunction|GCForeground|GCBackground, &gcv);
150
151   gcv.foreground = 0;
152   if (erase_gc) XFreeGC(dpy, erase_gc);
153   erase_gc = XCreateGC (dpy, p0, GCForeground, &gcv);
154
155   gcv.foreground = fg_pixel;
156   gcv.background = bg_pixel;
157   if (window_gc) XFreeGC(dpy, window_gc);
158   window_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
159
160 #define FROB(N,DN,MAX) \
161   N = (MAX/2) + (random() % MAX); \
162   DN = ((1 + (random() % (7*thickness))) * ((random() & 1) ? 1 : -1))
163
164   FROB(x1,dx1,width);
165   FROB(x2,dx2,width);
166   FROB(x3,dx3,width);
167   FROB(y1,dy1,height);
168   FROB(y2,dy2,height);
169   FROB(y3,dy3,height);
170 #undef FROB
171 }
172
173
174
175 static void
176 moire2 (Display *dpy, Window window)
177 {
178 #define FROB(N,DN,MAX) \
179   N += DN; \
180   if (N <= 0) N = 0, DN = -DN; \
181   else if (N >= MAX) N = MAX, DN = -DN; \
182   else if (0 == (random() % 100)) DN = -DN; \
183   else if (0 == (random() % 50)) \
184     DN += (DN <= -20 ? 1 : (DN >= 20 ? -1 : ((random() & 1) ? 1 : -1)))
185
186   FROB(x1,dx1,width);
187   FROB(x2,dx2,width);
188   FROB(x3,dx3,width);
189   FROB(y1,dy1,height);
190   FROB(y2,dy2,height);
191   FROB(y3,dy3,height);
192 #undef FROB
193
194   XFillRectangle(dpy, p0, erase_gc, 0, 0, width, height);
195   XCopyArea(dpy, p1, p0, copy_gc, x1, y1, width, height, 0, 0);
196   XCopyArea(dpy, p2, p0, copy_gc, x2, y2, width, height, 0, 0);
197   if (do_three)
198     XCopyArea(dpy, p3, p0, copy_gc, x3, y3, width, height, 0, 0);
199
200 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
201   if (back_buf)
202     {
203       XdbeSwapInfo info[1];
204       info[0].swap_window = window;
205       info[0].swap_action = XdbeUndefined;
206       XCopyPlane (dpy, p0, back_buf, window_gc, 0, 0, width, height, 0, 0, 1L);
207       XdbeSwapBuffers (dpy, info, 1);
208     }
209   else
210 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
211     XCopyPlane (dpy, p0, window, window_gc, 0, 0, width, height, 0, 0, 1L);
212
213   XSync(dpy, False);
214
215 #if 0
216   XCopyPlane(dpy, p1, window, window_gc, (width*2)/3, (height*2)/3,
217              width/2, height/2,
218              0, height/2, 1L);
219   XCopyPlane(dpy, p2, window, window_gc, (width*2)/3, (height*2)/3,
220              width/2, height/2,
221              width/2, height/2, 1L);
222 #endif
223 }
224
225
226
227 \f
228 char *progclass = "Moire2";
229
230 char *defaults [] = {
231   ".background:         black",
232   ".foreground:         white",
233   "*delay:              50000",
234   "*thickness:          0",
235   "*colors:             150",
236   "*colorShift:         5",
237
238 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
239   /* Off by default, since it slows it down a lot, and the flicker isn't really
240      all that bad without it... Or rather, it flickers just as badly with it.
241      The XFree86 implementation of the XDBE extension totally blows!  There is
242      just *no* excuse for the "swap buffers" operation to flicker like it does.
243    */
244   "*useDBE:             False",
245 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
246
247   0
248 };
249
250 XrmOptionDescRec options [] = {
251   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
252   { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
253   { "-thickness",       ".thickness",   XrmoptionSepArg, 0 },
254   { 0, 0, 0, 0 }
255 };
256
257 void
258 screenhack (Display *dpy, Window window)
259 {
260   int delay = get_integer_resource ("delay", "Integer");
261   int color_shift = get_integer_resource ("colorShift", "Integer");
262   int pix = 0;
263   Bool flip_a, flip_b;
264
265   if (color_shift <= 0) color_shift = 1;
266   init_moire2 (dpy, window);
267   while (1)
268     {
269       int iterations = 30 + (random() % 70) + (random() % 70);
270       reset_moire2 (dpy, window);
271
272       flip_a = mono_p ? False : (random() & 1);
273       flip_b = mono_p ? False : (random() & 1);
274
275       if (flip_b)
276         {
277           XSetForeground(dpy, window_gc, bg_pixel);
278           XSetBackground(dpy, window_gc, fg_pixel);
279         }
280       else
281         {
282           XSetForeground(dpy, window_gc, fg_pixel);
283           XSetBackground(dpy, window_gc, bg_pixel);
284         }
285
286       while (--iterations > 0)
287         {
288           int i;
289
290           if (!mono_p)
291             {
292               pix++;
293               pix = pix % ncolors;
294
295               if (flip_a)
296                 XSetBackground(dpy, window_gc, colors[pix].pixel);
297               else
298                 XSetForeground(dpy, window_gc, colors[pix].pixel);
299             }
300
301           for (i = 0; i < color_shift; i++)
302             {
303               moire2 (dpy, window);
304               screenhack_handle_events (dpy);
305               if (delay)
306                 usleep(delay);
307             }
308         }
309     }
310 }