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