deedb270b659da0c929e426e94c9a6a0ebadc429
[xscreensaver] / hacks / anemone.c
1 /* anemone, Copyright (c) 2001 Gabriel Finch
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 /*------------------------------------------------------------------------
13   |
14   |  FILE            anemone.c
15   |  MODULE OF       xscreensaver
16   |
17   |  DESCRIPTION     Anemone.
18   |
19   |  WRITTEN BY      Gabriel Finch
20   |                  
21   |
22   |
23   |  MODIFICATIONS   june 2001 started
24   |           
25   +----------------------------------------------------------------------*/
26
27
28 #include <math.h>
29 #include "screenhack.h"
30
31
32 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
33 #include "xdbe.h"
34 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
35
36
37 /*-----------------------------------------------------------------------+
38   |  PRIVATE DATA                                                          |
39   +-----------------------------------------------------------------------*/
40
41
42 #define TWO_PI     (2.0 * M_PI)
43 #define RND(x)     (random() % (x))
44 #define MAXPEND    2000
45 #define MAXPTS    200
46 #define TRUE 1
47 #define FALSE 0
48
49
50 typedef struct {
51   double x,y,z;
52   int sx,sy,sz;
53 } vPend;
54
55 typedef struct {
56   long col;
57   int numpt;
58   int growth;
59   unsigned short rate;
60 } appDef;
61
62 struct state {
63   Display *dpy;
64   Pixmap b, ba, bb;
65
66 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
67   XdbeBackBuffer backb;
68 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
69
70   int arms;                       /* number of arms */
71   int finpoints;                  /* final number of points in each array. */
72   long delay;              /* usecs to wait between updates. */
73
74   int scrWidth, scrHeight;
75   GC gcDraw, gcClear;
76
77   Bool dbuf;
78   int width;
79
80   vPend *vPendage;  /* 3D representation of appendages */
81   appDef *appD;  /* defaults */
82   vPend *vCurr, *vNext;
83   appDef *aCurr;
84
85   double turn, turndelta;
86
87   int mx, my;            /* max screen coordinates. */
88   int withdraw;
89
90   XGCValues gcv;
91   Colormap cmap;
92   XColor *colors;
93   int ncolors;
94 };
95
96
97
98 /*-----------------------------------------------------------------------+
99   |  PUBLIC DATA                                                           |
100   +-----------------------------------------------------------------------*/
101
102
103
104 /*-----------------------------------------------------------------------+
105   |  PRIVATE FUNCTIONS                                                     |
106   +-----------------------------------------------------------------------*/
107
108 static void *
109 xmalloc(size_t size)
110 {
111   void *ret;
112
113   if ((ret = malloc(size)) == NULL) {
114     fprintf(stderr, "anemone: out of memory\n");
115     exit(1);
116   }
117   return ret;
118 }
119
120
121 static void
122 initAppendages(struct state *st)
123 {
124   int    i;
125   /*int    marginx, marginy; */
126     
127   /*double scalex, scaley;*/
128
129   double x,y,z,dist;
130
131   st->mx = st->scrWidth - 1;
132   st->my = st->scrHeight - 1;
133
134   /* each appendage will have: colour,
135      number of points, and a grow or shrink indicator */
136
137   /* added: growth rate 1-10 (smaller==faster growth) */
138   /* each appendage needs virtual coords (x,y,z) with y and z combining to
139      give the screen y */
140
141   st->vPendage = (vPend *) xmalloc((st->finpoints + 1) * sizeof(vPend) * st->arms);
142   st->appD = (appDef *) xmalloc(sizeof(appDef) * st->arms);
143
144
145   for (i = 0; i < st->arms; i++) {
146     st->aCurr = st->appD + i;
147     st->vCurr = st->vPendage + (st->finpoints + 1) * i;
148     st->vNext = st->vCurr + 1;
149
150     st->aCurr->col = st->colors[random() % st->ncolors].pixel;
151     st->aCurr->numpt = 1;
152     st->aCurr->growth = st->finpoints / 2 + RND(st->finpoints / 2);
153     st->aCurr->rate = RND(11) * RND(11);
154
155     do {
156       x = (1 - RND(1001) / 500);
157       y = (1 - RND(1001) / 500);
158       z = (1 - RND(1001) / 500);
159       dist = x * x + y * y + z * z;
160     } while (dist >= 1.);
161
162     st->vCurr->x = x * 200;
163     st->vCurr->y = st->my / 2 + y * 200;
164     st->vCurr->z = 0 + z * 200;
165
166     /* start the arm going outwards */
167     st->vCurr->sx = st->vCurr->x / 5;
168     st->vCurr->sy = (st->vCurr->y - st->my / 2) / 5;
169     st->vCurr->sz = (st->vCurr->z) / 5;
170
171     
172     st->vNext->x = st->vCurr->x + st->vCurr->sx;
173     st->vNext->y = st->vCurr->y + st->vCurr->sy;
174     st->vNext->z = st->vCurr->z + st->vCurr->sz;
175   }
176 }
177
178 static void *
179 anemone_init (Display *disp, Window window)
180 {
181   struct state *st = (struct state *) calloc (1, sizeof(*st));
182   XWindowAttributes wa;
183
184   st->dpy = disp;
185   st->turn = 0.;
186   
187   st->width = get_integer_resource(st->dpy, "width", "Integer");
188   st->arms = get_integer_resource(st->dpy, "arms", "Integer");
189   st->finpoints = get_integer_resource(st->dpy, "finpoints", "Integer");
190   st->delay = get_integer_resource(st->dpy, "delay", "Integer");
191   st->withdraw = get_integer_resource(st->dpy, "withdraw", "Integer");
192   st->turndelta = get_float_resource(st->dpy, "turnspeed", "float") / 100000;
193
194   st->dbuf = TRUE;
195
196 # ifdef HAVE_JWXYZ      /* Don't second-guess Quartz's double-buffering */
197   st->dbuf = False;
198 # endif
199
200   st->b = st->ba = st->bb = 0;  /* double-buffer to reduce flicker */
201 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
202   st->b = st->backb = xdbe_get_backbuffer (st->dpy, window, XdbeUndefined);
203 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
204
205
206   XGetWindowAttributes(st->dpy, window, &wa);
207   st->scrWidth = wa.width;
208   st->scrHeight = wa.height;
209   st->cmap = wa.colormap;
210
211   st->ncolors = get_integer_resource (st->dpy, "colors", "Colors");
212   st->ncolors += 3;
213   st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
214   make_smooth_colormap (wa.screen, wa.visual, st->cmap,
215                         st->colors, &st->ncolors,
216                         True, 0, True);
217
218   st->gcDraw = XCreateGC(st->dpy, window, 0, &st->gcv);
219   st->gcv.foreground = get_pixel_resource(st->dpy, st->cmap,
220                                           "background", "Background");
221   st->gcClear = XCreateGC(st->dpy, window, GCForeground, &st->gcv);
222
223   if (st->dbuf) {
224     if (!st->b)
225       {
226         st->ba = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth);
227         st->bb = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth);
228         st->b = st->ba;
229       }
230   }
231   else
232     {   
233       st->b = window;
234     }
235
236   if (st->ba) XFillRectangle (st->dpy, st->ba, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
237   if (st->bb) XFillRectangle (st->dpy, st->bb, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
238
239   XClearWindow(st->dpy, window);
240   XSetLineAttributes(st->dpy, st->gcDraw,  st->width, LineSolid, CapRound, JoinBevel);
241
242   initAppendages(st);
243
244   return st;
245 }
246
247
248 static void
249 createPoints(struct state *st)
250 {
251   int i;
252   int withdrawall = RND(st->withdraw);
253
254   for (i = 0; i< st->arms; i++) {
255     st->aCurr = st->appD + i;
256     if (!withdrawall) {
257       st->aCurr->growth = -st->finpoints;
258       st->turndelta = -st->turndelta;
259     }
260
261     else if (withdrawall<11) st->aCurr->growth = -st->aCurr->numpt;
262
263     else if (RND(100)<st->aCurr->rate) {
264       if (st->aCurr->growth>0) {
265         if (!(--st->aCurr->growth)) st->aCurr->growth = -RND(st->finpoints) - 1;
266         st->vCurr = st->vPendage + (st->finpoints + 1) * i + st->aCurr->numpt - 1;
267         if (st->aCurr->numpt<st->finpoints - 1) {
268           /* add a piece */     
269           st->vNext = st->vCurr + 1;
270           st->aCurr->numpt++;
271           st->vNext->sx = st->vCurr->sx + RND(3) - 1;
272           st->vNext->sy = st->vCurr->sy + RND(3) - 1;
273           st->vNext->sz = st->vCurr->sz + RND(3) - 1;
274           st->vCurr = st->vNext + 1;
275           st->vCurr->x = st->vNext->x + st->vNext->sx;
276           st->vCurr->y = st->vNext->y + st->vNext->sy;
277           st->vCurr->z = st->vNext->z + st->vNext->sz;
278         }
279       }
280     }
281   }
282 }
283
284
285 static void
286 drawImage(struct state *st, Drawable curr_window, double sint, double cost)
287 {
288   int q,numpt,mx2 = st->mx / 2;
289   double cx,cy,cz,nx = 0,ny = 0,nz = 0;
290
291   if ((numpt = st->aCurr->numpt)==1) return;
292   XSetForeground(st->dpy, st->gcDraw, st->aCurr->col);
293     
294   st->vNext = st->vCurr + 1;
295
296   cx = st->vCurr->x;
297   cy = st->vCurr->y;
298   cz = st->vCurr->z;
299
300
301   for (q = 0; q < numpt - 1; q++) {
302     nx = st->vNext->x + 2 - RND(5);
303     ny = st->vNext->y + 2 - RND(5);
304     nz = st->vNext->z + 2 - RND(5);
305
306     XDrawLine(st->dpy, curr_window, st->gcDraw,
307               mx2 + cx * cost - cz * sint, cy,
308               mx2 + nx * cost - nz * sint, ny);
309     st->vCurr++;
310     st->vNext++;
311
312     cx = nx;
313     cy = ny;
314     cz = nz;
315   }
316   XSetLineAttributes(st->dpy, st->gcDraw, st->width * 3,
317                      LineSolid, CapRound, JoinBevel);
318   XDrawLine(st->dpy, curr_window, st->gcDraw,
319             st->mx / 2 + cx * cost - cz * sint, cy,
320             st->mx / 2 + nx * cost - nz * sint, ny);
321   XSetLineAttributes(st->dpy, st->gcDraw, st->width,
322                      LineSolid, CapRound, JoinBevel);
323
324 }
325
326 static void
327 animateAnemone(struct state *st, Drawable curr_window)
328 {
329   int i;
330   double sint = sin(st->turn),cost = cos(st->turn);
331
332   st->aCurr = st->appD;
333   for (i = 0; i< st->arms; i++) {
334     st->vCurr = st->vPendage + (st->finpoints + 1) * i;
335     if (RND(25)<st->aCurr->rate) {
336       if (st->aCurr->growth<0) {
337         st->aCurr->numpt -= st->aCurr->numpt>1;
338         if (!(++st->aCurr->growth)) st->aCurr->growth = RND(st->finpoints - st->aCurr->numpt) + 1;
339       }
340     }
341     drawImage(st, curr_window, sint, cost);
342     st->turn += st->turndelta;
343     st->aCurr++;
344   }
345   createPoints(st);
346
347   if (st->turn >= TWO_PI) st->turn -= TWO_PI;
348 }
349
350 static unsigned long
351 anemone_draw (Display *dpy, Window window, void *closure)
352 {
353   struct state *st = (struct state *) closure;
354
355     XFillRectangle (st->dpy, st->b, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
356
357     animateAnemone(st, st->b);
358
359 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
360     if (st->backb)
361       {
362         XdbeSwapInfo info[1];
363         info[0].swap_window = window;
364         info[0].swap_action = XdbeUndefined;
365         XdbeSwapBuffers (st->dpy, info, 1);
366       }
367     else
368 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
369       if (st->dbuf)
370         {
371           XCopyArea (st->dpy, st->b, window, st->gcClear, 0, 0,
372                      st->scrWidth, st->scrHeight, 0, 0);
373           st->b = (st->b == st->ba ? st->bb : st->ba);
374         }
375
376     return st->delay;
377 }
378
379
380 static void
381 anemone_reshape (Display *dpy, Window window, void *closure, 
382                  unsigned int w, unsigned int h)
383 {
384   struct state *st = (struct state *) closure;
385   st->scrWidth = w;
386   st->scrHeight = h;
387 #if 0
388   if (st->dbuf) {
389     XWindowAttributes wa;
390     XGetWindowAttributes(dpy, window, &wa);
391     if (st->ba) XFreePixmap (dpy, st->ba);
392     if (st->bb) XFreePixmap (dpy, st->bb);
393     st->ba = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth);
394     st->bb = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth);
395     st->b = st->ba;
396   }
397 #endif
398 }
399
400 static Bool
401 anemone_event (Display *dpy, Window window, void *closure, XEvent *event)
402 {
403   return False;
404 }
405
406 static void
407 anemone_free (Display *dpy, Window window, void *closure)
408 {
409   struct state *st = (struct state *) closure;
410   if (st->vPendage) free (st->vPendage);
411   if (st->appD) free (st->appD);
412   free (st);
413 }
414
415
416
417 static const char *anemone_defaults [] = {
418   ".background: black",
419   "*arms: 128",
420   "*width: 2",
421   "*finpoints: 64",
422   "*delay: 40000",
423   "*withdraw: 1200",
424   "*turnspeed: 50",
425   "*colors: 20",
426 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
427   "*useDBE:             True",
428 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
429 #ifdef HAVE_MOBILE
430   "*ignoreRotation: True",
431 #endif
432   0
433 };
434
435
436 static XrmOptionDescRec anemone_options [] = {
437   { "-arms",        ".arms",        XrmoptionSepArg, 0 },
438   { "-finpoints",   ".finpoints",   XrmoptionSepArg, 0 },
439   { "-delay",       ".delay",       XrmoptionSepArg, 0 },
440   { "-width",       ".width",       XrmoptionSepArg, 0 },
441   { "-withdraw",    ".withdraw",    XrmoptionSepArg, 0 },
442   { "-turnspeed",   ".turnspeed",   XrmoptionSepArg, 0 },
443   { "-colors",      ".colors",      XrmoptionSepArg, 0 },
444   { 0, 0, 0, 0 }
445 };
446
447
448 XSCREENSAVER_MODULE ("Anemone", anemone)