1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* t3d --- Flying Balls Clock Demo */
3 
4 #if 0
5 static const char sccsid[] = "@(#)t3d.c	5.0 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1998 Bernd Paysan , paysan@informatik.tu-muenchen.de.
11  *
12  * Copy, modify, and distribute T3D either under GPL  version 2 or newer,
13  * or under the standard MIT/X license notice.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * partly based on flying balls demo by Georg Acher,
22  * acher@informatik.tu-muenchen.de
23  * (developed on HP9000/720 (55 MIPS,20 MFLOPS) )
24  *
25  * Todo for xlock:
26  *    -Set default options right and make it more "random"
27  *    -Add original colour scheme
28  *    -Get trackmouse is working
29  *    -Add some more options which were handled in the original by the XEvents.
30  *    -Get working better in password window.
31  *
32  * Revision History:
33  * 01-Nov-2000: Allocation checks
34  * 26-Jan-2000: joukj AT hrem.nano.tudelft.nl (Jouk Jansen) : adapted for
35  *              xlockmore. Modified colour-schemes.
36  * 04-Jan-1999: jwz AT jwz.org -- adapted to xscreensaver framework,
37  *              to take advantage of the command-line options
38  *              provided by screenhack.c.
39  */
40 #ifdef WIN32
41 #include <sys/time.h>
42 #else
43 #include <time.h>
44 #endif /* WIN32 */
45 
46 #define FASTDRAW
47 #define FASTCOPY
48 #undef USE_POLYGON
49 
50 #ifdef STANDALONE
51 #define MODE_t3d
52 #define DEFAULTS "*delay: 10000 \n" \
53 	"*cycles: 60000 \n" \
54 	"*ncolors: 200 \n" \
55 	"*mouse: False \n" \
56 
57 # define free_t3d 0
58 # define reshape_t3d 0
59 # define t3d_handle_event 0
60 #define UNIFORM_COLORS
61 #include "xlockmore.h"		/* in xscreensaver distribution */
62 
63 #else /* STANDALONE */
64 #include "xlock.h"		/* in xlockmore distribution */
65 #include "color.h"
66 #endif /* STANDALONE */
67 
68 #include <time.h>
69 #ifdef TIME_WITH_SYS_TIME /* for sco */
70 #include <sys/time.h>
71 #endif
72 
73 #ifdef MODE_t3d
74 
75 #define DEF_TRACKMOUSE  "False"
76 #define DEF_MOVE "0.5"
77 #define DEF_WOBBLE "2.0"
78 #define DEF_MAG "10.0"
79 #define DEF_FAST "50"
80 #define DEF_MINUTES "False"
81 #define DEF_CYCLE "True"
82 
83 #define PI M_PI
84 #define TWOPI 2*M_PI
85 
86 #define MAXFAST 100
87 
88 #define   norm       20.0
89 
90 #ifdef FASTCOPY
91 #define sum1ton(a) (((a)*(a)+1)/2)
92 #define fastcw sum1ton(fastch)
93 #endif
94 
95 #undef ABS
96 #define ABS(x) ((x)<0.0 ? -(x) : (x))
97 
98 /* Anzahl der Kugeln */
99 #define kmax ((t3dp->minutes?60:24))
100 
101 /* Werte in der Sinus-Tabelle */
102 #define sines 52
103 
104 #define setink(inkcolor) XSetForeground(display,t3dp->gc,inkcolor)
105 
106 static Bool trackmouse , minutes , cycle_p;
107 
108 static float move, wobble , mag;
109 
110 static int fastch;
111 
112 static XrmOptionDescRec opts[] =
113 {
114 	{(char *) "-cycle", (char *) ".t3d.cycle", XrmoptionNoArg, (caddr_t) "on"},
115 	{(char *) "+cycle", (char *) ".t3d.cycle", XrmoptionNoArg, (caddr_t) "off"},
116 	{(char *) "-move", (char *) ".t3d.move", XrmoptionSepArg, (caddr_t) NULL},
117 	{(char *) "-wobble", (char *) ".t3d.wobble", XrmoptionSepArg, (caddr_t) NULL},
118 	{(char *) "-mag", (char *) ".t3d.mag", XrmoptionSepArg, (caddr_t) NULL},
119 	{(char *) "-fast", (char *) ".t3d.fast", XrmoptionSepArg, (caddr_t) NULL},
120         {(char *) "-minutes", (char *) ".t3d.minutes", XrmoptionNoArg, (caddr_t) "on"},
121         {(char *) "+minutes", (char *) ".t3d.minutes", XrmoptionNoArg, (caddr_t) "off"},
122         {(char *) "-trackmouse", (char *) ".t3d.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
123         {(char *) "+trackmouse", (char *) ".t3d.trackmouse", XrmoptionNoArg, (caddr_t) "off"}
124 };
125 
126 static argtype vars[] =
127 {
128 	{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool},
129 	{(void *) & move, (char *) "move", (char *) "Move", (char *) DEF_MOVE, t_Float},
130 	{(void *) & wobble, (char *) "wobble", (char *) "Wobble", (char *) DEF_WOBBLE, t_Float},
131 	{(void *) & mag, (char *) "mag", (char *) "Magnification", (char *) DEF_MAG, t_Float},
132 	{(void *) & fastch, (char *) "fast", (char *) "Fast", (char *) DEF_FAST, t_Int},
133         {(void *) & minutes, (char *) "minutes", (char *) "Minutes", (char *) DEF_MINUTES, t_Bool},
134         {(void *) & trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool}
135 };
136 
137 static OptionStruct desc[] =
138 {
139 	{(char *) "-/+cycle", (char *) "turn on/off colour cycling"},
140 	{(char *) "-move num", (char *) "Move speed"},
141 	{(char *) "-wobble num", (char *) "Wobble speed"},
142 	{(char *) "-mag num", (char *) "Magnification factor"},
143 	{(char *) "-fast num", (char *) "Fast"},
144         {(char *) "-/+minutes", (char *) "turn on/off minutes"},
145         {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"}
146 };
147 
148 ENTRYPOINT ModeSpecOpt t3d_opts =
149 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
150 
151 
152 #ifdef USE_MODULES
153 ModStruct   t3d_description =
154 {"t3d", "init_t3d", "draw_t3d", "release_t3d",
155  "refresh_t3d", "init_t3d", (char *) NULL, &t3d_opts,
156  250000, 1000, 60000 , 1, 64, 1.0, "",
157  "Flying Balls Clock Demo", 0, NULL};
158 
159 #endif
160 
161 typedef struct {
162   double x,y,z,r,d,r1;
163   int x1,y1;
164 } kugeldat;
165 
166 typedef struct {
167    Cursor      cursor;
168    double cycles , movef , wobber , a[3] , x[3] , y[3] , zoom , speed , vspeed;
169    double sinus[sines] , cosinus[sines] , v[3] , am[3] , zaehler , vnorm;
170    double vturn;
171    int fastch , minutes , maxk;
172    GC gc;
173    Pixmap buffer;
174 #ifdef FASTCOPY
175    GC orgc , andgc;
176    Pixmap fastcircles , fastmask;
177 #else
178    XImage* fastcircles[maxfast] , fastmask[maxfast];
179 #endif
180    Colormap    cmap;
181    XColor     *colors;
182    int         width, height, depth;
183    int         ncolors , fastdraw , scrnW2, scrnH2, startx , starty , px , py;
184    Bool        cycle_p, mono_p, no_colors;
185    unsigned long blackpixel, whitepixel, fg, bg;
186    int         direction;
187    struct tm  *zeit;
188    kugeldat kugeln[100];
189    int         color_offset;
190 } t3dstruct;
191 
192 static t3dstruct *t3ds = (t3dstruct *) NULL;
193 
194 static void
t3d_zeiger(ModeInfo * mi,double dist,double rad,double z,double sec,int * q)195 t3d_zeiger( ModeInfo* mi , double dist,double rad, double z, double sec,
196 		int *q)
197 /* Zeiger zeichnen */
198 {
199   int i,n;
200   double gratio=sqrt(2.0/(1.0+sqrt(5.0)));
201    t3dstruct *t3dp;
202 
203    t3dp = &t3ds[MI_SCREEN(mi)];
204 
205   n = *q;
206 
207   for(i=0;i<3;i++)
208     {
209       t3dp->kugeln[n].x=dist*cos(sec);
210       t3dp->kugeln[n].y=-dist*sin(sec);
211       t3dp->kugeln[n].z=z;
212       t3dp->kugeln[n].r=rad;
213       n++;
214 
215       dist += rad;
216       rad = rad*gratio;
217     }
218   *q = n;
219 }
220 
221 static void
t3d_manipulate(ModeInfo * mi,double k)222 t3d_manipulate( ModeInfo* mi , double k)
223 /*-----------------------------------------------------------------*
224  *                           Uhr zeichnen                          *
225  *-----------------------------------------------------------------*/
226 {
227   double i,l,/*xs,*/ys,zs,mod;
228   double /*persec,*/sec,min,hour;
229   int n;
230   t3dstruct *t3dp;
231 
232   t3dp = &t3ds[MI_SCREEN(mi)];
233 
234   sec=TWOPI*modf(k/60,&mod);
235   min=TWOPI*modf(k/3600,&mod);
236   hour=TWOPI*modf(k/43200,&mod);
237 
238   l=TWOPI*modf(k/300,&mod);
239   i=0.0;
240   for (n=0;n<kmax;n++)
241     {
242 
243       t3dp->kugeln[n].x=4.0*sin(i);
244       t3dp->kugeln[n].y=4.0*cos(i);
245       t3dp->kugeln[n].z=t3dp->wobber* /* (sin(floor(2+2*l/(PI))*i)*sin(2*l)); */
246 	cos((i-sec)*floor(2+5*l/(PI)))*sin(5*l);
247       if(t3dp->minutes)
248 	{
249 	  t3dp->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
250 	    ((n % 5!=0) ? 0.3 : 0.6)*
251 	      ((n % 15 ==0) ? 1.25 : .75);
252 	}
253       else
254 	{
255 	  t3dp->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
256 	    ((n & 1) ? 0.5 : 1.0)*
257 	      ((n % 6==0) ? 1.25 : .75);
258 	}
259       i+=TWOPI/kmax;
260     }
261 
262   t3dp->kugeln[n].x=0.0;
263   t3dp->kugeln[n].y=0.0;
264   t3dp->kugeln[n].z=0.0;
265   t3dp->kugeln[n].r=2.0+cos(TWOPI*modf(k,&mod))/2;
266   n++;
267 
268   t3d_zeiger( mi , 2.0,0.75,-2.0,sec,&n);
269   t3d_zeiger( mi , 1.0,1.0,-1.5,min,&n);
270   t3d_zeiger( mi , 0.0,1.5,-1.0,hour,&n);
271 
272   for(n=0;n<t3dp->maxk;n++)
273     {
274        double cycle = (double) MI_CYCLES( mi );
275 
276       ys=t3dp->kugeln[n].y*cos(t3dp->movef*sin(cycle*sec))+
277 	t3dp->kugeln[n].z*sin(t3dp->movef*sin(cycle*sec));
278       zs=-t3dp->kugeln[n].y*sin(t3dp->movef*sin(cycle*sec))+
279 	t3dp->kugeln[n].z*cos(t3dp->movef*sin(cycle*sec));
280       t3dp->kugeln[n].y=ys;
281       t3dp->kugeln[n].z=zs;
282     }
283 }
284 
285 static double
t3d_gettime(void)286 t3d_gettime (void)
287 {
288   struct timeval time1;
289   struct tm *zeit;
290   time_t lt;
291 
292 #if HAVE_GETTIMEOFDAY
293   GETTIMEOFDAY(&time1);
294   lt = time1.tv_sec;	/* avoid type cast lossage */
295 #else
296   lt = NULL;
297   time1.tv_sec = 0;
298 #endif
299   zeit = localtime((const time_t *) &lt);
300 
301   return (zeit->tm_sec+60*(zeit->tm_min+60*(zeit->tm_hour))
302 	  + time1.tv_usec*1.0E-6);
303 }
304 
305 
306 static void
t3d__sort(ModeInfo * mi,int l,int r)307 t3d__sort( ModeInfo* mi , int l, int r)
308 {
309   int i,j;
310   kugeldat ex;
311   double x;
312    t3dstruct *t3dp;
313 
314    t3dp = &t3ds[MI_SCREEN(mi)];
315 
316   i=l;j=r;
317   x=t3dp->kugeln[(l+r)/2].d;
318   for (;;) {
319       while(t3dp->kugeln[i].d>x) i++;
320       while(x>t3dp->kugeln[j].d) j--;
321       if (i<=j)
322 	{
323 	  ex=t3dp->kugeln[i];
324 	   t3dp->kugeln[i]=t3dp->kugeln[j];
325 	   t3dp->kugeln[j]=ex;
326 	  i++;j--;
327 	}
328       if (i>j) break;
329     }
330   if (l<j) t3d__sort( mi , l,j);
331   if (i<r) t3d__sort ( mi , i,r);
332 }
333 
334 static void
t3d_vektorprodukt(double feld1[],double feld2[],double feld3[])335 t3d_vektorprodukt(double feld1[], double feld2[], double feld3[])
336 {
337   feld3[0]=feld1[1]*feld2[2]-feld1[2]*feld2[1];
338   feld3[1]=feld1[2]*feld2[0]-feld1[0]*feld2[2];
339   feld3[2]=feld1[0]*feld2[1]-feld1[1]*feld2[0];
340 }
341 
342 static void
t3d_turn(double feld1[],double feld2[],double winkel)343 t3d_turn(double feld1[], double feld2[], double winkel)
344 {
345   double temp[3];
346   double s,ca,sa,sx1,sx2,sx3;
347 
348   t3d_vektorprodukt(feld1,feld2,temp);
349 
350   s=feld1[0]*feld2[0]+feld1[1]*feld2[1]+feld1[2]*feld2[2];
351 
352   sx1=s*feld2[0];
353   sx2=s*feld2[1];
354   sx3=s*feld2[2];
355   sa=sin(winkel);ca=cos(winkel);
356   feld1[0]=ca*(feld1[0]-sx1)+sa*temp[0]+sx1;
357   feld1[1]=ca*(feld1[1]-sx2)+sa*temp[1]+sx2;
358   feld1[2]=ca*(feld1[2]-sx3)+sa*temp[2]+sx3;
359 }
360 
361 static void
t3d_projektion(ModeInfo * mi)362 t3d_projektion( ModeInfo* mi)
363 {
364   double c1[3],c2[3],k[3],x_1,y_1;
365   double cno,cnorm/*,magnit*/;
366   int i;
367    t3dstruct *t3dp;
368 
369    t3dp = &t3ds[MI_SCREEN(mi)];
370 
371   for (i=0;i<t3dp->maxk;i++)
372     {
373       c1[0]=t3dp->kugeln[i].x-t3dp->a[0];
374       c1[1]=t3dp->kugeln[i].y-t3dp->a[1];
375       c1[2]=t3dp->kugeln[i].z-t3dp->a[2];
376       cnorm=sqrt(c1[0]*c1[0]+c1[1]*c1[1]+c1[2]*c1[2]);
377 
378       c2[0]=c1[0];
379       c2[1]=c1[1];
380       c2[2]=c1[2];
381 
382       cno=c2[0]*t3dp->v[0]+c2[1]*t3dp->v[1]+c2[2]*t3dp->v[2];
383       t3dp->kugeln[i].d=cnorm;
384       if (cno<0) t3dp->kugeln[i].d=-20.0;
385 
386 
387       t3dp->kugeln[i].r1=(mag*t3dp->zoom*t3dp->kugeln[i].r/cnorm);
388 
389       c2[0]=t3dp->v[0]/cno;
390       c2[1]=t3dp->v[1]/cno;
391       c2[2]=t3dp->v[2]/cno;
392 
393       t3d_vektorprodukt(c2,c1,k);
394 
395 
396       x_1=(t3dp->startx+(t3dp->x[0]*k[0]+t3dp->x[1]*k[1]+t3dp->x[2]*k[2])*mag);
397       y_1=(t3dp->starty-(t3dp->y[0]*k[0]+t3dp->y[1]*k[1]+t3dp->y[2]*k[2])*mag);
398       if(   (x_1>-2000.0)
399 	 && (x_1<t3dp->width+2000.0)
400 	 && (y_1>-2000.0)
401 	 && (y_1<t3dp->height+2000.0))
402 	{
403 	  t3dp->kugeln[i].x1=(int)x_1;
404 	  t3dp->kugeln[i].y1=(int)y_1;
405 	}
406       else
407 	{
408 	  t3dp->kugeln[i].x1=0;
409 	  t3dp->kugeln[i].y1=0;
410 	  t3dp->kugeln[i].d=-20.0;
411 	}
412     }
413 }
414 
415 
416 static void
t3d_viewpoint(ModeInfo * mi)417 t3d_viewpoint( ModeInfo* mi)
418 /* 1: Blickrichtung v;3:Ebenenmittelpunkt m
419    double feld1[],feld3[]; */
420 {
421    t3dstruct *t3dp;
422 
423    t3dp = &t3ds[MI_SCREEN(mi)];
424 
425    t3dp->am[0]=-t3dp->zoom*t3dp->v[0];
426    t3dp->am[1]=-t3dp->zoom*t3dp->v[1];
427    t3dp->am[2]=-t3dp->zoom*t3dp->v[2];
428 
429    t3dp->zaehler=norm*norm* t3dp->zoom;
430 }
431 
432 static void
t3d_fill_kugel(int i,Pixmap buf,int setcol,ModeInfo * mi)433 t3d_fill_kugel(int i, Pixmap buf, int setcol , ModeInfo* mi )
434 {
435    t3dstruct *t3dp;
436    Display    *display = MI_DISPLAY(mi);
437   double ra;
438   int m,inr=3,d;
439 #ifdef USE_POLYGON
440    int inc = 1;
441 #endif
442 
443    t3dp = &t3ds[MI_SCREEN(mi)];
444 
445   d=(int)((ABS(t3dp->kugeln[i].r1)*2));
446   if (d==0) d=1;
447 
448 # ifdef FASTDRAW
449   if(t3dp->fastdraw && d<t3dp->fastch)
450     {
451 #	ifdef FASTCOPY
452       XCopyArea(display, t3dp->fastmask, buf, t3dp->andgc, sum1ton(d)-(d+1)/2,
453 		1,d,d, (int)(t3dp->kugeln[i].x1)-d/2,
454 		(int)(t3dp->kugeln[i].y1)-d/2);
455       XCopyArea(display, t3dp->fastcircles, buf, t3dp->orgc,
456 		sum1ton(d)-(d+1)/2, 1,d,d, (int)(t3dp->kugeln[i].x1)-d/2,
457 		(int)(t3dp->kugeln[i].y1)-d/2);
458 #else
459       XPutImage(display, buf, t3dp->andgc, t3dp->fastmask[d-1], 0, 0,
460 		(int)(t3dp->kugeln[i].x1)-d/2, (int)(t3dp->kugeln[i].y1)-d/2,
461 		d, d);
462       XPutImage(display, buf, t3dp->orgc, t3dp->fastcircles[d-1], 0, 0,
463 		(int)(t3dp->kugeln[i].x1)-d/2, (int)(t3dp->kugeln[i].y1)-d/2,
464 		d, d);
465 #	endif
466     }
467   else
468 #endif
469     {
470        if(ABS(t3dp->kugeln[i].r1)<6.0) inr=9;
471 
472       for (m=0;m<=28;m+=inr)
473 	{
474 	  ra=t3dp->kugeln[i].r1*sqrt(1-m*m/(28.0*28.0));
475 #ifdef USE_POLYGON
476 	  if(-ra< 3.0) inc=14;
477 	  else if(-ra< 6.0) inc=8;
478 	  else if(-ra<20.0) inc=4;
479 	  else if(-ra<40.0) inc=2;
480 #endif
481 	  if(setcol)
482 	    {
483 	       if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
484 	         setink(t3dp->colors[m].pixel);
485 	       } else if (MI_NPIXELS(mi) <= 2) {
486 	         if ((m + t3dp->color_offset) % 2)
487 			setink(MI_WHITE_PIXEL(mi));
488 		 else
489 			setink(MI_BLACK_PIXEL(mi));
490 	       } else {
491 	         setink(MI_PIXEL(mi, ((m + t3dp->color_offset) % 29) * MI_NPIXELS(mi) / 29));
492 	       }
493 	    }
494 
495 #ifdef USE_POLYGON
496           {
497             int n, nr;
498 	  for (n=0,nr=0;n<=sines-1;n+=inc,nr++)
499 	    {
500 	      track[nr].x=t3dp->kugeln[i].x1+(int)(ra*t3dp->sinus[n])+
501 		 (t3dp->kugeln[i].r1-ra)/2;
502 	      track[nr].y=t3dp->kugeln[i].y1+(int)(ra*t3dp->cosinus[n])+
503 		 (t3dp->kugeln[i].r1-ra)/2;
504 	    }
505 	  XFillPolygon(display,buf,t3dp->gc,track,nr,Convex,CoordModeOrigin);
506           }
507 #else /* Use XFillArc */
508 	  XFillArc(display, buf, t3dp->gc,
509 		   (int)(t3dp->kugeln[i].x1+(t3dp->kugeln[i].r1+ra)/2),
510 		   (int)(t3dp->kugeln[i].y1+(t3dp->kugeln[i].r1+ra)/2),
511 		   (int)-(2*ra+1), (int)-(2*ra+1), 0, 360*64);
512 #endif
513 	}
514     }
515 }
516 
517 
518 static void
t3d_init_kugel(ModeInfo * mi)519 t3d_init_kugel( ModeInfo* mi )
520 {
521    t3dstruct *t3dp;
522 
523 #ifdef FASTDRAW
524    Display    *display = MI_DISPLAY(mi);
525   int i;
526 
527    t3dp = &t3ds[MI_SCREEN(mi)];
528 
529   for(i=0; i<t3dp->fastch; i++)
530     {
531 #	ifdef FASTCOPY
532       t3dp->kugeln[i].r1=-((double) i)/2 -1;
533       t3dp->kugeln[i].x1=sum1ton(i);
534       t3dp->kugeln[i].y1=i/2 +1;
535 
536       t3d_fill_kugel(i,t3dp->fastcircles,1 , mi );
537 /*      setink((1<<MIN(24,t3dp->depth))-1);*/
538       setink(MI_BLACK_PIXEL(mi));
539       t3d_fill_kugel(i,t3dp->fastmask,0 , mi );
540 #	else
541       t3dp->kugeln[i].r1=-((double) i)/2 -1;
542       t3dp->kugeln[i].x1=t3dp->kugeln[i].y1=i/2 +1;
543 
544       t3d_fill_kugel(i,t3dp->buffer,1 , mi );
545       t3dp->fastcircles[i]=XGetImage(display,t3dp->buffer,0,0,i+2,i+2,
546 				     (1<<t3dp->depth)-1, ZPixmap);
547        /* setink((1<<MIN(24,t3dp->depth))-1); */
548       setink(MI_WHITE_PIXEL(mi));
549       t3d_fill_kugel(i,t3dp->buffer,0 , mi );
550       t3dp->fastmask[i]=XGetImage(display,t3dp->buffer,0,0,i+2,i+2,
551 				  (1<<t3dp->depth)-1,ZPixmap);
552       setink(MI_BLACK_PIXEL(mi));
553       XFillRectangle (display, t3dp->buffer     , t3dp->gc, 0, 0,
554 		      t3dp->width, t3dp->height);
555 #	endif
556     }
557   t3dp->fastdraw=1;
558 #endif
559 }
560 
561 static void
t3d_init_3d(ModeInfo * mi)562 t3d_init_3d( ModeInfo* mi )
563 {
564    t3dstruct *t3dp;
565    double i;
566    int n=0;
567 
568    t3dp = &t3ds[MI_SCREEN(mi)];
569 
570    t3dp->a[0]=0.0;
571    t3dp->a[1]=0.0;
572    t3dp->a[2]=-10.0;
573 
574    t3dp->x[0]=10.0;
575    t3dp->x[1]=0.0;
576    t3dp->x[2]=0.0;
577 
578    t3dp->y[0]=0.0;
579    t3dp->y[1]=10.0;
580    t3dp->y[2]=0.0;
581 
582    t3dp->zoom=-10.0;
583    t3dp->speed=.0;
584 
585    for (i=0.0;n<sines;i+=TWOPI/sines,n++)
586     {
587       t3dp->sinus[n]=sin(i);
588       t3dp->cosinus[n]=cos(i);
589     }
590 
591 }
592 
593 static void
free_t3d_screen(ModeInfo * mi,t3dstruct * t3dp)594 free_t3d_screen(ModeInfo *mi, t3dstruct *t3dp)
595 {
596 	Display *display = MI_DISPLAY(mi);
597 	if (t3dp == NULL) {
598 		return;
599 	}
600 	if (t3dp->cursor != None) {
601 		XFreeCursor(display, t3dp->cursor);
602 		t3dp->cursor = None;
603 	}
604 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
605 		MI_WHITE_PIXEL(mi) = t3dp->whitepixel;
606 		MI_BLACK_PIXEL(mi) = t3dp->blackpixel;
607 #ifndef STANDALONE
608 		MI_FG_PIXEL(mi) = t3dp->fg;
609 		MI_BG_PIXEL(mi) = t3dp->bg;
610 #endif
611 		if (t3dp->colors != NULL) {
612 			if (t3dp->ncolors && !t3dp->no_colors)
613 				free_colors(
614 #ifdef STANDALONE
615 					MI_SCREENPTR(mi),
616 #else
617 					display,
618 #endif
619 					t3dp->cmap, t3dp->colors, t3dp->ncolors);
620 			free(t3dp->colors);
621 			t3dp->colors = (XColor *) NULL;
622 		}
623 		if (t3dp->cmap != None) {
624 			XFreeColormap(display, t3dp->cmap);
625 			t3dp->cmap = None;
626 		}
627 	}
628 	if (t3dp->buffer != None) {
629 		XFreePixmap(display, t3dp->buffer);
630 		t3dp->buffer = None;
631 	}
632 	if (t3dp->gc != None) {
633 		XFreeGC(display, t3dp->gc);
634 		t3dp->gc = None;
635 	}
636 #ifdef FASTCOPY
637 	if (t3dp->orgc != None) {
638 		XFreeGC(display, t3dp->orgc);
639 		t3dp->orgc = None;
640 	}
641 	if (t3dp->andgc != None) {
642 		XFreeGC(display, t3dp->andgc);
643 		t3dp->andgc = None;
644 	}
645 	if (t3dp->fastcircles != None) {
646 		XFreePixmap(display, t3dp->fastcircles);
647 		t3dp->fastcircles = None;
648 	}
649 	if (t3dp->fastmask != None) {
650 		XFreePixmap(display, t3dp->fastmask);
651 		t3dp->fastmask = None;
652 	}
653 #endif
654 	if (t3dp->zeit != NULL) {
655 		free(t3dp->zeit);
656 		t3dp->zeit = (struct tm *) NULL;
657 	}
658 	t3dp = NULL;
659 }
660 
661 static Bool
t3d_initialize(ModeInfo * mi)662 t3d_initialize( ModeInfo* mi )
663 {
664    Display    *display = MI_DISPLAY(mi);
665    Window      window = MI_WINDOW(mi);
666    t3dstruct *t3dp;
667    XGCValues   xgcv;
668 
669    t3dp = &t3ds[MI_SCREEN(mi)];
670 
671    t3dp->cycles = MI_CYCLES( mi ) / 6000.0;
672    if ( t3dp->cycles <= 1.0 )
673      t3dp->cycles = 10.0;
674 
675    t3dp->movef = (double) move;
676    t3dp->wobber = (double) wobble;
677    t3dp->fastch = (int) (fastch * mag);
678    if ( t3dp->fastch > MAXFAST )
679      t3dp->fastch = MAXFAST;
680 
681    if ( minutes )
682      {
683 	t3dp->minutes = 1;
684 	t3dp->maxk = 70;
685      }
686    else
687      {
688 	t3dp->minutes = 0;
689 	t3dp->maxk = 34;
690      }
691    xgcv.foreground = MI_WHITE_PIXEL(mi);
692    if ((t3dp->gc = XCreateGC (display, window, GCForeground, &xgcv)) == None) {
693 	free_t3d_screen(mi, t3dp);
694 	return False;
695    }
696 #ifdef FASTDRAW
697    xgcv.function = GXor;
698    if ((t3dp->orgc = XCreateGC (display, window, GCFunction | GCForeground,
699 		&xgcv)) == None) {
700 	free_t3d_screen(mi, t3dp);
701 	return False;
702    }
703    xgcv.function = GXandInverted;
704    if ((t3dp->andgc = XCreateGC (display, window, GCFunction | GCForeground,
705 		&xgcv)) == None) {
706 	free_t3d_screen(mi, t3dp);
707 	return False;
708    }
709 #endif
710    if (MI_IS_VERBOSE(mi))
711      {
712 	(void) printf("Time 3D drawing ");
713 #ifdef FASTDRAW
714 #	ifdef FASTCOPY
715 	(void) puts("fast by Pixmap copy");
716 #	else
717 	(void) puts("fast by XImage copy");
718 #	endif
719 #else
720 	(void) puts("slow");
721 #endif
722      }
723 
724 #ifdef FASTCOPY
725    if (((t3dp->fastcircles = XCreatePixmap (display, window,
726 		fastcw, t3dp->fastch+1, t3dp->depth)) == None) ||
727        ((t3dp->fastmask    = XCreatePixmap (display, window,
728 		fastcw, t3dp->fastch+1, t3dp->depth)) == None)) {
729 	free_t3d_screen(mi, t3dp);
730 	return False;
731    }
732 #endif
733 
734   setink(MI_BLACK_PIXEL(mi));
735   XFillRectangle (display, t3dp->buffer , t3dp->gc, 0, 0, t3dp->width,
736 		  t3dp->height);
737 
738 #ifdef FASTCOPY
739   setink(MI_BLACK_PIXEL(mi));
740   XFillRectangle (display, t3dp->fastcircles, t3dp->gc, 0, 0, fastcw,
741 		  t3dp->fastch+1);
742   XFillRectangle (display, t3dp->fastmask   , t3dp->gc, 0, 0, fastcw,
743 		  t3dp->fastch+1);
744 #endif
745 
746    if (MI_IS_VERBOSE(mi))
747    {
748 	(void) printf("move\t%.2f\nwobber\t%.2f\nmag\t%.2f\n",
749 	       t3dp->movef, t3dp->wobber, mag );
750 	(void) printf("fast\t%i\nmarks\t%i\n", t3dp->fastch, t3dp->maxk);
751    }
752    return True;
753 }
754 
755 #ifndef STANDALONE
756 extern char *background;
757 extern char *foreground;
758 #endif
759 
760 ENTRYPOINT void
init_t3d(ModeInfo * mi)761 init_t3d(ModeInfo * mi)
762 {
763 	Display    *display = MI_DISPLAY(mi);
764 	Window      window = MI_WINDOW(mi);
765 	t3dstruct *t3dp;
766 
767 	MI_INIT(mi, t3ds);
768 	t3dp = &t3ds[MI_SCREEN(mi)];
769 
770 	if (trackmouse && !t3dp->cursor) {	/* Create an invisible cursor */
771 		Pixmap      bit;
772 		XColor      black;
773 
774 		black.red = 0;
775 		black.green = 0;
776 		black.blue = 0;
777 		black.flags = DoRed | DoGreen | DoBlue;
778 		if ((bit = XCreatePixmapFromBitmapData(display, window,
779 				(char *) "\000", 1, 1, MI_BLACK_PIXEL(mi),
780 				MI_BLACK_PIXEL(mi), 1)) == None) {
781 			free_t3d_screen(mi, t3dp);
782 			return;
783 		}
784 		if ((t3dp->cursor = XCreatePixmapCursor(display, bit, bit,
785 				&black, &black, 0, 0)) == None) {
786 			XFreePixmap(display, bit);
787 			free_t3d_screen(mi, t3dp);
788 			return;
789 		}
790 		XFreePixmap(display, bit);
791 	}
792 	XDefineCursor(display, window, t3dp->cursor);
793 
794 	t3dp->width = MI_WIDTH(mi);
795 	t3dp->height = MI_HEIGHT(mi);
796 	t3dp->depth = MI_DEPTH(mi);
797 	if (t3dp->buffer != None) {
798 		XFreePixmap(display, t3dp->buffer);
799 		t3dp->buffer = None;
800 	}
801 	if ((t3dp->buffer = XCreatePixmap (display, window,
802 			t3dp->width, t3dp->height, t3dp->depth)) == None) {
803 		free_t3d_screen(mi, t3dp);
804 		return;
805   	}
806 
807    /* Initialization */
808    if (t3dp->gc == None) {
809 	if (!t3d_initialize(mi))
810 		return;
811 
812 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2)
813 	  {
814 	     XColor      color;
815 
816 #ifndef STANDALONE
817 	     t3dp->fg = MI_FG_PIXEL(mi);
818 	     t3dp->bg = MI_BG_PIXEL(mi);
819 #endif
820 	     t3dp->blackpixel = MI_BLACK_PIXEL(mi);
821 	     t3dp->whitepixel = MI_WHITE_PIXEL(mi);
822 	     if ((t3dp->cmap = XCreateColormap(display, window, MI_VISUAL(mi),
823 			AllocNone)) == None) {
824 		free_t3d_screen(mi, t3dp);
825 		return;
826 	     }
827 	     XSetWindowColormap(display, window, t3dp->cmap);
828 	     (void) XParseColor(display, t3dp->cmap, "black", &color);
829 	     (void) XAllocColor(display, t3dp->cmap, &color);
830 	     MI_BLACK_PIXEL(mi) = color.pixel;
831 	     (void) XParseColor(display, t3dp->cmap, "white", &color);
832 	     (void) XAllocColor(display, t3dp->cmap, &color);
833 	     MI_WHITE_PIXEL(mi) = color.pixel;
834 #ifndef STANDALONE
835 	     (void) XParseColor(display, t3dp->cmap, background, &color);
836 	     (void) XAllocColor(display, t3dp->cmap, &color);
837 	     MI_BG_PIXEL(mi) = color.pixel;
838 	     (void) XParseColor(display, t3dp->cmap, foreground, &color);
839 	     (void) XAllocColor(display, t3dp->cmap, &color);
840 	     MI_FG_PIXEL(mi) = color.pixel;
841 #endif
842 	     t3dp->colors = (XColor *) NULL;
843 	     t3dp->ncolors = 0;
844      	  }
845      }
846      t3dp->color_offset = NRAND(29);
847 
848 /*Set up t2d data */
849    t3dp->direction = (LRAND() & 1) ? 1 : -1;
850    t3dp->fastdraw = 0;
851    t3dp->vturn = 0.0;
852 
853    if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
854 #ifdef STANDALONE
855 		Screen *screen = MI_SCREENPTR(mi);
856 #endif
857 /* Set up colour map */
858 		if (t3dp->colors != NULL) {
859 			if (t3dp->ncolors && !t3dp->no_colors)
860 				free_colors(
861 #ifdef STANDALONE
862 					screen,
863 #else
864 					display,
865 #endif
866 					t3dp->cmap, t3dp->colors, t3dp->ncolors);
867 			free(t3dp->colors);
868 			t3dp->colors = (XColor *) NULL;
869 		}
870 		t3dp->ncolors = MI_NCOLORS(mi);
871 		if (t3dp->ncolors < 2)
872 			t3dp->ncolors = 2;
873 		if (t3dp->ncolors <= 2)
874 			t3dp->mono_p = True;
875 		else
876 			t3dp->mono_p = False;
877 
878 		if (t3dp->mono_p)
879 			t3dp->colors = (XColor *) NULL;
880 		else
881 			if ((t3dp->colors = (XColor *) malloc(sizeof (*t3dp->colors) *
882 					(t3dp->ncolors + 1))) == NULL) {
883 				free_t3d_screen(mi, t3dp);
884 				return;
885 			}
886 		t3dp->cycle_p = has_writable_cells(
887 #ifdef STANDALONE
888 			screen, MI_VISUAL(mi)
889 #else
890 			mi
891 #endif
892 			);
893 		if (t3dp->cycle_p) {
894 			if (MI_IS_FULLRANDOM(mi)) {
895 				if (!NRAND(8))
896 					t3dp->cycle_p = False;
897 				else
898 					t3dp->cycle_p = True;
899 			} else {
900 				t3dp->cycle_p = cycle_p;
901 			}
902 		}
903 		if (!t3dp->mono_p) {
904 			if (!(LRAND() % 10))
905 				make_random_colormap(
906 #ifdef STANDALONE
907 					screen, MI_VISUAL(mi),
908 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
909 					True, True, &t3dp->cycle_p, True
910 #else
911 					mi,
912 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
913 					True, True, &t3dp->cycle_p
914 #endif
915 					);
916 			else if (!(LRAND() % 2))
917 				make_uniform_colormap(
918 #ifdef STANDALONE
919 					screen, MI_VISUAL(mi),
920 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
921 					True, &t3dp->cycle_p, True
922 #else
923 					mi,
924 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
925 					True, &t3dp->cycle_p
926 #endif
927 					);
928 			else
929 				make_smooth_colormap(
930 #ifdef STANDALONE
931 					screen, MI_VISUAL(mi),
932 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
933 					True, &t3dp->cycle_p, True
934 #else
935 					mi,
936 					t3dp->cmap, t3dp->colors, &t3dp->ncolors,
937 					True, &t3dp->cycle_p
938 #endif
939 					);
940 		}
941 		XInstallColormap(display, t3dp->cmap);
942 		if (t3dp->ncolors < 2) {
943 			t3dp->ncolors = 2;
944 			t3dp->no_colors = True;
945 		} else
946 			t3dp->no_colors = False;
947 		if (t3dp->ncolors <= 2)
948 			t3dp->mono_p = True;
949 
950 		if (t3dp->mono_p)
951 			t3dp->cycle_p = False;
952 
953 	}
954 
955    t3d_init_3d( mi );
956 
957    if (t3dp->zeit == NULL)
958      if ((t3dp->zeit = (struct tm *) malloc(sizeof(struct tm))) == NULL) {
959 	free_t3d_screen(mi, t3dp);
960 	return;
961      }
962 
963    t3d_init_kugel( mi );
964 
965    t3dp->startx = t3dp->width / 2;
966    t3dp->starty = t3dp->height / 2;
967    t3dp->scrnH2 = t3dp->startx;
968    t3dp->scrnW2 = t3dp->starty;
969    t3dp->vspeed=0;
970 
971    t3d_vektorprodukt( t3dp->x, t3dp->y, t3dp->v);
972    t3d_viewpoint( mi );
973 
974    MI_CLEARWINDOW(mi);
975 }
976 
977 ENTRYPOINT void
release_t3d(ModeInfo * mi)978 release_t3d(ModeInfo * mi)
979 {
980 	if (t3ds != NULL) {
981 		int         screen;
982 
983 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
984 			free_t3d_screen(mi, &t3ds[screen]);
985 		free(t3ds);
986 		t3ds = (t3dstruct *) NULL;
987 	}
988 }
989 
990 ENTRYPOINT void
draw_t3d(ModeInfo * mi)991 draw_t3d(ModeInfo * mi)
992 {
993 	Display    *display = MI_DISPLAY(mi);
994 	Window      window = MI_WINDOW(mi);
995 	double dtime;
996 	int button;
997 	t3dstruct *t3dp;
998 
999 	if (t3ds == NULL)
1000 		return;
1001 	t3dp = &t3ds[MI_SCREEN(mi)];
1002  	if (t3dp->zeit == NULL)
1003 		return;
1004 
1005 	if (t3dp->no_colors) {
1006 		free_t3d_screen(mi, t3dp);
1007 		init_t3d(mi);
1008 		return;
1009 	}
1010 
1011    MI_IS_DRAWN(mi) = True;
1012 
1013 /* Rotate colours */
1014    if (t3dp->cycle_p)
1015      {
1016 	rotate_colors(
1017 #ifdef STANDALONE
1018 		MI_SCREENPTR(mi),
1019 #else
1020 		display,
1021 #endif
1022 		t3dp->cmap, t3dp->colors, t3dp->ncolors, t3dp->direction);
1023 	if (!(LRAND() % 1000))
1024 	  t3dp->direction = -t3dp->direction;
1025      }
1026 
1027    t3d_vektorprodukt( t3dp->x, t3dp->y , t3dp->v);
1028 
1029    	t3dp->vnorm=sqrt(t3dp->v[0]*t3dp->v[0]+t3dp->v[1]*t3dp->v[1]+
1030 			 t3dp->v[2]*t3dp->v[2]);
1031 	t3dp->v[0]=t3dp->v[0]*norm/t3dp->vnorm;
1032 	t3dp->v[1]=t3dp->v[1]*norm/t3dp->vnorm;
1033 	t3dp->v[2]=t3dp->v[2]*norm/t3dp->vnorm;
1034 	t3dp->vnorm=sqrt(t3dp->x[0]*t3dp->x[0]+t3dp->x[1]*t3dp->x[1]+
1035 			 t3dp->x[2]*t3dp->x[2]);
1036 	t3dp->x[0]=t3dp->x[0]*norm/t3dp->vnorm;
1037 	t3dp->x[1]=t3dp->x[1]*norm/t3dp->vnorm;
1038 	t3dp->x[2]=t3dp->x[2]*norm/t3dp->vnorm;
1039 	t3dp->vnorm=sqrt(t3dp->y[0]*t3dp->y[0]+t3dp->y[1]*t3dp->y[1]+
1040 			 t3dp->y[2]*t3dp->y[2]);
1041 	t3dp->y[0]=t3dp->y[0]*norm/t3dp->vnorm;
1042 	t3dp->y[1]=t3dp->y[1]*norm/t3dp->vnorm;
1043 	t3dp->y[2]=t3dp->y[2]*norm/t3dp->vnorm;
1044 
1045    t3d_projektion( mi );
1046    t3d__sort ( mi , 0,t3dp->maxk-1);
1047 
1048    dtime= t3d_gettime();
1049 
1050    setink(MI_BLACK_PIXEL(mi));
1051    XFillRectangle(display, t3dp->buffer,t3dp->gc,0,0,t3dp->width,
1052 		  t3dp->height);
1053 
1054    	{
1055 	  int i;
1056 
1057 	  t3d_manipulate( mi , dtime);
1058 
1059 	  for (i=0;i<t3dp->maxk;i++)
1060 	    {
1061 	      if (t3dp->kugeln[i].d>0.0)
1062 		t3d_fill_kugel(i,t3dp->buffer,1 , mi );
1063 	    }
1064 	}
1065 
1066    XFlush(display);
1067 
1068    XCopyArea (display, t3dp->buffer, window, t3dp->gc, 0, 0, t3dp->width,
1069 	      t3dp->height, 0, 0);
1070 
1071    XFlush(display);
1072 
1073    if ( trackmouse )
1074      {
1075 	Window junk_win,in_win;
1076 	int junk;
1077 	unsigned int kb;
1078 
1079 	(void)(XQueryPointer (display, window, &junk_win, &in_win, &junk,
1080 			      &junk, &t3dp->px, &t3dp->py, &kb));
1081 	/* The following may have to much interference with the Xlockmore
1082 	 * event handling  (JJ) */
1083 	if ( (kb&Button2Mask) )
1084 	  {
1085 	     button = 2;
1086 	  }
1087 	else
1088 	  {
1089 	     if (kb&Button1Mask)
1090 	       {
1091 		  button = 1;
1092 	       }
1093 	     else
1094 	       {
1095 		  if (kb&Button3Mask)
1096 		    {
1097 		       button = 3;
1098 		    }
1099 		  else
1100 		    {
1101 		       button = 0;
1102 		    }
1103 	       }
1104 	  }
1105      }
1106    else
1107      {
1108 	t3dp->px = NRAND( t3dp->width );
1109         t3dp->py = NRAND( t3dp->height );
1110 	button = NRAND( 50 );
1111 	if ( button > 3 ) button = 0;
1112      }
1113 
1114    if ((t3dp->px>0)&&(t3dp->px<t3dp->width)&&(t3dp->py>0)&&
1115        (t3dp->py<t3dp->height) )
1116 	  {
1117 	    if ((t3dp->px !=t3dp->startx)&&( button == 2 ))
1118 	      {
1119 		t3d_turn(t3dp->y,t3dp->x,((double)(t3dp->px-t3dp->startx))/
1120 			 (8000*mag));
1121 	      }
1122 	    if ((t3dp->py !=t3dp->starty)&&( button == 2 ))
1123 	      {
1124 		t3d_turn(t3dp->x,t3dp->y,((double)(t3dp->py-t3dp->starty))/
1125 			 (-8000*mag));
1126 	      }
1127 	    if ( button == 1 )
1128 	      {
1129 		if (t3dp->vturn==0.0) t3dp->vturn=.005;
1130 		 else if (t3dp->vturn<2)  t3dp->vturn+=.01;
1131 		t3d_turn(t3dp->x,t3dp->v,.002*t3dp->vturn);
1132 		t3d_turn(t3dp->y,t3dp->v,.002*t3dp->vturn);
1133 	      }
1134 	    if ( button == 3 )
1135 	      {
1136 		if (t3dp->vturn==0.0) t3dp->vturn=.005;
1137 		 else if (t3dp->vturn<2) t3dp->vturn+=.01;
1138 		t3d_turn(t3dp->x,t3dp->v,-.002*t3dp->vturn);
1139 		t3d_turn(t3dp->y,t3dp->v,-.002*t3dp->vturn);
1140 	      }
1141 	  }
1142 	if (!( button == 1 )&&!( button == 3 ))
1143 	  t3dp->vturn=0;
1144 
1145 	t3dp->speed=t3dp->speed+t3dp->speed*t3dp->vspeed;
1146 	if ((t3dp->speed<0.0000001) &&(t3dp->vspeed>0.000001)) t3dp->speed=0.000001;
1147 	t3dp->vspeed=.1*t3dp->vspeed;
1148 	if (t3dp->speed>0.01) t3dp->speed=.01;
1149 	t3dp->a[0]=t3dp->a[0]+t3dp->speed*t3dp->v[0];
1150 	t3dp->a[1]=t3dp->a[1]+t3dp->speed*t3dp->v[1];
1151 	t3dp->a[2]=t3dp->a[2]+t3dp->speed*t3dp->v[2];
1152 }
1153 
1154 #ifndef STANDALONE
1155 ENTRYPOINT void
refresh_t3d(ModeInfo * mi)1156 refresh_t3d(ModeInfo * mi)
1157 {
1158 	MI_CLEARWINDOW(mi);
1159 }
1160 #endif
1161 
1162 XSCREENSAVER_MODULE ("T3d", t3d)
1163 
1164 #endif /* MODE_t3d */
1165