From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / hacks / moire2.c
1 /* xscreensaver, Copyright (c) 1997-2013 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
14 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
15 # include "xdbe.h"
16 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
17
18 struct state {
19   Display *dpy;
20   Window window;
21
22   int ncolors;
23   XColor *colors;
24   int fg_pixel, bg_pixel;
25   Pixmap p0, p1, p2, p3;
26   GC copy_gc, erase_gc, window_gc;
27   int width, height, size;
28   int x1, x2, y1, y2, x3, y3;
29   int dx1, dx2, dx3, dy1, dy2, dy3;
30   int othickness, thickness;
31   Bool do_three;
32 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
33   XdbeBackBuffer back_buf;
34 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
35
36   Bool flip_a, flip_b;
37   int pix;
38   int delay, color_shift;
39
40   int reset;
41   int iterations, iteration;
42 };
43
44 static void
45 moire2_init_1 (struct state *st)
46 {
47   XWindowAttributes xgwa;
48   XGetWindowAttributes (st->dpy, st->window, &xgwa);
49
50   st->othickness = get_integer_resource(st->dpy, "thickness", "Thickness");
51
52   if (mono_p)
53     st->ncolors = 2;
54   else
55     st->ncolors = get_integer_resource (st->dpy, "colors", "Colors");
56   if (st->ncolors < 2) st->ncolors = 2;
57   if (st->ncolors <= 2) mono_p = True;
58
59   if (mono_p)
60     st->colors = 0;
61   else
62     st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
63
64   if (mono_p)
65     ;
66   else
67     make_smooth_colormap (xgwa.screen, xgwa.visual, xgwa.colormap,
68                           st->colors, &st->ncolors,
69                           True, 0, True);
70
71   st->bg_pixel = get_pixel_resource(st->dpy,
72                                 xgwa.colormap, "background", "Background");
73   st->fg_pixel = get_pixel_resource(st->dpy,
74                                 xgwa.colormap, "foreground", "Foreground");
75
76 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
77   st->back_buf = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
78 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
79 }
80
81
82 static void
83 reset_moire2 (struct state *st)
84 {
85   GC gc;
86   XWindowAttributes xgwa;
87   XGCValues gcv;
88   Bool xor;
89   XGetWindowAttributes (st->dpy, st->window, &xgwa);
90
91   st->do_three = (0 == (random() % 3));
92
93   st->width = xgwa.width;
94   st->height = xgwa.height;
95   st->size = st->width > st->height ? st->width : st->height;
96
97   if (st->p0) XFreePixmap(st->dpy, st->p0);
98   if (st->p1) XFreePixmap(st->dpy, st->p1);
99   if (st->p2) XFreePixmap(st->dpy, st->p2);
100   if (st->p3) XFreePixmap(st->dpy, st->p3);
101
102   st->p0 = XCreatePixmap(st->dpy, st->window, st->width, st->height, 1);
103   st->p1 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1);
104   st->p2 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1);
105   if (st->do_three)
106     st->p3 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1);
107   else
108     st->p3 = 0;
109
110   st->thickness = (st->othickness > 0 ? st->othickness : (1 + (random() % 4)));
111
112   gcv.foreground = 0;
113   gcv.line_width = (st->thickness == 1 ? 0 : st->thickness);
114   gc = XCreateGC (st->dpy, st->p1, GCForeground|GCLineWidth, &gcv);
115
116   XFillRectangle(st->dpy, st->p1, gc, 0, 0, st->width*2, st->height*2);
117   XFillRectangle(st->dpy, st->p2, gc, 0, 0, st->width*2, st->height*2);
118   if (st->do_three)
119     XFillRectangle(st->dpy, st->p3, gc, 0, 0, st->width*2, st->height*2);
120
121   XSetForeground(st->dpy, gc, 1);
122
123   xor = (st->do_three || (st->thickness == 1) || (random() & 1));
124
125   {
126     int i, ii, maxx, maxy;
127
128 #define FROB(P) do { \
129     maxx = (st->size*4); \
130     maxy = (st->size*4); \
131     if (0 == (random() % 5)) { \
132         float f = 1.0 + frand(0.05); \
133         if (random() & 1) maxx *= f; \
134         else maxy *= f; \
135       } \
136     ii = (st->thickness + 1 + (xor ? 0 : 1) + (random() % (4 * st->thickness)));  \
137     for (i = 0; i < (st->size*2); i += ii)  \
138       XDrawArc(st->dpy, (P), gc, i-st->size, i-st->size, maxx-i-i, maxy-i-i, 0, 360*64); \
139     if (0 == (random() % 5)) \
140       { \
141         XSetFunction(st->dpy, gc, GXxor); \
142         XFillRectangle(st->dpy, (P), gc, 0, 0, st->width*2, st->height*2); \
143         XSetFunction(st->dpy, gc, GXcopy); \
144       } \
145     } while(0)
146
147     FROB(st->p1);
148     FROB(st->p2);
149     if (st->do_three)
150       FROB(st->p3);
151 #undef FROB
152   }
153
154   XFreeGC(st->dpy, gc);
155
156   if (st->copy_gc) XFreeGC(st->dpy, st->copy_gc);
157   gcv.function = (xor ? GXxor : GXor);
158   gcv.foreground = 1;
159   gcv.background = 0;
160
161   st->copy_gc = XCreateGC (st->dpy, st->p0, GCFunction|GCForeground|GCBackground, &gcv);
162
163   gcv.foreground = 0;
164   if (st->erase_gc) XFreeGC(st->dpy, st->erase_gc);
165   st->erase_gc = XCreateGC (st->dpy, st->p0, GCForeground, &gcv);
166
167   gcv.foreground = st->fg_pixel;
168   gcv.background = st->bg_pixel;
169   if (st->window_gc) XFreeGC(st->dpy, st->window_gc);
170   st->window_gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv);
171
172 #define FROB(N,DN,MAX) \
173   N = (MAX/2) + (random() % MAX); \
174   DN = ((1 + (random() % (7*st->thickness))) * ((random() & 1) ? 1 : -1))
175
176   FROB(st->x1,st->dx1,st->width);
177   FROB(st->x2,st->dx2,st->width);
178   FROB(st->x3,st->dx3,st->width);
179   FROB(st->y1,st->dy1,st->height);
180   FROB(st->y2,st->dy2,st->height);
181   FROB(st->y3,st->dy3,st->height);
182 #undef FROB
183 }
184
185
186
187 static void
188 moire2 (struct state *st)
189 {
190 #define FROB(N,DN,MAX) \
191   N += DN; \
192   if (N <= 0) N = 0, DN = -DN; \
193   else if (N >= MAX) N = MAX, DN = -DN; \
194   else if (0 == (random() % 100)) DN = -DN; \
195   else if (0 == (random() % 50)) \
196     DN += (DN <= -20 ? 1 : (DN >= 20 ? -1 : ((random() & 1) ? 1 : -1)))
197
198   FROB(st->x1,st->dx1,st->width);
199   FROB(st->x2,st->dx2,st->width);
200   FROB(st->x3,st->dx3,st->width);
201   FROB(st->y1,st->dy1,st->height);
202   FROB(st->y2,st->dy2,st->height);
203   FROB(st->y3,st->dy3,st->height);
204 #undef FROB
205
206   XFillRectangle(st->dpy, st->p0, st->erase_gc, 0, 0, st->width, st->height);
207   XCopyArea(st->dpy, st->p1, st->p0, st->copy_gc, st->x1, st->y1, st->width, st->height, 0, 0);
208   XCopyArea(st->dpy, st->p2, st->p0, st->copy_gc, st->x2, st->y2, st->width, st->height, 0, 0);
209   if (st->do_three)
210     XCopyArea(st->dpy, st->p3, st->p0, st->copy_gc, st->x3, st->y3, st->width, st->height, 0, 0);
211
212 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
213   if (st->back_buf)
214     {
215       XdbeSwapInfo info[1];
216       info[0].swap_window = st->window;
217       info[0].swap_action = XdbeUndefined;
218       XCopyPlane (st->dpy, st->p0, st->back_buf, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L);
219       XdbeSwapBuffers (st->dpy, info, 1);
220     }
221   else
222 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
223     XCopyPlane (st->dpy, st->p0, st->window, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L);
224
225 #if 0
226   XCopyPlane(st->dpy, st->p1, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3,
227              st->width/2, st->height/2,
228              0, st->height/2, 1L);
229   XCopyPlane(st->dpy, st->p2, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3,
230              st->width/2, st->height/2,
231              st->width/2, st->height/2, 1L);
232 #endif
233 }
234
235
236
237 static void *
238 moire2_init (Display *dpy, Window window)
239 {
240   struct state *st = (struct state *) calloc (1, sizeof(*st));
241   st->dpy = dpy;
242   st->window = window;
243   st->reset = 1;
244
245   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
246   st->color_shift = get_integer_resource (st->dpy, "colorShift", "Integer");
247
248   if (st->color_shift <= 0) st->color_shift = 1;
249   moire2_init_1 (st);
250   return st;
251 }
252
253 static unsigned long
254 moire2_draw (Display *dpy, Window window, void *closure)
255 {
256   struct state *st = (struct state *) closure;
257
258   if (st->reset)
259     {
260       st->reset = 0;
261
262       st->iteration = 0;
263       st->iterations = 30 + (random() % 70) + (random() % 70);
264       reset_moire2 (st);
265
266       st->flip_a = mono_p ? False : (random() & 1);
267       st->flip_b = mono_p ? False : (random() & 1);
268
269       if (st->flip_b)
270         {
271           XSetForeground(st->dpy, st->window_gc, st->bg_pixel);
272           XSetBackground(st->dpy, st->window_gc, st->fg_pixel);
273         }
274       else
275         {
276           XSetForeground(st->dpy, st->window_gc, st->fg_pixel);
277           XSetBackground(st->dpy, st->window_gc, st->bg_pixel);
278         }
279     }
280
281   if (!mono_p)
282     {
283       st->pix++;
284       st->pix = st->pix % st->ncolors;
285
286       if (st->flip_a)
287         XSetBackground(st->dpy, st->window_gc, st->colors[st->pix].pixel);
288       else
289         XSetForeground(st->dpy, st->window_gc, st->colors[st->pix].pixel);
290     }
291
292
293   moire2 (st);
294   st->iteration++;
295   if (st->iteration >= st->color_shift) 
296     {
297       st->iteration = 0;
298       st->iterations--;
299       if (st->iterations <= 0)
300         st->reset = 1;
301     }
302
303   return st->delay;
304 }
305
306 static void
307 moire2_reshape (Display *dpy, Window window, void *closure, 
308                  unsigned int w, unsigned int h)
309 {
310   struct state *st = (struct state *) closure;
311   st->reset = 1;
312 }
313
314 static Bool
315 moire2_event (Display *dpy, Window window, void *closure, XEvent *event)
316 {
317   return False;
318 }
319
320 static void
321 moire2_free (Display *dpy, Window window, void *closure)
322 {
323 }
324
325 static const char *moire2_defaults [] = {
326   ".background:         black",
327   ".foreground:         white",
328   "*delay:              50000",
329   "*thickness:          0",
330   "*colors:             150",
331   "*colorShift:         5",
332 #ifdef USE_IPHONE
333   "*ignoreRotation:     True",
334 #endif
335
336 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
337   /* Off by default, since it slows it down a lot, and the flicker isn't really
338      all that bad without it... Or rather, it flickers just as badly with it.
339      The XFree86 implementation of the XDBE extension totally blows!  There is
340      just *no* excuse for the "swap buffers" operation to flicker like it does.
341    */
342   "*useDBE:             False",
343 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
344
345   0
346 };
347
348 static XrmOptionDescRec moire2_options [] = {
349   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
350   { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
351   { "-thickness",       ".thickness",   XrmoptionSepArg, 0 },
352   { 0, 0, 0, 0 }
353 };
354
355 XSCREENSAVER_MODULE ("Moire2", moire2)