home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Party 1994: Try This At Home
/
disk_image.bin
/
source
/
vexsrc
/
scenery.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-29
|
15KB
|
633 lines
/*****************************************************************************
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);
}