/* xd - X11 demo framefork Copyright (C) 2002 Ian Cowburn (ianc@noddybox.demon.co.uk) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------- */ static const char id[]="$Id$"; #include #include #include #include #include #include #include #include #include #include #include /* ---------------------------------------- HANDY MACROS */ #ifndef TRUE #define TRUE True #endif #ifndef FALSE #define FALSE False #endif #ifndef M_PI # define M_PI 3.14159265358979323846 #endif #define RAD(x) ((x)*M_PI/180.0) #define DEG(x) ((x)/(M_PI/180.0)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) #define LIMIT(v,m,l) MIN((m),MAX((v),(l))) #define RND(x) (rand()%(x)) #define RND2(h,l) ((rand()%((h)-(l)))+(l)) /* ---------------------------------------- TYPES */ typedef enum {UsesImage, UsesPixmap} DType; typedef enum {MousePress, MouseRelease, MouseMove} Mouse; typedef struct { const char *name; void (*draw)(void); DType type; } DemoInfo; typedef struct { double x,y,z; } Point3D; #define MAX_POLY_POINTS 32 typedef struct { int p[MAX_POLY_POINTS]; int no; int col; } Poly3D; typedef struct { int no_points; int no_poly; Point3D origin; Point3D *ps; Poly3D *poly; Point3D *workp3; XPoint *workxp; int x_rot; int y_rot; int z_rot; int mode; int col; int cull; } Obj3D; #define MODE_SOLID 0 #define MODE_WIRE 1 #define MODE_EDGE 2 typedef struct { Point3D origin; int radius; int mode; unsigned long col; } Sphere3D; typedef struct { Point3D origin; int w; int h; int mode; unsigned long col; } Rect3D; typedef struct { Point3D origin; unsigned long col; } Particle3D; typedef enum {eObj, eSphere, eRect, eParticle} ObjType; typedef struct { ObjType type; void *p; } WorldObj; /* ---------------------------------------- DEMO PROTOS */ static void AutoDropDemo(void); static void DropDemo(void); static void FastDropDemo(void); static void TrailDemo(void); static void TunnelDemo(void); static void StarDemo(void); static void StarSphereDemo(void); static void Test3DDemo(void); static void ColScapeDemo(void); static void FluidDemo(void); static void ParticleDropDemo(void); static void PolyDropDemo(void); static void CraterDemo(void); static void TriangleDemo(void); static void TriangleDemo2(void); static void FollowDemo(void); /* ---------------------------------------- GLOBAL VARS */ #define NO_DEMOS 16 static int demo=NO_DEMOS-1; static int cycle=FALSE; static DemoInfo demotbl[NO_DEMOS]= { { "Z-Buffered Pyramids", TrailDemo, UsesPixmap }, { "Auto Drops", AutoDropDemo, UsesPixmap }, { "Drops (LMB to drop, RMB to toggle clear)", DropDemo, UsesPixmap }, { "Fast Drops (LMB to drop, RMB to toggle clear)", FastDropDemo, UsesPixmap }, { "Tunnel (RMB to toggle clear)", TunnelDemo, UsesPixmap }, { "Starfield (RMB to toggle warp)", StarDemo, UsesPixmap }, { "Star Sphere", StarSphereDemo, UsesPixmap }, { "Test3DDemo", Test3DDemo, UsesPixmap }, { "Column Landscape", ColScapeDemo, UsesPixmap }, { "Fluid Particles", FluidDemo, UsesPixmap }, { "Fluid Drops", ParticleDropDemo, UsesPixmap }, { "Polygon Water", PolyDropDemo, UsesPixmap }, { "Crater Landscape", CraterDemo, UsesPixmap }, { "Triangle Trench", TriangleDemo, UsesPixmap }, { "Triangle Wavy Trench", TriangleDemo2, UsesPixmap }, { "Following swarm", FollowDemo, UsesPixmap }, }; /* ---------------------------------------- X11 VARS */ static int use_root=FALSE; static Window win=None; static Pixmap pix=None; static Pixmap saved=None; static GC gc=None; static Display *disp=NULL; static XFontStruct *font=NULL; static int width = 640; static int height = 480; static int centre_x; static int centre_y; static unsigned long black; static unsigned long white; static unsigned long red; static unsigned long green; static unsigned long blue; static int mouse_x; static int mouse_y; static int mouse_b; static double sintab[3600]; static double costab[3600]; #define FONTW (font->max_bounds.rbearing - \ font->min_bounds.lbearing) #define FONTH (font->max_bounds.descent + \ font->max_bounds.ascent + 1) /* ---------------------------------------- PROTOS */ static void OpenX(void); static unsigned long GetCol(unsigned long, unsigned long, unsigned long); static void SetCol(unsigned long col); static void Cls(void); static void ClsCol(unsigned long col); static void Redraw(void); static void UpdateDisplay(void); static void Line(int x1,int y1,int x2,int y2,int col); static void LineP(XPoint *p1,XPoint *p2,int col); static void Plot(int x,int y,int col); static void Circle(int x,int y,int r,int col); static void FCircle(int x,int y,int r,int col); static void Print(int x,int y,int col,char *fmt,...); static void Rect(int x,int y,int w,int h,int col); static void FRect(int x,int y,int w,int h,int col); static void Polygon(XPoint pts[], int no, int col); static void FPolygon(XPoint pts[], int no, int col); static int AngToCol(int ang, int no_col); static double Distance(Point3D *a, Point3D *b); static int Project(double x,double y,double z,XPoint *xp); static void RotateX(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a); static void RotateY(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a); static void RotateZ(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a); static void DrawObj(Obj3D *o, unsigned long cmap[]); static void DrawList(WorldObj *w, int no, unsigned long cmap[], int inv_z_order, int do_sort); static void DrawSubList(Obj3D *o, int obj_no, Sphere3D *s, int sphere_no, Rect3D *r, int rect_no, Particle3D *p, int particle_no, unsigned long cmap[], int inv_z_order, int do_sort); static void HandleKey(XKeyEvent *key); static void HandleMouse(int x, int y, int b, Mouse mode); /* ---------------------------------------- MAIN */ int main(int argc, char *argv[]) { XEvent ev; int f; f = 1; while(argv[f] && argv[f][0] == '-') { switch(argv[f++][1]) { case 'r': use_root = TRUE; break; case 'c': cycle = TRUE; break; case 'w': if (argv[f]) { width = atoi(argv[f++]); } break; case 'h': if (argv[f]) { height = atoi(argv[f++]); } break; default: break; } } if (argv[f]) { demo=atoi(argv[f]); demo=MAX(0,MIN(demo,NO_DEMOS-1)); } OpenX(); XMapWindow(disp,win); black=GetCol(0,0,0); white=GetCol(255,255,255); red=GetCol(255,0,0); green=GetCol(0,255,0); blue=GetCol(0,0,255); for(f=0;f<3600;f++) { sintab[f]=sin(RAD(f*0.10)); costab[f]=cos(RAD(f*0.10)); } srand(getpid()); while(TRUE) { int update; Window w1,w2; int i1,i2; if (XPending(disp)) { XNextEvent(disp,&ev); switch(ev.type) { case KeyPress: HandleKey(&ev.xkey); break; /* case ButtonPress: HandleMouse(ev.xbutton.x,ev.xbutton.y, ev.xbutton.button,MousePress); break; case ButtonRelease: HandleMouse(ev.xbutton.x,ev.xbutton.y, ev.xbutton.button,MouseRelease); break; case MotionNotify: HandleMouse(ev.xbutton.x,ev.xbutton.y, ev.xbutton.button,MouseMove); break; case Expose: if (ev.xexpose.count==0) Redraw(); break; */ default: break; } } XQueryPointer(disp,win,&w1,&w2,&i1,&i2,&mouse_x,&mouse_y,&mouse_b); demotbl[demo].draw(); Redraw(); } return EXIT_SUCCESS; } /* ---------------------------------------- UTILS */ static void Error(char *p) { fprintf(stderr,"%s\n",p); exit(EXIT_FAILURE); } static void SysError(char *p) { perror(p); exit(EXIT_FAILURE); } static void *Grab(size_t s) { void *p; if (!(p=malloc(s))) { SysError("malloc()"); } return p; } static void Release(void *p) { free(p); } static void Bounce(int *x, int *y, int *ix, int *iy) { *x+=*ix; *y+=*iy; if (*x<0 || *x>=width) { *ix=-(*ix); *x+=*ix; } if (*y<0 || *y>=height) { *iy=-(*iy); *y+=*iy; } } /* ---------------------------------------- X11 UTILS */ static void OpenX(void) { /* XVisualInfo visual_info; */ Visual *visual; int depth; XGCValues gc_val; XSizeHints hint; int f; /* Open display and find an appropriate visual */ if (!(disp=XOpenDisplay(NULL))) { Error("Couldn't open X display"); } /* if (!XMatchVisualInfo(disp,DefaultScreen(disp),32,TrueColor,&visual_info) && !XMatchVisualInfo(disp,DefaultScreen(disp),24,TrueColor,&visual_info) && !XMatchVisualInfo(disp,DefaultScreen(disp),16,TrueColor,&visual_info) && !XMatchVisualInfo(disp,DefaultScreen(disp),15,TrueColor,&visual_info)) { Error("Couldn't find a visual"); } */ visual = DefaultVisual(disp, DefaultScreen(disp)); depth = DefaultDepth(disp, DefaultScreen(disp)); font=XLoadQueryFont(disp,"fixed"); if (!font) { Error("Couldn't load font fixed"); } if (!use_root) { win=XCreateWindow (disp, DefaultRootWindow(disp), 0, 0, width, height, 0, depth, InputOutput, visual, 0, NULL); } else { win=DefaultRootWindow(disp); width=DisplayWidth(disp,DefaultScreen(disp)); height=DisplayHeight(disp,DefaultScreen(disp)); } centre_x=width/2; centre_y=height/2; /* XSelectInput (disp,win, KeyPressMask|ButtonPressMask|ButtonReleaseMask| PointerMotionMask|ExposureMask); */ XSelectInput(disp,win,KeyPressMask); XStoreName(disp,win,demotbl[demo].name); hint.width=hint.min_width=hint.max_width=width; hint.height=hint.min_height=hint.max_height=height; hint.flags=PSize|PMinSize|PMaxSize; XSetWMNormalHints(disp,win,&hint); pix=XCreatePixmap(disp,win,width,height,depth); saved=XCreatePixmap(disp,win,width,height,depth); gc_val.function=GXcopy; gc_val.plane_mask=AllPlanes; gc_val.line_width=0; gc_val.line_style=LineSolid; gc_val.graphics_exposures=False; gc_val.foreground=WhitePixel(disp,DefaultScreen(disp)); gc_val.background=BlackPixel(disp,DefaultScreen(disp)); gc=XCreateGC(disp,pix, GCFunction|GCPlaneMask|GCLineWidth|GCForeground|GCBackground| GCLineStyle|GCGraphicsExposures, &gc_val); if (use_root) { /* XSetCloseDownMode(disp,RetainTemporary); XSetWindowBackgroundPixmap(disp,win,pix); */ } /* TODO: XImage creation */ Cls(); Redraw(); } static void Cls() { SetCol(black); XFillRectangle(disp,pix,gc,0,0,width,height); } static void ClsCol(unsigned long col) { SetCol(col); XFillRectangle(disp,pix,gc,0,0,width,height); } static void Redraw(void) { if (demotbl[demo].type==UsesPixmap) { XCopyArea(disp,pix,win,gc,0,0,width,height,0,0); } else { /* TODO: XImage copy */ } /* XFlush(disp); */ XSync(disp,FALSE); } static void Line(int x1,int y1,int x2,int y2,int col) { SetCol(col); XDrawLine(disp,pix,gc,x1,y1,x2,y2); } static void LineP(XPoint *p1, XPoint *p2, int col) { SetCol(col); XDrawLine(disp,pix,gc,p1->x,p1->y,p2->x,p2->y); } static void Plot(int x,int y,int col) { SetCol(col); XDrawPoint(disp,pix,gc,x,y); } static void Circle(int x,int y,int r,int col) { if (r<1) { Plot(x,y,col); return; } SetCol(col); XDrawArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); } static void FCircle(int x,int y,int r,int col) { if (r<1) { Plot(x,y,col); return; } SetCol(col); XFillArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); } static void Print(int x,int y,int col,char *fmt,...) { char s[1024]; va_list va; size_t len; va_start(va,fmt); vsprintf(s,fmt,va); va_end(va); len=strlen(s); y+=FONTH-1; SetCol(col); XDrawString(disp,pix,gc,x,y,s,len); } static void Rect(int x,int y,int w,int h,int col) { if (w==0 && h==0) { Plot(x,y,col); return; } SetCol(col); XDrawRectangle(disp,pix,gc,x,y,w,h); } static void FRect(int x,int y,int w,int h,int col) { if (w==0 && h==0) { Plot(x,y,col); return; } SetCol(col); XFillRectangle(disp,pix,gc,x,y,w,h); } static void Polygon(XPoint p[], int no, int col) { int f; for(f=0;f1800) { ang=1800-(ang-1800); } d=(int)((no_col/1800.0)*(double)ang); return MIN(d,no_col-1); } static double Distance(Point3D *a, Point3D *b) { double x,y,z; x=a->x-b->x; y=a->y-b->y; z=a->z-b->z; return sqrt((x*x)+(y*y)+(z*z)); } static int Project(double x,double y,double z,XPoint *xp) { if (z<10.0) return False; z=z/800.0; xp->x=centre_x+(int)(x/z); xp->y=centre_y+(int)(y/z); return True; } static void RotateX(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a) { double dy,dz,si,co; while(a<0) { a+=3600; } a%=3600; if (a==0) { *x=ix; *y=iy; *z=iz; return; } dy=iy-cy; dz=iz-cz; *x=ix; si=sintab[a]; co=costab[a]; *y=cy+(dz*si+dy*co); *z=cz+(dz*co-dy*si); } static void RotateY(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a) { double dx,dz,si,co; while(a<0) { a+=3600; } a%=3600; if (a==0) { *x=ix; *y=iy; *z=iz; return; } dx=ix-cx; dz=iz-cz; *y=iy; si=sintab[a]; co=costab[a]; *x=cy+(dz*si+dx*co); *z=cz+(dz*co-dx*si); } static void RotateZ(double cx, double cy, double cz, double ix, double iy, double iz, double *x, double *y, double *z, int a) { double dy,dx,si,co; while(a<0) { a+=3600; } a%=3600; if (a==0) { *x=ix; *y=iy; *z=iz; return; } dy=iy-cy; dx=ix-cx; *z=iz; si=sintab[a]; co=costab[a]; *y=cy+(dx*si+dy*co); *x=cx+(dx*co-dy*si); } static void DrawObj(Obj3D *o, unsigned long cmap[]) { int f; for(f=0;fno_points;f++) { RotateX(0,0,0, o->ps[f].x,o->ps[f].y,o->ps[f].z, &o->workp3[f].x,&o->workp3[f].y,&o->workp3[f].z, o->x_rot); RotateY(0,0,0, o->workp3[f].x,o->workp3[f].y,o->workp3[f].z, &o->workp3[f].x,&o->workp3[f].y,&o->workp3[f].z, o->y_rot); RotateZ(0,0,0, o->workp3[f].x,o->workp3[f].y,o->workp3[f].z, &o->workp3[f].x,&o->workp3[f].y,&o->workp3[f].z, o->z_rot); Project(o->origin.x+o->workp3[f].x, o->origin.y+o->workp3[f].y, o->origin.z+o->workp3[f].z, o->workxp+f); } for(f=0;fno_poly;f++) { static XPoint p[MAX_POLY_POINTS]; int r; int c=-1; int col; for(r=0;rpoly[f].no;r++) { p[r]=o->workxp[o->poly[f].p[r]]; } if (o->cull) { c=(p[0].x-p[1].x)*(p[2].y-p[1].y)-(p[0].y-p[1].y)*(p[2].x-p[1].x); } if (o->col!=-1) { col=cmap[o->col]; } else { col=cmap[o->poly[f].col]; } if (c<0) { switch(o->mode) { case MODE_SOLID: FPolygon(p,o->poly[f].no,col); break; case MODE_EDGE: FPolygon(p,o->poly[f].no,black); Polygon(p,o->poly[f].no,col); break; case MODE_WIRE: default: Polygon(p,o->poly[f].no,col); break; } } } } static int ZSort(const void *p1, const void *p2) { double z1,z2; const WorldObj *o1, *o2; o1=p1; o2=p2; switch(o1->type) { case eObj: z1=((const Obj3D *)o1->p)->origin.z; break; case eSphere: z1=((const Sphere3D *)o1->p)->origin.z; break; case eRect: z1=((const Rect3D *)o1->p)->origin.z; break; case eParticle: z1=((const Particle3D *)o1->p)->origin.z; break; default: z1=-1; break; } switch(o2->type) { case eObj: z2=((const Obj3D *)o2->p)->origin.z; break; case eSphere: z2=((const Sphere3D *)o2->p)->origin.z; break; case eRect: z2=((const Rect3D *)o2->p)->origin.z; break; case eParticle: z2=((const Particle3D *)o2->p)->origin.z; break; default: z2=-1; break; } return (int)(z2-z1); } static int InvZSort(const void *p1, const void *p2) { double z1,z2; const WorldObj *o1, *o2; o1=p1; o2=p2; switch(o1->type) { case eObj: z1=((const Obj3D *)o1->p)->origin.z; break; case eSphere: z1=((const Sphere3D *)o1->p)->origin.z; break; case eRect: z1=((const Rect3D *)o1->p)->origin.z; break; case eParticle: z1=((const Particle3D *)o1->p)->origin.z; break; default: z1=-1; break; } switch(o2->type) { case eObj: z2=((const Obj3D *)o2->p)->origin.z; break; case eSphere: z2=((const Sphere3D *)o2->p)->origin.z; break; case eRect: z2=((const Rect3D *)o2->p)->origin.z; break; case eParticle: z2=((const Particle3D *)o2->p)->origin.z; break; default: z2=-1; break; } return (int)(z1-z2); } static void DrawList(WorldObj *w, int no, unsigned long cmap[], int inv_z_order,int do_sort) { int f; XPoint xp,xp2; Particle3D *p; Sphere3D *s; Rect3D *r; if (do_sort) { if (inv_z_order) { qsort(w,no,sizeof(WorldObj),InvZSort); } else { qsort(w,no,sizeof(WorldObj),ZSort); } } for(f=0;forigin.x,s->origin.y,s->origin.z,&xp)) { if (Project(s->origin.x+s->radius,s->origin.y, s->origin.z,&xp2)) { switch(s->mode) { case MODE_SOLID: FCircle(xp.x,xp.y,xp2.x-xp.x,cmap[s->col]); break; case MODE_WIRE: Circle(xp.x,xp.y,xp2.x-xp.x,cmap[s->col]); break; case MODE_EDGE: FCircle(xp.x,xp.y,xp2.x-xp.x,black); Circle(xp.x,xp.y,xp2.x-xp.x,cmap[s->col]); break; } } } break; case eRect: r=w[f].p; if (Project(r->origin.x,r->origin.y,r->origin.z,&xp)) { if (Project(r->origin.x+r->w,r->origin.y+r->h, r->origin.z,&xp2)) { int w,h; w=xp2.x-xp.x; h=xp2.y-xp.y; switch(r->mode) { case MODE_SOLID: FRect(xp.x,xp.y,w,h,cmap[r->col]); break; case MODE_WIRE: Rect(xp.x,xp.y,w,h,cmap[r->col]); break; case MODE_EDGE: FRect(xp.x,xp.y,w,h,black); Rect(xp.x,xp.y,w,h,cmap[r->col]); break; } } } break; case eParticle: p=w[f].p; if (Project(p->origin.x,p->origin.y,p->origin.z,&xp)) { Plot(xp.x,xp.y,cmap[p->col]); } break; default: break; } } } static void DrawSubList(Obj3D *o, int obj_no, Sphere3D *s, int sphere_no, Rect3D *r, int rect_no, Particle3D *p, int particle_no, unsigned long cmap[], int inv_z_order, int do_sort) { WorldObj *w; int no; int f; int i; no=obj_no+sphere_no+rect_no+particle_no; w=Grab(sizeof(WorldObj)*no); i=0; for(f=0;fx=mouse_x; new->y=mouse_y; new->r=3; new->c=0; new->next=NULL; if (!head) { head=tail=new; } else { tail->next=new; tail=new; } last=time(NULL); } if (clr) { Cls(); } d=head; while(d) { if (d->c>=256) { Drop *t; if (d->next) { head=d->next; } else { head=tail=NULL; } t=d; d=d->next; Release(t); } else { Circle(d->x,d->y,d->r,col[d->c]); d->r+=scale; d->c+=speed; d=d->next; } } } /* ---------------------------------------- AUTO DROP DEMO */ static void AutoDropDemo(void) { static const int speed=1; static const int scale=1; static const int num=10; static int init=FALSE; static unsigned long col[256]; static time_t last=0; typedef struct Drop { int x,y,r,c; int speed; int scale; struct Drop *next; } Drop; static Drop *head=NULL; static Drop *tail=NULL; Drop *d; int f; if (!init) { int f; for(f=0;f<256;f++) { col[f]=GetCol(MAX(255-f*2,0),MAX(255-f*2,0),255-f); } init=TRUE; } if (last!=time(NULL) && !head) { int x,y,sc; x=RND(width); y=RND(height); sc=scale; for(f=0;fx=x+RND(num); new->y=y+RND(num); new->r=3; new->c=0; new->scale=sc; new->speed=speed; new->next=NULL; if (!head) { head=tail=new; } else { tail->next=new; tail=new; } } last=time(NULL); } /* Cls(); */ d=head; while(d) { if (d->c>=256) { Drop *t; if (d->next) { head=d->next; } else { head=tail=NULL; } t=d; d=d->next; Release(t); } else { Circle(d->x,d->y,d->r,col[d->c]); d->r+=d->scale; d->c+=d->speed; d=d->next; } } } /* ---------------------------------------- FAST DROP DEMO */ static void FastDropDemo(void) { static const int speed=30; static const int scale=2; static int init=FALSE; static int clr=TRUE; static unsigned long col[256]; static time_t last=0; typedef struct Drop { int x,y,r,c; struct Drop *next; } Drop; static Drop *head=NULL; static Drop *tail=NULL; Drop *d; if (!init) { int f; for(f=0;f<256;f++) { col[f]=GetCol(255-f,255-f,255-f); } init=TRUE; } if (mouse_b&Button3Mask) { static time_t bounce=0; if (bounce!=time(NULL)) { clr=!clr; bounce=time(NULL); } } if (mouse_b&Button1Mask /*&& (last!=time(NULL))*/) { Drop *new; new=Grab(sizeof *new); new->x=mouse_x; new->y=mouse_y; new->r=3; new->c=0; new->next=NULL; if (!head) { head=tail=new; } else { tail->next=new; tail=new; } last=time(NULL); } if (clr) { Cls(); } d=head; while(d) { if (d->c>=256) { Drop *t; if (d->next) { head=d->next; } else { head=tail=NULL; } t=d; d=d->next; Release(t); } else { Rect(d->x-d->r/2,d->y-d->r/2,d->r,d->r,col[d->c]); d->r+=scale; d->c+=speed; d=d->next; } } } /* ---------------------------------------- TRAIL DEMO */ static void TrailDemo(void) { static const int NO=20; static const int speed=20; static const int scale=10; static int init=FALSE; static unsigned long col[256]; static struct { int x,y,xi,yi; } *p; typedef struct Drop { int x,y,r,c; struct Drop *next; } Drop; static Drop *head=NULL; static Drop *tail=NULL; Drop *new; Drop *d; int f; if (!init) { for(f=0;f<256;f++) { col[f]=GetCol(255-f,255-f,255-f); } p=Grab(sizeof(*p)*NO); for(f=0;fx=p[f].x; new->y=p[f].y; new->r=3; new->c=0; new->next=NULL; if (!head) { head=tail=new; } else { tail->next=new; tail=new; } Bounce(&p[f].x,&p[f].y,&p[f].xi,&p[f].yi); } /* Cls(); */ d=head; while(d) { if (d->c>=256) { Drop *t; if (d->next) { head=d->next; } else { head=tail=NULL; } t=d; d=d->next; Release(t); } else { FRect(d->x-d->r/2,d->y-d->r/2,d->r,d->r,col[d->c]); d->r+=scale; d->c+=speed; d=d->next; } } } /* ---------------------------------------- TUNNEL DEMO */ static void TunnelDemo(void) { static const int speed=100; static const int radius=1000; static const int points=10; static const int max_z=50000; static const int delay=20; static double *si; static double *co; static int init=FALSE; static int clr=TRUE; static unsigned long col[256]; static time_t last=0; static int create=0; typedef struct Drop { double x[points]; double y[points]; double z; int r,c; int ang; struct Drop *next; } Drop; static Drop *head=NULL; static Drop *tail=NULL; Drop *d; int f; if (!init) { for(f=0;f<256;f++) { col[f]=GetCol(255-f,255-f,255-f); } si=Grab(sizeof(double)*points); co=Grab(sizeof(double)*points); for(f=0;fx[f]=(RND(radius>>1)+radius>>1)*si[f]; new->y[f]=(RND(radius>>1)+radius>>1)*co[f]; } new->r=radius; new->z=max_z; new->c=255; new->ang=RND(20)-10; if (new->ang<0) { new->ang+=3600; } new->next=NULL; if (!head) { head=tail=new; } else { tail->next=new; tail=new; } create=delay; } else { create--; } if (clr) { Cls(); } d=head; while(d) { if (d->z<10) { Drop *t; if (d->next) { head=d->next; } else { head=tail=NULL; } t=d; d=d->next; Release(t); } else { XPoint p[points]; if (d->c) { d->c=MAX(0,d->c-10); } for(f=0;fz, d->x[f],d->y[f],d->z, &d->x[f],&d->y[f],&d->z, d->ang); Project(d->x[f],d->y[f],d->z,p+f); } for(f=0;fc]); } d->z-=speed; d=d->next; } } } /* ---------------------------------------- STAR DEMO */ static void StarDemo(void) { # define TYPE Particle3D # undef ISSPHERE static const int no_points=4; static const int no_poly=4; static Point3D pset[4]= { {-100,50,100}, {100,50,100}, {0,-50,100}, {0,0,-300}, }; static Poly3D plist[4]= { { {0,3,1}, 3, 0 }, { {0,1,2}, 3, 0 }, { {0,2,3}, 3, 0 }, { {1,3,2}, 3, 0 }, }; static Obj3D *obj; #ifdef ISSPHERE static const int no=200; #else static const int no=2000; #endif static const int no_obj=3; static const int radius=25000; static const int max_z=50000; static const double max_speed=50.0; static const double min_speed=1.0; static const double speed_inc=0.1; static int init=FALSE; static unsigned long col[256]; static int clr=TRUE; static time_t last=0; static double speed=1.0; static TYPE *star; int fg,bg; int f; if (!init) { for(f=0;f<256;f++) { col[f]=GetCol(255-f,255-f,255-f); } star=Grab(sizeof(TYPE)*no); for(f=0;fmin_speed) { speed-=speed_inc; } } Cls(); for(f=0;fmin_speed) { XPoint p; XPoint p2; Project(star[f].origin.x,star[f].origin.y,star[f].origin.z,&p); Project(star[f].origin.x,star[f].origin.y,star[f].origin.z+speed*speed,&p2); LineP(&p,&p2,col[star[f].col]); } star[f].origin.z-=20*speed; if (star[f].col) { star[f].col--; } } } for(f=0;fmin_speed) { speed-=speed_inc; } } Cls(); for(f=0;fMODE_EDGE) { obj.mode=MODE_SOLID; } bounce=time(NULL); } } Cls(); for(f=0;fradius) { p[f].origin.y=-radius; } } switch(rot) { case 0: Print(0,20,white,"Y rotation"); obj.y_rot+=10; break; case 1: Print(0,20,white,"X rotation"); obj.x_rot+=10; break; case 2: Print(0,20,white,"Z rotation"); obj.z_rot+=10; break; default: break; } Print(0,30,white,"Mode : %d Culling: %s",obj.mode,obj.cull ? "on":"off"); DrawList(w,no_particle+1,col,False,False); } /* ---------------------------------------- COL SCAPE DEMO */ static void ColScapeDemo(void) { static const int gap=200; static const int no_pt=8; static const int no_poly=6; static const int no_x=20; static const int no_z=20; static const int no=400; static const int z_off=1000; static const double y_range=200.0; static const double y_base=100.0; static Point3D pset[8]= { {-50,-20,50}, {50,-20,50}, {50,-20,-50}, {-50,-20,-50}, {50,20,50}, {-50,20,50}, {-50,20,-50}, {50,20,-50}, }; static Poly3D plist[6]= { { {0,1,2,3}, 4, 0 }, { {4,5,6,7}, 4, 0 }, { {0,5,4,1}, 4, 0 }, { {2,1,4,7}, 4, 0 }, { {3,2,7,6}, 4, 0 }, { {0,3,6,5}, 4, 0 }, }; static Obj3D *obj; static WorldObj *w; static int ang=0; static int init=FALSE; static unsigned long col[4]; int f,a; if (!init) { int x,z; col[0]=white; col[1]=red; col[2]=green; col[3]=blue; init=TRUE; obj=Grab(sizeof(Obj3D)*no); w=Grab(sizeof(WorldObj)*no); x=-(no_x/2)*gap; z=(no_z)*gap+z_off; a=0; for(f=0;fy_base) { amp=init_amp; ang=0; dist=1; ctr=drop.origin; drop.origin.x=RND2(max_x,min_x); drop.origin.z=RND2(max_z,min_z); drop.origin.y=drop_y; } if (amp>0.0) { int a; if (ang<0) { ang+=3600; } a=ang; for(f=0;fy_base) { amp=init_amp; ang=0; dist=1; ctr=drop.origin; drop.origin.x=RND2(max_x,min_x); drop.origin.z=RND2(max_z,min_z); drop.origin.y=drop_y; } if (amp>0.0) { int a; if (ang<0) { ang+=3600; } a=ang; for(f=0;fMODE_EDGE) { obj.mode=MODE_SOLID; } bounce=time(NULL); } } Cls(); if (view) { obj.x_rot=MAX(2700,MIN(3599,2700+mouse_y*3)); obj.y_rot=(centre_x-mouse_x)*3; obj.y_rot=MAX(-900,MIN(obj.y_rot,900)); } else { drop.origin.y+=drop_speed*speed; speed+=0.1; if (drop.origin.y>y_base) { int a; speed=1.0; ctr=drop.origin; drop.origin.z=RND2(max_z,min_z)/gap*gap; drop.origin.x=RND2((int)drop.origin.z,(int)-drop.origin.z)/gap*gap; drop.origin.y=drop_y; for(f=0;f=gap) { for(f=no-1;f>=no_x;f--) { pt[f].y=pt[f-no_x].y; } for(f=0;f=gap) { for(f=no-1;f>=no_x;f--) { pt[f].y=pt[f-no_x].y; } for(f=0;f fabs(d_y)) { d = fabs(d_x); } else { d = fabs(d_y); } d_x = d_x / d * FOLLOW_WEIGHT; d_y = d_y / d * FOLLOW_WEIGHT; dx[f] += d_x; dy[f] += d_y; if (dx[f] < -FOLLOW_SPEED) { dx[f] = -FOLLOW_SPEED; } if (dx[f] > FOLLOW_SPEED) { dx[f] = FOLLOW_SPEED; } if (dy[f] < -FOLLOW_SPEED) { dy[f] = -FOLLOW_SPEED; } if (dy[f] > FOLLOW_SPEED) { dy[f] = FOLLOW_SPEED; } x[f] += dx[f]; y[f] += dy[f]; Line(x[f], y[f], x[f]-dx[f], y[f]-dy[f], red); } } /* END OF FILE */