diff options
Diffstat (limited to 'xd.c')
-rw-r--r-- | xd.c | 3425 |
1 files changed, 3425 insertions, 0 deletions
@@ -0,0 +1,3425 @@ +/* + + 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 <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <math.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> + +/* ---------------------------------------- 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 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,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); + +/* ---------------------------------------- GLOBAL VARS +*/ +#define NO_DEMOS 15 + +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 + }, + }; + +/* ---------------------------------------- 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 XVisualInfo visual; +static XFontStruct *font=NULL; +static int width; +static int height; +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; + + for(f=1;f<argc;f++) + { + if (!strcmp(argv[f],"-r")) + use_root=TRUE; + else if (!strcmp(argv[f],"-c")) + cycle=TRUE; + else + { + 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; + + 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; + } + } + + { + Window w1,w2; + int i1,i2; + + 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 *Grab(size_t s) +{ + void *p; + + if (!(p=malloc(s))) + Error("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) +{ + 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) && + !XMatchVisualInfo(disp,DefaultScreen(disp),24,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),16,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),15,TrueColor,&visual)) + Error("Couldn't find a visual\n"); + + font=XLoadQueryFont(disp,"fixed"); + + if (!font) + Error("Couldn't load font fixed"); + + width=640; + height=480; + + if (!use_root) + win=XCreateWindow(disp,DefaultRootWindow(disp), + 0,0,width,height,0, + visual.depth, + InputOutput, + visual.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,visual.depth); + saved=XCreatePixmap(disp,win,width,height,visual.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;f<no;f++) + LineP(p+f,p+(f+1)%no,col); +} + + +static void FPolygon(XPoint pts[], int no, int col) +{ + SetCol(col); + XFillPolygon(disp,pix,gc,pts,no,Nonconvex,CoordModeOrigin); +} + + +static unsigned long GetCol(unsigned long r, unsigned long g, unsigned long b) +{ + XColor pix; + + pix.red=(r<<8)|(r?0xff:0); + pix.green=(g<<8)|(g?0xff:0); + pix.blue=(b<<8)|(b?0xff:0); + pix.flags=DoRed|DoBlue|DoGreen; + + XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix); + + return pix.pixel; +} + + +static void SetCol(unsigned long col) +{ + static unsigned long last_col=123; + + if (col==last_col) + return; + + last_col=col; + + XSetForeground(disp,gc,col); +} + + +static void HandleKey(XKeyEvent *key) +{ + switch(XLookupKeysym(key,0)) + { + case XK_Prior: + demo--; + + if (demo<0) + demo=NO_DEMOS-1; + + XStoreName(disp,win,demotbl[demo].name); + Cls(); + break; + + case XK_Next: + demo=(demo+1)%NO_DEMOS; + + XStoreName(disp,win,demotbl[demo].name); + Cls(); + break; + + default: + break; + } +} + + +static void HandleMouse(int x, int y, int b, Mouse mode) +{ + switch(mode) + { + case MousePress: + mouse_b|=(1<<(b-1)); + break; + + case MouseRelease: + mouse_b&=~(1<<(b-1)); + break; + + default: + break; + } + + mouse_x=x; + mouse_y=y; +} + + +static int AngToCol(int ang, int no_col) +{ + int d; + + if (ang>1800) + 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;f<o->no_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;f<o->no_poly;f++) + { + static XPoint p[MAX_POLY_POINTS]; + int r; + int c=-1; + int col; + + for(r=0;r<o->poly[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;f<no;f++) + { + switch(w[f].type) + { + case eObj: + DrawObj(w[f].p,cmap); + break; + + case eSphere: + s=w[f].p; + + if (Project(s->origin.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;f<obj_no;f++,i++) + { + w[i].type=eObj; + w[i].p=o+f; + } + + for(f=0;f<sphere_no;f++,i++) + { + w[i].type=eSphere; + w[i].p=s+f; + } + + for(f=0;f<rect_no;f++,i++) + { + w[i].type=eRect; + w[i].p=r+f; + } + + for(f=0;f<particle_no;f++,i++) + { + w[i].type=eParticle; + w[i].p=p+f; + } + + DrawList(w,no,cmap,inv_z_order,do_sort); + + Release(w); +} + + +/* ---------------------------------------- EXAMPLE DEMO +*/ + +static void ExampleDemo(void) +{ + Cls(); + + Print(0,20,GetCol(255,255,255),"X: %d Y:%d B:%d",mouse_x,mouse_y,mouse_b); + + if (mouse_b&Button1Mask) + Line(0,0,mouse_x,mouse_y,GetCol(RND(0xff),RND(0xff),RND(0xff))); +} + + +/* ---------------------------------------- DROP DEMO +*/ +static void DropDemo(void) +{ + static const int speed=1; + static const int scale=1; + 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 + { + 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;f<num;f++) + { + Drop *new; + + new=Grab(sizeof *new); + + new->x=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;f<NO;f++) + { + p[f].x=RND(width); + p[f].y=RND(height); + + do { + p[f].xi=RND(5)-2; + p[f].yi=RND(5)-2; + } while (p[f].xi==0 || p[f].yi==0); + } + + init=TRUE; + } + + for(f=0;f<NO;f++) + { + int r; + + new=Grab(sizeof *new); + + new->x=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;f<points;f++) + { + si[f]=sin(RAD(360.0/points*f)); + co[f]=cos(RAD(360.0/points*f)); + } + + init=TRUE; + } + + if (mouse_b&Button3Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + clr=!clr; + bounce=time(NULL); + } + } + + if (create==0) + { + Drop *new; + + new=Grab(sizeof *new); + + for(f=0;f<points;f++) + { + new->x[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;f<points;f++) + { + RotateZ(0,0,d->z, + 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;f<points;f++) + LineP(p+f,p+((f+1)%points),col[d->c]); + + 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;f<no;f++) + { + star[f].origin.x=RND(radius)-radius/2; + star[f].origin.y=RND(radius)-radius/2; + star[f].origin.z=RND(max_z); + +# if defined(ISSPHERE) + star[f].radius=100; + star[f].mode=MODE_EDGE; +# endif + star[f].col=255; + } + + obj=Grab(sizeof(Obj3D)*no_obj); + + for(f=0;f<no_obj;f++) + { + obj[f].no_points=no_points; + obj[f].no_poly=no_poly; + obj[f].ps=pset; + obj[f].poly=plist; + obj[f].workp3=Grab(sizeof(Point3D)*no_points); + obj[f].workxp=Grab(sizeof(XPoint)*no_points); + obj[f].x_rot=0; + obj[f].y_rot=0; + obj[f].z_rot=RND(3600); + obj[f].cull=True; + obj[f].mode=MODE_EDGE; + + obj[f].origin.x=RND(radius/8)-radius/16; + obj[f].origin.y=RND(radius/8)-radius/16; + obj[f].origin.z=RND(radius); + + obj[f].col=255; + } + + init=TRUE; + } + + if (mouse_b&Button3Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + clr=!clr; + bounce=time(NULL); + } + } + + if (!clr) + { + if (speed<max_speed) + speed+=speed_inc; + } + else + { + if (speed>min_speed) + speed-=speed_inc; + } + + Cls(); + + for(f=0;f<no;f++) + { + if (star[f].origin.z<1000) + { + star[f].origin.x=RND(radius)-radius/2; + star[f].origin.y=RND(radius)-radius/2; + star[f].origin.z=max_z; + star[f].col=255; + } + else + { + /* + RotateZ(0,0,0, + star[f].origin.x,star[f].origin.y,star[f].origin.z, + &star[f].origin.x,&star[f].origin.y,&star[f].origin.z, + 1); + */ + + if (speed>min_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;f<no_obj;f++) + { + obj[f].origin.z-=100*speed; + obj[f].z_rot+=10; + + if (obj[f].col) + obj[f].col=MAX(0,obj[f].col-speed); + + if (obj[f].origin.z<400) + { + obj[f].origin.x=RND(radius/8)-radius/16; + obj[f].origin.y=RND(radius/8)-radius/16; + obj[f].origin.z=radius*2; + obj[f].col=255; + } + } + +# if defined(ISSPHERE) + DrawSubList(obj,no_obj,star,no,NULL,0,NULL,0,col,False,True); +# else + DrawSubList(obj,no_obj,NULL,0,NULL,0,star,no,col,False,True); +# endif +} + + +/* ---------------------------------------- STAR SPHERE DEMO +*/ +static void StarSphereDemo(void) +{ + static const int no=100; + static const int radius=25000; + static const int max_z=100000; + static const int base_speed=20; + static const int sphere_radius=500; + 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 Sphere3D *star; + static WorldObj *wo; + 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(Sphere3D)*no); + wo=Grab(sizeof(WorldObj)*no); + + for(f=0;f<no;f++) + { + star[f].origin.x=RND(radius)-radius/2; + star[f].origin.y=RND(radius)-radius/2; + star[f].origin.z=RND(max_z); + star[f].radius=sphere_radius; + star[f].mode=MODE_EDGE; + star[f].col=255; + + wo[f].type=eSphere; + wo[f].p=star+f; + } + + init=TRUE; + } + + if (mouse_b&Button3Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + clr=!clr; + bounce=time(NULL); + } + } + + if (!clr) + { + if (speed<max_speed) + speed+=speed_inc; + } + else + { + if (speed>min_speed) + speed-=speed_inc; + } + + Cls(); + + for(f=0;f<no;f++) + { + if (star[f].origin.z<1000) + { + star[f].origin.x=RND(radius)-radius/2; + star[f].origin.y=RND(radius)-radius/2; + star[f].origin.z=max_z; + star[f].col=255; + } + else + { + star[f].origin.z-=base_speed*speed; + + if (star[f].col) + star[f].col=MAX(0,star[f].col-speed); + } + } + + DrawList(wo,no,col,False,True); +} + + +/* ---------------------------------------- TEST 3D DEMO +*/ +static void Test3DDemo(void) +{ + static const int no_particle=2000; + static const int max_z=2000; + static const int min_z=500; + static const int radius=2000; + + static Point3D pwork[8]; + static XPoint xpwork[8]; + + static Point3D pset[8]= + { + {-50,-200,50}, + {50,-200,50}, + {50,-200,-50}, + {-50,-200,-50}, + + {50,200,50}, + {-50,200,50}, + {-50,200,-50}, + {50,200,-50}, + }; + + static Poly3D plist[6]= + { + { + {0,1,2,3}, + 4, + 0 + }, + { + {4,5,6,7}, + 4, + 0 + }, + { + {0,5,4,1}, + 4, + 1 + }, + { + {2,1,4,7}, + 4, + 2 + }, + { + {3,2,7,6}, + 4, + 3 + }, + { + {0,3,6,5}, + 4, + 2 + }, + }; + + static Obj3D obj= + { + 8, + 6, + {0,0,1000}, + pset, + plist, + pwork, + xpwork, + 0,0,0, + MODE_SOLID, + -1, + True + }; + + static Particle3D *p; + static WorldObj *w; + + static int init=FALSE; + static unsigned long col[4]; + static int rot=0; + + int f; + + if (!init) + { + col[0]=white; + col[1]=red; + col[2]=green; + col[3]=blue; + + init=TRUE; + + p=Grab(sizeof(Particle3D)*no_particle); + w=Grab(sizeof(WorldObj)*(no_particle+1)); + + for(f=0;f<no_particle;f++) + { + p[f].origin.x=RND(radius*2)-radius; + p[f].origin.y=RND(radius*2)-radius; + p[f].origin.z=RND(max_z-min_z)+min_z; + if (RND(2)==1) + p[f].origin.z=max_z; + else + p[f].origin.z=min_z; + p[f].col=0; + w[f].p=p+f; + w[f].type=eParticle; + } + + w[no_particle].type=eObj; + w[no_particle].p=&obj; + + DrawList(w,no_particle+1,col,False,True); + } + + if (mouse_b&Button2Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + rot=(rot+1)%3; + bounce=time(NULL); + } + } + + if (mouse_b&Button3Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + obj.cull=!obj.cull; + bounce=time(NULL); + } + } + + if (mouse_b&Button1Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + obj.mode++; + + if (obj.mode>MODE_EDGE) + obj.mode=MODE_SOLID; + + bounce=time(NULL); + } + } + + Cls(); + + for(f=0;f<no_particle;f++) + { + p[f].origin.y+=1; + + if (p[f].origin.y>radius) + 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;f<no;f++) + { + w[f].p=obj+f; + w[f].type=eObj; + + obj[f].no_points=no_pt; + obj[f].no_poly=no_poly; + obj[f].ps=pset; + obj[f].poly=plist; + obj[f].workp3=Grab(sizeof(Point3D)*no_pt); + obj[f].workxp=Grab(sizeof(XPoint)*no_pt); + obj[f].x_rot=a; + obj[f].y_rot=a; + obj[f].z_rot=0; + obj[f].cull=True; + obj[f].mode=MODE_EDGE; + + obj[f].origin.x=x; + obj[f].origin.y=0; + obj[f].origin.z=z; + + obj[f].col=RND(4); + + x+=gap; + a+=20; + + if (((f+1)%no_x)==0) + { + x=-(no_x/2)*gap; + z-=gap; + } + } + + DrawList(w,no,col,False,True); + } + + Cls(); + + a=ang; + + for(f=0;f<no;f++) + { + obj[f].origin.y=y_base+sintab[a]*y_range; + obj[f].y_rot+=10; + obj[f].x_rot+=10; + a=(a+5)%3600; + } + + ang=(ang+10)%3600; + + DrawList(w,no,col,False,False); +} + + +/* ---------------------------------------- FLUID DEMO +*/ +static void FluidDemo(void) +{ + static const int gap=20; + static const int no_x=100; + static const int no_z=100; + static const int no=10000; + static const int z_off=300; + static const double y_range=30.0; + static const double y_base=100.0; + + static unsigned long *col; + static Sphere3D *p; + static WorldObj *w; + + static int ang=0; + + static int init=FALSE; + + int f,a,a2; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof(*col)*no_z); + + for(f=0;f<no_z;f++) + col[f]=GetCol(64,64,255-((no_z-f-1)*2)); + + p=Grab(sizeof(Sphere3D)*no); + w=Grab(sizeof(WorldObj)*no); + + x=-(no_x/2)*gap; + z=(no_z)*gap+z_off; + a=0; + c=0; + + for(f=0;f<no;f++) + { + w[f].p=p+f; + w[f].type=eSphere; + + p[f].origin.x=x; + p[f].origin.y=y_base; + p[f].origin.z=z; + + p[f].radius=gap/2+2; + p[f].col=c; + p[f].mode=MODE_SOLID; + + x+=gap; + a+=20; + + if (((f+1)%no_x)==0) + { + x=-(no_x/2)*gap; + z-=gap; + c++; + } + } + + DrawList(w,no,col,False,True); + + init=TRUE; + } + + Cls(); + + a=ang; + a2=ang; + + for(f=0;f<no;f++) + { + p[f].origin.y=y_base+(sintab[a]+costab[a])*y_range; + a=(a+60)%3600; + + if (((f+1)%no_x)==0) + { + a2=(a2+60)%3600; + a=a2; + } + } + + ang=(ang+60)%3600; + + DrawList(w,no,col,False,False); +} + + +/* ---------------------------------------- PARTICLE DROP DEMO +*/ +static void ParticleDropDemo(void) +{ + static const int gap=30; + static const int radius=17; + static const int no_x=50; + static const int no_z=50; + static const int no=2500; + static const int z_off=300; + static const double y_range=30.0; + static const double y_base=100.0; + static const double drop_y=-1000; + static const double drop_speed=10; + static const double init_amp=500.0; + static const double amp_dropoff=0.5; + static const double amp_decay=6.0; + static const double ang_dropoff=0.01; + + static int min_x,max_x; + static int min_z,max_z; + + static unsigned long *col; + static Sphere3D *p; + static Sphere3D drop; + static WorldObj *w; + + static Point3D ctr; + + static double amp=0.0; + static int ang=0; + static int dist=0; + + static int init=FALSE; + + int f,a,a2; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof(*col)*no_z); + + for(f=0;f<no_z;f++) + col[f]=GetCol(64,64,255-((no_z-f-1)*4)); + + p=Grab(sizeof(Sphere3D)*no); + w=Grab(sizeof(WorldObj)*(no+1)); + + min_x=x=-(no_x/2)*gap; + max_z=z=(no_z)*gap+z_off; + a=0; + c=0; + + for(f=0;f<no;f++) + { + w[f].p=p+f; + w[f].type=eSphere; + + p[f].origin.x=x; + p[f].origin.y=y_base; + p[f].origin.z=z; + + p[f].radius=radius; + p[f].col=c; + p[f].mode=MODE_SOLID; + + x+=gap; + a+=20; + + if (((f+1)%no_x)==0) + { + max_x=x; + x=-(no_x/2)*gap; + z-=gap; + c++; + } + } + + min_z=z; + + max_x/=2; + min_x/=2; + min_z+=(max_z-min_z)/2; + + w[no].p=&drop; + w[no].type=eSphere; + + drop.origin.x=RND2(max_x,min_x); + drop.origin.z=RND2(max_z,min_z); + drop.origin.y=0; + + drop.radius=gap/2+2; + drop.col=0; + drop.mode=MODE_SOLID; + + init=TRUE; + } + + Cls(); + + drop.origin.y+=drop_speed; + + if (drop.origin.y>y_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;f<no;f++) + { + double d; + double y; + + d=Distance(&ctr,&p[f].origin)/gap; + + if (d<3.0) + d=3.0; + + if (d<dist) + { + y=amp/(d/amp_dropoff); + a=(int)(ang+(d/ang_dropoff))%3600; + + p[f].origin.y=y_base+y*sintab[a]; + } + } + + amp-=amp_decay; + ang-=200; + dist++; + } + else + for(f=0;f<no;f++) + p[f].origin.y=y_base; + + DrawList(w,no+1,col,False,True); +} + + +/* ---------------------------------------- POLY DROP DEMO +*/ +static void PolyDropDemo(void) +{ + static const int gap=30; + static const int no_x=50; + static const int no_z=50; + static const int no=2500; + static const int z_off=300; + static const double y_range=30.0; + static const double y_base=100.0; + static const double drop_y=-1000; + static const double drop_speed=10; + static const double init_amp=500.0; + static const double amp_dropoff=2.0; + static const double amp_decay=6.0; + static const double ang_dropoff=0.01; + + static int min_x,max_x; + static int min_z,max_z; + + static unsigned long *col; + + static int no_poly; + static Point3D *pt; + static Poly3D *poly; + + static Point3D *workp; + static XPoint *workxp; + + static Sphere3D drop; + + static Obj3D obj= + {0,0,{0,0,0},NULL,NULL,NULL,NULL,0,0,0,MODE_EDGE,-1,True}; + + static WorldObj w[2]; + + static Point3D ctr; + + static double amp=0.0; + static int ang=0; + static int dist=0; + + static int init=FALSE; + + int f,r; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof(*col)*no_z); + + for(f=0;f<no_z;f++) + col[f]=GetCol(64,64,255-((no_z-f-1)*4)); + + no_poly=(no_z-1)*(no_x-1); + + pt=Grab(sizeof(Point3D)*no); + poly=Grab(sizeof(Poly3D)*no_poly); + + workp=Grab(sizeof(Point3D)*no); + workxp=Grab(sizeof(XPoint)*no); + + obj.no_points=no; + obj.no_poly=no_poly; + obj.ps=pt; + obj.poly=poly; + obj.workp3=workp; + obj.workxp=workxp; + + w[0].p=&obj; + w[0].type=eObj; + w[1].p=&drop; + w[1].type=eSphere; + + min_x=x=-(no_x/2)*gap; + max_z=z=(no_z)*gap+z_off; + + for(f=0;f<no;f++) + { + pt[f].x=x; + pt[f].y=y_base; + pt[f].z=z; + + x+=gap; + + if (((f+1)%no_x)==0) + { + max_x=x; + x=-(no_x/2)*gap; + z-=gap; + c++; + } + } + + min_z=z; + + max_x/=2; + min_x/=2; + min_z+=(max_z-min_z)/2; + + drop.origin.x=RND2(max_x,min_x); + drop.origin.z=RND2(max_z,min_z); + drop.origin.y=0; + + drop.radius=gap/2+2; + drop.col=0; + drop.mode=MODE_SOLID; + + c=0; + r=0; + + for(f=0,r=0;f<no_poly;f++,r++) + { + poly[f].col=c; + poly[f].no=4; + + poly[f].p[0]=r; + poly[f].p[1]=r+1; + poly[f].p[2]=r+1+no_x; + poly[f].p[3]=r+no_x; + + if (((f+1)%(no_x-1))==0) + { + c++; + r++; + } + } + + init=TRUE; + } + + Cls(); + + drop.origin.y+=drop_speed; + + if (drop.origin.y>y_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;f<no;f++) + { + double d; + double y; + + d=Distance(&ctr,&pt[f])/gap; + + if (d<2.0) + d=2.0; + + if (d<dist) + { + y=amp/(d/amp_dropoff); + a=(int)(ang+(d/ang_dropoff))%3600; + + pt[f].y=y_base+y*sintab[a]; + } + } + + amp-=amp_decay; + ang-=200; + dist++; + } + else + for(f=0;f<no;f++) + pt[f].y=y_base; + + DrawList(w,2,col,False,False); +} + + +/* ---------------------------------------- CRATER DEMO +*/ +static void CraterDemo(void) +{ + static const int gap=30; + static const int no_x=70; + static const int no_z=70; + static const int no=4900; + static const int z_off=300; + static const double y_range=30.0; + static const double y_base=100.0; + static const double drop_y=-100; + static const double drop_speed=10; + static const double amp_dropoff=0.1; + static const double ang_dropoff=0.0035; + + static const double max_dist=10; + + static int min_x,max_x; + static int min_z,max_z; + + static unsigned long *col; + + static int no_poly; + static Point3D *pt; + static Poly3D *poly; + + static Point3D *workp; + static XPoint *workxp; + + static Point3D initp; + + static Sphere3D drop; + + static Obj3D obj= + {0,0,{0,0,0},NULL,NULL,NULL,NULL,0,0,0,MODE_SOLID,-1,True}; + + static WorldObj w[2]; + + static Point3D ctr; + + static double speed=1.0; + + static int view=FALSE; + static int init=FALSE; + + int f,r; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof(*col)*no_z); + + initp.x=0; + initp.y=y_base; + initp.z=z_off+(no_z*gap)/2; + + for(f=0;f<no_z;f++) + col[f]=GetCol(64,64,255-((no_z-f-1)*3)); + + no_poly=(no_z-1)*(no_x-1)*2; + + pt=Grab(sizeof(Point3D)*no); + poly=Grab(sizeof(Poly3D)*no_poly); + + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + min_x=x=-(no_x/2)*gap; + max_z=z=(no_z/2)*gap; + + for(f=0;f<no;f++) + { + pt[f].x=x; + pt[f].y=0; + pt[f].z=z; + + x+=gap; + + if (((f+1)%no_x)==0) + { + max_x=x; + x=-(no_x/2)*gap; + z-=gap; + c++; + } + } + + min_z=z; + + min_x+=initp.x; + max_x+=initp.x; + min_z+=initp.z; + max_z+=initp.z; + + 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=0; + + drop.radius=gap/2+2; + drop.col=0; + drop.mode=MODE_SOLID; + + c=0; + r=0; + + for(f=0,r=0;f<no_poly;f+=2,r++) + { + poly[f].col=c; + poly[f].no=3; + + poly[f].p[0]=r; + poly[f].p[1]=r+1; + poly[f].p[2]=r+no_x; + + poly[f+1].col=c; + poly[f+1].no=3; + + poly[f+1].p[0]=r+1; + poly[f+1].p[1]=r+no_x+1; + poly[f+1].p[2]=r+no_x; + + if (((f+2)%(no_x-1))==0) + { + r++; + c=(c+1)%no_z; + } + } + + obj.origin=initp; + obj.no_points=no; + obj.no_poly=no_poly; + obj.ps=pt; + obj.poly=poly; + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + + w[0].p=&obj; + w[0].type=eObj; + w[1].p=&drop; + w[1].type=eSphere; + + init=TRUE; + } + + if (mouse_b&Button1Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + view=!view; + + if (!view) + { + obj.origin=initp; + obj.x_rot=0; + obj.y_rot=0; + obj.z_rot=0; + } + else + obj.origin.z+=800; + + bounce=time(NULL); + } + } + + if (mouse_b&Button3Mask) + { + static time_t bounce=0; + + if (bounce!=time(NULL)) + { + obj.mode++; + + if (obj.mode>MODE_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<no;f++) + { + Point3D p; + double d; + double y; + + p=pt[f]; + p.x+=obj.origin.x; + p.y+=obj.origin.y; + p.z+=obj.origin.z; + + d=Distance(&ctr,&p)/gap; + + if (d<1.0) + d=1.0; + + if (d<max_dist) + { + y=y_range; + a=(int)(900+(d/ang_dropoff))%3600; + + pt[f].y+=y*sintab[a]; + } + } + } + } + + if (view) + { + DrawObj(&obj,col); + Print(0,0,white,"Viewing mode (LMB to end)"); + } + else + { + DrawList(w,2,col,False,False); + DrawSubList(NULL,0,&drop,1,NULL,0,NULL,0,col,FALSE,FALSE); + } +} + + +/* ---------------------------------------- TRIANGLE DEMO +*/ +static void TriangleDemo(void) +{ + static const int gap=100; + static const int no_x=6; + static const int no_z=100; + static const int no=600; + static const int z_off=300; + static const int no_col=1; + static const double y_wall=-500.0; + static const double y_range=80.0; + static const double y_base=200.0; + static const int speed=50; + + static int min_x,max_x; + static int min_z,max_z; + + static unsigned long *col; + + static int no_poly; + static Point3D *pt; + static Poly3D *poly; + + static Point3D *workp; + static XPoint *workxp; + + static Point3D initp; + + static Obj3D obj= + {0,0,{0,0,0},NULL,NULL,NULL,NULL,0,0,0,MODE_EDGE,-1,True}; + + static Point3D ctr; + + static int move=0; + static int ang=0; + + static int view=FALSE; + static int init=FALSE; + + int f,r; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof *col * no_col); + + initp.x=0; + initp.y=y_base; + initp.z=z_off+(no_z*gap)/2; + + for(f=0;f<no_col;f++) + { + int i=255-f; + col[f]=GetCol(i,i,i); + } + + no_poly=(no_z-1)*(no_x-1)*2; + + pt=Grab(sizeof(Point3D)*no); + poly=Grab(sizeof(Poly3D)*no_poly); + + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + min_x=x=-(no_x/2)*gap+gap/2; + max_z=z=(no_z/2)*gap; + + for(f=0;f<no;f++) + { + int m=f%no_x; + + pt[f].x=x; + pt[f].z=z; + + if (m==0 || m==no_x-1) + pt[f].y=y_wall; + else + pt[f].y=sintab[RND(3600)]*y_range; + + x+=gap; + + if (((f+1)%no_x)==0) + { + max_x=x; + x=min_x; + z-=gap; + c++; + } + } + + min_z=z; + + min_x+=initp.x; + max_x+=initp.x; + min_z+=initp.z; + max_z+=initp.z; + + r=0; + + for(f=0,r=0;f<no_poly;f+=2,r++) + { + poly[f].col=0; + poly[f].no=3; + + poly[f].p[0]=r; + poly[f].p[1]=r+1; + poly[f].p[2]=r+no_x; + + poly[f+1].col=0; + poly[f+1].no=3; + + poly[f+1].p[0]=r+1; + poly[f+1].p[1]=r+no_x+1; + poly[f+1].p[2]=r+no_x; + + if (((f+2)%(no_x-1))==0) + { + r++; + c++; + } + } + + obj.origin=initp; + obj.no_points=no; + obj.no_poly=no_poly; + obj.ps=pt; + obj.poly=poly; + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + init=TRUE; + } + + Cls(); + DrawObj(&obj,col); + + ang=(ang+1)%3600; + + move+=speed; + + while (move>=gap) + { + for(f=no-1;f>=no_x;f--) + pt[f].y=pt[f-no_x].y; + + for(f=0;f<no_x;f++) + if (f==0 || f==no_x-1) + pt[f].y=y_wall; + else + pt[f].y=sintab[RND(3600)]*y_range; + + move-=gap; + } + + obj.origin.z=initp.z-move; +} + + +/* ---------------------------------------- TRIANGLE DEMO +*/ +static void TriangleDemo2(void) +{ + static const int gap=100; + static const int no_x=6; + static const int no_z=100; + static const int no=600; + static const int z_off=300; + static const int no_col=1; + static const double y_wall=-500.0; + static const double y_range=80.0; + static const double y_base=200.0; + static const int speed=50; + + static int min_x,max_x; + static int min_z,max_z; + + static unsigned long *col; + + static int no_poly; + static Point3D *pt; + static Poly3D *poly; + + static Point3D *workp; + static XPoint *workxp; + + static Point3D initp; + + static Obj3D obj= + {0,0,{0,0,0},NULL,NULL,NULL,NULL,0,0,0,MODE_EDGE,-1,True}; + + static Point3D ctr; + + static int move=0; + static int ang=3599; + static int angi=1; + + static int view=FALSE; + static int init=FALSE; + + int f,r; + int newa; + + if (!init) + { + int x,z,c; + + col=Grab(sizeof *col * no_col); + + initp.x=0; + initp.y=y_base; + initp.z=z_off+(no_z*gap)/2; + + for(f=0;f<no_col;f++) + { + int i=255-f*200; + col[f]=GetCol(i/2,i,i/2); + } + + no_poly=(no_z-1)*(no_x-1)*2; + + pt=Grab(sizeof(Point3D)*no); + poly=Grab(sizeof(Poly3D)*no_poly); + + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + min_x=x=-(no_x/2)*gap+gap/2; + max_z=z=(no_z/2)*gap; + + for(f=0;f<no;f++) + { + int m=f%no_x; + + pt[f].x=x; + pt[f].z=z; + + pt[f].y=sintab[ang]*y_range; + + if (m==0 || m==no_x-1) + pt[f].y+=y_wall; + + x+=gap; + + if (((f+1)%no_x)==0) + { + max_x=x; + x=min_x; + z-=gap; + c++; + + newa=(ang+angi)%3600; + + if (newa<ang) + { + angi=RND2(450,100); + } + + ang=newa; + + } + } + + min_z=z; + + min_x+=initp.x; + max_x+=initp.x; + min_z+=initp.z; + max_z+=initp.z; + + r=0; + c=0; + + for(f=0,r=0;f<no_poly;f+=2,r++) + { + poly[f].col=c; + poly[f].no=3; + + poly[f].p[0]=r; + poly[f].p[1]=r+1; + poly[f].p[2]=r+no_x; + + c=(c+1)%no_col; + + poly[f+1].col=c; + poly[f+1].no=3; + + poly[f+1].p[0]=r+1; + poly[f+1].p[1]=r+no_x+1; + poly[f+1].p[2]=r+no_x; + + c=(c+1)%no_col; + + if (((f+2)%(no_x-1))==0) + { + r++; + } + } + + obj.origin=initp; + obj.no_points=no; + obj.no_poly=no_poly; + obj.ps=pt; + obj.poly=poly; + obj.workp3=Grab(sizeof(Point3D)*no); + obj.workxp=Grab(sizeof(XPoint)*no); + + init=TRUE; + } + + Cls(); + DrawObj(&obj,col); + + newa=(ang+angi)%3600; + + if (newa<ang) + { + angi=RND2(450,100); + } + + ang=newa; + + move+=speed; + + while (move>=gap) + { + for(f=no-1;f>=no_x;f--) + pt[f].y=pt[f-no_x].y; + + for(f=0;f<no_x;f++) + { + pt[f].y=sintab[ang]*y_range; + + if (f==0 || f==no_x-1) + pt[f].y+=y_wall; + } + + move-=gap; + } + + obj.origin.z=initp.z-move; +} + + +/* END OF FILE */ |