1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* anemone --- */
3
4 #if 0
5 static const char sccsid[] = "@(#)anemone.c 5.22 2006/03/04 xlockmore";
6
7 #endif
8
9 /* anemon, Copyright (c) 2001 Gabriel Finch
10 *
11 * Permission to use, copy, modify, distribute, and sell this software and its
12 * documentation for any purpose is hereby granted without fee, provided that
13 * the above copyright notice appear in all copies and that both that
14 * copyright notice and this permission notice appear in supporting
15 * documentation. No representations are made about the suitability of this
16 * software for any purpose. It is provided "as is" without express or
17 * implied warranty.
18 */
19
20 /*------------------------------------------------------------------------
21 |
22 | FILE anemone.c
23 | MODULE OF xscreensaver
24 |
25 | DESCRIPTION Anemone.
26 |
27 | WRITTEN BY Gabriel Finch
28 |
29 |
30 |
31 | MODIFICATIONS june 2001 started
32 | March 2006 adaption for xlockmore
33 |
34 +----------------------------------------------------------------------*/
35
36
37
38 #ifdef STANDALONE
39 # define MODE_anemone
40 # define DEFAULTS "*delay: 100000 \n" \
41 "*size: 4 \n" \
42 "*ncolors: 8 \n" \
43 "*fullrandom: True \n" \
44 "*verbose: False \n" \
45 "*delay: 40000 \n" \
46
47 #if 0
48 ".background: black \n" \
49
50 #endif
51 #if 0
52 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
53 "*useDBE: True \n" \
54
55 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
56 #endif
57 # define reshape_anemone 0
58 # define anemone_handle_event 0
59 # include "xlockmore.h" /* in xscreensaver distribution */
60 #else /* STANDALONE */
61 # include "xlock.h" /* in xlockmore distribution */
62 #endif /* STANDALONE */
63
64 #ifdef MODE_anemone
65
66 #undef HAVE_DOUBLE_BUFFER_EXTENSION
67 /* xdbe_get_backbuffer does not exist */
68 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
69 #include "xdbe.h"
70 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
71
72
73 /*-----------------------------------------------------------------------+
74 | PRIVATE DATA |
75 +-----------------------------------------------------------------------*/
76
77
78 #define TWO_PI (2.0 * M_PI)
79 #define MAXPEND 2000
80 #define MAXPTS 200
81
82 #define DEF_ARMS "256"
83 #define DEF_FINPOINTS "64"
84 #define DEF_WIDTH "2"
85 #define DEF_WITHDRAW "2400"
86 #define DEF_TURNSPEED "5"
87
88 static int st_arms;
89 static int st_finpoints;
90 static int st_width;
91 static int st_withdraw;
92 static int st_turnspeed;
93
94 typedef struct {
95 double x,y,z;
96 int sx,sy,sz;
97 } vPend;
98
99 typedef struct {
100 long col;
101 int numpt;
102 int growth;
103 unsigned short rate;
104 } appDef;
105
106
107 typedef struct {
108 Display *dpy;
109 Window window;
110
111 Pixmap b,ba,bb;
112
113 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
114 XdbeBackBuffer backb;
115 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
116
117 int
118 arms, /* number of arms */
119 finpoints; /* final number of points in each array. */
120
121 int scrWidth, scrHeight;
122 GC gcDraw, gcClear;
123
124
125 unsigned short dbuf;
126 int width;
127
128 vPend *vPendage; /* 3D representation of appendages */
129 appDef *appD; /* defaults */
130 vPend *vCurr, *vNext;
131 appDef *aCurr;
132
133 double turn, turndelta;
134
135 int mx, my; /* max screen coordinates. */
136 int withdraw;
137
138 XGCValues gcv;
139 Colormap cmap;
140 } anemonestruct;
141
142 static anemonestruct *anemones = (anemonestruct *) NULL;
143
144
145 /*-----------------------------------------------------------------------+
146 | PUBLIC DATA |
147 +-----------------------------------------------------------------------*/
148
149 static XrmOptionDescRec opts[] =
150 {
151 {(char *) "-arms", (char *) ".anemone.arms", XrmoptionSepArg, (caddr_t) NULL},
152 {(char *) "-finpoints", (char *) ".anemone.finpoints", XrmoptionSepArg, (caddr_t) NULL},
153 {(char *) "-width", (char *) ".anemone.width", XrmoptionSepArg, (caddr_t) NULL},
154 {(char *) "-withdraw", (char *) ".anemone.withdraw", XrmoptionSepArg, (caddr_t) NULL},
155 {(char *) "-turnspeed", (char *) ".anemone.turnspeed", XrmoptionSepArg, (caddr_t) NULL}
156 };
157
158 static argtype vars[] =
159 {
160 {(void *) &st_arms, (char *) "arms",
161 (char *) "Arms", (char *) DEF_ARMS , t_Int},
162 {(void *) &st_finpoints, (char *) "finpoints",
163 (char *) "Finpoints", (char *) DEF_FINPOINTS , t_Int},
164 {(void *) &st_width, (char *) "width",
165 (char *) "Width", (char *) DEF_WIDTH , t_Int},
166 {(void *) &st_withdraw, (char *) "withdraw",
167 (char *) "Withdt=raw", (char *) DEF_WITHDRAW , t_Int},
168 {(void *) &st_turnspeed, (char *) "turnspeed",
169 (char *) "Turnspeed", (char *) DEF_TURNSPEED , t_Int}
170 };
171
172
173 static OptionStruct desc[] =
174 {
175 {(char *) "-arms num", (char *) "Number of arms"},
176 {(char *) "-width num", (char *) "Width of arms"},
177 {(char *) "-finpoints num", (char *) "final number of points in each array"},
178 {(char *) "-withdraw num", (char *) "withdraw frequency"},
179 {(char *) "-turnspeed num", (char *) "turning speed"}
180 };
181
182 ENTRYPOINT ModeSpecOpt anemone_opts =
183 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
184
185 #ifdef USE_MODULES
186 ModStruct anemone_description =
187 {"anemone", "init_anemone", "draw_anemone", "release_anemone",
188 (char *) NULL, "init_anemone", "free_anemone", &anemone_opts,
189 50000, 1, 1, 1, 64, 1.0, "",
190 "Shows wiggling tentacles", 0, NULL};
191
192 #endif
193
194 /*-----------------------------------------------------------------------+
195 | PRIVATE FUNCTIONS |
196 +-----------------------------------------------------------------------*/
197
198 static void
free_anemone_screen(Display * display,anemonestruct * sp)199 free_anemone_screen(Display *display, anemonestruct *sp)
200 {
201 if (sp == NULL) {
202 return;
203 }
204 if ( sp->vPendage )
205 {
206 free( sp->vPendage );
207 sp->vPendage = (vPend*) NULL;
208 }
209 if ( sp->appD )
210 {
211 free( sp->appD );
212 sp->appD = (appDef*) NULL;
213 }
214 if ( sp->gcDraw != None )
215 {
216 XFreeGC(display, sp->gcDraw );
217 sp->gcDraw = None;
218 }
219 if ( sp->gcClear != None )
220 {
221 XFreeGC(display, sp->gcClear );
222 sp->gcClear = None;
223 }
224 if (sp->ba != None)
225 {
226 XFreePixmap(display, sp->ba);
227 sp->ba = None;
228 }
229 if (sp->bb != None)
230 {
231 XFreePixmap(display, sp->bb);
232 sp->bb = None;
233 }
234 sp = NULL;
235 }
236
237 ENTRYPOINT void
free_anemone(ModeInfo * mi)238 free_anemone(ModeInfo * mi)
239 {
240 free_anemone_screen(MI_DISPLAY(mi), &anemones[MI_SCREEN(mi)]);
241 }
242
243 static void *
xmalloc(size_t size)244 xmalloc(size_t size)
245 {
246 void *ret;
247
248 if ((ret = malloc(size)) == NULL) {
249 fprintf(stderr, "anemone: out of memory\n");
250 }
251 return ret;
252 }
253
254
255 static void
initAppendages(ModeInfo * mi,anemonestruct * sp)256 initAppendages(ModeInfo *mi, anemonestruct *sp)
257 {
258 int i;
259 /*int marginx, marginy; */
260
261 /*double scalex, scaley;*/
262
263 double x,y,z,dist;
264
265 sp->mx = sp->scrWidth - 1;
266 sp->my = sp->scrHeight - 1;
267
268 /* each appendage will have: colour,
269 number of points, and a grow or shrink indicator */
270
271 /* added: growth rate 1-10 (smaller==faster growth) */
272 /* each appendage needs virtual coords (x,y,z) with y and z combining to
273 give the screen y */
274
275 sp->vPendage = (vPend *) xmalloc((sp->finpoints + 1) * sizeof(vPend) * sp->arms);
276 sp->appD = (appDef *) xmalloc(sizeof(appDef) * sp->arms);
277
278
279 for (i = 0; i < sp->arms; i++) {
280 sp->aCurr = sp->appD + i;
281 sp->vCurr = sp->vPendage + (sp->finpoints + 1) * i;
282 sp->vNext = sp->vCurr + 1;
283
284 #ifdef WIN32
285 sp->aCurr->col = (long)NRAND(MI_NCOLORS(mi));
286 #else
287 sp->aCurr->col = (long)NRAND(256)*NRAND(256)+32768;
288 #endif
289 sp->aCurr->numpt = 1;
290 sp->aCurr->growth=sp->finpoints/2+NRAND(sp->finpoints/2);
291 sp->aCurr->rate=NRAND(11)*NRAND(11);
292
293 dist=1.;
294
295 do {
296 x=(1-NRAND(1001)/500);
297 y=(1-NRAND(1001)/500);
298 z=(1-NRAND(1001)/500);
299 dist=x*x+y*y+z*z;
300 } while (dist>=1.);
301
302 sp->vCurr->x=x*200;
303 sp->vCurr->y=sp->my/2+y*200;
304 sp->vCurr->z=0+z*200;
305
306 /* start the arm going outwards */
307 sp->vCurr->sx=(int) (sp->vCurr->x/5);
308 sp->vCurr->sy=(int) ((sp->vCurr->y-sp->my/2)/5);
309 sp->vCurr->sz=(int) (sp->vCurr->z/5);
310
311
312 sp->vNext->x=sp->vCurr->x+sp->vCurr->sx;
313 sp->vNext->y=sp->vCurr->y+sp->vCurr->sy;
314 sp->vNext->z=sp->vCurr->z+sp->vCurr->sz;
315 }
316 }
317
318 static void
initAnemone(ModeInfo * mi,anemonestruct * sp)319 initAnemone( ModeInfo * mi , anemonestruct *sp )
320 {
321 XWindowAttributes wa;
322
323 sp->turn = 0.;
324 if ( st_width < 0 )
325 sp->width = NRAND( -st_width ) + 1;
326 else
327 sp->width = st_width;
328 if ( st_arms < 0 )
329 sp->arms = NRAND( -st_arms ) + 1;
330 else
331 sp->arms = st_arms;
332 if ( st_finpoints < 0 )
333 sp->finpoints = NRAND( -st_finpoints ) + 1;
334 else
335 sp->finpoints = st_finpoints;
336 if ( st_withdraw < 0 )
337 sp->withdraw = NRAND( -st_withdraw );
338 else
339 sp->withdraw = st_withdraw;
340 if ( st_turnspeed < 0 )
341 sp->turndelta = NRAND( -st_turnspeed ) / 10000.;
342 else
343 sp->turndelta =st_turnspeed / 10000.0;
344
345 #ifdef WIN32
346 sp->dbuf=False;
347 #else
348 sp->dbuf=True;
349 #endif
350
351 sp->b=sp->ba=sp->bb=0; /* double-buffer to reduce flicker */
352 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
353 sp->b = sp->backb = xdbe_get_backbuffer (sp->dpy, sp->window, XdbeUndefined);
354 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
355
356
357 XGetWindowAttributes(sp->dpy, sp->window, &wa);
358 sp->scrWidth = wa.width;
359 sp->scrHeight = wa.height;
360 sp->cmap = wa.colormap;
361 sp->gcDraw = XCreateGC(sp->dpy, sp->window, GCForeground, &sp->gcv);
362 sp->gcv.foreground = MI_BLACK_PIXEL(mi);
363 sp->gcClear = XCreateGC(sp->dpy, sp->window, GCForeground, &sp->gcv);
364
365 if (sp->dbuf) {
366 if (!sp->b)
367 {
368 sp->ba = XCreatePixmap (sp->dpy, sp->window, sp->scrWidth, sp->scrHeight, wa.depth);
369 sp->bb = XCreatePixmap (sp->dpy, sp->window, sp->scrWidth, sp->scrHeight, wa.depth);
370 sp->b = sp->ba;
371 }
372 }
373 else
374 {
375 sp->b= sp->window;
376 }
377
378 if (sp->ba) XFillRectangle (sp->dpy, sp->ba, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
379 if (sp->bb) XFillRectangle (sp->dpy, sp->bb, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
380
381 XClearWindow(sp->dpy, sp->window);
382 XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width, LineSolid, CapRound, JoinBevel);
383
384 initAppendages(mi, sp);
385 }
386
387
388 static void
createPoints(anemonestruct * sp)389 createPoints(anemonestruct *sp)
390 {
391 int i;
392 int withdrawall=NRAND(sp->withdraw);
393
394 for (i = 0; i< sp->arms; i++) {
395 sp->aCurr = sp->appD + i;
396 if (!withdrawall) {
397 sp->aCurr->growth=-sp->finpoints;
398 sp->turndelta=-sp->turndelta;
399 }
400
401 else if (withdrawall<11) sp->aCurr->growth=-sp->aCurr->numpt;
402
403 else if (NRAND(100)<sp->aCurr->rate) {
404 if (sp->aCurr->growth>0) {
405 if (!(--sp->aCurr->growth)) sp->aCurr->growth=-NRAND(sp->finpoints)-1;
406 sp->vCurr = sp->vPendage + (sp->finpoints + 1) * i + sp->aCurr->numpt-1;
407 if (sp->aCurr->numpt<sp->finpoints - 1) {
408 /* add a piece */
409 sp->vNext=sp->vCurr + 1;
410 sp->aCurr->numpt++;
411 sp->vNext->sx=sp->vCurr->sx+NRAND(3)-1;
412 sp->vNext->sy=sp->vCurr->sy+NRAND(3)-1;
413 sp->vNext->sz=sp->vCurr->sz+NRAND(3)-1;
414 sp->vCurr=sp->vNext+1;
415 sp->vCurr->x=sp->vNext->x+sp->vNext->sx;
416 sp->vCurr->y=sp->vNext->y+sp->vNext->sy;
417 sp->vCurr->z=sp->vNext->z+sp->vNext->sz;
418 }
419 }
420 }
421 }
422 }
423
424
425 static void
drawImage(Drawable curr_window,double sint,double cost,anemonestruct * sp,ModeInfo * mi)426 drawImage(Drawable curr_window, double sint, double cost , anemonestruct *sp, ModeInfo *mi)
427 {
428 int q,numpt,mx2=sp->mx/2;
429 double cx,cy,cz,nx=0,ny=0,nz=0;
430
431 if ((numpt=sp->aCurr->numpt)==1) return;
432 #ifdef WIN32
433 XSetForeground(sp->dpy, sp->gcDraw, MI_PIXEL(mi, sp->aCurr->col));
434 #else
435 XSetForeground(sp->dpy, sp->gcDraw, sp->aCurr->col);
436 #endif
437
438 sp->vNext=sp->vCurr+1;
439
440 cx=sp->vCurr->x;
441 cy=sp->vCurr->y;
442 cz=sp->vCurr->z;
443
444
445 for (q = 0; q < numpt-1; q++) {
446 nx=sp->vNext->x+2-NRAND(5);
447 ny=sp->vNext->y+2-NRAND(5);
448 nz=sp->vNext->z+2-NRAND(5);
449
450 XDrawLine(sp->dpy, curr_window, sp->gcDraw,
451 (int) (mx2+cx*cost-cz*sint), (int) cy,
452 (int) (mx2+nx*cost-nz*sint), (int) ny);
453 sp->vCurr++;
454 sp->vNext++;
455
456 cx=nx;
457 cy=ny;
458 cz=nz;
459 }
460 XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width*3, LineSolid, CapRound, JoinBevel);
461 XDrawLine(sp->dpy, curr_window, sp->gcDraw,
462 (int) (sp->mx/2+cx*cost-cz*sint), (int) cy,
463 (int) (sp->mx/2+nx*cost-nz*sint), (int) ny);
464 XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width, LineSolid, CapRound, JoinBevel);
465
466 }
467
468 static void
animateAnemone(Drawable curr_window,anemonestruct * sp,ModeInfo * mi)469 animateAnemone(Drawable curr_window , anemonestruct *sp, ModeInfo *mi)
470 {
471 int i;
472 double sint=sin(sp->turn),cost=cos(sp->turn);
473
474 sp->aCurr = sp->appD;
475 for (i = 0; i< sp->arms; i++) {
476 sp->vCurr=sp->vPendage + (sp->finpoints + 1) * i;
477 if (NRAND(25)<sp->aCurr->rate) {
478 if (sp->aCurr->growth<0) {
479 sp->aCurr->numpt-=sp->aCurr->numpt>1;
480 if (!(++sp->aCurr->growth)) sp->aCurr->growth=NRAND(sp->finpoints-sp->aCurr->numpt)+1;
481 }
482 }
483 drawImage(curr_window, sint, cost , sp, mi);
484 sp->turn+=sp->turndelta;
485 sp->aCurr++;
486 }
487 createPoints(sp);
488
489 if (sp->turn>=TWO_PI) sp->turn-=TWO_PI;
490 }
491
492 /*-----------------------------------------------------------------------+
493 | PUBLIC FUNCTIONS |
494 +-----------------------------------------------------------------------*/
495
496 ENTRYPOINT void
init_anemone(ModeInfo * mi)497 init_anemone(ModeInfo * mi)
498 {
499 anemonestruct *sp;
500
501 MI_INIT(mi, anemones);
502 sp = &anemones[MI_SCREEN(mi)];
503
504 sp->dpy= MI_DISPLAY(mi);
505 sp->window=MI_WINDOW(mi);
506
507 initAnemone( mi , sp );
508
509 XFillRectangle (sp->dpy, sp->b, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
510
511 animateAnemone( sp->b , sp, mi);
512 }
513
514 ENTRYPOINT void
draw_anemone(ModeInfo * mi)515 draw_anemone(ModeInfo * mi)
516 {
517 anemonestruct *sp = &anemones[MI_SCREEN(mi)];
518
519 if (anemones == NULL)
520 return;
521 MI_IS_DRAWN(mi) = True;
522
523 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
524 if (sp->backb)
525 {
526 XdbeSwapInfo info[1];
527 info[0].swap_window = sp->window;
528 info[0].swap_action = XdbeUndefined;
529 XdbeSwapBuffers (sp->dpy, info, 1);
530 }
531 else
532 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
533 if (sp->dbuf)
534 {
535 XCopyArea (sp->dpy, sp->b, sp->window, sp->gcClear, 0, 0,
536 sp->scrWidth, sp->scrHeight, 0, 0);
537 sp->b = (sp->b == sp->ba ? sp->bb : sp->ba);
538 }
539
540 XFillRectangle (sp->dpy, sp->b, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
541
542 animateAnemone( sp->b , sp, mi);
543 }
544
545 ENTRYPOINT void
release_anemone(ModeInfo * mi)546 release_anemone(ModeInfo * mi)
547 {
548 if (anemones != NULL) {
549 int screen;
550
551 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
552 free_anemone_screen(MI_DISPLAY(mi), &anemones[screen]);
553 free(anemones);
554 anemones = (anemonestruct *) NULL;
555 }
556 }
557
558 /*
559 void
560 refresh_anemone(ModeInfo * mi)
561 {
562 if (anemones == NULL)
563 return;
564 }
565 */
566
567 XSCREENSAVER_MODULE ("Anemone", anemone)
568
569 #endif /* MODE_anemone */
570