http://ftp.x.org/contrib/applications/xscreensaver-3.10.tar.gz
[xscreensaver] / hacks / t3d.c
1 /* t3d -- Flying Balls Clock Demo
2    by Bernd Paysan , paysan@informatik.tu-muenchen.de
3
4    Copy, modify, and distribute T3D either under GPL  version 2 or newer, 
5    or under the standard MIT/X license notice.
6
7   partly based on flying balls demo by Georg Acher, 
8   acher@informatik.tu-muenchen.de
9   (developed on HP9000/720 (55 MIPS,20 MFLOPS) )
10   NO warranty at all ! Complaints to /dev/null !
11
12   4-Jan-99 jwz@jwz.org -- adapted to xscreensaver framework, to take advantage
13                           of the command-line options provided by screenhack.c.
14 */
15
16 #define FASTDRAW
17 #define FASTCOPY
18 #undef USE_POLYGON
19
20 #include <stdio.h>
21 #include <math.h>
22 #include <time.h> /* for localtime() and gettimeofday() */
23
24 #include "screenhack.h"
25
26
27 static int maxk=34;
28
29 #define   WIDTH      200
30 #define   HEIGHT     200
31 #define   norm       20.0
32
33 int timewait=40000;
34
35 #define   ROOT       0x1
36 #define PI M_PI
37 #define TWOPI 2*M_PI
38
39 #define MIN(i,j) ((i)<(j)?(i):(j))
40
41 #define kmax ((minutes?60:24))
42 /* Anzahl der Kugeln */
43 #define sines 52
44 /* Werte in der Sinus-Tabelle */
45 /*-----------------------------------------------------------------*/
46 #define setink(inkcolor) \
47         XSetForeground (dpy,gc,inkcolor)
48
49 #define drawline(xx1,yy1,xx2,yy2) \
50         XDrawLine(dpy,win,gc,xx1,yy1,xx2,yy2) 
51
52 #define drawseg(segments,nr_segments) \
53         XDrawSegments(dpy,win,gc,segments,nr_segments) 
54
55
56 #define polyfill(ppts,pcount) \
57         XFillPolygon(dpy,win,gc,ppts,pcount,Convex,CoordModeOrigin)
58
59
60 #define frac(argument) argument-floor(argument)
61
62 #define abs(x) ((x)<0.0 ? -(x) : (x))
63
64 static Colormap cmap;
65 /* static XColor gray1; */
66 static double r=1.0,g=1.0,b=1.0;
67 static double hue=0.0,sat=0.0,val=1.0;
68
69 typedef struct {
70   double x,y,z,r,d,r1;
71   int x1,y1;
72 } kugeldat;
73
74 /* Felder fuer 3D */
75
76 static kugeldat kugeln[100];
77
78 static double  a[3],/*m[3],*/am[3],x[3],y[3],v[3];
79 static double zoom,speed,zaehler,vspeed/*,AE*/;
80 static double vturn/*,aturn*/;
81 /* static XPoint track[sines]; */
82 static double sinus[sines];
83 static double cosinus[sines];
84
85 static int startx,starty;
86 static double /*magx,magy,*/mag=10;
87 /* static double lastx,lasty,lastz; */
88 /* static int lastcx,lastcy,lastcz; */
89 /* static int move=1; */
90 static int minutes=0;
91 static int cycl=0;
92 static double hsvcycl=0.0;
93 static double movef =0.5, wobber=2.0, cycle=6.0;
94
95 /* time */
96
97 /* static double sec; */
98
99 /* Windows */
100 static XWindowAttributes xgwa;
101 static GC       gc;
102 static GC orgc;
103 static GC andgc;
104 static Window   win;
105 /* static Font font; */
106 static Display  *dpy;
107 static int      screen, scrnWidth = WIDTH, scrnHeight = HEIGHT;
108 static Pixmap  buffer;
109 #define maxfast 100
110 static int fastch=50;
111 #ifdef FASTDRAW
112 #       ifdef FASTCOPY
113 #               define sum1ton(a) (((a)*(a)+1)/2)
114 #               define fastcw sum1ton(fastch)
115                 static Pixmap fastcircles;
116                 static Pixmap fastmask;
117 #       else
118                 static XImage* fastcircles[maxfast];
119                 static XImage* fastmask[maxfast];
120 #       endif
121 static int fastdraw=0;
122 #endif
123
124 static int scrnW2,scrnH2;
125 /* static unsigned short flags = 0; */
126 /* static char *text; */
127 static XColor colors[64];
128 static struct tm *zeit;
129
130 static int planes;
131 /* compute time */
132
133 static double
134 gettime (void)
135 {
136   struct timeval time1;
137   struct tm *zeit;
138   time_t lt;
139
140 #ifdef GETTIMEOFDAY_TWO_ARGS
141   struct timezone zone1;
142   gettimeofday(&time1,&zone1);
143 #else
144   gettimeofday(&time1);
145 #endif
146   lt = time1.tv_sec;    /* avoid type cast lossage */
147   zeit=localtime(&lt);
148   
149   return (zeit->tm_sec+60*(zeit->tm_min+60*(zeit->tm_hour))
150           + time1.tv_usec*1.0E-6);
151 }
152
153 /* --------------------COLORMAP---------------------*/ 
154
155 static void
156 hsv2rgb (double h, double s, double v, double *r, double *g, double *b)
157 {
158   h/=360.0;     h=6*(h-floor(h));
159
160   if(s==0.0)
161     {
162       *r=*g=*b=v;
163     }
164   else
165     {   int i=(int)h;
166         double t,u,w;
167         
168         h=h-floor(h);
169         
170         u=v*(s*(1.0-h));
171         w=v*(1.0-s);
172         t=v*(s*h+1.0-s);
173         
174         switch(i)
175           {
176           case 0:       *r=v;   *g=t;   *b=w;   break;
177           case 1:       *r=u;   *g=v;   *b=w;   break;
178           case 2:       *r=w;   *g=v;   *b=t;   break;
179           case 3:       *r=w;   *g=u;   *b=v;   break;
180           case 4:       *r=t;   *g=w;   *b=v;   break;
181           case 5:       *r=v;   *g=w;   *b=u;   break;
182           }
183       }
184 #ifdef PRTDBX
185   printf("HSV: %f %f %f to\nRGB: %f %f %f\n",h,s,v,*r,*g,*b);
186 #endif
187 }
188
189 static void
190 changeColor (double r, double g, double b)
191 {
192   int n,n1;
193   
194   n1=0;
195   for(n=30;n<64;n+=3)
196     {
197       colors[n1].red   =1023+ n*(int)(1024.*r);
198       colors[n1].blue  =1023+ n*(int)(1024.*b);
199       colors[n1].green =1023+ n*(int)(1024.*g);
200       
201       n1++;
202     }
203   
204   XStoreColors (dpy, cmap, colors, 12);
205 }
206
207 static void 
208 initColor (double r, double g, double b)
209 {
210   int n,n1;
211   unsigned long pixels[12];
212   unsigned long dummy;
213   
214   cmap = xgwa.colormap;
215   
216   if(hsvcycl!=0.0 && XAllocColorCells(dpy, cmap, 0, &dummy, 0, pixels, 12))
217     {
218       for(n1=0;n1<12;n1++)
219         {
220           colors[n1].pixel=pixels[n1];
221           colors[n1].flags=DoRed | DoGreen | DoBlue;
222         }
223       
224       changeColor(r,g,b);
225     }
226   else
227     {
228       n1=0;
229       for(n=30;n<64;n+=3)
230         {
231           colors[n1].red   =1023+ n*(int)(1024.*r);
232           colors[n1].blue  =1023+ n*(int)(1024.*b);
233           colors[n1].green =1023+ n*(int)(1024.*g);
234           
235           if (!(XAllocColor (dpy, cmap, &colors[n1]))) {
236             (void) fprintf (stderr, "Error:  Cannot allocate colors\n");
237             exit (1);
238           }
239           
240           n1++;
241         }
242     }
243 }
244
245 /* ----------------WINDOW-------------------*/
246
247 static void
248 initialize (void)
249 {
250   XGCValues *xgc;
251   XGCValues *xorgc;
252   XGCValues *xandgc;
253
254   XGetWindowAttributes (dpy, win, &xgwa);
255   scrnWidth = xgwa.width;
256   scrnHeight = xgwa.height;
257
258   {
259     float f = get_float_resource ("cycle", "Float");
260     if (f <= 0 || f > 60) f = 6.0;
261     cycle = 60.0 / f;
262   }
263   movef = get_float_resource ("move", "Float");
264   wobber = get_float_resource ("wobble", "Float");
265
266   {
267     double magfac = get_float_resource ("mag", "Float");
268     mag *= magfac;
269     fastch=(int)(fastch*magfac);
270   }
271
272   if (get_boolean_resource ("minutes", "Boolean")) {
273     minutes=1; maxk+=60-24;
274   }
275
276   timewait = get_integer_resource ("delay", "Integer");
277   fastch = get_integer_resource ("fast", "Integer");
278   cycl = get_boolean_resource ("colcycle", "Integer");
279   hsvcycl = get_float_resource ("hsvcycle", "Integer");
280
281   {
282     char *s = get_string_resource ("rgb", "RGB");
283     char dummy;
284     if (s && *s)
285       {
286         double rr, gg, bb;
287         if (3 == sscanf (s, "%lf %lf %lf %c", &rr, &gg, &bb, &dummy))
288           r = rr, g = gg, b = bb;
289       }
290     if (s) free (s);
291
292     s = get_string_resource ("hsv", "HSV");
293     if (s && *s)
294       {
295         double hh, ss, vv;
296         if (3 == sscanf (s, "%lf %lf %lf %c", &hh, &ss, &vv, &dummy)) {
297           hue = hh, sat = ss, val = vv;
298           hsv2rgb(hue,sat,val,&r,&g,&b);
299         }
300       }
301     if (s) free (s);
302   }
303
304   if (fastch>maxfast)
305                 fastch=maxfast;
306   
307   xgc=( XGCValues *) malloc(sizeof(XGCValues) );
308   xorgc=( XGCValues *) malloc(sizeof(XGCValues) );
309   xandgc=( XGCValues *) malloc(sizeof(XGCValues) );
310
311   screen = screen_number (xgwa.screen);
312   
313   planes=xgwa.depth;
314
315   gc = XCreateGC (dpy, win, 0,  xgc);
316   xorgc->function =GXor;
317   orgc = XCreateGC (dpy, win, GCFunction,  xorgc);
318   xandgc->function =GXandInverted;
319   andgc = XCreateGC (dpy, win, GCFunction,  xandgc);
320   
321   buffer = XCreatePixmap (dpy, win, scrnWidth, scrnHeight,
322                           xgwa.depth); 
323   
324 #ifdef DEBUG
325   printf("Time 3D drawing ");
326 #ifdef FASTDRAW
327 #       ifdef FASTCOPY
328   puts("fast by Pixmap copy");
329 #       else
330   puts("fast by XImage copy");
331 #       endif
332 #else
333   puts("slow");
334 #endif
335 #endif /* DEBUG */
336   
337 #ifdef FASTCOPY
338   fastcircles = XCreatePixmap (dpy, win, fastcw, fastch+1, xgwa.depth);
339   fastmask    = XCreatePixmap (dpy, win, fastcw, fastch+1, xgwa.depth);
340 #endif
341   
342   setink(BlackPixel (dpy, screen));
343   XFillRectangle (dpy, buffer     , gc, 0, 0, scrnWidth, scrnHeight);   
344   
345 #ifdef FASTCOPY
346   
347   setink(0);
348   XFillRectangle (dpy, fastcircles, gc, 0, 0, fastcw, fastch+1);
349   XFillRectangle (dpy, fastmask   , gc, 0, 0, fastcw, fastch+1);
350   
351 #endif
352
353 #ifdef PRTDBX
354   printf("move\t%.2f\nwobber\t%.2f\nmag\t%.2f\ncycle\t%.4f\n",
355          movef,wobber,mag/10,cycle);
356   printf("fast\t%i\nmarks\t%i\nwait\t%i\n",fastch,maxk,timewait);
357 #endif
358  
359 }
360
361 static void fill_kugel(int i, Pixmap buf, int setcol);
362
363
364 /*------------------------------------------------------------------*/
365 static void 
366 init_kugel(void)
367 {
368   
369 #ifdef FASTDRAW
370   int i;
371
372   for(i=0; i<fastch; i++)
373     {
374 #       ifdef FASTCOPY
375       kugeln[i].r1=-((double) i)/2 -1;
376       kugeln[i].x1=sum1ton(i);
377       kugeln[i].y1=((double) i)/2 +1;
378       
379       fill_kugel(i,fastcircles,1);
380       setink((1<<MIN(24,xgwa.depth))-1);
381       fill_kugel(i,fastmask,0);
382 #       else
383       kugeln[i].r1=-((double) i)/2 -1;
384       kugeln[i].x1=kugeln[i].y1=((double) i)/2 +1;
385       
386       fill_kugel(i,buffer,1);
387       fastcircles[i]=XGetImage(dpy,buffer,0,0,i+2,i+2,(1<<planes)-1,ZPixmap);
388       
389       setink((1<<MIN(24,xgwa.depth))-1);
390       fill_kugel(i,buffer,0);
391       fastmask[i]=XGetImage(dpy,buffer,0,0,i+2,i+2,(1<<planes)-1,ZPixmap);
392       
393       setink(0);
394       XFillRectangle (dpy, buffer     , gc, 0, 0, scrnWidth, scrnHeight);       
395 #       endif
396     }
397   fastdraw=1;
398 #endif
399 }
400
401 /* Zeiger zeichnen */
402
403 static void
404 zeiger(double dist,double rad, double z, double sec, int *q)
405 {
406   int i,n;
407   double gratio=sqrt(2.0/(1.0+sqrt(5.0)));
408   
409   n = *q;
410   
411   for(i=0;i<3;i++)
412     {
413       kugeln[n].x=dist*cos(sec);
414       kugeln[n].y=-dist*sin(sec);
415       kugeln[n].z=z;
416       kugeln[n].r=rad;
417       n++;
418
419       dist += rad;
420       rad = rad*gratio;
421     }
422   *q = n;
423 }
424
425 /*-----------------------------------------------------------------*
426  *                           Uhr zeichnen                          *
427  *-----------------------------------------------------------------*/
428
429 static void
430 manipulate(double k)
431 {
432   double i,l,/*xs,*/ys,zs,mod;
433   double /*persec,*/sec,min,hour;
434   int n;
435   
436   sec=TWOPI*modf(k/60,&mod);
437   min=TWOPI*modf(k/3600,&mod);
438   hour=TWOPI*modf(k/43200,&mod);
439   
440   l=TWOPI*modf(k/300,&mod);
441   i=0.0;
442   for (n=0;n<kmax;n++)
443     {
444       
445       kugeln[n].x=4.0*sin(i);
446       kugeln[n].y=4.0*cos(i);
447       kugeln[n].z=wobber* /* (sin(floor(2+2*l/(PI))*i)*sin(2*l)); */
448         cos((i-sec)*floor(2+5*l/(PI)))*sin(5*l);
449       if(minutes)
450         {
451           kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
452             ((n % 5!=0) ? 0.3 : 0.6)*
453               ((n % 15 ==0) ? 1.25 : .75);
454         }
455       else
456         {
457           kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
458             ((n & 1) ? 0.5 : 1.0)*
459               ((n % 6==0) ? 1.25 : .75);
460         }
461       i+=TWOPI/kmax;
462     }
463
464   kugeln[n].x=0.0;
465   kugeln[n].y=0.0;
466   kugeln[n].z=0.0;
467   kugeln[n].r=2.0+cos(TWOPI*modf(k,&mod))/2;
468   n++;
469   
470   zeiger(2.0,0.75,-2.0,sec,&n);
471   zeiger(1.0,1.0,-1.5,min,&n);
472   zeiger(0.0,1.5,-1.0,hour,&n);
473   
474   for(n=0;n<maxk;n++)
475     {
476       ys=kugeln[n].y*cos(movef*sin(cycle*sec))+
477         kugeln[n].z*sin(movef*sin(cycle*sec));
478       zs=-kugeln[n].y*sin(movef*sin(cycle*sec))+
479         kugeln[n].z*cos(movef*sin(cycle*sec));
480       kugeln[n].y=ys;
481       kugeln[n].z=zs;
482     }
483 }
484 /*------------------------------------------------------------------*/
485 static void
486 t3d_sort(int l, int r)
487 {
488   int i,j;
489   kugeldat ex;
490   double x;
491   
492   i=l;j=r;
493   x=kugeln[(l+r)/2].d;
494   while(1)
495     {
496       while(kugeln[i].d>x) i++;
497       while(x>kugeln[j].d) j--;
498       if (i<=j)
499         {
500           ex=kugeln[i];kugeln[i]=kugeln[j];kugeln[j]=ex;
501           i++;j--;
502         }
503       if (i>j) break;
504     }
505   if (l<j) t3d_sort(l,j);
506   if (i<r) t3d_sort (i,r);
507 }
508
509 /*------------------------------------------------------------------*/
510 static void
511 fill_kugel(int i, Pixmap buf, int setcol)
512 {
513   double ra;
514   int m,col,inc=1,inr=3,d;
515   d=(int)((abs(kugeln[i].r1)*2));
516   if (d==0) d=1;
517   
518 #ifdef FASTDRAW
519   if(fastdraw && d<fastch)
520     {
521 #       ifdef FASTCOPY
522       XCopyArea(dpy, fastmask, buf, andgc, sum1ton(d)-(d+1)/2, 1,d,d,
523                 (int)(kugeln[i].x1)-d/2, (int)(kugeln[i].y1)-d/2);
524       XCopyArea(dpy, fastcircles, buf, orgc, sum1ton(d)-(d+1)/2, 1,d,d,
525                 (int)(kugeln[i].x1)-d/2, (int)(kugeln[i].y1)-d/2);
526 #       else
527       XPutImage(dpy, buf, andgc, fastmask[d-1], 0, 0,
528                 (int)(kugeln[i].x1)-d/2, (int)(kugeln[i].y1)-d/2, d, d);
529       XPutImage(dpy, buf, orgc, fastcircles[d-1], 0, 0,
530                 (int)(kugeln[i].x1)-d/2, (int)(kugeln[i].y1)-d/2, d, d);
531 #       endif
532     }
533   else
534 #endif
535     {
536       if(abs(kugeln[i].r1)<6.0) inr=9;
537       
538       for (m=0;m<=28;m+=inr)
539         {
540           ra=kugeln[i].r1*sqrt(1-m*m/(28.0*28.0));
541 #ifdef PRTDBX
542           printf("Radius: %f\n",ra);
543 #endif
544           if(-ra< 3.0) inc=14;
545           else if(-ra< 6.0) inc=8;
546           else if(-ra<20.0) inc=4;
547           else if(-ra<40.0) inc=2;
548           if(setcol)
549             {
550               if (m==27) col=33;
551               else
552                 col=(int)(m);
553               if (col>33) col=33;       col/=3;
554               setink(colors[col].pixel);
555             }
556
557 #ifdef USE_POLYGON
558           {
559             int n, nr;
560           for (n=0,nr=0;n<=sines-1;n+=inc,nr++)
561             {
562               track[nr].x=kugeln[i].x1+(int)(ra*sinus[n])+(kugeln[i].r1-ra)/2;
563               track[nr].y=kugeln[i].y1+(int)(ra*cosinus[n])+(kugeln[i].r1-ra)/2;
564             }
565           XFillPolygon(dpy,buf,gc,track,nr,Convex,CoordModeOrigin);
566           }
567 #else /* Use XFillArc */
568           XFillArc(dpy, buf, gc,
569                    (int)(kugeln[i].x1+(kugeln[i].r1+ra)/2),
570                    (int)(kugeln[i].y1+(kugeln[i].r1+ra)/2),
571                    (int)-(2*ra+1), (int)-(2*ra+1), 0, 360*64);
572 #endif
573         }
574     }
575 }
576
577 /*------------------------------------------------------------------*/
578
579 static void
580 init_3d(void)
581 {
582   double i;
583   int n=0;
584   
585   a[0]=0.0;
586   a[1]=0.0;
587   a[2]=-10.0;
588   
589   x[0]=10.0;
590   x[1]=0.0;
591   x[2]=0.0;
592   
593   y[0]=0.0;
594   y[1]=10.0;
595   y[2]=0.0;
596   
597   
598   zoom=-10.0;
599   speed=.0;
600   
601   for (i=0.0;n<sines;i+=TWOPI/sines,n++)
602     {
603       sinus[n]=sin(i);
604       cosinus[n]=cos(i);
605     }
606 }
607 /*------------------------------------------------------------------*/
608
609
610 static void
611 vektorprodukt(double feld1[], double feld2[], double feld3[])
612 {
613   feld3[0]=feld1[1]*feld2[2]-feld1[2]*feld2[1];
614   feld3[1]=feld1[2]*feld2[0]-feld1[0]*feld2[2];
615   feld3[2]=feld1[0]*feld2[1]-feld1[1]*feld2[0];
616 }
617 /*------------------------------------------------------------------*/
618 static void
619 turn(double feld1[], double feld2[], double winkel)
620 {
621   double temp[3];
622   double s,ca,sa,sx1,sx2,sx3;
623   
624   vektorprodukt(feld1,feld2,temp);
625   
626   s=feld1[0]*feld2[0]+feld1[1]*feld2[1]+feld1[2]*feld2[2];
627   
628   sx1=s*feld2[0];
629   sx2=s*feld2[1];
630   sx3=s*feld2[2];
631   sa=sin(winkel);ca=cos(winkel);
632   feld1[0]=ca*(feld1[0]-sx1)+sa*temp[0]+sx1;
633   feld1[1]=ca*(feld1[1]-sx2)+sa*temp[1]+sx2;
634   feld1[2]=ca*(feld1[2]-sx3)+sa*temp[2]+sx3;
635 }
636 /*------------------------------------------------------------------*/
637
638 /* 1: Blickrichtung v;3:Ebenenmittelpunkt m 
639    double feld1[],feld3[]; */
640 static void 
641 viewpoint(void)
642 {
643   am[0]=-zoom*v[0];
644   am[1]=-zoom*v[1];
645   am[2]=-zoom*v[2];
646   
647   zaehler=norm*norm*zoom;
648 }
649 /*------------------------------------------------------------------*/
650 static void 
651 projektion(void)
652 {
653   double c1[3],c2[3],k[3],x1,y1;
654   double cno,cnorm/*,magnit*/;
655   int i;
656   
657   for (i=0;i<maxk;i++)
658     {
659       c1[0]=kugeln[i].x-a[0];
660       c1[1]=kugeln[i].y-a[1];
661       c1[2]=kugeln[i].z-a[2];
662       cnorm=sqrt(c1[0]*c1[0]+c1[1]*c1[1]+c1[2]*c1[2]);
663       
664       c2[0]=c1[0];
665       c2[1]=c1[1];
666       c2[2]=c1[2];
667       
668       cno=c2[0]*v[0]+c2[1]*v[1]+c2[2]*v[2];
669       kugeln[i].d=cnorm;
670       if (cno<0) kugeln[i].d=-20.0;
671       
672       
673       kugeln[i].r1=(mag*zoom*kugeln[i].r/cnorm);
674       
675       c2[0]=v[0]/cno;
676       c2[1]=v[1]/cno;
677       c2[2]=v[2]/cno;
678       
679       vektorprodukt(c2,c1,k);
680
681       
682       x1=(startx+(x[0]*k[0]+x[1]*k[1]+x[2]*k[2])*mag);
683       y1=(starty-(y[0]*k[0]+y[1]*k[1]+y[2]*k[2])*mag);
684       if(   (x1>-2000.0)
685          && (x1<scrnWidth+2000.0)
686          && (y1>-2000.0)
687          && (y1<scrnHeight+2000.0))
688         {
689           kugeln[i].x1=(int)x1;
690           kugeln[i].y1=(int)y1;
691         }
692       else
693         {
694           kugeln[i].x1=0;
695           kugeln[i].y1=0;
696           kugeln[i].d=-20.0;
697         }
698     }
699 }
700
701 /*---------- event-handler ----------------*/
702 static void
703 event_handler(void)
704 {
705   while (XEventsQueued (dpy, QueuedAfterReading))
706     {
707       XEvent event;
708       
709       XNextEvent (dpy, &event);
710       switch (event.type)
711         {
712         case ConfigureNotify:
713           if (event.xconfigure.width != scrnWidth ||
714               event.xconfigure.height != scrnHeight)
715             {
716               XFreePixmap (dpy, buffer); 
717               scrnWidth = event.xconfigure.width;
718               scrnHeight = event.xconfigure.height;
719               buffer = XCreatePixmap (dpy, win, scrnWidth, scrnHeight,
720                                       xgwa.depth);
721               
722               startx=scrnWidth/2;
723               starty=scrnHeight/2;
724               scrnH2=startx;
725               scrnW2=starty;
726             };
727           break;
728
729         case KeyPress:
730           {
731             KeySym kpr=XKeycodeToKeysym(dpy,event.xkey.keycode,0);
732
733             switch (kpr)
734               {
735               case 's': case 'S':
736                 vspeed = 0.5;
737                 break;
738               case 'a': case 'A':
739                 vspeed = -0.3;
740                 break;
741
742               case '0':
743                 speed = 0;
744                 vspeed = 0;
745                 break;
746
747               case 'z': case 'Z':
748                 mag *= 1.02;
749                 break;
750
751               case 'x': case 'X':
752                 mag /= 1.02;
753                 break;
754
755               default:
756                 screenhack_handle_event (dpy, &event);
757                 break;
758               }
759           }
760
761         case ButtonPress: case ButtonRelease:
762           break;
763
764         default:
765           screenhack_handle_event (dpy, &event);
766           break;
767         }
768     }
769   /*nap(40);-Ersatz*/ 
770   {
771     struct timeval timeout;
772     timeout.tv_sec=timewait/1000000;
773     timeout.tv_usec=timewait%1000000;
774     (void)select(0,0,0,0,&timeout);
775   }
776 }
777
778
779 /*-------------------------------------------------*/
780
781 char *progclass = "T3D";
782
783 char *defaults [] = {
784   ".background: black",
785   ".foreground: white",
786   "*move:       0.5",
787   "*wobble:     2.0",
788   "*cycle:      10.0",
789   "*mag:        1",
790   "*minutes:    False",
791   "*delay:      40000",
792   "*fast:       50",
793   "*ccycle:     False",
794   "*hsvcycle:   0.0",
795   0
796 };
797
798 XrmOptionDescRec options [] = {
799   { "-move",            ".move",        XrmoptionSepArg, 0 },
800   { "-wobble",          ".wobble",      XrmoptionSepArg, 0 },
801   { "-cycle",           ".cycle",       XrmoptionSepArg, 0 },
802   { "-mag",             ".mag",         XrmoptionSepArg, 0 },
803   { "-minutes",         ".minutes",     XrmoptionSepArg, 0 },
804   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
805   { "-fast",            ".fast",        XrmoptionSepArg, 0 },
806   { "-colcycle",        ".colcycle",    XrmoptionSepArg, 0 },
807   { "-hsvcycle",        ".hsvcycle",    XrmoptionSepArg, 0 },
808   { "-rgb",             ".rgb",         XrmoptionSepArg, 0 },
809   { "-hsv",             ".hsv",         XrmoptionSepArg, 0 },
810   { 0, 0, 0, 0 }
811 };
812
813
814 void
815 screenhack (Display *d, Window w)
816 {
817   Window junk_win,in_win;
818   
819   int px,py,junk/*,wai*/;
820   unsigned int kb;
821 /*  int act,act1,tc;*/
822   double vnorm;
823   /* double var=0.0; */
824   int color=0/*, dir=1*/;
825   
826   dpy = d;
827   win = w;
828   initialize();
829   
830   initColor(r,g,b);
831   init_3d();
832   zeit=(struct tm *)malloc(sizeof(struct tm));
833   init_kugel();
834   
835   startx=scrnWidth/2;
836   starty=scrnHeight/2;
837   scrnH2=startx;
838   scrnW2=starty;
839   vspeed=0;
840   
841   
842   vektorprodukt(x,y,v);
843   viewpoint(/*m,v*/);
844   
845   setink (BlackPixel (dpy, screen));
846   XFillRectangle (dpy, win, gc, 0, 0, scrnWidth, scrnHeight);
847   XQueryPointer (dpy, win, &junk_win, &junk_win, &junk, &junk,
848                  &px, &py, &kb);
849   
850   for (;;)
851     {   double dtime;
852         
853         /*--------------- Zeichenteil --------------*/
854
855         event_handler();
856         
857         vektorprodukt(x,y,v);
858         
859         vnorm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
860         v[0]=v[0]*norm/vnorm;
861         v[1]=v[1]*norm/vnorm;
862         v[2]=v[2]*norm/vnorm;
863         vnorm=sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]);
864         x[0]=x[0]*norm/vnorm;
865         x[1]=x[1]*norm/vnorm;
866         x[2]=x[2]*norm/vnorm;
867         vnorm=sqrt(y[0]*y[0]+y[1]*y[1]+y[2]*y[2]);
868         y[0]=y[0]*norm/vnorm;
869         y[1]=y[1]*norm/vnorm;
870         y[2]=y[2]*norm/vnorm;
871         
872         projektion();
873         t3d_sort (0,maxk-1);
874         
875         dtime=gettime();
876         
877         if(cycl)
878           {
879             color=(int)(64.0*(dtime/60-floor(dtime/60)))-32;
880             
881             if(color<0)
882               color=-color;
883             
884             setink(colors[color/3].pixel);
885           }
886         else
887           setink(BlackPixel (dpy, screen));
888         
889         XFillRectangle(dpy,buffer,gc,0,0,scrnWidth,scrnHeight);
890         
891         {
892           int i;
893           
894           manipulate(dtime);
895           
896           for (i=0;i<maxk;i++)
897             {
898               if (kugeln[i].d>0.0)
899                 fill_kugel(i,buffer,1);
900             }
901         }
902
903         XSync(dpy,0);
904         
905         /* manipulate(gettime());
906            var+=PI/500;
907            if (var>=TWOPI) var=PI/500; */
908         
909         /*event_handler();*/
910         
911         if(hsvcycl!=0.0)
912           {
913             dtime=hsvcycl*dtime/10.0+hue/360.0;
914             dtime=360*(dtime-floor(dtime));
915             
916             hsv2rgb(dtime,sat,val,&r,&g,&b);
917             changeColor(r,g,b);
918           }
919
920         XCopyArea (dpy, buffer, win, gc, 0, 0, scrnWidth, scrnHeight, 0, 0);
921         
922         
923         /*-------------------------------------------------*/
924         XSync(dpy,0);
925         
926         event_handler();
927         
928         (void)(XQueryPointer (dpy, win, &junk_win, &in_win, &junk, &junk,
929                               &px, &py, &kb));
930         
931         if ((px>0)&&(px<scrnWidth)&&(py>0)&&(py<scrnHeight) )           
932           {
933             if ((px !=startx)&&(kb&Button2Mask))
934               {
935                 /* printf("y=(%f,%f,%f)",y[0],y[1],y[2]);*/
936                 turn(y,x,((double)(px-startx))/(8000*mag));
937                 /* printf("->(%f,%f,%f)\n",y[0],y[1],y[2]);*/
938               }
939             if ((py !=starty)&&(kb&Button2Mask)) 
940               {
941                 /* printf("x=(%f,%f,%f)",x[0],x[1],x[2]);*/
942                 turn(x,y,((double)(py-starty))/(-8000*mag));
943                 /* printf("->(%f,%f,%f)\n",x[0],x[1],x[2]);*/
944               }
945             if ((kb&Button1Mask)) 
946               {
947                 if (vturn==0.0) vturn=.005; else if (vturn<2)  vturn+=.01;
948                 turn(x,v,.002*vturn);
949                 turn(y,v,.002*vturn); 
950               }
951             if ((kb&Button3Mask)) 
952               {
953                 if (vturn==0.0) vturn=.005; else if (vturn<2) vturn+=.01;
954                 turn(x,v,-.002*vturn);
955                 turn(y,v,-.002*vturn);
956               }
957           }
958         if (!(kb&Button1Mask)&&!(kb&Button3Mask)) 
959           vturn=0;
960         
961         speed=speed+speed*vspeed;
962         if ((speed<0.0000001) &&(vspeed>0.000001)) speed=0.000001;
963         vspeed=.1*vspeed;
964         if (speed>0.01) speed=.01;
965         a[0]=a[0]+speed*v[0];
966         a[1]=a[1]+speed*v[1];
967         a[2]=a[2]+speed*v[2];
968       }
969 }