From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / hacks / kumppa.c
1 /*
2
3 Copyright (C) Teemu Suutari (temisu@utu.fi) Feb 1998
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of the X Consortium shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
27 from the X Consortium.
28
29 */
30
31
32
33
34 /*
35
36 *** This is contest-version. Don't look any further, code is *very* ugly.
37
38 */
39
40 #include <math.h>
41 #include "screenhack.h"
42
43 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
44 # include "xdbe.h"
45 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
46
47 #undef countof
48 #define countof(x) (sizeof((x))/sizeof((*x)))
49
50 static const char *kumppa_defaults [] ={
51   ".background:         black",
52   "*fpsSolid:           true",
53   "*speed:              0.1",
54   "*delay:              10000",
55   "*random:             True",
56   /* leave this off by default, since it slows things down.  -- jwz. */
57   "*useDBE:             False",
58 #ifdef USE_IPHONE
59   "*ignoreRotation:     True",
60 #endif
61   0
62 };
63
64 static XrmOptionDescRec kumppa_options [] = {
65   {"-delay",     ".delay",  XrmoptionSepArg, 0 },
66   {"-speed",     ".speed",  XrmoptionSepArg, 0 },
67   {"-random",    ".random", XrmoptionNoArg, "True"  },
68   {"-no-random", ".random", XrmoptionNoArg, "False" },
69   {"-db",       ".useDBE",  XrmoptionNoArg, "True"  },
70   {"-no-db",    ".useDBE",  XrmoptionNoArg, "False" },
71   {0,0,0,0}
72 };
73
74 static const unsigned char colors[96]=
75   {0,0,255, 0,51,255, 0,102,255, 0,153,255, 0,204,255,
76    0,255,255,0,255,204, 0,255,153, 0,255,102, 0,255,51,
77    0,255,0, 51,255,0, 102,255,0, 153,255,0, 204,255,0,
78    255,255,0, 255,204,0, 255,153,0, 255,102,0, 255,51,0,
79    255,0,0, 255,0,51, 255,0,102, 255,0,153, 255,0,204,
80    255,0,255, 219,0,255, 182,0,255, 146,0,255, 109,0,255,
81    73,0,255, 37,0,255};
82 static const float cosinus[8][6]=
83  {{-0.07,0.12,-0.06,32,25,37},{0.08,-0.03,0.05,51,46,32},{0.12,0.07,-0.13,27,45,36},
84   {0.05,-0.04,-0.07,36,27,39},{-0.02,-0.07,0.1,21,43,42},{-0.11,0.06,0.02,51,25,34},{0.04,-0.15,0.02,42,32,25},
85   {-0.02,-0.04,-0.13,34,20,15}};
86
87
88 struct state {
89   Display *dpy;
90   Window win[2];
91
92   float acosinus[8][3];
93   int coords[8];
94   int ocoords[8];
95
96   GC fgc[33];
97   GC cgc;
98   int sizx,sizy;
99   int midx,midy;
100   unsigned long delay;
101   Bool cosilines;
102
103   int *Xrotations;
104   int *Yrotations;
105   int *Xrottable;
106   int *Yrottable;
107
108   int *rotateX;
109   int *rotateY;
110
111   int rotsizeX,rotsizeY;
112   int stateX,stateY;
113
114   int rx,ry;
115
116 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
117   XdbeSwapInfo xdswp;
118   Bool usedouble;
119 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
120
121   int draw_count;
122 };
123
124
125 static int Satnum(int maxi)
126 {
127   return (int)(maxi*frand(1));
128 }
129
130
131 static void palaRotate(struct state *st, int x,int y)
132 {
133   int ax,ay,bx,by,cx,cy;
134
135   ax=st->rotateX[x];
136   ay=st->rotateY[y];
137   bx=st->rotateX[x+1]+2;
138   by=st->rotateY[y+1]+2;
139   cx=st->rotateX[x]-(y-st->ry)+x-st->rx;
140   cy=st->rotateY[y]+(x-st->rx)+y-st->ry;
141   if (cx<0)
142     {
143       ax-=cx;
144       cx=0;
145     }
146   if (cy<0)
147     {
148       ay-=cy;
149       cy=0;
150     }
151   if (cx+bx-ax>st->sizx) bx=ax-cx+st->sizx;
152   if (cy+by-ay>st->sizy) by=ay-cy+st->sizy;
153   if (ax<bx && ay<by)
154     XCopyArea(st->dpy,st->win[0],st->win[1],st->cgc,ax,ay,bx-ax,by-ay,cx,cy);
155 }
156
157
158 static void rotate(struct state *st)
159 {
160   int x,y;
161   int dx,dy;
162
163   st->rx=st->Xrottable[st->stateX+1]-st->Xrottable[st->stateX];
164   st->ry=st->Yrottable[st->stateY+1]-st->Yrottable[st->stateY];
165
166
167   for (x=0;x<=st->rx;x++)
168     st->rotateX[x]=(x)?st->midx-1-st->Xrotations[st->Xrottable[st->stateX+1]-x]:0;
169   for (x=0;x<=st->rx;x++)
170     st->rotateX[x+st->rx+1]=(x==st->rx)?st->sizx-1:st->midx+st->Xrotations[st->Xrottable[st->stateX]+x];
171   for (y=0;y<=st->ry;y++)
172     st->rotateY[y]=(y)?st->midy-1-st->Yrotations[st->Yrottable[st->stateY+1]-y]:0;
173   for (y=0;y<=st->ry;y++)
174     st->rotateY[y+st->ry+1]=(y==st->ry)?st->sizy-1:st->midy+st->Yrotations[st->Yrottable[st->stateY]+y];
175
176   x=(st->rx>st->ry)?st->rx:st->ry;
177   for (dy=0;dy<(x+1)<<1;dy++)
178     for (dx=0;dx<(x+1)<<1;dx++)
179       {
180         y=(st->rx>st->ry)?st->ry-st->rx:0;
181         if (dy+y>=0 && dy<(st->ry+1)<<1 && dx<(st->rx+1)<<1)
182           if (dy+y+dx<=st->ry+st->rx && dy+y-dx<=st->ry-st->rx)
183             {
184               palaRotate(st, (st->rx<<1)+1-dx,dy+y);
185               palaRotate(st, dx,(st->ry<<1)+1-dy-y);
186             }
187         y=(st->ry>st->rx)?st->rx-st->ry:0;
188         if (dy+y>=0 && dx<(st->ry+1)<<1 && dy<(st->rx+1)<<1)
189           if (dy+y+dx<=st->ry+st->rx && dx-dy-y>=st->ry-st->rx)
190             {
191               palaRotate(st, dy+y,dx);
192               palaRotate(st, (st->rx<<1)+1-dy-y,(st->ry<<1)+1-dx);
193             }
194       }
195   st->stateX++;
196   if (st->stateX==st->rotsizeX) st->stateX=0;
197   st->stateY++;
198   if (st->stateY==st->rotsizeY) st->stateY=0;
199 }
200
201
202
203 static Bool make_rots(struct state *st, double xspeed,double yspeed)
204 {
205   int a,b,c,f,g,j,k=0,l;
206   double m,om,ok;
207   double d,ix,iy;
208   int maxi;
209
210   Bool *chks;
211
212   st->rotsizeX=(int)(2/xspeed+1);
213   ix=(double)(st->midx+1)/(double)(st->rotsizeX);
214   st->rotsizeY=(int)(2/yspeed+1);
215   iy=(double)(st->midy+1)/(double)(st->rotsizeY);
216
217   st->Xrotations=malloc((st->midx+2)*sizeof(unsigned int));
218   st->Xrottable=malloc((st->rotsizeX+1)*sizeof(unsigned int));
219   st->Yrotations=malloc((st->midy+2)*sizeof(unsigned int));
220   st->Yrottable=malloc((st->rotsizeY+1)*sizeof(unsigned int));
221   chks=malloc(((st->midx>st->midy)?st->midx:st->midy)*sizeof(Bool));
222   if (!st->Xrottable || !st->Yrottable || !st->Xrotations || !st->Yrotations || !chks) return False;
223
224
225   maxi=0;
226   c=0;
227   d=0;
228   g=0;
229   for (a=0;a<st->midx;a++) chks[a]=True;
230   for (a=0;a<st->rotsizeX;a++)
231     {
232       st->Xrottable[a]=c;
233       f=(int)(d+ix)-g;                          /*viivojen lkm.*/
234       g+=f;
235       if (g>st->midx)
236         {
237           f-=g-st->midx;
238           g=st->midx;
239         }
240       for (b=0;b<f;b++)
241         {
242           m=0;
243           for (j=0;j<st->midx;j++)                      /*testi*/
244             {
245               if (chks[j])
246                 {
247                   om=0;
248                   ok=1;
249                   l=0;
250                   while (j+l<st->midx && om+12*ok>m)
251                     {
252                       if (j-l>=0) if (chks[j-l]) om+=ok;
253                       else; else if (chks[l-j]) om+=ok;
254                       if (chks[j+l]) om+=ok;
255                       ok/=1.5;
256                       l++;
257                     }
258                   if (om>=m)
259                     {
260                       k=j;
261                       m=om;
262                     }
263                 }
264             }
265           chks[k]=False;
266           l=c;
267           while (l>=st->Xrottable[a])
268             {
269               if (l!=st->Xrottable[a]) st->Xrotations[l]=st->Xrotations[l-1];
270               if (k>st->Xrotations[l] || l==st->Xrottable[a])
271                 {
272                   st->Xrotations[l]=k;
273                   c++;
274                   l=st->Xrottable[a];
275                 }
276               l--;
277             }
278         }
279       d+=ix;
280       if (maxi<c-st->Xrottable[a]) maxi=c-st->Xrottable[a];
281     }
282   st->Xrottable[a]=c;
283   st->rotateX=malloc((maxi+2)*sizeof(int)<<1);
284   if (!st->rotateX) return False;
285
286   maxi=0;
287   c=0;
288   d=0;
289   g=0;
290   for (a=0;a<st->midy;a++) chks[a]=True;
291   for (a=0;a<st->rotsizeY;a++)
292     {
293       st->Yrottable[a]=c;
294       f=(int)(d+iy)-g;                          /*viivojen lkm.*/
295       g+=f;
296       if (g>st->midy)
297         {
298           f-=g-st->midy;
299           g=st->midy;
300         }
301       for (b=0;b<f;b++)
302         {
303           m=0;
304           for (j=0;j<st->midy;j++)                      /*testi*/
305             {
306               if (chks[j])
307                 {
308                   om=0;
309                   ok=1;
310                   l=0;
311                   while (j+l<st->midy && om+12*ok>m)
312                     {
313                       if (j-l>=0) if (chks[j-l]) om+=ok;
314                       else; else if (chks[l-j]) om+=ok;
315                       if (chks[j+l]) om+=ok;
316                       ok/=1.5;
317                       l++;
318                     }
319                   if (om>=m)
320                     {
321                       k=j;
322                       m=om;
323                     }
324                 }
325             }
326           chks[k]=False;
327           l=c;
328           while (l>=st->Yrottable[a])
329             {
330               if (l!=st->Yrottable[a]) st->Yrotations[l]=st->Yrotations[l-1];
331               if (k>st->Yrotations[l] || l==st->Yrottable[a])
332                 {
333                   st->Yrotations[l]=k;
334                   c++;
335                   l=st->Yrottable[a];
336                 }
337               l--;
338             }
339
340         }
341       d+=iy;
342       if (maxi<c-st->Yrottable[a]) maxi=c-st->Yrottable[a];
343     }
344   st->Yrottable[a]=c;
345   st->rotateY=malloc((maxi+2)*sizeof(int)<<1);
346   if (!st->rotateY) return False;
347
348   free(chks);
349   return (True);
350 }
351
352
353 static Bool InitializeAll(struct state *st)
354 {
355   XGCValues xgcv;
356   XWindowAttributes xgwa;
357 /*  XSetWindowAttributes xswa;*/
358   Colormap cmap;
359   XColor color;
360   int n,i;
361   double rspeed;
362
363   st->cosilines = True;
364
365   XGetWindowAttributes(st->dpy,st->win[0],&xgwa);
366   cmap=xgwa.colormap;
367 /*  xswa.backing_store=Always;
368   XChangeWindowAttributes(st->dpy,st->win[0],CWBackingStore,&xswa);*/
369   xgcv.function=GXcopy;
370
371   xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
372   st->fgc[32]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
373
374   n=0;
375   if (mono_p)
376     {
377       st->fgc[0]=st->fgc[32];
378       xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
379       st->fgc[1]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
380       for (i=0;i<32;i+=2) st->fgc[i]=st->fgc[0];
381       for (i=1;i<32;i+=2) st->fgc[i]=st->fgc[1];
382     } else
383     for (i=0;i<32;i++)
384       {
385         color.red=colors[n++]<<8;
386         color.green=colors[n++]<<8;
387         color.blue=colors[n++]<<8;
388         color.flags=DoRed|DoGreen|DoBlue;
389         XAllocColor(st->dpy,cmap,&color);
390         xgcv.foreground=color.pixel;
391         st->fgc[i]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
392       }
393   st->cgc=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
394   XSetGraphicsExposures(st->dpy,st->cgc,False);
395
396   st->cosilines = get_boolean_resource(st->dpy, "random","Boolean");
397
398 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
399   if (get_boolean_resource (st->dpy, "useDBE", "Boolean"))
400     st->usedouble = True;
401   st->win[1] = xdbe_get_backbuffer (st->dpy, st->win[0], XdbeUndefined);
402   if (!st->win[1])
403     {
404       st->usedouble = False;
405       st->win[1] = st->win[0];
406     }
407 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
408
409   st->delay=get_integer_resource(st->dpy, "delay","Integer");
410   rspeed=get_float_resource(st->dpy, "speed","Float");
411   if (rspeed<0.0001 || rspeed>0.2)
412     {
413       fprintf(stderr,"Speed not in valid range! (0.0001 - 0.2), using 0.1 \n");
414       rspeed=0.1;
415     }
416
417   st->sizx=xgwa.width;
418   st->sizy=xgwa.height;
419   st->midx=st->sizx>>1;
420   st->midy=st->sizy>>1;
421   st->stateX=0;
422   st->stateY=0;
423
424   if (!make_rots(st,rspeed,rspeed))
425     {
426       fprintf(stderr,"Not enough memory for tables!\n");
427       return False;
428     }
429   return True;
430 }
431
432 static void *
433 kumppa_init (Display *d, Window w)
434 {
435   struct state *st = (struct state *) calloc (1, sizeof(*st));
436   st->dpy=d;
437   st->win[0]=w;
438   if (!InitializeAll(st)) abort();
439
440 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
441   if (st->usedouble)
442     {
443       st->xdswp.swap_action=XdbeUndefined;
444       st->xdswp.swap_window=st->win[0];
445     }
446   else
447 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
448     st->win[1]=st->win[0];
449
450   return st;
451 }
452
453 static unsigned long
454 kumppa_draw (Display *d, Window w, void *closure)
455 {
456   struct state *st = (struct state *) closure;
457   if (st->cosilines)
458     {
459       int a;
460       st->draw_count++;
461       for (a=0;a<8;a++)
462         {
463           float f=0;
464           int b;
465           for (b=0;b<3;b++)
466             {
467               st->acosinus[a][b]+=cosinus[a][b];
468               f+=cosinus[a][b+3]*sin((double)st->acosinus[a][b]);
469             }
470           st->coords[a]=(int)f;
471         }
472       for (a=0;a<4;a++)
473         {
474           XDrawLine(st->dpy,st->win[0],(mono_p)?st->fgc[1]:st->fgc[((a<<2)+st->draw_count)&31],st->midx+st->ocoords[a<<1],st->midy+st->ocoords[(a<<1)+1]
475                     ,st->midx+st->coords[a<<1],st->midy+st->coords[(a<<1)+1]);
476           st->ocoords[a<<1]=st->coords[a<<1];
477           st->ocoords[(a<<1)+1]=st->coords[(a<<1)+1];
478         }
479
480     } else {
481     int e;
482     for (e=0;e<8;e++)
483       {
484         int a=Satnum(50);
485         int b;
486         if (a>=32) a=32;
487         b=Satnum(32)-16+st->midx;
488         st->draw_count=Satnum(32)-16+st->midy;
489         XFillRectangle(st->dpy,st->win[0],st->fgc[a],b,st->draw_count,2,2);
490       }
491   }
492   XFillRectangle(st->dpy,st->win[0],st->fgc[32],st->midx-2,st->midy-2,4,4);
493   rotate(st);
494 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
495   if (st->usedouble) XdbeSwapBuffers(st->dpy,&st->xdswp,1);
496 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
497
498   return st->delay;
499 }
500
501
502 static void
503 kumppa_reshape (Display *dpy, Window window, void *closure, 
504                  unsigned int w, unsigned int h)
505 {
506   struct state *st = (struct state *) closure;
507   st->sizx=w;
508   st->sizy=w;
509   st->midx=st->sizx>>1;
510   st->midy=st->sizy>>1;
511   st->stateX=0;
512   st->stateY=0;
513 }
514
515 static Bool
516 kumppa_event (Display *dpy, Window window, void *closure, XEvent *event)
517 {
518   return False;
519 }
520
521 static void
522 kumppa_free (Display *dpy, Window window, void *closure)
523 {
524   struct state *st = (struct state *) closure;
525   int i;
526   for (i = 0; i < countof(st->fgc); i++)
527     if (st->fgc[i]) XFreeGC (dpy, st->fgc[i]);
528   XFreeGC (dpy, st->cgc);
529   free (st->Xrotations);
530   free (st->Yrotations);
531   free (st->Xrottable);
532   free (st->Yrottable);
533   free (st);
534 }
535
536 XSCREENSAVER_MODULE ("Kumppa", kumppa)