ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / deluxe.c
1 /* xscreensaver, Copyright (c) 1999 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 <math.h>
13 #include "screenhack.h"
14 #include "alpha.h"
15
16 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
17 # include "xdbe.h"
18 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
19
20 #define countof(x) (sizeof(x)/sizeof(*(x)))
21 #define ABS(x) ((x)<0?-(x):(x))
22
23 static Bool transparent_p;
24 static int nplanes;
25 static unsigned long base_pixel, *plane_masks;
26
27 struct throbber {
28   int x, y;
29   int size;
30   int max_size;
31   int thickness;
32   int speed;
33   int fuse;
34   GC gc;
35   void (*draw) (Display *, Drawable, struct throbber *);
36 };
37
38 static void
39 draw_star (Display *dpy, Drawable w, struct throbber *t)
40 {
41   XPoint points[11];
42   int x = t->x;
43   int y = t->y;
44   int s = t->size / 0.383;  /* trial and error, I forget how to derive this */
45   int s2 = t->size;
46   double c = M_PI * 2;
47   double o = -M_PI / 2;
48
49   points[0].x = x + s  * cos(o + 0.0*c); points[0].y = y + s  * sin(o + 0.0*c);
50   points[1].x = x + s2 * cos(o + 0.1*c); points[1].y = y + s2 * sin(o + 0.1*c);
51   points[2].x = x + s  * cos(o + 0.2*c); points[2].y = y + s  * sin(o + 0.2*c);
52   points[3].x = x + s2 * cos(o + 0.3*c); points[3].y = y + s2 * sin(o + 0.3*c);
53   points[4].x = x + s  * cos(o + 0.4*c); points[4].y = y + s  * sin(o + 0.4*c);
54   points[5].x = x + s2 * cos(o + 0.5*c); points[5].y = y + s2 * sin(o + 0.5*c);
55   points[6].x = x + s  * cos(o + 0.6*c); points[6].y = y + s  * sin(o + 0.6*c);
56   points[7].x = x + s2 * cos(o + 0.7*c); points[7].y = y + s2 * sin(o + 0.7*c);
57   points[8].x = x + s  * cos(o + 0.8*c); points[8].y = y + s  * sin(o + 0.8*c);
58   points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
59   points[10] = points[0];
60
61   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
62 }
63
64 static void
65 draw_circle (Display *dpy, Drawable w, struct throbber *t)
66 {
67   XDrawArc (dpy, w, t->gc,
68             t->x - t->size / 2,
69             t->y - t->size / 2,
70             t->size, t->size,
71             0, 360*64);
72 }
73
74 static void
75 draw_hlines (Display *dpy, Drawable w, struct throbber *t)
76 {
77   XDrawLine (dpy, w, t->gc, 0,
78              t->y - t->size, t->max_size,
79              t->y - t->size);
80   XDrawLine (dpy, w, t->gc, 0,
81              t->y + t->size, t->max_size,
82              t->y + t->size);
83 }
84
85 static void
86 draw_vlines (Display *dpy, Drawable w, struct throbber *t)
87 {
88   XDrawLine (dpy, w, t->gc,
89              t->x - t->size, 0,
90              t->x - t->size, t->max_size);
91   XDrawLine (dpy, w, t->gc,
92              t->x + t->size, 0,
93              t->x + t->size, t->max_size);
94 }
95
96 static void
97 draw_corners (Display *dpy, Drawable w, struct throbber *t)
98 {
99   int s = (t->size + t->thickness) / 2;
100   XPoint points[3];
101
102   points[0].x = 0;        points[0].y = t->y - s;
103   points[1].x = t->x - s; points[1].y = t->y - s;
104   points[2].x = t->x - s; points[2].y = 0;
105   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
106
107   points[0].x = 0;        points[0].y = t->y + s;
108   points[1].x = t->x - s; points[1].y = t->y + s;
109   points[2].x = t->x - s; points[2].y = t->max_size;
110   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
111
112   points[0].x = t->x + s;    points[0].y = 0;
113   points[1].x = t->x + s;    points[1].y = t->y - s;
114   points[2].x = t->max_size; points[2].y = t->y - s;
115   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
116
117   points[0].x = t->x + s;    points[0].y = t->max_size;
118   points[1].x = t->x + s;    points[1].y = t->y + s;
119   points[2].x = t->max_size; points[2].y = t->y + s;
120   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
121 }
122
123
124 static struct throbber *
125 make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
126 {
127   XGCValues gcv;
128   unsigned long flags;
129   struct throbber *t = (struct throbber *) malloc (sizeof (*t));
130   t->x = w / 2;
131   t->y = h / 2;
132   t->max_size = w;
133   t->speed = get_integer_resource ("speed", "Speed");
134   t->fuse = 1 + (random() % 4);
135   t->thickness = get_integer_resource ("thickness", "Thickness");
136
137   if (t->speed < 0) t->speed = -t->speed;
138   t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
139   if (t->speed > 0) t->speed = -t->speed;
140
141   if (random() % 4)
142     t->size = t->max_size;
143   else
144     t->size = t->thickness, t->speed = -t->speed;
145
146   flags = GCForeground;
147   if (transparent_p)
148     {
149       gcv.foreground = ~0L;
150       gcv.plane_mask = base_pixel | plane_masks[random() % nplanes];
151       flags |= GCPlaneMask;
152     }
153   else
154     {
155       gcv.foreground = pixel;
156     }
157
158   gcv.line_width = t->thickness;
159   gcv.line_style = LineSolid;
160   gcv.cap_style = CapProjecting;
161   gcv.join_style = JoinMiter;
162
163   flags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
164   t->gc = XCreateGC (dpy, d, flags, &gcv);
165
166   switch (random() % 11) {
167   case 0: case 1: case 2: case 3: t->draw = draw_star; break;
168   case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
169   case 8: t->draw = draw_hlines; break;
170   case 9: t->draw = draw_vlines; break;
171   case 10: t->draw = draw_corners; break;
172   default: abort(); break;
173   }
174
175   return t;
176 }
177
178 static int
179 throb (Display *dpy, Drawable window, struct throbber *t)
180 {
181   t->size += t->speed;
182   if (t->size <= (t->thickness / 2))
183     {
184       t->speed = -t->speed;
185       t->size += (t->speed * 2);
186     }
187   else if (t->size > t->max_size)
188     {
189       t->speed = -t->speed;
190       t->size += (t->speed * 2);
191       t->fuse--;
192     }
193
194   if (t->fuse <= 0)
195     {
196       XFreeGC (dpy, t->gc);
197       memset (t, 0, sizeof(*t));
198       free (t);
199       return -1;
200     }
201   else
202     {
203       t->draw (dpy, window, t);
204       return 0;
205     }
206 }
207
208
209 \f
210 char *progclass = "Deluxe";
211
212 char *defaults [] = {
213   ".background:         black",
214   ".foreground:         white",
215   "*delay:              5000",
216   "*count:              5",
217   "*thickness:          50",
218   "*speed:              15",
219   "*ncolors:            20",
220   "*nlayers:            0",
221   "*transparent:        False",
222   "*doubleBuffer:       True",
223 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
224   "*useDBE:             True",
225 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
226   0
227 };
228
229 XrmOptionDescRec options [] = {
230   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
231   { "-thickness",       ".thickness",   XrmoptionSepArg, 0 },
232   { "-count",           ".count",       XrmoptionSepArg, 0 },
233   { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
234   { "-speed",           ".speed",       XrmoptionSepArg, 0 },
235   { "-transparent",     ".transparent",  XrmoptionNoArg,  "True" },
236   { "-opaque",          ".transparent",  XrmoptionNoArg,  "False" },
237   { "-db",              ".doubleBuffer", XrmoptionNoArg,  "True" },
238   { "-no-db",           ".doubleBuffer", XrmoptionNoArg,  "False" },
239   { 0, 0, 0, 0 }
240 };
241
242 void
243 screenhack (Display *dpy, Window window)
244 {
245   int count = get_integer_resource ("count", "Integer");
246   int delay = get_integer_resource ("delay", "Integer");
247   int ncolors = get_integer_resource ("ncolors", "Integer");
248   Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
249   XColor colors[255];
250   XGCValues gcv;
251   GC erase_gc = 0;
252   int i;
253   struct throbber **throbbers;
254   XWindowAttributes xgwa;
255   Pixmap b=0, ba=0, bb=0;       /* double-buffer to reduce flicker */
256 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
257   XdbeBackBuffer backb = 0;
258 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
259
260   XGetWindowAttributes (dpy, window, &xgwa);
261
262   transparent_p = get_boolean_resource("transparent", "Transparent");
263
264   if (get_boolean_resource("mono", "Boolean"))
265     {
266     MONO:
267       ncolors = 1;
268       colors[0].pixel = get_pixel_resource("foreground", "Foreground",
269                                            dpy, xgwa.colormap);
270     }
271   else if (transparent_p)
272     {
273       nplanes = get_integer_resource ("planes", "Planes");
274       if (nplanes <= 0)
275         nplanes = (random() % (xgwa.depth-2)) + 2;
276
277       allocate_alpha_colors (xgwa.screen, xgwa.visual, xgwa.colormap,
278                              &nplanes, True, &plane_masks,
279                              &base_pixel);
280       if (nplanes <= 1)
281         {
282           fprintf (stderr,
283          "%s: couldn't allocate any color planes; turning transparency off.\n",
284                    progname);
285           transparent_p = False;
286           goto COLOR;
287         }
288     }
289   else
290     {
291     COLOR:
292       make_random_colormap (dpy, xgwa.visual, xgwa.colormap,
293                             colors, &ncolors, True, True, 0, True);
294       if (ncolors < 2)
295         goto MONO;
296     }
297
298   if (dbuf)
299     {
300 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
301       b = backb = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
302 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
303
304       if (!b)
305         {
306           ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
307           bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
308           b = ba;
309         }
310     }
311   else
312     {
313       b = window;
314     }
315
316   throbbers = (struct throbber **) calloc (count, sizeof(struct throbber *));
317   for (i = 0; i < count; i++)
318     throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
319                                   colors[random() % ncolors].pixel);
320
321   gcv.foreground = get_pixel_resource ("background", "Background",
322                                        dpy, xgwa.colormap);
323   erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
324
325   if (ba) XFillRectangle (dpy, ba, erase_gc, 0, 0, xgwa.width, xgwa.height);
326   if (bb) XFillRectangle (dpy, bb, erase_gc, 0, 0, xgwa.width, xgwa.height);
327
328   while (1)
329     {
330       XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
331
332       for (i = 0; i < count; i++)
333         if (throb (dpy, b, throbbers[i]) < 0)
334           throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
335                                         colors[random() % ncolors].pixel);
336
337 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
338       if (backb)
339         {
340           XdbeSwapInfo info[1];
341           info[0].swap_window = window;
342           info[0].swap_action = XdbeUndefined;
343           XdbeSwapBuffers (dpy, info, 1);
344         }
345       else
346 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
347       if (dbuf)
348         {
349           XCopyArea (dpy, b, window, erase_gc, 0, 0,
350                      xgwa.width, xgwa.height, 0, 0);
351           b = (b == ba ? bb : ba);
352         }
353
354       XSync (dpy, False);
355       screenhack_handle_events (dpy);
356       if (delay)
357         usleep (delay);
358     }
359 }