home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- ATTENTION!
- this source is VOTEWARE,
- you may only use it to the conditions listed below:
-
- -You may modify it, or use parts of it in your own source as long as
- this header stays on top of all files containing this source.
- -You must give proper credit to the author, Niklas Beisert / pascal.
- -You may not use it in commercial productions without the written
- permission of the author.
- -AND MOST IMPORTANT: you have to buy an Assembly '94 CD-ROM
- by Sound Solutions (if you don't have it already) and vote for VEX-InTrO
- in the PC-64k-Intro-Compo! (if you have already sent your voting card,
- buy another one and fill it out CORRECTLY!!!)
- *****************************************************************************/
-
-
-
- // the heart of the vector engine...
- // at first it gets all objects and sorts them. then it draws the objects.
- // if some objects are to be intersected, all their planes are put in a
- // list, and a new bsp tree is generated (greetings go to jinx and avatar ;)
- // a z-buffer might be better, but a) this is borland c++ 3.1, b) this is
- // not really fast for a small number of planes and c) i did not know
- // z-buffering at that time...
- // a bsp tree is generated by recursively taking one plane
- // and sorting all the others to a behind or before-list (compared to the one)
- // if one plane is on both sides, it will be cut and sorted to the before-
- // and behind-list. then do the same to both lists, till all lists are single
- // planes
-
- #include <dos.h>
- #include <stdlib.h>
- #include <mem.h>
- //#include <fcntl.h>
- //#include <io.h>
- //#include "..\ovlio.h"
- #include "polygons.h"
- #include "ints.h"
- #include "matrix.h"
- #include "intrsect.h"
- #include "project.h"
- #include "vect.h"
-
- vector *verts;
- short vertnum;
- vector *norms;
- short normnum;
- plane *planes;
- short planenum;
- objdata *objlist;
- object *mainobj;
- lightdata lights[8];
- short lightnum;
-
- void viewmirror(const plane& p);
-
- unsigned char mirror=0;
- void getlights(const short *v, const lightspot *l, long *cols, short n)
- {
- short i, j;
- for (j=0; j<n; j++, v++, l++, cols++)
- {
- if (!l->cn)
- {
- *cols=l->c0+mirror;
- continue;
- }
- long intens=dtol(0.2);
- vector &cv=verts[*v];
- vector &cn=norms[l->n];
- for (i=0; i<lightnum; i++)
- {
- vector vc;
- vecsub(vc, lights[i].pos, cv);
- long x=vecmul(vc, cn);
- if (x<0)
- continue;
- intens+=IntMulDiv(lights[i].intens, x, vecsqr(vc));
- }
- if (intens>=dtol(1))
- intens=dtol(1);
- *cols=(itol(l->c0)+intens*l->cn)+itol(mirror);
- }
- }
-
- // draw one plane
- void drawplane(const plane &p)
- {
- long coords[MAXVERT][2];
- long cols[MAXVERT];
- projectverts(verts, p.v, coords, p.num, dtol(345), dtol(300));
- short i;
- char *bmp;
- unsigned short wid;
- long texv[MAXVERT][2];
- switch (p.disp)
- {
- case DISP_NORM:
- case DISP_ORPUT:
- case DISP_TEXT:
- case DISP_TEXTX:
- if (p.nr.cn)
- {
- getlights(&p.mid, &p.nr, cols, 1);
- cols[0]>>=16;
- }
- else
- cols[0]=p.nr.c0+mirror;
- switch (p.disp)
- {
- case DISP_NORM:
- fillpolygon(coords, p.num, cols[0], xfillline, scrpage<<14);
- break;
- case DISP_ORPUT:
- outpw(0x3ce, 0x1003);
- fillpolygon(coords, p.num, cols[0], xfillliner, scrpage<<14);
- outpw(0x3ce, 0x0003);
- break;
- case DISP_TEXT:
- gettexture(p.textnum, p.tex, p.num, texv, bmp, wid);
- vtexturepolygon(coords, texv, p.num, bmp, wid, cols[0], vxtextureline, scrpage<<14);
- break;
- case DISP_TEXTX:
- gettexture(p.textnum, p.tex, p.num, texv, bmp, wid);
- vtexturepolygon(coords, texv, p.num, bmp, wid, cols[0], vxtexturelinex, scrpage<<14);
- break;
- }
- break;
- case DISP_SHADED:
- getlights(p.v, p.col, cols, p.num);
- vshadepolygon(coords, cols, p.num, vxshadelined, scrpage<<14);
- break;
- case DISP_MIRROR:
- i=mirror;
- mirror+=p.nr.c0;
- fillpolygon(coords, p.num, p.nr.cn, xfillline, scrpage<<14);
- viewmirror(p);
- mirror=i;
- break;
- }
- }
-
- // cut a plane by the cutdata
- // very important for building a bsp tree and clipping to the screen bounds.
- inline static plane *intersectplane(plane &pl, const cutdata &rt, short split)
- {
- short v1=vertnum++;
- planecutv(rt.vpa, verts[pl.v[rt.pal]], verts[pl.v[rt.pac]], verts[v1]);
- short v2=vertnum++;
- planecutv(rt.vpb, verts[pl.v[rt.pbl]], verts[pl.v[rt.pbc]], verts[v2]);
- unsigned long ct1, ct2;
- if (pl.disp==DISP_SHADED)
- {
- vector *nrm=&norms[normnum];
- planecutv(rt.vpa, norms[pl.col[rt.pal].n], norms[pl.col[rt.pac].n], *nrm);
- ((lightspot*)&ct1)->n=normnum++;
- planecutc2(rt.vpa, &pl.col[rt.pal].c0, &pl.col[rt.pac].c0, &((lightspot*)&ct1)->c0);
- vecnorm(*nrm);
- nrm++;
- planecutv(rt.vpb, norms[pl.col[rt.pbl].n], norms[pl.col[rt.pbc].n], *nrm);
- ((lightspot*)&ct2)->n=normnum++;
- planecutc2(rt.vpb, &pl.col[rt.pbl].c0, &pl.col[rt.pbc].c0, &((lightspot*)&ct2)->c0);
- vecnorm(*nrm);
- }
- else if (pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
- {
- planecuts2(rt.vpa, &pl.tex[rt.pal], &pl.tex[rt.pac], &ct1);
- planecuts2(rt.vpb, &pl.tex[rt.pbl], &pl.tex[rt.pbc], &ct2);
- }
-
- if (split)
- {
- plane &p=planes[planenum++];
- p=pl;
- if (rt.pbc>rt.pal)
- {
- p.num+=rt.pal+3-rt.pbc;
- memmove(&p.v[rt.pal+3], &p.v[rt.pbc], (p.num-rt.pal-3)<<1);
- p.v[rt.pal+1]=v1;
- p.v[rt.pal+2]=v2;
- p.v[p.num]=p.v[0];
- if (p.disp==DISP_SHADED||p.disp==DISP_TEXT||p.disp==DISP_TEXTX)
- {
- memmove(&p.ct[rt.pal+3], &p.ct[rt.pbc], (p.num-rt.pal-3)<<2);
- p.ct[rt.pal+1]=ct1;
- p.ct[rt.pal+2]=ct2;
- p.ct[p.num]=p.ct[0];
- }
- }
- else
- {
- p.num=rt.pal+3-rt.pbc;
- memmove(&p.v[2], &p.v[rt.pbc], (p.num-2)<<1);
- p.v[0]=v1;
- p.v[1]=v2;
- p.v[p.num]=p.v[0];
- if (p.disp==DISP_SHADED||p.disp==DISP_TEXT||p.disp==DISP_TEXTX)
- {
- memmove(&p.ct[2], &p.ct[rt.pbc], (p.num-2)<<2);
- p.ct[0]=ct1;
- p.ct[1]=ct2;
- p.ct[p.num]=p.ct[0];
- }
- }
- }
-
- if (rt.pac>rt.pbl)
- {
- pl.num+=rt.pbl+3-rt.pac;
- memmove(&pl.v[rt.pbl+3], &pl.v[rt.pac], (pl.num-rt.pbl-3)<<1);
- pl.v[rt.pbl+1]=v2;
- pl.v[rt.pbl+2]=v1;
- pl.v[pl.num]=pl.v[0];
- if (pl.disp==DISP_SHADED||pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
- {
- memmove(&pl.ct[rt.pbl+3], &pl.ct[rt.pac], (pl.num-rt.pbl-3)<<2);
- pl.ct[rt.pbl+1]=ct2;
- pl.ct[rt.pbl+2]=ct1;
- pl.ct[pl.num]=pl.ct[0];
- }
- }
- else
- {
- pl.num=rt.pbl+3-rt.pac;
- memmove(&pl.v[2], &pl.v[rt.pac], (pl.num-2)<<1);
- pl.v[0]=v2;
- pl.v[1]=v1;
- pl.v[pl.num]=pl.v[0];
- if (pl.disp==DISP_SHADED||pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
- {
- memmove(&pl.col[2], &pl.col[rt.pac], (pl.num-2)<<2);
- pl.ct[0]=ct2;
- pl.ct[1]=ct1;
- pl.ct[pl.num]=pl.ct[0];
- }
- }
-
- if (split)
- return &planes[planenum-1];
- else
- return 0;
- }
-
- // is this plane visible??
- inline short checkvisible(const plane &p)
- {
- return (vecmul(norms[p.nr.n], verts[p.mid])<1)&&!!(p.opt&OPT_DISPLAY);
- }
-
- // clip a plane
- inline plane *clipplane(plane *p, const long (§)[4], short copy)
- {
- cutdata rt;
- short s=chkplanecut(sect, verts, p->v, p->num, rt);
- if (s==3)
- {
- if (copy)
- {
- planes[planenum]=*p;
- p=&planes[planenum++];
- }
- intersectplane(*p, rt, 0);
- return p;
- }
- else
- if (s==2)
- return p;
- else
- return 0;
- }
-
- // draw some planes (with intersections)
- void drawplanesbsphelp(const plane *p, const long (*sect)[4], unsigned sects)
- {
- short opn=planenum;
- short ovn=vertnum;
- short onn=normnum;
-
- const plane *p2;
- short i;
- for (; p; p=p->m)
- if (checkvisible(*p))
- {
- for (p2=p, i=0; i<16; i++)
- if ((sects>>i)&1)
- if (!(p2=clipplane((plane*)p2, sect[i], p2==p)))
- break;
- if (!p2)
- continue;
- drawplane(*p2);
- }
-
- planenum=opn;
- vertnum=ovn;
- normnum=onn;
- }
-
- // draw an object with the bsp tree
- void drawplanesbsp(const plane *p, const long (*sect)[4], unsigned short sects)
- {
- // do we see the front of the plane?
- short flipped=vecmul(norms[p->nr.n], verts[p->mid])>=1;
- // draw everything behind the plane first
- if (flipped)
- {
- if (p->f)
- drawplanesbsp(p->f, sect, sects);
- }
- else
- {
- if (p->b)
- drawplanesbsp(p->b, sect, sects);
- }
-
- // then draw coplanar planes
- drawplanesbsphelp(p, sect, sects);
-
- // finally everything before the plane
- if (flipped)
- {
- if (p->b)
- drawplanesbsp(p->b, sect, sects);
- }
- else
- {
- if (p->f)
- drawplanesbsp(p->f, sect, sects);
- }
- }
-
- // add some planes to the list, clipping them by the screen boundaries
- void addlist(plane *&p0, const plane *p, short n, short vo, short no, const long (*sect)[4], unsigned short sects)
- {
- plane **pp;
- for (pp=&p0; *pp; pp=&(*pp)->next);
-
- const plane *end;
- for (end=p+n; p<end; p++)
- {
- *pp=&planes[planenum];
- **pp=*p;
-
- short i;
- (*pp)->mid+=vo;
- (*pp)->nr.n+=no;
- for (i=0; i<=(*pp)->num; i++)
- (*pp)->v[i]+=vo;
- if ((*pp)->disp==DISP_SHADED)
- for (i=0; i<=(*pp)->num; i++)
- (*pp)->col[i].n+=no;
-
- if (!checkvisible(**pp))
- continue;
-
- for (i=0; i<16; i++)
- if ((sects>>i)&1)
- if (!clipplane(*pp, sect[i], 0))
- break;
- if (i!=16)
- continue;
-
- planenum++;
- pp=&(*pp)->next;
- }
- *pp=0;
- }
-
- // this function seems to arrange the spacecut, but i don't really know how it
- // works anymore... sorry...
- void drawplanesmbsphelp(plane *p)
- {
- plane **pb=&p->b, **pm=&p->m, **pf=&p->f, *c;
- long pl[4];
- cutdata rt;
- calcplane(norms[p->nr.n], verts[p->mid], pl);
- for (c=p->next; c; c=c->next)
- switch (chkplanecut(pl, verts, c->v, c->num, rt))
- {
- case 0:
- pb=&(*pb=c)->next;
- break;
- case 1:
- pm=&(*pm=c)->m;
- break;
- case 2:
- pf=&(*pf=c)->next;
- break;
- case 3:
- pb=&(*pb=intersectplane(*c, rt, 1))->next;
- pf=&(*pf=c)->next;
- break;
- }
- *pb=*pm=*pf=0;
- }
-
- // this function seems to arrange the spacecut, but i don't really know how it
- // works anymore... sorry...
- void drawplanesmbsp(plane *p)
- {
- short opn=planenum;
- short ovn=vertnum;
- short onn=normnum;
-
- drawplanesmbsphelp(p);
- if (p->b)
- drawplanesmbsp(p->b);
- plane *p2;
- for (p2=p; p2; p2=p2->m)
- drawplane(*p2);
- if (p->f)
- drawplanesmbsp(p->f);
-
- planenum=opn;
- vertnum=ovn;
- normnum=onn;
- }
-
- struct objsort
- {
- long dist;
- objdata *o;
- unsigned short cuts;
- };
-
- short objsortfn(const objsort *a, const objsort *b)
- {
- long c=b->dist-a->dist;
- return c>0?1:c?-1:0;
- }
-
- // view the scenery... clips are the screen boundaries
- void viewscenery(const matrix &cam, long (*clips)[4], short num)
- {
- short opn=planenum;
- short ovn=vertnum;
- short onn=normnum;
- verts+=ovn;
- norms+=onn;
-
- objsort sl[20];
- short n;
- objdata *o;
- for (n=0, o=objlist; o; o=o->next)
- {
- vector mid;
- vecxform(&mid, &o->mid, o->xform, 1);
- vecxform(&mid, &mid, cam, 1);
- long rad=o->rad;
- sl[n].dist=mid.v[1];
- sl[n].o=o;
- sl[n].cuts=0;
- short i;
- for (i=0; i<num; i++)
- {
- long x=vecmul(*(vector*)&clips[i], mid)+clips[i][3];
- if (x-rad>0)
- continue;
- if (x+rad<0)
- break;
- sl[n].cuts|=1<<i;
- }
- if (i==num)
- n++;
- }
- qsort(sl, n, sizeof (objsort), (int (*)(const void *, const void *))objsortfn);
-
- short i;
- for (i=0; i<n; i++)
- {
- objdata *o=sl[i].o;
- if (!o->sub)
- {
- matrix m;
- matmul(m, cam, o->xform);
- vecxform(verts, o->verts, m, o->vertnum);
- vecxformvec(norms, o->norms, m, o->normnum);
- vertnum=o->vertnum;
- normnum=o->normnum;
- if (o->planes)
- drawplanesbsp(o->planes, clips, sl[i].cuts);
- }
- else
- {
- plane *p=0;
- objdata *o2;
- vertnum=normnum=0;
- for (o2=o; o2; o2=o2->sub)
- {
- matrix m;
- matmul(m, cam, o2->xform);
- vecxform(verts+vertnum, o2->verts, m, o2->vertnum);
- vecxformvec(norms+normnum, o2->norms, m, o2->normnum);
- vertnum+=o2->vertnum;
- normnum+=o2->normnum;
- addlist(p, o2->planes, o2->planenum, vertnum-o2->vertnum, normnum-o2->normnum, clips, sl[i].cuts);
- }
- if (p)
- drawplanesmbsp(p);
- }
- }
-
- planenum=opn;
- vertnum=ovn;
- normnum=onn;
- verts-=vertnum;
- norms-=normnum;
- }
-
- // view through a mirror, look at the inverted scenery through a small view,
- // cut everything outside the mirror away
- void viewmirror(const plane &p)
- {
- static level=0;
- if (level==1)
- return;
- level++;
-
- long clips[MAXVERT+2][4];
-
- clips[0][0]=-norms[p.nr.n].v[0];
- clips[0][1]=-norms[p.nr.n].v[1];
- clips[0][2]=-norms[p.nr.n].v[2];
- clips[0][3]=vecmul(norms[p.nr.n], verts[p.mid]);
- short i,j;
- long (*cp)[4]=&clips[1];
-
- for (i=0; i<p.num; i++)
- {
- vecxmul(*(vector*)(*cp), verts[p.v[i+1]], verts[p.v[i]]);
- vecnorm(*(vector*)(*cp));
- (*cp++)[3]=0;
- }
-
- matrix m;
- vectsqr(m, *(vector*)clips[0], clips[0][3]);
- for (i=0; i<3; i++)
- {
- for (j=0; j<4; j++)
- m.m[i][j]=-(m.m[i][j]<<1);
- m.m[i][i]+=dtol(1);
- }
-
- (*cp)[0]=(*cp)[2]=0;
- (*cp)[1]=dtol(1);
- (*cp++)[3]=dtol(-0.5);
-
- viewscenery(m, clips, cp-clips);
-
- level--;
- }
-
- short initscenery(short file)
- {
- mainobj=readobject(file);
- verts=new vector[300];
- norms=new vector[300];
- planes=new plane[200];
- return verts&&norms&&planes&&mainobj;
- }
-
- void closescenery()
- {
- delete verts;
- delete norms;
- delete planes;
- delete mainobj;
- }
-
- void addlight(const vector &pos, long intens)
- {
- lights[lightnum].pos=pos;
- lights[lightnum++].intens=intens;
- }
-
- void addobject(objdata &o)
- {
- if (o.id==-1)
- {
- o.next=objlist;
- o.sub=0;
- objlist=&o;
- return;
- }
- objdata **op=&objlist;
- for (op=&objlist; *op; op=&(*op)->next)
- if ((o.id&252)==((*op)->id&252))
- break;
- if (!*op)
- {
- o.next=o.sub=0;
- *op=&o;
- return;
- }
- if ((o.id&3)<=((*op)->id&3))
- {
- o.next=(*op)->next;
- o.sub=*op;
- *op=&o;
- return;
- }
- for (; (*op); op=&(*op)->sub)
- if ((o.id&3)<=((*op)->id&3))
- break;
- o.sub=*op;
- *op=&o;
- }
-
- // view the scenery through the screen, cut everything outside the screen
- // away...
- void getscenery()
- {
- objlist=0;
- planenum=0;
- vertnum=0;
- normnum=0;
- lightnum=0;
-
- matrix a;
- makematnorm(a);
- mainobj->getobject(a);
-
- // also clip screen!!!
- long clips[5][4]={{0, dtol(1), 0, dtol(-0.5)},
- {dtol(0.908), dtol(0.419), 0, 0},
- {dtol(-0.908), dtol(0.419), 0, 0},
- {0, dtol(3.16), dtol(0.95), 0},
- {0, dtol(3.16), dtol(-0.95), 0}};
-
- makematnorm(a);
- viewscenery(a, clips, 1);
- }
-