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