b835f5bf9fa8f63896be7bd6df94858cec95cf5f
[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   0
59 };
60
61 static XrmOptionDescRec kumppa_options [] = {
62   {"-delay",     ".delay",  XrmoptionSepArg, 0 },
63   {"-speed",     ".speed",  XrmoptionSepArg, 0 },
64   {"-random",    ".random", XrmoptionNoArg, "True"  },
65   {"-no-random", ".random", XrmoptionNoArg, "False" },
66   {"-db",       ".useDBE",  XrmoptionNoArg, "True"  },
67   {"-no-db",    ".useDBE",  XrmoptionNoArg, "False" },
68   {0,0,0,0}
69 };
70
71 static const unsigned char colors[96]=
72   {0,0,255, 0,51,255, 0,102,255, 0,153,255, 0,204,255,
73    0,255,255,0,255,204, 0,255,153, 0,255,102, 0,255,51,
74    0,255,0, 51,255,0, 102,255,0, 153,255,0, 204,255,0,
75    255,255,0, 255,204,0, 255,153,0, 255,102,0, 255,51,0,
76    255,0,0, 255,0,51, 255,0,102, 255,0,153, 255,0,204,
77    255,0,255, 219,0,255, 182,0,255, 146,0,255, 109,0,255,
78    73,0,255, 37,0,255};
79 static const float cosinus[8][6]=
80  {{-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},
81   {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},
82   {-0.02,-0.04,-0.13,34,20,15}};
83
84
85 struct state {
86   Display *dpy;
87   Window win[2];
88
89   float acosinus[8][3];
90   int coords[8];
91   int ocoords[8];
92
93   GC fgc[33];
94   GC cgc;
95   int sizx,sizy;
96   int midx,midy;
97   unsigned long delay;
98   Bool cosilines;
99
100   int *Xrotations;
101   int *Yrotations;
102   int *Xrottable;
103   int *Yrottable;
104
105   int *rotateX;
106   int *rotateY;
107
108   int rotsizeX,rotsizeY;
109   int stateX,stateY;
110
111   int rx,ry;
112
113 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
114   XdbeSwapInfo xdswp;
115   Bool usedouble;
116 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
117
118   int draw_count;
119 };
120
121
122 static int Satnum(int maxi)
123 {
124   return (int)(maxi*frand(1));
125 }
126
127
128 static void palaRotate(struct state *st, int x,int y)
129 {
130   int ax,ay,bx,by,cx,cy;
131
132   ax=st->rotateX[x];
133   ay=st->rotateY[y];
134   bx=st->rotateX[x+1]+2;
135   by=st->rotateY[y+1]+2;
136   cx=st->rotateX[x]-(y-st->ry)+x-st->rx;
137   cy=st->rotateY[y]+(x-st->rx)+y-st->ry;
138   if (cx<0)
139     {
140       ax-=cx;
141       cx=0;
142     }
143   if (cy<0)
144     {
145       ay-=cy;
146       cy=0;
147     }
148   if (cx+bx-ax>st->sizx) bx=ax-cx+st->sizx;
149   if (cy+by-ay>st->sizy) by=ay-cy+st->sizy;
150   if (ax<bx && ay<by)
151     XCopyArea(st->dpy,st->win[0],st->win[1],st->cgc,ax,ay,bx-ax,by-ay,cx,cy);
152 }
153
154
155 static void rotate(struct state *st)
156 {
157   int x,y;
158   int dx,dy;
159
160   st->rx=st->Xrottable[st->stateX+1]-st->Xrottable[st->stateX];
161   st->ry=st->Yrottable[st->stateY+1]-st->Yrottable[st->stateY];
162
163
164   for (x=0;x<=st->rx;x++)
165     st->rotateX[x]=(x)?st->midx-1-st->Xrotations[st->Xrottable[st->stateX+1]-x]:0;
166   for (x=0;x<=st->rx;x++)
167     st->rotateX[x+st->rx+1]=(x==st->rx)?st->sizx-1:st->midx+st->Xrotations[st->Xrottable[st->stateX]+x];
168   for (y=0;y<=st->ry;y++)
169     st->rotateY[y]=(y)?st->midy-1-st->Yrotations[st->Yrottable[st->stateY+1]-y]:0;
170   for (y=0;y<=st->ry;y++)
171     st->rotateY[y+st->ry+1]=(y==st->ry)?st->sizy-1:st->midy+st->Yrotations[st->Yrottable[st->stateY]+y];
172
173   x=(st->rx>st->ry)?st->rx:st->ry;
174   for (dy=0;dy<(x+1)<<1;dy++)
175     for (dx=0;dx<(x+1)<<1;dx++)
176       {
177         y=(st->rx>st->ry)?st->ry-st->rx:0;
178         if (dy+y>=0 && dy<(st->ry+1)<<1 && dx<(st->rx+1)<<1)
179           if (dy+y+dx<=st->ry+st->rx && dy+y-dx<=st->ry-st->rx)
180             {
181               palaRotate(st, (st->rx<<1)+1-dx,dy+y);
182               palaRotate(st, dx,(st->ry<<1)+1-dy-y);
183             }
184         y=(st->ry>st->rx)?st->rx-st->ry:0;
185         if (dy+y>=0 && dx<(st->ry+1)<<1 && dy<(st->rx+1)<<1)
186           if (dy+y+dx<=st->ry+st->rx && dx-dy-y>=st->ry-st->rx)
187             {
188               palaRotate(st, dy+y,dx);
189               palaRotate(st, (st->rx<<1)+1-dy-y,(st->ry<<1)+1-dx);
190             }
191       }
192   st->stateX++;
193   if (st->stateX==st->rotsizeX) st->stateX=0;
194   st->stateY++;
195   if (st->stateY==st->rotsizeY) st->stateY=0;
196 }
197
198
199
200 static Bool make_rots(struct state *st, double xspeed,double yspeed)
201 {
202   int a,b,c,f,g,j,k=0,l;
203   double m,om,ok;
204   double d,ix,iy;
205   int maxi;
206
207   Bool *chks;
208
209   st->rotsizeX=(int)(2/xspeed+1);
210   ix=(double)(st->midx+1)/(double)(st->rotsizeX);
211   st->rotsizeY=(int)(2/yspeed+1);
212   iy=(double)(st->midy+1)/(double)(st->rotsizeY);
213
214   st->Xrotations=malloc((st->midx+2)*sizeof(unsigned int));
215   st->Xrottable=malloc((st->rotsizeX+1)*sizeof(unsigned int));
216   st->Yrotations=malloc((st->midy+2)*sizeof(unsigned int));
217   st->Yrottable=malloc((st->rotsizeY+1)*sizeof(unsigned int));
218   chks=malloc(((st->midx>st->midy)?st->midx:st->midy)*sizeof(Bool));
219   if (!st->Xrottable || !st->Yrottable || !st->Xrotations || !st->Yrotations || !chks) return False;
220
221
222   maxi=0;
223   c=0;
224   d=0;
225   g=0;
226   for (a=0;a<st->midx;a++) chks[a]=True;
227   for (a=0;a<st->rotsizeX;a++)
228     {
229       st->Xrottable[a]=c;
230       f=(int)(d+ix)-g;                          /*viivojen lkm.*/
231       g+=f;
232       if (g>st->midx)
233         {
234           f-=g-st->midx;
235           g=st->midx;
236         }
237       for (b=0;b<f;b++)
238         {
239           m=0;
240           for (j=0;j<st->midx;j++)                      /*testi*/
241             {
242               if (chks[j])
243                 {
244                   om=0;
245                   ok=1;
246                   l=0;
247                   while (j+l<st->midx && om+12*ok>m)
248                     {
249                       if (j-l>=0) if (chks[j-l]) om+=ok;
250                       else; else if (chks[l-j]) om+=ok;
251                       if (chks[j+l]) om+=ok;
252                       ok/=1.5;
253                       l++;
254                     }
255                   if (om>=m)
256                     {
257                       k=j;
258                       m=om;
259                     }
260                 }
261             }
262           chks[k]=False;
263           l=c;
264           while (l>=st->Xrottable[a])
265             {
266               if (l!=st->Xrottable[a]) st->Xrotations[l]=st->Xrotations[l-1];
267               if (k>st->Xrotations[l] || l==st->Xrottable[a])
268                 {
269                   st->Xrotations[l]=k;
270                   c++;
271                   l=st->Xrottable[a];
272                 }
273               l--;
274             }
275         }
276       d+=ix;
277       if (maxi<c-st->Xrottable[a]) maxi=c-st->Xrottable[a];
278     }
279   st->Xrottable[a]=c;
280   st->rotateX=malloc((maxi+2)*sizeof(int)<<1);
281   if (!st->rotateX) return False;
282
283   maxi=0;
284   c=0;
285   d=0;
286   g=0;
287   for (a=0;a<st->midy;a++) chks[a]=True;
288   for (a=0;a<st->rotsizeY;a++)
289     {
290       st->Yrottable[a]=c;
291       f=(int)(d+iy)-g;                          /*viivojen lkm.*/
292       g+=f;
293       if (g>st->midy)
294         {
295           f-=g-st->midy;
296           g=st->midy;
297         }
298       for (b=0;b<f;b++)
299         {
300           m=0;
301           for (j=0;j<st->midy;j++)                      /*testi*/
302             {
303               if (chks[j])
304                 {
305                   om=0;
306                   ok=1;
307                   l=0;
308                   while (j+l<st->midy && om+12*ok>m)
309                     {
310                       if (j-l>=0) if (chks[j-l]) om+=ok;
311                       else; else if (chks[l-j]) om+=ok;
312                       if (chks[j+l]) om+=ok;
313                       ok/=1.5;
314                       l++;
315                     }
316                   if (om>=m)
317                     {
318                       k=j;
319                       m=om;
320                     }
321                 }
322             }
323           chks[k]=False;
324           l=c;
325           while (l>=st->Yrottable[a])
326             {
327               if (l!=st->Yrottable[a]) st->Yrotations[l]=st->Yrotations[l-1];
328               if (k>st->Yrotations[l] || l==st->Yrottable[a])
329                 {
330                   st->Yrotations[l]=k;
331                   c++;
332                   l=st->Yrottable[a];
333                 }
334               l--;
335             }
336
337         }
338       d+=iy;
339       if (maxi<c-st->Yrottable[a]) maxi=c-st->Yrottable[a];
340     }
341   st->Yrottable[a]=c;
342   st->rotateY=malloc((maxi+2)*sizeof(int)<<1);
343   if (!st->rotateY) return False;
344
345   free(chks);
346   return (True);
347 }
348
349
350 static Bool InitializeAll(struct state *st)
351 {
352   XGCValues xgcv;
353   XWindowAttributes xgwa;
354 /*  XSetWindowAttributes xswa;*/
355   Colormap cmap;
356   XColor color;
357   int n,i;
358   double rspeed;
359
360   st->cosilines = True;
361
362   XGetWindowAttributes(st->dpy,st->win[0],&xgwa);
363   cmap=xgwa.colormap;
364 /*  xswa.backing_store=Always;
365   XChangeWindowAttributes(st->dpy,st->win[0],CWBackingStore,&xswa);*/
366   xgcv.function=GXcopy;
367
368   xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
369   st->fgc[32]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
370
371   n=0;
372   if (mono_p)
373     {
374       st->fgc[0]=st->fgc[32];
375       xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
376       st->fgc[1]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
377       for (i=0;i<32;i+=2) st->fgc[i]=st->fgc[0];
378       for (i=1;i<32;i+=2) st->fgc[i]=st->fgc[1];
379     } else
380     for (i=0;i<32;i++)
381       {
382         color.red=colors[n++]<<8;
383         color.green=colors[n++]<<8;
384         color.blue=colors[n++]<<8;
385         color.flags=DoRed|DoGreen|DoBlue;
386         XAllocColor(st->dpy,cmap,&color);
387         xgcv.foreground=color.pixel;
388         st->fgc[i]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
389       }
390   st->cgc=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv);
391   XSetGraphicsExposures(st->dpy,st->cgc,False);
392
393   st->cosilines = get_boolean_resource(st->dpy, "random","Boolean");
394
395 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
396   if (get_boolean_resource (st->dpy, "useDBE", "Boolean"))
397     st->usedouble = True;
398   st->win[1] = xdbe_get_backbuffer (st->dpy, st->win[0], XdbeUndefined);
399   if (!st->win[1])
400     {
401       st->usedouble = False;
402       st->win[1] = st->win[0];
403     }
404 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
405
406   st->delay=get_integer_resource(st->dpy, "delay","Integer");
407   rspeed=get_float_resource(st->dpy, "speed","Float");
408   if (rspeed<0.0001 || rspeed>0.2)
409     {
410       fprintf(stderr,"Speed not in valid range! (0.0001 - 0.2), using 0.1 \n");
411       rspeed=0.1;
412     }
413
414   st->sizx=xgwa.width;
415   st->sizy=xgwa.height;
416   st->midx=st->sizx>>1;
417   st->midy=st->sizy>>1;
418   st->stateX=0;
419   st->stateY=0;
420
421   if (!make_rots(st,rspeed,rspeed))
422     {
423       fprintf(stderr,"Not enough memory for tables!\n");
424       return False;
425     }
426   return True;
427 }
428
429 static void *
430 kumppa_init (Display *d, Window w)
431 {
432   struct state *st = (struct state *) calloc (1, sizeof(*st));
433   st->dpy=d;
434   st->win[0]=w;
435   if (!InitializeAll(st)) abort();
436
437 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
438   if (st->usedouble)
439     {
440       st->xdswp.swap_action=XdbeUndefined;
441       st->xdswp.swap_window=st->win[0];
442     }
443   else
444 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
445     st->win[1]=st->win[0];
446
447   return st;
448 }
449
450 static unsigned long
451 kumppa_draw (Display *d, Window w, void *closure)
452 {
453   struct state *st = (struct state *) closure;
454   if (st->cosilines)
455     {
456       int a;
457       st->draw_count++;
458       for (a=0;a<8;a++)
459         {
460           float f=0;
461           int b;
462           for (b=0;b<3;b++)
463             {
464               st->acosinus[a][b]+=cosinus[a][b];
465               f+=cosinus[a][b+3]*sin((double)st->acosinus[a][b]);
466             }
467           st->coords[a]=(int)f;
468         }
469       for (a=0;a<4;a++)
470         {
471           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]
472                     ,st->midx+st->coords[a<<1],st->midy+st->coords[(a<<1)+1]);
473           st->ocoords[a<<1]=st->coords[a<<1];
474           st->ocoords[(a<<1)+1]=st->coords[(a<<1)+1];
475         }
476
477     } else {
478     int e;
479     for (e=0;e<8;e++)
480       {
481         int a=Satnum(50);
482         int b;
483         if (a>=32) a=32;
484         b=Satnum(32)-16+st->midx;
485         st->draw_count=Satnum(32)-16+st->midy;
486         XFillRectangle(st->dpy,st->win[0],st->fgc[a],b,st->draw_count,2,2);
487       }
488   }
489   XFillRectangle(st->dpy,st->win[0],st->fgc[32],st->midx-2,st->midy-2,4,4);
490   rotate(st);
491 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
492   if (st->usedouble) XdbeSwapBuffers(st->dpy,&st->xdswp,1);
493 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
494
495   return st->delay;
496 }
497
498
499 static void
500 kumppa_reshape (Display *dpy, Window window, void *closure, 
501                  unsigned int w, unsigned int h)
502 {
503   struct state *st = (struct state *) closure;
504   st->sizx=w;
505   st->sizy=w;
506   st->midx=st->sizx>>1;
507   st->midy=st->sizy>>1;
508   st->stateX=0;
509   st->stateY=0;
510 }
511
512 static Bool
513 kumppa_event (Display *dpy, Window window, void *closure, XEvent *event)
514 {
515   return False;
516 }
517
518 static void
519 kumppa_free (Display *dpy, Window window, void *closure)
520 {
521   struct state *st = (struct state *) closure;
522   int i;
523   for (i = 0; i < countof(st->fgc); i++)
524     if (st->fgc[i]) XFreeGC (dpy, st->fgc[i]);
525   XFreeGC (dpy, st->cgc);
526   free (st->Xrotations);
527   free (st->Yrotations);
528   free (st->Xrottable);
529   free (st->Yrottable);
530   free (st);
531 }
532
533 XSCREENSAVER_MODULE ("Kumppa", kumppa)