began for maemo
[xscreensaver] / xscreensaver / hacks / wormhole.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998, 2004, 2006
2  *  Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* wormhole:
14  * Animation of moving through a wormhole. Based on my own code written
15  * a few years ago.
16  * author: Jon Rafkind <jon@rafkind.com>
17  * date: 1/19/04
18  */
19
20 #include <math.h>
21 #include "screenhack.h"
22
23 #ifndef debug
24 #define debug printf("File:%s Line:%d\n", __FILE__, __LINE__ );
25 #endif
26
27 typedef struct STAR{
28         int x, y;
29         int calc_x, calc_y;
30         int Z;
31         int center_x, center_y;
32 } star;
33
34 typedef struct STARLINE{
35         star begin, end;
36 } starline;
37
38 /*
39 typedef struct RGBHANDLE{
40         XColor mine;
41         unsigned short rwant, gwant, bwant;
42 } RGBHandle;
43 */
44
45 typedef struct COLORCHANGER{
46         XColor * shade;
47         int min, max; 
48         int shade_use;
49         int shade_max;
50         int min_want;
51         /* RGBHandle handle_begin, handle_end; */
52 } color_changer;
53
54 typedef struct WORMHOLE{
55         int diameter;
56         int diameter_change;
57         int actualx, actualy;
58         double virtualx, virtualy;
59         double speed;
60         int ang;
61         int want_ang;
62         int want_x, want_y;
63         int max_Z;
64         int addStar;
65         int spiral;
66         color_changer changer;
67         starline ** stars;
68         int num_stars; /* top of array we are using */
69         XColor black;
70         Pixmap work;
71 } wormhole;
72
73 struct state {
74   Display *dpy;
75   Window window;
76
77   int SCREEN_X, SCREEN_Y;
78   int z_speed;
79   int make_stars;
80
81   int delay;
82   wormhole worm;
83   GC gc;
84   Colormap cmap;
85 };
86
87
88 /*inline*/ static int rnd( int q )
89 {
90
91         return random() % q;
92
93 }
94
95 static int gang( int x1, int y1, int x2, int y2 )
96 {
97
98         int tang = 0;
99         if ( x1 == x2 ) {
100                 if ( y1 < y2 )
101                         tang = 90;
102                 else
103                         tang = 270;
104         }
105         if ( y1 == y2 ) {
106
107                 if ( x1 < x2 )
108                         tang = 0;
109                 else
110                         tang = 180;
111
112         } else
113         tang = (int)(0.5+atan2( -(y2-y1), x2 - x1 ) * 180.0 / M_PI );
114
115         while ( tang < 0 )
116                 tang += 360;
117         return tang % 360;
118
119 }
120
121 static void blend_palette( XColor * pal, int max, XColor * sc, XColor * ec ) 
122 {
123
124         int q;
125
126         int sc_r = sc->red;
127         int sc_g = sc->green;
128         int sc_b = sc->blue;
129
130         int ec_r = ec->red;
131         int ec_g = ec->green;
132         int ec_b = ec->blue;
133
134         for ( q = 0; q < max; q++ ) {
135                 float j = (float)( q ) / (float)( max );
136                 int f_r = (int)( 0.5 + (float)( sc_r ) + (float)( ec_r-sc_r ) * j );
137                 int f_g = (int)( 0.5 + (float)( sc_g ) + (float)( ec_g-sc_g ) * j );
138                 int f_b = (int)( 0.5 + (float)( sc_b ) + (float)( ec_b-sc_b ) * j );
139                 /* pal[q] = makecol( f_r, f_g, f_b ); */
140                 pal[q].red = f_r;
141                 pal[q].blue = f_b;
142                 pal[q].green = f_g; 
143         }
144
145 }
146
147
148 /*
149 static void initHandle( RGBHandle * handle )
150 {
151
152         handle->mine.red = rnd( 65536 );
153         handle->mine.green = rnd( 65536 );
154         handle->mine.blue = rnd( 65536 );
155         handle->rwant = rnd( 65536 );
156         handle->gwant = rnd( 65536 );
157         handle->bwant = rnd( 65536 );
158
159 }
160 */
161
162 static void initXColor( XColor * color )
163 {
164         color->red = rnd( 50000 ) + 10000;
165         color->blue = rnd( 50000 ) + 10000;
166         color->green = rnd( 50000 ) + 10000;
167 }
168
169 static void initColorChanger( struct state *st, color_changer * ch )
170 {
171
172         int q;
173         int min, max;
174         XColor old_color, new_color;
175
176         ch->shade_max = 2048;
177         ch->shade_use = 128;
178         ch->min = 0;
179         ch->max = ch->shade_use;
180         ch->min_want = rnd( ch->shade_max - ch->shade_use );
181         ch->shade = (XColor *)malloc( sizeof(XColor) * ch->shade_max );
182         memset( ch->shade, 0, sizeof(XColor) * ch->shade_max );
183
184         initXColor( &old_color );
185         initXColor( &new_color );
186         
187         for ( q = 0; q < ch->shade_max; q += ch->shade_use ){
188                 min = q;
189                 max = q + ch->shade_use;
190                 if ( max >= ch->shade_max ) max = ch->shade_max-1;
191                 blend_palette( ch->shade + q, ch->shade_use, &old_color, &new_color );
192                 old_color = new_color;
193
194                 initXColor( &new_color );
195         }
196
197         for ( q = 0; q < ch->shade_max; q++ )
198                 XAllocColor( st->dpy, st->cmap, &( ch->shade[q] ) );
199
200         /*
201         initHandle( &(ch->handle_begin) );
202         initHandle( &(ch->handle_end) );
203         ch->shade = (XColor *)malloc( sizeof(XColor) * MAX_COLORS );
204         ch->max = MAX_COLORS;
205         memset( ch->shade, 0, sizeof(XColor) * ch->max );
206
207         blend_palette( ch->shade, ch->max, &(ch->handle_begin.mine), &(ch->handle_end.mine) );
208         for ( q = 0; q < ch->max; q++ )
209                 XAllocColor( st->dpy, *cmap, &( ch->shade[q] ) );
210         */
211
212 }
213
214 /*
215 static void changeColor( unsigned short * col, unsigned short * change, int min, int max )
216 {
217         int RGB_GO_BLACK = 30;
218         if ( *col < *change ) *col++;
219         if ( *col > *change ) *col--;
220         if ( *col == *change ){
221                 if ( rnd( RGB_GO_BLACK ) == rnd( RGB_GO_BLACK ) )
222                         *change = 0;
223                 else    *change = rnd(max-min) + min;
224         }
225 }
226 */
227
228 /*
229 static void moveRGBHandle( RGBHandle * handle, int min, int max )
230 {
231
232         unsigned short * want[ 3 ];
233         int q;
234         int cy = 0;
235         want[0] = &(handle->rwant);
236         want[1] = &(handle->gwant);
237         want[2] = &(handle->bwant);
238
239         for ( q = 0; q < 10; q++ ){
240                 changeColor( &( handle->mine.red ), &handle->rwant, min, max );
241                 changeColor( &( handle->mine.green ), &handle->gwant, min, max );
242                 changeColor( &( handle->mine.blue ), &handle->bwant, min, max );
243         }
244         
245         for ( q = 0; q < 3; q++ )
246                 cy = cy || (*(want[q]) >= min && *(want[q]) <= max);
247         if ( !cy ) *(want[rnd(3)]) = rnd(max-min)+min;
248         cy = 1;
249         for ( q = 0; q < 3; q++ )
250                 cy = cy && *(want[q]) == 0;
251         if ( cy ) *(want[rnd(3)]) = rnd(max-min)+min;
252
253         if ( rnd( 30 ) == rnd( 30 ) )
254                 *(want[rnd(3)]) = rnd(max-min)+min;
255
256 }
257 */
258
259 static void moveColorChanger( color_changer * ch )
260 {
261
262         /* int q; */
263
264         if ( ch->min < ch->min_want ){
265                 ch->min++;
266                 ch->max++;
267         }
268         if ( ch->min > ch->min_want ) {
269                 ch->min--;
270                 ch->max--;
271         }
272         if ( ch->min == ch->min_want )
273                 ch->min_want = rnd( ch->shade_max - ch->shade_use );
274
275         /*
276         for ( q = 0; q < ch->max; q++ )
277                 XFreeColors( st->dpy, *cmap, &( ch->shade[q].pixel ), 1, 0 );
278
279         moveRGBHandle( &( ch->handle_begin ), 5000, 65500 );
280         moveRGBHandle( &( ch->handle_end ), 5000, 65500 );
281         
282         blend_palette( ch->shade, ch->max, &(ch->handle_begin.mine), &(ch->handle_end.mine) );
283         for ( q = 0; q < ch->max; q++ )
284                 XAllocColor( st->dpy, *cmap, &( ch->shade[q] ) );
285         */
286
287 }
288
289 #if 0
290 static void destroyColorChanger( color_changer * ch )
291 {
292         int q;
293         for ( q = 0; q < ch->max; q++ )
294                 XFreeColors( st->dpy, *cmap, &( ch->shade[q].pixel ), 1, 0 );
295         free( ch->shade );
296 }
297 #endif
298
299 static void resizeWormhole( struct state *st, wormhole * worm )
300 {
301         
302         XWindowAttributes attr;
303
304         XGetWindowAttributes( st->dpy, st->window, &attr );
305
306         st->cmap = attr.colormap;
307         
308         st->SCREEN_X = attr.width;
309         st->SCREEN_Y = attr.height;
310
311 # ifndef HAVE_COCOA     /* Don't second-guess Quartz's double-buffering */
312         XFreePixmap( st->dpy, worm->work );
313         worm->work = XCreatePixmap( st->dpy, st->window, st->SCREEN_X, st->SCREEN_Y, attr.depth );
314 # endif
315
316 }
317
318 static void initWormhole( struct state *st, wormhole * worm, Display * display, Window win )
319 {
320         
321         int i;
322         XWindowAttributes attr;
323
324         XGetWindowAttributes( st->dpy, st->window, &attr );
325
326         st->cmap = attr.colormap;
327         
328         st->SCREEN_X = attr.width;
329         st->SCREEN_Y = attr.height;
330
331 # ifdef HAVE_COCOA      /* Don't second-guess Quartz's double-buffering */
332         worm->work = st->window;
333 # else
334         worm->work = XCreatePixmap( st->dpy, st->window, st->SCREEN_X, st->SCREEN_Y, attr.depth );
335 # endif
336
337         worm->diameter = rnd( 10 ) + 15;
338         worm->diameter_change = rnd( 10 ) + 15;
339         /* worm->actualx = rnd( attr.width );
340         worm->actualy = rnd( attr.height ); */
341         worm->actualx = attr.width / 2;
342         worm->actualy = attr.height / 2;
343         worm->virtualx = worm->actualx;
344         worm->virtualy = worm->actualy;
345         worm->speed = (float)st->SCREEN_X / 180.0;
346         /* z_speed = SCREEN_X / 120; */
347         worm->spiral = 0;
348         worm->addStar = st->make_stars;
349         worm->want_x = rnd( attr.width - 50 ) + 25;
350         worm->want_y = rnd( attr.height - 50 ) + 25;
351         worm->want_ang = gang( worm->actualx, worm->actualy, worm->want_x, worm->want_y );
352         worm->ang = worm->want_ang;
353         worm->max_Z = 600;
354         worm->black.red = 0;
355         worm->black.green = 0;
356         worm->black.blue = 0;
357         XAllocColor( st->dpy, st->cmap, &worm->black );
358         initColorChanger( st, &(worm->changer) );
359
360         worm->num_stars = 64;
361         worm->stars = (starline **)malloc( sizeof(starline *) * worm->num_stars );
362         for ( i = 0; i < worm->num_stars; i++ )
363                 worm->stars[i] = NULL;
364
365 }
366
367 #if 0
368 static void destroyWormhole( wormhole * worm )
369 {
370         destroyColorChanger( &(worm->changer), st->dpy, cmap );
371         if (work->work != st->window)
372           XFreePixmap( st->dpy, worm->work );
373         free( worm->stars );
374 }
375 #endif
376
377 static double Cos( int a )
378 {
379         return cos( a * 180.0 / M_PI );
380 }
381
382 static double Sine( int a )
383 {
384         return sin( a * 180.0 / M_PI );
385 }
386
387
388
389 static void calcStar( star * st )
390 {
391         if ( st->center_x == 0 || st->center_y == 0 ){
392                 st->Z = 0;
393                 return;
394         }
395         if ( st->Z <= 0 ){
396                 st->calc_x = (st->x << 10) / st->center_x;
397                 st->calc_y = (st->y << 10) / st->center_y;
398         } else {
399                 st->calc_x = (st->x << 10 ) / st->Z + st->center_x;
400                 st->calc_y = (st->y << 10 ) / st->Z + st->center_y;
401         }
402 }
403
404 static void initStar( star * st, int Z, int ang, wormhole * worm )
405 {
406
407         st->x = Cos( ang ) * worm->diameter;
408         st->y = Sine( ang ) * worm->diameter;
409         st->center_x = worm->actualx;
410         st->center_y = worm->actualy;
411         st->Z = Z;
412         calcStar( st );
413
414 }
415
416 static void addStar( wormhole * worm )
417 {
418
419         starline * star_new;
420         starline ** xstars;
421         int old_stars;
422         int q;
423         int ang;
424         star_new = (starline *)malloc( sizeof( starline ) );
425         ang = rnd( 360 );
426         initStar( &star_new->begin, worm->max_Z, ang, worm );
427         initStar( &star_new->end, worm->max_Z+rnd(6)+4, ang, worm );
428
429         for ( q = 0; q < worm->num_stars; q++ ){
430                 if ( worm->stars[q] == NULL ){
431                         worm->stars[q] = star_new;
432                         return;
433                 }
434         }
435
436         old_stars = worm->num_stars;
437         worm->num_stars = worm->num_stars << 1;
438         xstars = (starline **)malloc( sizeof(starline *) * worm->num_stars );
439         for ( q = 0; q < worm->num_stars; q++ )
440                 xstars[q] = NULL;
441
442         for ( q = 0; q < old_stars; q++ )
443                 if ( worm->stars[q] != NULL ) xstars[q] = worm->stars[q];
444         free( worm->stars );
445         worm->stars = xstars;
446
447         worm->stars[ old_stars ] = star_new;
448
449 }
450
451 static int moveStar( struct state *st, starline * stl )
452 {
453
454         stl->begin.Z -= st->z_speed;    
455         stl->end.Z -= st->z_speed;
456
457         calcStar( &stl->begin );
458         calcStar( &stl->end );
459
460         return ( stl->begin.Z <= 0 || stl->end.Z <= 0 );
461
462
463
464 static int dist( int x1, int y1, int x2, int y2 )
465 {
466         int xs, ys;
467         xs = x1-x2;
468         ys = y1-y2;
469         return (int)sqrt( xs*xs + ys*ys );
470 }
471
472 static void moveWormhole( struct state *st, wormhole * worm )
473 {
474
475         int q;
476         double dx, dy;
477         /* int x1, y1, x2, y2; */
478         int min_dist = 100;
479         int find = 0;
480         dx = Cos( worm->ang ) * worm->speed;
481         dy = Sine( worm->ang ) * worm->speed;
482
483         worm->virtualx += dx;
484         worm->virtualy += dy;
485         worm->actualx = (int)worm->virtualx;
486         worm->actualy = (int)worm->virtualy;
487
488         if ( worm->spiral ){
489
490                 if ( worm->spiral % 5 == 0 )
491                         worm->ang = (worm->ang + 1 ) % 360;
492                 worm->spiral--;
493                 if ( worm->spiral <= 0 ) find = 1;
494
495         } else {
496
497                 if ( dist( worm->actualx, worm->actualy, worm->want_x, worm->want_y ) < 20 )
498                         find = 1;
499
500                 if ( rnd( 20 ) == rnd( 20 ) )
501                         find = 1;
502
503                 if ( worm->actualx < min_dist ){
504                         worm->actualx = min_dist;
505                         worm->virtualx = worm->actualx;
506                         find = 1;
507                 }
508                 if ( worm->actualy < min_dist ){
509                         worm->actualy = min_dist;
510                         worm->virtualy = worm->actualy;
511                         find = 1;
512                 }
513                 if ( worm->actualx > st->SCREEN_X - min_dist ){
514                         worm->actualx = st->SCREEN_X - min_dist;
515                         worm->virtualx = worm->actualx;
516                         find = 1;
517                 }
518                 if ( worm->actualy > st->SCREEN_Y - min_dist ){
519                         worm->actualy = st->SCREEN_Y - min_dist;
520                         worm->virtualy = worm->actualy;
521                         find = 1;
522                 }
523         
524                 if ( rnd( 500 ) == rnd( 500 ) ) worm->spiral = rnd( 30 ) + 50;
525         }
526
527         if ( find ){
528                 worm->want_x = rnd( st->SCREEN_X - min_dist * 2 ) + min_dist;
529                 worm->want_y = rnd( st->SCREEN_Y - min_dist * 2 ) + min_dist;
530                 worm->ang = gang( worm->actualx, worm->actualy, worm->want_x, worm->want_y );
531         }
532
533
534         /* worm->ang = ( worm->ang + 360 + rnd( 30 ) - 15 ) % 360; */
535
536         /*
537         if ( worm->ang < worm->want_ang ) worm->ang++;
538         if ( worm->ang > worm->want_ang ) worm->ang--;
539         if ( worm->ang == worm->want_ang && rnd( 3 ) == rnd( 3 ) ) worm->want_ang = rnd( 360 );
540         */
541
542         /*
543         if ( rnd( 25 ) == rnd( 25 ) ){
544                 x1 = worm->actualx;
545                 y1 = worm->actualy;
546                 x2 = SCREEN_X / 2 + rnd( 20 ) - 10;
547                 y2 = SCREEN_Y / 2 + rnd( 20 ) - 10;
548                 worm->want_ang = gang(x1,y1,x2,y2);
549         }
550         */
551
552         /*
553         if ( worm->actualx < min_dist || worm->actualx > SCREEN_X - min_dist || worm->actualy < min_dist || worm->actualy > SCREEN_Y - min_dist ){
554                 x1 = worm->actualx;
555                 y1 = worm->actualy;
556                 x2 = SCREEN_X / 2 + rnd( 20 ) - 10;
557                 y2 = SCREEN_Y / 2 + rnd( 20 ) - 10;
558                 / * worm->ang = gang( worm->actualx, worm->actualy, SCREEN_X/2+rnd(20)-10, SCREEN_Y/2+rnd(20)-10 ); * /
559                 worm->ang = gang( x1, y1, x2, y2 );
560                 worm->want_ang = worm->ang;
561                 / * printf("Angle = %d\n", worm->ang ); * /
562
563                 if ( worm->actualx < min_dist )
564                         worm->actualx = min_dist;
565                 if ( worm->actualx > SCREEN_X - min_dist )
566                         worm->actualx = SCREEN_X - min_dist;
567                 if ( worm->actualy < min_dist )
568                         worm->actualy = min_dist;
569                 if ( worm->actualy > SCREEN_Y - min_dist )
570                         worm->actualy = SCREEN_Y - min_dist;
571                 worm->virtualx = worm->actualx;
572                 worm->virtualy = worm->actualy;
573         }
574         */
575
576         for ( q = 0; q < worm->num_stars; q++ ){
577                 if ( worm->stars[q] != NULL ){
578                         if ( moveStar( st, worm->stars[q] ) ){
579                                 free( worm->stars[q] );
580                                 worm->stars[q] = NULL;
581                         }
582                 }
583         }
584
585         moveColorChanger( &worm->changer );
586
587         if ( worm->diameter < worm->diameter_change )
588                 worm->diameter++;
589         if ( worm->diameter > worm->diameter_change )
590                 worm->diameter--;
591         if ( rnd( 30 ) == rnd( 30 ) )
592                 worm->diameter_change = rnd( 35 ) + 5;
593
594         for ( q = 0; q < worm->addStar; q++ )
595                 addStar( worm );
596
597 }
598
599 static XColor * getColorShade( color_changer * ch )
600 {
601         return ch->shade + ch->min;
602 }
603
604 static void drawWormhole( struct state *st, wormhole * worm )
605 {
606
607         int i;
608         int color;
609         int z;
610         starline * current;
611         XColor * xcol;
612         XColor * shade;
613
614         XSetForeground( st->dpy, st->gc, worm->black.pixel );
615         XFillRectangle( st->dpy, worm->work, st->gc, 0, 0, st->SCREEN_X, st->SCREEN_Y );
616
617         for ( i = 0; i < worm->num_stars; i++ )
618                 if ( worm->stars[i] != NULL ){
619         
620                         current = worm->stars[i];
621                         z = current->begin.Z;
622
623                         color = z * worm->changer.shade_use / worm->max_Z;
624                         shade = getColorShade( &worm->changer );
625                         /* xcol = &worm->changer.shade[ color ]; */
626                         xcol = &shade[ color ];
627
628                         XSetForeground( st->dpy, st->gc, xcol->pixel );
629                         /* XDrawLine( st->dpy, st->window, *gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y ); */
630                         XDrawLine( st->dpy, worm->work, st->gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y );
631
632                 }
633         if (worm->work != st->window)
634           XCopyArea( st->dpy, worm->work, st->window, st->gc, 0, 0, st->SCREEN_X, st->SCREEN_Y, 0, 0 );
635 }
636
637 /*
638 static void eraseWormhole( Display * display, Window * st->window, wormhole * worm ){
639         starline * current;
640         int i;
641         XColor * xcol;
642         for ( i = 0; i < worm->num_stars; i++ )
643                 if ( worm->stars[i] != NULL ){
644                         xcol = &worm->black;
645                         current = worm->stars[i];
646                         XSetForeground( st->dpy, *gc, xcol->pixel );
647                         XDrawLine( st->dpy, st->window, *gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y );
648                 }
649 }
650 */
651
652
653
654 static void *
655 wormhole_init (Display *dpy, Window window)
656 {
657         struct state *st = (struct state *) calloc (1, sizeof(*st));
658         XGCValues gcv;
659         XWindowAttributes attr;
660
661         st->dpy = dpy;
662         st->window = window;
663         st->delay = get_integer_resource(st->dpy,  "delay", "Integer" );
664         st->make_stars = get_integer_resource(st->dpy,  "stars", "Integer" );
665         st->z_speed = get_integer_resource(st->dpy,  "zspeed", "Integer" );
666
667         initWormhole( st, &st->worm, st->dpy, st->window );
668
669         st->gc = XCreateGC( st->dpy, st->window, 0, &gcv );
670         XGetWindowAttributes( st->dpy, st->window, &attr );
671         st->cmap = attr.colormap;
672
673         return st;
674 }
675
676 static unsigned long
677 wormhole_draw (Display *dpy, Window window, void *closure)
678 {
679   struct state *st = (struct state *) closure;
680
681   moveWormhole( st, &st->worm );
682   drawWormhole( st, &st->worm );
683   return st->delay;
684 }
685
686 static void
687 wormhole_reshape (Display *dpy, Window window, void *closure, 
688                  unsigned int w, unsigned int h)
689 {
690   struct state *st = (struct state *) closure;
691   resizeWormhole( st, &st->worm );
692 }
693
694 static Bool
695 wormhole_event (Display *dpy, Window window, void *closure, XEvent *event)
696 {
697   return False;
698 }
699
700 static void
701 wormhole_free (Display *dpy, Window window, void *closure)
702 {
703   struct state *st = (struct state *) closure;
704   free (st);
705 }
706
707
708
709
710 static const char *wormhole_defaults [] = {
711   ".background: Black",
712   ".foreground: #E9967A",
713   "*delay:      10000",
714   "*zspeed:     10",
715   "*stars:      20",
716   0
717 };
718
719 static XrmOptionDescRec wormhole_options [] = {
720   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
721   { "-zspeed",          ".zspeed",      XrmoptionSepArg, 0 },
722   { "-stars",           ".stars",       XrmoptionSepArg, 0 },
723   { 0, 0, 0, 0 }
724 };
725
726 XSCREENSAVER_MODULE ("Wormhole", wormhole)