xenocara/app/xlockmore/modes/t3d.c
2006-11-26 11:07:42 +00:00

1129 lines
27 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* t3d --- Flying Balls Clock Demo */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)t3d.c 5.0 2000/11/01 xlockmore";
#endif
/*-
* Copyright (c) 1998 Bernd Paysan , paysan@informatik.tu-muenchen.de.
*
* Copy, modify, and distribute T3D either under GPL version 2 or newer,
* or under the standard MIT/X license notice.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* partly based on flying balls demo by Georg Acher,
* acher@informatik.tu-muenchen.de
* (developed on HP9000/720 (55 MIPS,20 MFLOPS) )
*
* Todo for xlock:
* -Set default options right and make it more "random"
* -Add original colour scheme
* -Get trackmouse is working
* -Add some more options which were handled in the original by the XEvents.
* -Get working better in password window.
*
* Revision History:
* 01-Nov-2000: Allocation checks
* 26-Jan-2000: joukj@hrem.stm.tudelft.nl (Jouk Jansen) : adapted for
* xlockmore. Modified colour-schemes.
* 04-Jan-1999: jwz@jwz.org -- adapted to xscreensaver framework,
* to take advantage of the command-line options
* provided by screenhack.c.
*/
#ifdef WIN32
#include <sys/time.h>
#else
#include <time.h>
#endif /* WIN32 */
#define FASTDRAW
#define FASTCOPY
#undef USE_POLYGON
#ifdef STANDALONE
#define MODE_t3d
#define PROGCLASS "t3d"
#define HACK_INIT init_t3d
#define HACK_DRAW draw_t3d
#define t3d_opts xlockmore_opts
#define DEFAULTS "*delay: 10000 \n" \
"*cycles: 60000 \n" \
"*ncolors: 200 \n" \
"*mouse: False \n"
#define UNIFORM_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#include "color.h"
#endif /* STANDALONE */
#include <time.h>
#ifdef TIME_WITH_SYS_TIME /* for sco */
#include <sys/time.h>
#endif
#ifdef MODE_t3d
#define DEF_TRACKMOUSE "False"
#define DEF_MOVE "0.5"
#define DEF_WOBBLE "2.0"
#define DEF_MAG "10.0"
#define DEF_FAST "50"
#define DEF_MINUTES "False"
#define DEF_CYCLE "True"
#define PI M_PI
#define TWOPI 2*M_PI
#define MAXFAST 100
#define norm 20.0
#ifdef FASTCOPY
#define sum1ton(a) (((a)*(a)+1)/2)
#define fastcw sum1ton(fastch)
#endif
#undef ABS
#define ABS(x) ((x)<0.0 ? -(x) : (x))
/* Anzahl der Kugeln */
#define kmax ((t3dp->minutes?60:24))
/* Werte in der Sinus-Tabelle */
#define sines 52
#define setink(inkcolor) XSetForeground(display,t3dp->gc,inkcolor)
static Bool trackmouse , minutes , cycle_p;
static float move, wobble , mag;
static int fastch;
static XrmOptionDescRec opts[] =
{
{(char *) "-cycle", (char *) ".t3d.cycle", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+cycle", (char *) ".t3d.cycle", XrmoptionNoArg, (caddr_t) "off"},
{(char *) "-move", (char *) ".t3d.move", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-wobble", (char *) ".t3d.wobble", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-mag", (char *) ".t3d.mag", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-fast", (char *) ".t3d.fast", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-minutes", (char *) ".t3d.minutes", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+minutes", (char *) ".t3d.minutes", XrmoptionNoArg, (caddr_t) "off"},
{(char *) "-trackmouse", (char *) ".t3d.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+trackmouse", (char *) ".t3d.trackmouse", XrmoptionNoArg, (caddr_t) "off"}
};
static argtype vars[] =
{
{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool},
{(void *) & move, (char *) "move", (char *) "Move", (char *) DEF_MOVE, t_Float},
{(void *) & wobble, (char *) "wobble", (char *) "Wobble", (char *) DEF_WOBBLE, t_Float},
{(void *) & mag, (char *) "mag", (char *) "Magnification", (char *) DEF_MAG, t_Float},
{(void *) & fastch, (char *) "fast", (char *) "Fast", (char *) DEF_FAST, t_Int},
{(void *) & minutes, (char *) "minutes", (char *) "Minutes", (char *) DEF_MINUTES, t_Bool},
{(void *) & trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool}
};
static OptionStruct desc[] =
{
{(char *) "-/+cycle", (char *) "turn on/off colour cycling"},
{(char *) "-move num", (char *) "Move speed"},
{(char *) "-wobble num", (char *) "Wobble speed"},
{(char *) "-mag num", (char *) "Magnification factor"},
{(char *) "-fast num", (char *) "Fast"},
{(char *) "-/+minutes", (char *) "turn on/off minutes"},
{(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"}
};
ModeSpecOpt t3d_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct t3d_description =
{"t3d", "init_t3d", "draw_t3d", "release_t3d",
"refresh_t3d", "init_t3d", (char *) NULL, &t3d_opts,
250000, 1000, 60000 , 1, 64, 1.0, "",
"Flying Balls Clock Demo", 0, NULL};
#endif
typedef struct {
double x,y,z,r,d,r1;
int x1,y1;
} kugeldat;
typedef struct {
Cursor cursor;
double cycles , movef , wobber , a[3] , x[3] , y[3] , zoom , speed , vspeed;
double sinus[sines] , cosinus[sines] , v[3] , am[3] , zaehler , vnorm;
double vturn;
int fastch , minutes , maxk;
GC gc;
Pixmap buffer;
#ifdef FASTCOPY
GC orgc , andgc;
Pixmap fastcircles , fastmask;
#else
XImage* fastcircles[maxfast] , fastmask[maxfast];
#endif
Colormap cmap;
XColor *colors;
int width, height, depth;
int ncolors , fastdraw , scrnW2, scrnH2, startx , starty , px , py;
Bool cycle_p, mono_p, no_colors;
unsigned long blackpixel, whitepixel, fg, bg;
int direction;
struct tm *zeit;
kugeldat kugeln[100];
int color_offset;
ModeInfo *mi;
} t3dstruct;
static t3dstruct *t3ds = (t3dstruct *) NULL;
static void
t3d_zeiger( ModeInfo* mi , double dist,double rad, double z, double sec,
int *q)
/* Zeiger zeichnen */
{
int i,n;
double gratio=sqrt(2.0/(1.0+sqrt(5.0)));
t3dstruct *t3dp;
t3dp = &t3ds[MI_SCREEN(mi)];
n = *q;
for(i=0;i<3;i++)
{
t3dp->kugeln[n].x=dist*cos(sec);
t3dp->kugeln[n].y=-dist*sin(sec);
t3dp->kugeln[n].z=z;
t3dp->kugeln[n].r=rad;
n++;
dist += rad;
rad = rad*gratio;
}
*q = n;
}
static void
t3d_manipulate( ModeInfo* mi , double k)
/*-----------------------------------------------------------------*
* Uhr zeichnen *
*-----------------------------------------------------------------*/
{
double i,l,/*xs,*/ys,zs,mod;
double /*persec,*/sec,min,hour;
int n;
t3dstruct *t3dp;
t3dp = &t3ds[MI_SCREEN(mi)];
sec=TWOPI*modf(k/60,&mod);
min=TWOPI*modf(k/3600,&mod);
hour=TWOPI*modf(k/43200,&mod);
l=TWOPI*modf(k/300,&mod);
i=0.0;
for (n=0;n<kmax;n++)
{
t3dp->kugeln[n].x=4.0*sin(i);
t3dp->kugeln[n].y=4.0*cos(i);
t3dp->kugeln[n].z=t3dp->wobber* /* (sin(floor(2+2*l/(PI))*i)*sin(2*l)); */
cos((i-sec)*floor(2+5*l/(PI)))*sin(5*l);
if(t3dp->minutes)
{
t3dp->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
((n % 5!=0) ? 0.3 : 0.6)*
((n % 15 ==0) ? 1.25 : .75);
}
else
{
t3dp->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */
((n & 1) ? 0.5 : 1.0)*
((n % 6==0) ? 1.25 : .75);
}
i+=TWOPI/kmax;
}
t3dp->kugeln[n].x=0.0;
t3dp->kugeln[n].y=0.0;
t3dp->kugeln[n].z=0.0;
t3dp->kugeln[n].r=2.0+cos(TWOPI*modf(k,&mod))/2;
n++;
t3d_zeiger( mi , 2.0,0.75,-2.0,sec,&n);
t3d_zeiger( mi , 1.0,1.0,-1.5,min,&n);
t3d_zeiger( mi , 0.0,1.5,-1.0,hour,&n);
for(n=0;n<t3dp->maxk;n++)
{
double cycle = (double) MI_CYCLES( mi );
ys=t3dp->kugeln[n].y*cos(t3dp->movef*sin(cycle*sec))+
t3dp->kugeln[n].z*sin(t3dp->movef*sin(cycle*sec));
zs=-t3dp->kugeln[n].y*sin(t3dp->movef*sin(cycle*sec))+
t3dp->kugeln[n].z*cos(t3dp->movef*sin(cycle*sec));
t3dp->kugeln[n].y=ys;
t3dp->kugeln[n].z=zs;
}
}
static double
t3d_gettime (void)
{
struct timeval time1;
struct tm *zeit;
time_t lt;
#if HAVE_GETTIMEOFDAY
GETTIMEOFDAY(&time1);
lt = time1.tv_sec; /* avoid type cast lossage */
#else
lt = NULL;
#endif
zeit = localtime((const time_t *) &lt);
return (zeit->tm_sec+60*(zeit->tm_min+60*(zeit->tm_hour))
+ time1.tv_usec*1.0E-6);
}
static void
t3d__sort( ModeInfo* mi , int l, int r)
{
int i,j;
kugeldat ex;
double x;
t3dstruct *t3dp;
t3dp = &t3ds[MI_SCREEN(mi)];
i=l;j=r;
x=t3dp->kugeln[(l+r)/2].d;
for (;;) {
while(t3dp->kugeln[i].d>x) i++;
while(x>t3dp->kugeln[j].d) j--;
if (i<=j)
{
ex=t3dp->kugeln[i];
t3dp->kugeln[i]=t3dp->kugeln[j];
t3dp->kugeln[j]=ex;
i++;j--;
}
if (i>j) break;
}
if (l<j) t3d__sort( mi , l,j);
if (i<r) t3d__sort ( mi , i,r);
}
static void
t3d_vektorprodukt(double feld1[], double feld2[], double feld3[])
{
feld3[0]=feld1[1]*feld2[2]-feld1[2]*feld2[1];
feld3[1]=feld1[2]*feld2[0]-feld1[0]*feld2[2];
feld3[2]=feld1[0]*feld2[1]-feld1[1]*feld2[0];
}
static void
t3d_turn(double feld1[], double feld2[], double winkel)
{
double temp[3];
double s,ca,sa,sx1,sx2,sx3;
t3d_vektorprodukt(feld1,feld2,temp);
s=feld1[0]*feld2[0]+feld1[1]*feld2[1]+feld1[2]*feld2[2];
sx1=s*feld2[0];
sx2=s*feld2[1];
sx3=s*feld2[2];
sa=sin(winkel);ca=cos(winkel);
feld1[0]=ca*(feld1[0]-sx1)+sa*temp[0]+sx1;
feld1[1]=ca*(feld1[1]-sx2)+sa*temp[1]+sx2;
feld1[2]=ca*(feld1[2]-sx3)+sa*temp[2]+sx3;
}
static void
t3d_projektion( ModeInfo* mi)
{
double c1[3],c2[3],k[3],x_1,y_1;
double cno,cnorm/*,magnit*/;
int i;
t3dstruct *t3dp;
t3dp = &t3ds[MI_SCREEN(mi)];
for (i=0;i<t3dp->maxk;i++)
{
c1[0]=t3dp->kugeln[i].x-t3dp->a[0];
c1[1]=t3dp->kugeln[i].y-t3dp->a[1];
c1[2]=t3dp->kugeln[i].z-t3dp->a[2];
cnorm=sqrt(c1[0]*c1[0]+c1[1]*c1[1]+c1[2]*c1[2]);
c2[0]=c1[0];
c2[1]=c1[1];
c2[2]=c1[2];
cno=c2[0]*t3dp->v[0]+c2[1]*t3dp->v[1]+c2[2]*t3dp->v[2];
t3dp->kugeln[i].d=cnorm;
if (cno<0) t3dp->kugeln[i].d=-20.0;
t3dp->kugeln[i].r1=(mag*t3dp->zoom*t3dp->kugeln[i].r/cnorm);
c2[0]=t3dp->v[0]/cno;
c2[1]=t3dp->v[1]/cno;
c2[2]=t3dp->v[2]/cno;
t3d_vektorprodukt(c2,c1,k);
x_1=(t3dp->startx+(t3dp->x[0]*k[0]+t3dp->x[1]*k[1]+t3dp->x[2]*k[2])*mag);
y_1=(t3dp->starty-(t3dp->y[0]*k[0]+t3dp->y[1]*k[1]+t3dp->y[2]*k[2])*mag);
if( (x_1>-2000.0)
&& (x_1<t3dp->width+2000.0)
&& (y_1>-2000.0)
&& (y_1<t3dp->height+2000.0))
{
t3dp->kugeln[i].x1=(int)x_1;
t3dp->kugeln[i].y1=(int)y_1;
}
else
{
t3dp->kugeln[i].x1=0;
t3dp->kugeln[i].y1=0;
t3dp->kugeln[i].d=-20.0;
}
}
}
static void
t3d_viewpoint( ModeInfo* mi)
/* 1: Blickrichtung v;3:Ebenenmittelpunkt m
double feld1[],feld3[]; */
{
t3dstruct *t3dp;
t3dp = &t3ds[MI_SCREEN(mi)];
t3dp->am[0]=-t3dp->zoom*t3dp->v[0];
t3dp->am[1]=-t3dp->zoom*t3dp->v[1];
t3dp->am[2]=-t3dp->zoom*t3dp->v[2];
t3dp->zaehler=norm*norm* t3dp->zoom;
}
static void
t3d_fill_kugel(int i, Pixmap buf, int setcol , ModeInfo* mi )
{
t3dstruct *t3dp;
Display *display = MI_DISPLAY(mi);
double ra;
int m,inr=3,d;
#ifdef USE_POLYGON
int inc = 1;
#endif
t3dp = &t3ds[MI_SCREEN(mi)];
d=(int)((ABS(t3dp->kugeln[i].r1)*2));
if (d==0) d=1;
# ifdef FASTDRAW
if(t3dp->fastdraw && d<t3dp->fastch)
{
# ifdef FASTCOPY
XCopyArea(display, t3dp->fastmask, buf, t3dp->andgc, sum1ton(d)-(d+1)/2,
1,d,d, (int)(t3dp->kugeln[i].x1)-d/2,
(int)(t3dp->kugeln[i].y1)-d/2);
XCopyArea(display, t3dp->fastcircles, buf, t3dp->orgc,
sum1ton(d)-(d+1)/2, 1,d,d, (int)(t3dp->kugeln[i].x1)-d/2,
(int)(t3dp->kugeln[i].y1)-d/2);
#else
XPutImage(display, buf, t3dp->andgc, t3dp->fastmask[d-1], 0, 0,
(int)(t3dp->kugeln[i].x1)-d/2, (int)(t3dp->kugeln[i].y1)-d/2,
d, d);
XPutImage(display, buf, t3dp->orgc, t3dp->fastcircles[d-1], 0, 0,
(int)(t3dp->kugeln[i].x1)-d/2, (int)(t3dp->kugeln[i].y1)-d/2,
d, d);
# endif
}
else
#endif
{
if(ABS(t3dp->kugeln[i].r1)<6.0) inr=9;
for (m=0;m<=28;m+=inr)
{
ra=t3dp->kugeln[i].r1*sqrt(1-m*m/(28.0*28.0));
#ifdef USE_POLYGON
if(-ra< 3.0) inc=14;
else if(-ra< 6.0) inc=8;
else if(-ra<20.0) inc=4;
else if(-ra<40.0) inc=2;
#endif
if(setcol)
{
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
setink(t3dp->colors[m].pixel);
} else if (MI_NPIXELS(mi) <= 2) {
if ((m + t3dp->color_offset) % 2)
setink(MI_WHITE_PIXEL(mi));
else
setink(MI_BLACK_PIXEL(mi));
} else {
setink(MI_PIXEL(mi, ((m + t3dp->color_offset) % 29) * MI_NPIXELS(mi) / 29));
}
}
#ifdef USE_POLYGON
{
int n, nr;
for (n=0,nr=0;n<=sines-1;n+=inc,nr++)
{
track[nr].x=t3dp->kugeln[i].x1+(int)(ra*t3dp->sinus[n])+
(t3dp->kugeln[i].r1-ra)/2;
track[nr].y=t3dp->kugeln[i].y1+(int)(ra*t3dp->cosinus[n])+
(t3dp->kugeln[i].r1-ra)/2;
}
XFillPolygon(display,buf,t3dp->gc,track,nr,Convex,CoordModeOrigin);
}
#else /* Use XFillArc */
XFillArc(display, buf, t3dp->gc,
(int)(t3dp->kugeln[i].x1+(t3dp->kugeln[i].r1+ra)/2),
(int)(t3dp->kugeln[i].y1+(t3dp->kugeln[i].r1+ra)/2),
(int)-(2*ra+1), (int)-(2*ra+1), 0, 360*64);
#endif
}
}
}
static void
t3d_init_kugel( ModeInfo* mi )
{
t3dstruct *t3dp;
#ifdef FASTDRAW
Display *display = MI_DISPLAY(mi);
int i;
t3dp = &t3ds[MI_SCREEN(mi)];
for(i=0; i<t3dp->fastch; i++)
{
# ifdef FASTCOPY
t3dp->kugeln[i].r1=-((double) i)/2 -1;
t3dp->kugeln[i].x1=sum1ton(i);
t3dp->kugeln[i].y1=i/2 +1;
t3d_fill_kugel(i,t3dp->fastcircles,1 , mi );
/* setink((1<<MIN(24,t3dp->depth))-1);*/
setink(MI_BLACK_PIXEL(mi));
t3d_fill_kugel(i,t3dp->fastmask,0 , mi );
# else
t3dp->kugeln[i].r1=-((double) i)/2 -1;
t3dp->kugeln[i].x1=t3dp->kugeln[i].y1=i/2 +1;
t3d_fill_kugel(i,t3dp->buffer,1 , mi );
t3dp->fastcircles[i]=XGetImage(display,t3dp->buffer,0,0,i+2,i+2,
(1<<t3dp->depth)-1, ZPixmap);
/* setink((1<<MIN(24,t3dp->depth))-1); */
setink(MI_WHITE_PIXEL(mi));
t3d_fill_kugel(i,t3dp->buffer,0 , mi );
t3dp->fastmask[i]=XGetImage(display,t3dp->buffer,0,0,i+2,i+2,
(1<<t3dp->depth)-1,ZPixmap);
setink(MI_BLACK_PIXEL(mi));
XFillRectangle (display, t3dp->buffer , t3dp->gc, 0, 0,
t3dp->width, t3dp->height);
# endif
}
t3dp->fastdraw=1;
#endif
}
static void
t3d_init_3d( ModeInfo* mi )
{
t3dstruct *t3dp;
double i;
int n=0;
t3dp = &t3ds[MI_SCREEN(mi)];
t3dp->a[0]=0.0;
t3dp->a[1]=0.0;
t3dp->a[2]=-10.0;
t3dp->x[0]=10.0;
t3dp->x[1]=0.0;
t3dp->x[2]=0.0;
t3dp->y[0]=0.0;
t3dp->y[1]=10.0;
t3dp->y[2]=0.0;
t3dp->zoom=-10.0;
t3dp->speed=.0;
for (i=0.0;n<sines;i+=TWOPI/sines,n++)
{
t3dp->sinus[n]=sin(i);
t3dp->cosinus[n]=cos(i);
}
}
static void
free_t3d(Display *display, t3dstruct *t3dp)
{
ModeInfo *mi = t3dp->mi;
if (t3dp->cursor != None) {
XFreeCursor(display, t3dp->cursor);
t3dp->cursor = None;
}
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
MI_WHITE_PIXEL(mi) = t3dp->whitepixel;
MI_BLACK_PIXEL(mi) = t3dp->blackpixel;
#ifndef STANDALONE
MI_FG_PIXEL(mi) = t3dp->fg;
MI_BG_PIXEL(mi) = t3dp->bg;
#endif
if (t3dp->colors != NULL) {
if (t3dp->ncolors && !t3dp->no_colors)
free_colors(display, t3dp->cmap, t3dp->colors, t3dp->ncolors);
free(t3dp->colors);
t3dp->colors = (XColor *) NULL;
}
if (t3dp->cmap != None) {
XFreeColormap(display, t3dp->cmap);
t3dp->cmap = None;
}
}
if (t3dp->buffer != None) {
XFreePixmap(display, t3dp->buffer);
t3dp->buffer = None;
}
if (t3dp->gc != None) {
XFreeGC(display, t3dp->gc);
t3dp->gc = None;
}
#ifdef FASTCOPY
if (t3dp->orgc != None) {
XFreeGC(display, t3dp->orgc);
t3dp->orgc = None;
}
if (t3dp->andgc != None) {
XFreeGC(display, t3dp->andgc);
t3dp->andgc = None;
}
if (t3dp->fastcircles != None) {
XFreePixmap(display, t3dp->fastcircles);
t3dp->fastcircles = None;
}
if (t3dp->fastmask != None) {
XFreePixmap(display, t3dp->fastmask);
t3dp->fastmask = None;
}
#endif
if (t3dp->zeit != NULL) {
free(t3dp->zeit);
t3dp->zeit = (struct tm *) NULL;
}
}
static Bool
t3d_initialize( ModeInfo* mi )
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
t3dstruct *t3dp;
XGCValues xgcv;
t3dp = &t3ds[MI_SCREEN(mi)];
t3dp->cycles = MI_CYCLES( mi ) / 6000.0;
if ( t3dp->cycles <= 1.0 )
t3dp->cycles = 10.0;
t3dp->movef = (double) move;
t3dp->wobber = (double) wobble;
t3dp->fastch = (int) (fastch * mag);
if ( t3dp->fastch > MAXFAST )
t3dp->fastch = MAXFAST;
if ( minutes )
{
t3dp->minutes = 1;
t3dp->maxk = 70;
}
else
{
t3dp->minutes = 0;
t3dp->maxk = 34;
}
xgcv.foreground = MI_WHITE_PIXEL(mi);
if ((t3dp->gc = XCreateGC (display, window, GCForeground, &xgcv)) == None) {
free_t3d(display, t3dp);
return False;
}
#ifdef FASTDRAW
xgcv.function = GXor;
if ((t3dp->orgc = XCreateGC (display, window, GCFunction | GCForeground,
&xgcv)) == None) {
free_t3d(display, t3dp);
return False;
}
xgcv.function = GXandInverted;
if ((t3dp->andgc = XCreateGC (display, window, GCFunction | GCForeground,
&xgcv)) == None) {
free_t3d(display, t3dp);
return False;
}
#endif
if (MI_IS_VERBOSE(mi))
{
(void) printf("Time 3D drawing ");
#ifdef FASTDRAW
# ifdef FASTCOPY
(void) puts("fast by Pixmap copy");
# else
(void) puts("fast by XImage copy");
# endif
#else
(void) puts("slow");
#endif
}
#ifdef FASTCOPY
if (((t3dp->fastcircles = XCreatePixmap (display, window,
fastcw, t3dp->fastch+1, t3dp->depth)) == None) ||
((t3dp->fastmask = XCreatePixmap (display, window,
fastcw, t3dp->fastch+1, t3dp->depth)) == None)) {
free_t3d(display, t3dp);
return False;
}
#endif
setink(MI_BLACK_PIXEL(mi));
XFillRectangle (display, t3dp->buffer , t3dp->gc, 0, 0, t3dp->width,
t3dp->height);
#ifdef FASTCOPY
setink(MI_BLACK_PIXEL(mi));
XFillRectangle (display, t3dp->fastcircles, t3dp->gc, 0, 0, fastcw,
t3dp->fastch+1);
XFillRectangle (display, t3dp->fastmask , t3dp->gc, 0, 0, fastcw,
t3dp->fastch+1);
#endif
if (MI_IS_VERBOSE(mi))
{
(void) printf("move\t%.2f\nwobber\t%.2f\nmag\t%.2f\n",
t3dp->movef, t3dp->wobber, mag );
(void) printf("fast\t%i\nmarks\t%i\n", t3dp->fastch, t3dp->maxk);
}
return True;
}
#ifndef STANDALONE
extern char *background;
extern char *foreground;
#endif
void
init_t3d(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
t3dstruct *t3dp;
if (t3ds == NULL) {
if ((t3ds = (t3dstruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (t3dstruct))) == NULL)
return;
}
t3dp = &t3ds[MI_SCREEN(mi)];
t3dp->mi = mi;
if (trackmouse && !t3dp->cursor) { /* Create an invisible cursor */
Pixmap bit;
XColor black;
black.red = 0;
black.green = 0;
black.blue = 0;
black.flags = DoRed | DoGreen | DoBlue;
if ((bit = XCreatePixmapFromBitmapData(display, window,
(char *) "\000", 1, 1, MI_BLACK_PIXEL(mi),
MI_BLACK_PIXEL(mi), 1)) == None) {
free_t3d(display, t3dp);
return;
}
if ((t3dp->cursor = XCreatePixmapCursor(display, bit, bit,
&black, &black, 0, 0)) == None) {
XFreePixmap(display, bit);
free_t3d(display, t3dp);
return;
}
XFreePixmap(display, bit);
}
XDefineCursor(display, window, t3dp->cursor);
t3dp->width = MI_WIDTH(mi);
t3dp->height = MI_HEIGHT(mi);
t3dp->depth = MI_DEPTH(mi);
if (t3dp->buffer != None) {
XFreePixmap(display, t3dp->buffer);
t3dp->buffer = None;
}
if ((t3dp->buffer = XCreatePixmap (display, window,
t3dp->width, t3dp->height, t3dp->depth)) == None) {
free_t3d(display, t3dp);
return;
}
/* Initialization */
if (t3dp->gc == None) {
if (!t3d_initialize(mi))
return;
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2)
{
XColor color;
#ifndef STANDALONE
t3dp->fg = MI_FG_PIXEL(mi);
t3dp->bg = MI_BG_PIXEL(mi);
#endif
t3dp->blackpixel = MI_BLACK_PIXEL(mi);
t3dp->whitepixel = MI_WHITE_PIXEL(mi);
if ((t3dp->cmap = XCreateColormap(display, window, MI_VISUAL(mi),
AllocNone)) == None) {
free_t3d(display, t3dp);
return;
}
XSetWindowColormap(display, window, t3dp->cmap);
(void) XParseColor(display, t3dp->cmap, "black", &color);
(void) XAllocColor(display, t3dp->cmap, &color);
MI_BLACK_PIXEL(mi) = color.pixel;
(void) XParseColor(display, t3dp->cmap, "white", &color);
(void) XAllocColor(display, t3dp->cmap, &color);
MI_WHITE_PIXEL(mi) = color.pixel;
#ifndef STANDALONE
(void) XParseColor(display, t3dp->cmap, background, &color);
(void) XAllocColor(display, t3dp->cmap, &color);
MI_BG_PIXEL(mi) = color.pixel;
(void) XParseColor(display, t3dp->cmap, foreground, &color);
(void) XAllocColor(display, t3dp->cmap, &color);
MI_FG_PIXEL(mi) = color.pixel;
#endif
t3dp->colors = (XColor *) NULL;
t3dp->ncolors = 0;
}
}
t3dp->color_offset = NRAND(29);
/*Set up t2d data */
t3dp->direction = (LRAND() & 1) ? 1 : -1;
t3dp->fastdraw = 0;
t3dp->vturn = 0.0;
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
/* Set up colour map */
if (t3dp->colors != NULL) {
if (t3dp->ncolors && !t3dp->no_colors)
free_colors(display, t3dp->cmap, t3dp->colors, t3dp->ncolors);
free(t3dp->colors);
t3dp->colors = (XColor *) NULL;
}
t3dp->ncolors = MI_NCOLORS(mi);
if (t3dp->ncolors < 2)
t3dp->ncolors = 2;
if (t3dp->ncolors <= 2)
t3dp->mono_p = True;
else
t3dp->mono_p = False;
if (t3dp->mono_p)
t3dp->colors = (XColor *) NULL;
else
if ((t3dp->colors = (XColor *) malloc(sizeof (*t3dp->colors) *
(t3dp->ncolors + 1))) == NULL) {
free_t3d(display, t3dp);
return;
}
t3dp->cycle_p = has_writable_cells(mi);
if (t3dp->cycle_p) {
if (MI_IS_FULLRANDOM(mi)) {
if (!NRAND(8))
t3dp->cycle_p = False;
else
t3dp->cycle_p = True;
} else {
t3dp->cycle_p = cycle_p;
}
}
if (!t3dp->mono_p) {
if (!(LRAND() % 10))
make_random_colormap(
#ifdef STANDALONE
MI_DISPLAY(mi), MI_WINDOW(mi),
#else
mi,
#endif
t3dp->cmap, t3dp->colors, &t3dp->ncolors,
True, True, &t3dp->cycle_p);
else if (!(LRAND() % 2))
make_uniform_colormap(
#ifdef STANDALONE
MI_DISPLAY(mi), MI_WINDOW(mi),
#else
mi,
#endif
t3dp->cmap, t3dp->colors, &t3dp->ncolors,
True, &t3dp->cycle_p);
else
make_smooth_colormap(
#ifdef STANDALONE
MI_DISPLAY(mi), MI_WINDOW(mi),
#else
mi,
#endif
t3dp->cmap, t3dp->colors, &t3dp->ncolors,
True, &t3dp->cycle_p);
}
XInstallColormap(display, t3dp->cmap);
if (t3dp->ncolors < 2) {
t3dp->ncolors = 2;
t3dp->no_colors = True;
} else
t3dp->no_colors = False;
if (t3dp->ncolors <= 2)
t3dp->mono_p = True;
if (t3dp->mono_p)
t3dp->cycle_p = False;
}
t3d_init_3d( mi );
if (t3dp->zeit == NULL)
if ((t3dp->zeit = (struct tm *) malloc(sizeof(struct tm))) == NULL) {
free_t3d(display, t3dp);
return;
}
t3d_init_kugel( mi );
t3dp->startx = t3dp->width / 2;
t3dp->starty = t3dp->height / 2;
t3dp->scrnH2 = t3dp->startx;
t3dp->scrnW2 = t3dp->starty;
t3dp->vspeed=0;
t3d_vektorprodukt( t3dp->x, t3dp->y, t3dp->v);
t3d_viewpoint( mi );
MI_CLEARWINDOW(mi);
}
void
release_t3d(ModeInfo * mi)
{
if (t3ds != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_t3d(MI_DISPLAY(mi), &t3ds[screen]);
free(t3ds);
t3ds = (t3dstruct *) NULL;
}
}
void
draw_t3d(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
double dtime;
int button;
t3dstruct *t3dp;
if (t3ds == NULL)
return;
t3dp = &t3ds[MI_SCREEN(mi)];
if (t3dp->zeit == NULL)
return;
if (t3dp->no_colors) {
free_t3d(display, t3dp);
init_t3d(mi);
return;
}
MI_IS_DRAWN(mi) = True;
/* Rotate colours */
if (t3dp->cycle_p)
{
rotate_colors(display, t3dp->cmap, t3dp->colors, t3dp->ncolors,
t3dp->direction);
if (!(LRAND() % 1000))
t3dp->direction = -t3dp->direction;
}
t3d_vektorprodukt( t3dp->x, t3dp->y , t3dp->v);
t3dp->vnorm=sqrt(t3dp->v[0]*t3dp->v[0]+t3dp->v[1]*t3dp->v[1]+
t3dp->v[2]*t3dp->v[2]);
t3dp->v[0]=t3dp->v[0]*norm/t3dp->vnorm;
t3dp->v[1]=t3dp->v[1]*norm/t3dp->vnorm;
t3dp->v[2]=t3dp->v[2]*norm/t3dp->vnorm;
t3dp->vnorm=sqrt(t3dp->x[0]*t3dp->x[0]+t3dp->x[1]*t3dp->x[1]+
t3dp->x[2]*t3dp->x[2]);
t3dp->x[0]=t3dp->x[0]*norm/t3dp->vnorm;
t3dp->x[1]=t3dp->x[1]*norm/t3dp->vnorm;
t3dp->x[2]=t3dp->x[2]*norm/t3dp->vnorm;
t3dp->vnorm=sqrt(t3dp->y[0]*t3dp->y[0]+t3dp->y[1]*t3dp->y[1]+
t3dp->y[2]*t3dp->y[2]);
t3dp->y[0]=t3dp->y[0]*norm/t3dp->vnorm;
t3dp->y[1]=t3dp->y[1]*norm/t3dp->vnorm;
t3dp->y[2]=t3dp->y[2]*norm/t3dp->vnorm;
t3d_projektion( mi );
t3d__sort ( mi , 0,t3dp->maxk-1);
dtime= t3d_gettime();
setink(MI_BLACK_PIXEL(mi));
XFillRectangle(display, t3dp->buffer,t3dp->gc,0,0,t3dp->width,
t3dp->height);
{
int i;
t3d_manipulate( mi , dtime);
for (i=0;i<t3dp->maxk;i++)
{
if (t3dp->kugeln[i].d>0.0)
t3d_fill_kugel(i,t3dp->buffer,1 , mi );
}
}
XFlush(display);
XCopyArea (display, t3dp->buffer, window, t3dp->gc, 0, 0, t3dp->width,
t3dp->height, 0, 0);
XFlush(display);
if ( trackmouse )
{
Window junk_win,in_win;
int junk;
unsigned int kb;
(void)(XQueryPointer (display, window, &junk_win, &in_win, &junk,
&junk, &t3dp->px, &t3dp->py, &kb));
/* The following may have to much interference with the Xlockmore
* event handling (JJ) */
if ( (kb&Button2Mask) )
{
button = 2;
}
else
{
if (kb&Button1Mask)
{
button = 1;
}
else
{
if (kb&Button3Mask)
{
button = 3;
}
else
{
button = 0;
}
}
}
}
else
{
t3dp->px = NRAND( t3dp->width );
t3dp->py = NRAND( t3dp->height );
button = NRAND( 50 );
if ( button > 3 ) button = 0;
}
if ((t3dp->px>0)&&(t3dp->px<t3dp->width)&&(t3dp->py>0)&&
(t3dp->py<t3dp->height) )
{
if ((t3dp->px !=t3dp->startx)&&( button == 2 ))
{
t3d_turn(t3dp->y,t3dp->x,((double)(t3dp->px-t3dp->startx))/
(8000*mag));
}
if ((t3dp->py !=t3dp->starty)&&( button == 2 ))
{
t3d_turn(t3dp->x,t3dp->y,((double)(t3dp->py-t3dp->starty))/
(-8000*mag));
}
if ( button == 1 )
{
if (t3dp->vturn==0.0) t3dp->vturn=.005;
else if (t3dp->vturn<2) t3dp->vturn+=.01;
t3d_turn(t3dp->x,t3dp->v,.002*t3dp->vturn);
t3d_turn(t3dp->y,t3dp->v,.002*t3dp->vturn);
}
if ( button == 3 )
{
if (t3dp->vturn==0.0) t3dp->vturn=.005;
else if (t3dp->vturn<2) t3dp->vturn+=.01;
t3d_turn(t3dp->x,t3dp->v,-.002*t3dp->vturn);
t3d_turn(t3dp->y,t3dp->v,-.002*t3dp->vturn);
}
}
if (!( button == 1 )&&!( button == 3 ))
t3dp->vturn=0;
t3dp->speed=t3dp->speed+t3dp->speed*t3dp->vspeed;
if ((t3dp->speed<0.0000001) &&(t3dp->vspeed>0.000001)) t3dp->speed=0.000001;
t3dp->vspeed=.1*t3dp->vspeed;
if (t3dp->speed>0.01) t3dp->speed=.01;
t3dp->a[0]=t3dp->a[0]+t3dp->speed*t3dp->v[0];
t3dp->a[1]=t3dp->a[1]+t3dp->speed*t3dp->v[1];
t3dp->a[2]=t3dp->a[2]+t3dp->speed*t3dp->v[2];
}
void
refresh_t3d(ModeInfo * mi)
{
MI_CLEARWINDOW(mi);
}
#endif /* MODE_t3d */