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