summaryrefslogtreecommitdiff
path: root/xd.c
diff options
context:
space:
mode:
Diffstat (limited to 'xd.c')
-rw-r--r--xd.c3425
1 files changed, 3425 insertions, 0 deletions
diff --git a/xd.c b/xd.c
new file mode 100644
index 0000000..cc2502f
--- /dev/null
+++ b/xd.c
@@ -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 */