1 /* t3d -- Flying Balls Clock Demo
2 by Bernd Paysan , paysan@informatik.tu-muenchen.de
4 Copy, modify, and distribute T3D either under GPL version 2 or newer,
5 or under the standard MIT/X license notice.
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 !
12 4-Jan-99 jwz@jwz.org -- adapted to xscreensaver framework, to take advantage
13 of the command-line options provided by screenhack.c.
22 #include <time.h> /* for localtime() and gettimeofday() */
24 #include "screenhack.h"
39 #define MIN(i,j) ((i)<(j)?(i):(j))
41 #define kmax ((minutes?60:24))
42 /* Anzahl der Kugeln */
44 /* Werte in der Sinus-Tabelle */
45 /*-----------------------------------------------------------------*/
46 #define setink(inkcolor) \
47 XSetForeground (dpy,gc,inkcolor)
49 #define drawline(xx1,yy1,xx2,yy2) \
50 XDrawLine(dpy,win,gc,xx1,yy1,xx2,yy2)
52 #define drawseg(segments,nr_segments) \
53 XDrawSegments(dpy,win,gc,segments,nr_segments)
56 #define polyfill(ppts,pcount) \
57 XFillPolygon(dpy,win,gc,ppts,pcount,Convex,CoordModeOrigin)
60 #define frac(argument) argument-floor(argument)
63 #define ABS(x) ((x)<0.0 ? -(x) : (x))
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;
77 static kugeldat kugeln[100];
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];
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; */
93 static double hsvcycl=0.0;
94 static double movef =0.5, wobber=2.0, cycle=6.0;
98 /* static double sec; */
101 static XWindowAttributes xgwa;
106 /* static Font font; */
108 static int screen, scrnWidth = WIDTH, scrnHeight = HEIGHT;
109 static Pixmap buffer;
111 static int fastch=50;
114 # define sum1ton(a) (((a)*(a)+1)/2)
115 # define fastcw sum1ton(fastch)
116 static Pixmap fastcircles;
117 static Pixmap fastmask;
119 static XImage* fastcircles[maxfast];
120 static XImage* fastmask[maxfast];
122 static int fastdraw=0;
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;
137 struct timeval time1;
141 #ifdef GETTIMEOFDAY_TWO_ARGS
142 struct timezone zone1;
143 gettimeofday(&time1,&zone1);
145 gettimeofday(&time1);
147 lt = time1.tv_sec; /* avoid type cast lossage */
150 return (zeit->tm_sec+60*(zeit->tm_min+60*(zeit->tm_hour))
151 + time1.tv_usec*1.0E-6);
154 /* --------------------COLORMAP---------------------*/
157 hsv2rgb (double h, double s, double v, double *r, double *g, double *b)
159 h/=360.0; h=6*(h-floor(h));
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;
186 printf("HSV: %f %f %f to\nRGB: %f %f %f\n",h,s,v,*r,*g,*b);
191 changeColor (double r, double g, double b)
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);
205 XStoreColors (dpy, cmap, colors, 12);
209 initColor (double r, double g, double b)
212 unsigned long pixels[12];
215 cmap = xgwa.colormap;
217 if(hsvcycl!=0.0 && XAllocColorCells(dpy, cmap, 0, &dummy, 0, pixels, 12))
221 colors[n1].pixel=pixels[n1];
222 colors[n1].flags=DoRed | DoGreen | DoBlue;
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);
236 if (!(XAllocColor (dpy, cmap, &colors[n1]))) {
237 (void) fprintf (stderr, "Error: Cannot allocate colors\n");
246 /* ----------------WINDOW-------------------*/
255 XGetWindowAttributes (dpy, win, &xgwa);
256 scrnWidth = xgwa.width;
257 scrnHeight = xgwa.height;
260 float f = get_float_resource ("cycle", "Float");
261 if (f <= 0 || f > 60) f = 6.0;
264 movef = get_float_resource ("move", "Float");
265 wobber = get_float_resource ("wobble", "Float");
268 double magfac = get_float_resource ("mag", "Float");
270 fastch=(int)(fastch*magfac);
273 if (get_boolean_resource ("minutes", "Boolean")) {
274 minutes=1; maxk+=60-24;
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");
283 char *s = get_string_resource ("rgb", "RGB");
288 if (3 == sscanf (s, "%lf %lf %lf %c", &rr, &gg, &bb, &dummy))
289 r = rr, g = gg, b = bb;
293 s = get_string_resource ("hsv", "HSV");
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);
308 xgc=( XGCValues *) malloc(sizeof(XGCValues) );
309 xorgc=( XGCValues *) malloc(sizeof(XGCValues) );
310 xandgc=( XGCValues *) malloc(sizeof(XGCValues) );
312 screen = screen_number (xgwa.screen);
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);
322 buffer = XCreatePixmap (dpy, win, scrnWidth, scrnHeight,
326 printf("Time 3D drawing ");
329 puts("fast by Pixmap copy");
331 puts("fast by XImage copy");
339 fastcircles = XCreatePixmap (dpy, win, fastcw, fastch+1, xgwa.depth);
340 fastmask = XCreatePixmap (dpy, win, fastcw, fastch+1, xgwa.depth);
343 setink(BlackPixel (dpy, screen));
344 XFillRectangle (dpy, buffer , gc, 0, 0, scrnWidth, scrnHeight);
349 XFillRectangle (dpy, fastcircles, gc, 0, 0, fastcw, fastch+1);
350 XFillRectangle (dpy, fastmask , gc, 0, 0, fastcw, fastch+1);
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);
362 static void fill_kugel(int i, Pixmap buf, int setcol);
365 /*------------------------------------------------------------------*/
373 for(i=0; i<fastch; i++)
376 kugeln[i].r1=-((double) i)/2 -1;
377 kugeln[i].x1=sum1ton(i);
378 kugeln[i].y1=((double) i)/2 +1;
380 fill_kugel(i,fastcircles,1);
381 setink((1<<MIN(24,xgwa.depth))-1);
382 fill_kugel(i,fastmask,0);
384 kugeln[i].r1=-((double) i)/2 -1;
385 kugeln[i].x1=kugeln[i].y1=((double) i)/2 +1;
387 fill_kugel(i,buffer,1);
388 fastcircles[i]=XGetImage(dpy,buffer,0,0,i+2,i+2,(1<<planes)-1,ZPixmap);
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);
395 XFillRectangle (dpy, buffer , gc, 0, 0, scrnWidth, scrnHeight);
402 /* Zeiger zeichnen */
405 zeiger(double dist,double rad, double z, double sec, int *q)
408 double gratio=sqrt(2.0/(1.0+sqrt(5.0)));
414 kugeln[n].x=dist*cos(sec);
415 kugeln[n].y=-dist*sin(sec);
426 /*-----------------------------------------------------------------*
428 *-----------------------------------------------------------------*/
433 double i,l,/*xs,*/ys,zs,mod;
434 double /*persec,*/sec,min,hour;
437 sec=TWOPI*modf(k/60,&mod);
438 min=TWOPI*modf(k/3600,&mod);
439 hour=TWOPI*modf(k/43200,&mod);
441 l=TWOPI*modf(k/300,&mod);
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);
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);
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);
468 kugeln[n].r=2.0+cos(TWOPI*modf(k,&mod))/2;
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);
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));
485 /*------------------------------------------------------------------*/
487 t3d_sort(int l, int r)
497 while(kugeln[i].d>x) i++;
498 while(x>kugeln[j].d) j--;
501 ex=kugeln[i];kugeln[i]=kugeln[j];kugeln[j]=ex;
506 if (l<j) t3d_sort(l,j);
507 if (i<r) t3d_sort (i,r);
510 /*------------------------------------------------------------------*/
512 fill_kugel(int i, Pixmap buf, int setcol)
515 int m,col,inc=1,inr=3,d;
516 d=(int)((ABS(kugeln[i].r1)*2));
520 if(fastdraw && d<fastch)
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);
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);
537 if(ABS(kugeln[i].r1)<6.0) inr=9;
539 for (m=0;m<=28;m+=inr)
541 ra=kugeln[i].r1*sqrt(1-m*m/(28.0*28.0));
543 printf("Radius: %f\n",ra);
546 else if(-ra< 6.0) inc=8;
547 else if(-ra<20.0) inc=4;
548 else if(-ra<40.0) inc=2;
554 if (col>33) col=33; col/=3;
555 setink(colors[col].pixel);
561 for (n=0,nr=0;n<=sines-1;n+=inc,nr++)
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;
566 XFillPolygon(dpy,buf,gc,track,nr,Convex,CoordModeOrigin);
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);
578 /*------------------------------------------------------------------*/
602 for (i=0.0;n<sines;i+=TWOPI/sines,n++)
608 /*------------------------------------------------------------------*/
612 vektorprodukt(double feld1[], double feld2[], double feld3[])
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];
618 /*------------------------------------------------------------------*/
620 turn(double feld1[], double feld2[], double winkel)
623 double s,ca,sa,sx1,sx2,sx3;
625 vektorprodukt(feld1,feld2,temp);
627 s=feld1[0]*feld2[0]+feld1[1]*feld2[1]+feld1[2]*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;
637 /*------------------------------------------------------------------*/
639 /* 1: Blickrichtung v;3:Ebenenmittelpunkt m
640 double feld1[],feld3[]; */
648 zaehler=norm*norm*zoom;
650 /*------------------------------------------------------------------*/
654 double c1[3],c2[3],k[3],x1,y1;
655 double cno,cnorm/*,magnit*/;
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]);
669 cno=c2[0]*v[0]+c2[1]*v[1]+c2[2]*v[2];
671 if (cno<0) kugeln[i].d=-20.0;
674 kugeln[i].r1=(mag*zoom*kugeln[i].r/cnorm);
680 vektorprodukt(c2,c1,k);
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);
686 && (x1<scrnWidth+2000.0)
688 && (y1<scrnHeight+2000.0))
690 kugeln[i].x1=(int)x1;
691 kugeln[i].y1=(int)y1;
702 /*---------- event-handler ----------------*/
706 while (XEventsQueued (dpy, QueuedAfterReading))
710 XNextEvent (dpy, &event);
713 case ConfigureNotify:
714 if (event.xconfigure.width != scrnWidth ||
715 event.xconfigure.height != scrnHeight)
717 XFreePixmap (dpy, buffer);
718 scrnWidth = event.xconfigure.width;
719 scrnHeight = event.xconfigure.height;
720 buffer = XCreatePixmap (dpy, win, scrnWidth, scrnHeight,
732 KeySym kpr=XKeycodeToKeysym(dpy,event.xkey.keycode,0);
757 screenhack_handle_event (dpy, &event);
762 case ButtonPress: case ButtonRelease:
766 screenhack_handle_event (dpy, &event);
772 struct timeval timeout;
773 timeout.tv_sec=timewait/1000000;
774 timeout.tv_usec=timewait%1000000;
775 (void)select(0,0,0,0,&timeout);
780 /*-------------------------------------------------*/
782 char *progclass = "T3D";
784 char *defaults [] = {
785 ".background: black",
786 ".foreground: white",
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 },
816 screenhack (Display *d, Window w)
818 Window junk_win,in_win;
820 int px,py,junk/*,wai*/;
822 /* int act,act1,tc;*/
824 /* double var=0.0; */
825 int color=0/*, dir=1*/;
833 zeit=(struct tm *)malloc(sizeof(struct tm));
843 vektorprodukt(x,y,v);
846 setink (BlackPixel (dpy, screen));
847 XFillRectangle (dpy, win, gc, 0, 0, scrnWidth, scrnHeight);
848 XQueryPointer (dpy, win, &junk_win, &junk_win, &junk, &junk,
854 /*--------------- Zeichenteil --------------*/
858 vektorprodukt(x,y,v);
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;
880 color=(int)(64.0*(dtime/60-floor(dtime/60)))-32;
885 setink(colors[color/3].pixel);
888 setink(BlackPixel (dpy, screen));
890 XFillRectangle(dpy,buffer,gc,0,0,scrnWidth,scrnHeight);
900 fill_kugel(i,buffer,1);
906 /* manipulate(gettime());
908 if (var>=TWOPI) var=PI/500; */
914 dtime=hsvcycl*dtime/10.0+hue/360.0;
915 dtime=360*(dtime-floor(dtime));
917 hsv2rgb(dtime,sat,val,&r,&g,&b);
921 XCopyArea (dpy, buffer, win, gc, 0, 0, scrnWidth, scrnHeight, 0, 0);
924 /*-------------------------------------------------*/
929 (void)(XQueryPointer (dpy, win, &junk_win, &in_win, &junk, &junk,
932 if ((px>0)&&(px<scrnWidth)&&(py>0)&&(py<scrnHeight) )
934 if ((px !=startx)&&(kb&Button2Mask))
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]);*/
940 if ((py !=starty)&&(kb&Button2Mask))
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]);*/
946 if ((kb&Button1Mask))
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);
952 if ((kb&Button3Mask))
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);
959 if (!(kb&Button1Mask)&&!(kb&Button3Mask))
962 speed=speed+speed*vspeed;
963 if ((speed<0.0000001) &&(vspeed>0.000001)) speed=0.000001;
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];