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

  1. /*****************************************************************************
  2.                                   ATTENTION!
  3.                            this source is VOTEWARE,
  4.               you may only use it to the conditions listed below:
  5.  
  6.   -You may modify it, or use parts of it in your own source as long as
  7.     this header stays on top of all files containing this source.
  8.   -You must give proper credit to the author, Niklas Beisert / pascal.
  9.   -You may not use it in commercial productions without the written
  10.     permission of the author.
  11.   -AND MOST IMPORTANT: you have to buy an Assembly '94 CD-ROM
  12.     by Sound Solutions (if you don't have it already) and vote for VEX-InTrO
  13.     in the PC-64k-Intro-Compo! (if you have already sent your voting card,
  14.     buy another one and fill it out CORRECTLY!!!)
  15. *****************************************************************************/
  16.  
  17.  
  18.  
  19. // the heart of the vector engine...
  20. // at first it gets all objects and sorts them. then it draws the objects.
  21. // if some objects are to be intersected, all their planes are put in a
  22. // list, and a new bsp tree is generated (greetings go to jinx and avatar ;)
  23. // a z-buffer might be better, but a) this is borland c++ 3.1, b) this is
  24. // not really fast for a small number of planes and c) i did not know
  25. // z-buffering at that time...
  26. // a bsp tree is generated by recursively taking one plane
  27. // and sorting all the others to a behind or before-list (compared to the one)
  28. // if one plane is on both sides, it will be cut and sorted to the before-
  29. // and behind-list. then do the same to both lists, till all lists are single
  30. // planes
  31.  
  32. #include <dos.h>
  33. #include <stdlib.h>
  34. #include <mem.h>
  35. //#include <fcntl.h>
  36. //#include <io.h>
  37. //#include "..\ovlio.h"
  38. #include "polygons.h"
  39. #include "ints.h"
  40. #include "matrix.h"
  41. #include "intrsect.h"
  42. #include "project.h"
  43. #include "vect.h"
  44.  
  45. vector *verts;
  46. short vertnum;
  47. vector *norms;
  48. short normnum;
  49. plane *planes;
  50. short planenum;
  51. objdata *objlist;
  52. object *mainobj;
  53. lightdata lights[8];
  54. short lightnum;
  55.  
  56. void viewmirror(const plane& p);
  57.  
  58. unsigned char mirror=0;
  59. void getlights(const short *v, const lightspot *l, long *cols, short n)
  60. {
  61.   short i, j;
  62.   for (j=0; j<n; j++, v++, l++, cols++)
  63.   {
  64.     if (!l->cn)
  65.     {
  66.       *cols=l->c0+mirror;
  67.       continue;
  68.     }
  69.     long intens=dtol(0.2);
  70.     vector &cv=verts[*v];
  71.     vector &cn=norms[l->n];
  72.     for (i=0; i<lightnum; i++)
  73.     {
  74.       vector vc;
  75.       vecsub(vc, lights[i].pos, cv);
  76.       long x=vecmul(vc, cn);
  77.       if (x<0)
  78.         continue;
  79.       intens+=IntMulDiv(lights[i].intens, x, vecsqr(vc));
  80.     }
  81.     if (intens>=dtol(1))
  82.       intens=dtol(1);
  83.     *cols=(itol(l->c0)+intens*l->cn)+itol(mirror);
  84.   }
  85. }
  86.  
  87. // draw one plane
  88. void drawplane(const plane &p)
  89. {
  90.   long coords[MAXVERT][2];
  91.   long cols[MAXVERT];
  92.   projectverts(verts, p.v, coords, p.num, dtol(345), dtol(300));
  93.   short i;
  94.   char *bmp;
  95.   unsigned short wid;
  96.   long texv[MAXVERT][2];
  97.   switch (p.disp)
  98.   {
  99.   case DISP_NORM:
  100.   case DISP_ORPUT:
  101.   case DISP_TEXT:
  102.   case DISP_TEXTX:
  103.     if (p.nr.cn)
  104.     {
  105.       getlights(&p.mid, &p.nr, cols, 1);
  106.       cols[0]>>=16;
  107.     }
  108.     else
  109.       cols[0]=p.nr.c0+mirror;
  110.     switch (p.disp)
  111.     {
  112.     case DISP_NORM:
  113.       fillpolygon(coords, p.num, cols[0], xfillline, scrpage<<14);
  114.       break;
  115.     case DISP_ORPUT:
  116.       outpw(0x3ce, 0x1003);
  117.       fillpolygon(coords, p.num, cols[0], xfillliner, scrpage<<14);
  118.       outpw(0x3ce, 0x0003);
  119.       break;
  120.     case DISP_TEXT:
  121.       gettexture(p.textnum, p.tex, p.num, texv, bmp, wid);
  122.       vtexturepolygon(coords, texv, p.num, bmp, wid, cols[0], vxtextureline, scrpage<<14);
  123.       break;
  124.     case DISP_TEXTX:
  125.       gettexture(p.textnum, p.tex, p.num, texv, bmp, wid);
  126.       vtexturepolygon(coords, texv, p.num, bmp, wid, cols[0], vxtexturelinex, scrpage<<14);
  127.       break;
  128.     }
  129.     break;
  130.   case DISP_SHADED:
  131.     getlights(p.v, p.col, cols, p.num);
  132.     vshadepolygon(coords, cols, p.num, vxshadelined, scrpage<<14);
  133.     break;
  134.   case DISP_MIRROR:
  135.     i=mirror;
  136.     mirror+=p.nr.c0;
  137.     fillpolygon(coords, p.num, p.nr.cn, xfillline, scrpage<<14);
  138.     viewmirror(p);
  139.     mirror=i;
  140.     break;
  141.   }
  142. }
  143.  
  144. // cut a plane by the cutdata
  145. // very important for building a bsp tree and clipping to the screen bounds.
  146. inline static plane *intersectplane(plane &pl, const cutdata &rt, short split)
  147. {
  148.   short v1=vertnum++;
  149.   planecutv(rt.vpa, verts[pl.v[rt.pal]], verts[pl.v[rt.pac]], verts[v1]);
  150.   short v2=vertnum++;
  151.   planecutv(rt.vpb, verts[pl.v[rt.pbl]], verts[pl.v[rt.pbc]], verts[v2]);
  152.   unsigned long ct1, ct2;
  153.   if (pl.disp==DISP_SHADED)
  154.   {
  155.     vector *nrm=&norms[normnum];
  156.     planecutv(rt.vpa, norms[pl.col[rt.pal].n], norms[pl.col[rt.pac].n], *nrm);
  157.     ((lightspot*)&ct1)->n=normnum++;
  158.     planecutc2(rt.vpa, &pl.col[rt.pal].c0, &pl.col[rt.pac].c0, &((lightspot*)&ct1)->c0);
  159.     vecnorm(*nrm);
  160.     nrm++;
  161.     planecutv(rt.vpb, norms[pl.col[rt.pbl].n], norms[pl.col[rt.pbc].n], *nrm);
  162.     ((lightspot*)&ct2)->n=normnum++;
  163.     planecutc2(rt.vpb, &pl.col[rt.pbl].c0, &pl.col[rt.pbc].c0, &((lightspot*)&ct2)->c0);
  164.     vecnorm(*nrm);
  165.   }
  166.   else if (pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
  167.   {
  168.     planecuts2(rt.vpa, &pl.tex[rt.pal], &pl.tex[rt.pac], &ct1);
  169.     planecuts2(rt.vpb, &pl.tex[rt.pbl], &pl.tex[rt.pbc], &ct2);
  170.   }
  171.  
  172.   if (split)
  173.   {
  174.     plane &p=planes[planenum++];
  175.     p=pl;
  176.     if (rt.pbc>rt.pal)
  177.     {
  178.       p.num+=rt.pal+3-rt.pbc;
  179.       memmove(&p.v[rt.pal+3], &p.v[rt.pbc], (p.num-rt.pal-3)<<1);
  180.       p.v[rt.pal+1]=v1;
  181.       p.v[rt.pal+2]=v2;
  182.       p.v[p.num]=p.v[0];
  183.       if (p.disp==DISP_SHADED||p.disp==DISP_TEXT||p.disp==DISP_TEXTX)
  184.       {
  185.         memmove(&p.ct[rt.pal+3], &p.ct[rt.pbc], (p.num-rt.pal-3)<<2);
  186.         p.ct[rt.pal+1]=ct1;
  187.         p.ct[rt.pal+2]=ct2;
  188.         p.ct[p.num]=p.ct[0];
  189.       }
  190.     }
  191.     else
  192.     {
  193.       p.num=rt.pal+3-rt.pbc;
  194.       memmove(&p.v[2], &p.v[rt.pbc], (p.num-2)<<1);
  195.       p.v[0]=v1;
  196.       p.v[1]=v2;
  197.       p.v[p.num]=p.v[0];
  198.       if (p.disp==DISP_SHADED||p.disp==DISP_TEXT||p.disp==DISP_TEXTX)
  199.       {
  200.         memmove(&p.ct[2], &p.ct[rt.pbc], (p.num-2)<<2);
  201.         p.ct[0]=ct1;
  202.         p.ct[1]=ct2;
  203.         p.ct[p.num]=p.ct[0];
  204.       }
  205.     }
  206.   }
  207.  
  208.   if (rt.pac>rt.pbl)
  209.   {
  210.     pl.num+=rt.pbl+3-rt.pac;
  211.     memmove(&pl.v[rt.pbl+3], &pl.v[rt.pac], (pl.num-rt.pbl-3)<<1);
  212.     pl.v[rt.pbl+1]=v2;
  213.     pl.v[rt.pbl+2]=v1;
  214.     pl.v[pl.num]=pl.v[0];
  215.     if (pl.disp==DISP_SHADED||pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
  216.     {
  217.       memmove(&pl.ct[rt.pbl+3], &pl.ct[rt.pac], (pl.num-rt.pbl-3)<<2);
  218.       pl.ct[rt.pbl+1]=ct2;
  219.       pl.ct[rt.pbl+2]=ct1;
  220.       pl.ct[pl.num]=pl.ct[0];
  221.     }
  222.   }
  223.   else
  224.   {
  225.     pl.num=rt.pbl+3-rt.pac;
  226.     memmove(&pl.v[2], &pl.v[rt.pac], (pl.num-2)<<1);
  227.     pl.v[0]=v2;
  228.     pl.v[1]=v1;
  229.     pl.v[pl.num]=pl.v[0];
  230.     if (pl.disp==DISP_SHADED||pl.disp==DISP_TEXT||pl.disp==DISP_TEXTX)
  231.     {
  232.       memmove(&pl.col[2], &pl.col[rt.pac], (pl.num-2)<<2);
  233.       pl.ct[0]=ct2;
  234.       pl.ct[1]=ct1;
  235.       pl.ct[pl.num]=pl.ct[0];
  236.     }
  237.   }
  238.  
  239.   if (split)
  240.     return &planes[planenum-1];
  241.   else
  242.     return 0;
  243. }
  244.  
  245. // is this plane visible??
  246. inline short checkvisible(const plane &p)
  247. {
  248.   return (vecmul(norms[p.nr.n], verts[p.mid])<1)&&!!(p.opt&OPT_DISPLAY);
  249. }
  250.  
  251. // clip a plane
  252. inline plane *clipplane(plane *p, const long (§)[4], short copy)
  253. {
  254.   cutdata rt;
  255.   short s=chkplanecut(sect, verts, p->v, p->num, rt);
  256.   if (s==3)
  257.   {
  258.     if (copy)
  259.     {
  260.       planes[planenum]=*p;
  261.       p=&planes[planenum++];
  262.     }
  263.     intersectplane(*p, rt, 0);
  264.     return p;
  265.   }
  266.   else
  267.     if (s==2)
  268.       return p;
  269.     else
  270.       return 0;
  271. }
  272.  
  273. // draw some planes (with intersections)
  274. void drawplanesbsphelp(const plane *p, const long (*sect)[4], unsigned sects)
  275. {
  276.   short opn=planenum;
  277.   short ovn=vertnum;
  278.   short onn=normnum;
  279.  
  280.   const plane *p2;
  281.   short i;
  282.   for (; p; p=p->m)
  283.     if (checkvisible(*p))
  284.     {
  285.       for (p2=p, i=0; i<16; i++)
  286.         if ((sects>>i)&1)
  287.           if (!(p2=clipplane((plane*)p2, sect[i], p2==p)))
  288.             break;
  289.       if (!p2)
  290.         continue;
  291.       drawplane(*p2);
  292.     }
  293.  
  294.   planenum=opn;
  295.   vertnum=ovn;
  296.   normnum=onn;
  297. }
  298.  
  299. // draw an object with the bsp tree
  300. void drawplanesbsp(const plane *p, const long (*sect)[4], unsigned short sects)
  301. {
  302. // do we see the front of the plane?
  303.   short flipped=vecmul(norms[p->nr.n], verts[p->mid])>=1;
  304. // draw everything behind the plane first
  305.   if (flipped)
  306.   {
  307.     if (p->f)
  308.       drawplanesbsp(p->f, sect, sects);
  309.   }
  310.   else
  311.   {
  312.     if (p->b)
  313.       drawplanesbsp(p->b, sect, sects);
  314.   }
  315.  
  316. // then draw coplanar planes
  317.   drawplanesbsphelp(p, sect, sects);
  318.  
  319. // finally everything before the plane
  320.   if (flipped)
  321.   {
  322.     if (p->b)
  323.       drawplanesbsp(p->b, sect, sects);
  324.   }
  325.   else
  326.   {
  327.     if (p->f)
  328.       drawplanesbsp(p->f, sect, sects);
  329.   }
  330. }
  331.  
  332. // add some planes to the list, clipping them by the screen boundaries
  333. void addlist(plane *&p0, const plane *p, short n, short vo, short no, const long (*sect)[4], unsigned short sects)
  334. {
  335.   plane **pp;
  336.   for (pp=&p0; *pp; pp=&(*pp)->next);
  337.  
  338.   const plane *end;
  339.   for (end=p+n; p<end; p++)
  340.   {
  341.     *pp=&planes[planenum];
  342.     **pp=*p;
  343.  
  344.     short i;
  345.     (*pp)->mid+=vo;
  346.     (*pp)->nr.n+=no;
  347.     for (i=0; i<=(*pp)->num; i++)
  348.       (*pp)->v[i]+=vo;
  349.     if ((*pp)->disp==DISP_SHADED)
  350.       for (i=0; i<=(*pp)->num; i++)
  351.         (*pp)->col[i].n+=no;
  352.  
  353.     if (!checkvisible(**pp))
  354.       continue;
  355.  
  356.     for (i=0; i<16; i++)
  357.       if ((sects>>i)&1)
  358.         if (!clipplane(*pp, sect[i], 0))
  359.           break;
  360.     if (i!=16)
  361.       continue;
  362.  
  363.     planenum++;
  364.     pp=&(*pp)->next;
  365.   }
  366.   *pp=0;
  367. }
  368.  
  369. // this function seems to arrange the spacecut, but i don't really know how it
  370. // works anymore... sorry...
  371. void drawplanesmbsphelp(plane *p)
  372. {
  373.   plane **pb=&p->b, **pm=&p->m, **pf=&p->f, *c;
  374.   long pl[4];
  375.   cutdata rt;
  376.   calcplane(norms[p->nr.n], verts[p->mid], pl);
  377.   for (c=p->next; c; c=c->next)
  378.     switch (chkplanecut(pl, verts, c->v, c->num, rt))
  379.     {
  380.     case 0:
  381.       pb=&(*pb=c)->next;
  382.       break;
  383.     case 1:
  384.       pm=&(*pm=c)->m;
  385.       break;
  386.     case 2:
  387.       pf=&(*pf=c)->next;
  388.       break;
  389.     case 3:
  390.       pb=&(*pb=intersectplane(*c, rt, 1))->next;
  391.       pf=&(*pf=c)->next;
  392.       break;
  393.     }
  394.   *pb=*pm=*pf=0;
  395. }
  396.  
  397. // this function seems to arrange the spacecut, but i don't really know how it
  398. // works anymore... sorry...
  399. void drawplanesmbsp(plane *p)
  400. {
  401.   short opn=planenum;
  402.   short ovn=vertnum;
  403.   short onn=normnum;
  404.  
  405.   drawplanesmbsphelp(p);
  406.   if (p->b)
  407.     drawplanesmbsp(p->b);
  408.   plane *p2;
  409.   for (p2=p; p2; p2=p2->m)
  410.     drawplane(*p2);
  411.   if (p->f)
  412.     drawplanesmbsp(p->f);
  413.  
  414.   planenum=opn;
  415.   vertnum=ovn;
  416.   normnum=onn;
  417. }
  418.  
  419. struct objsort
  420. {
  421.   long dist;
  422.   objdata *o;
  423.   unsigned short cuts;
  424. };
  425.  
  426. short objsortfn(const objsort *a, const objsort *b)
  427. {
  428.   long c=b->dist-a->dist;
  429.   return c>0?1:c?-1:0;
  430. }
  431.  
  432. // view the scenery... clips are the screen boundaries
  433. void viewscenery(const matrix &cam, long (*clips)[4], short num)
  434. {
  435.   short opn=planenum;
  436.   short ovn=vertnum;
  437.   short onn=normnum;
  438.   verts+=ovn;
  439.   norms+=onn;
  440.  
  441.   objsort sl[20];
  442.   short n;
  443.   objdata *o;
  444.   for (n=0, o=objlist; o; o=o->next)
  445.   {
  446.     vector mid;
  447.     vecxform(&mid, &o->mid, o->xform, 1);
  448.     vecxform(&mid, &mid, cam, 1);
  449.     long rad=o->rad;
  450.     sl[n].dist=mid.v[1];
  451.     sl[n].o=o;
  452.     sl[n].cuts=0;
  453.     short i;
  454.     for (i=0; i<num; i++)
  455.     {
  456.       long x=vecmul(*(vector*)&clips[i], mid)+clips[i][3];
  457.       if (x-rad>0)
  458.         continue;
  459.       if (x+rad<0)
  460.         break;
  461.       sl[n].cuts|=1<<i;
  462.     }
  463.     if (i==num)
  464.       n++;
  465.   }
  466.   qsort(sl, n, sizeof (objsort), (int (*)(const void *, const void *))objsortfn);
  467.  
  468.   short i;
  469.   for (i=0; i<n; i++)
  470.   {
  471.     objdata *o=sl[i].o;
  472.     if (!o->sub)
  473.     {
  474.       matrix m;
  475.       matmul(m, cam, o->xform);
  476.       vecxform(verts, o->verts, m, o->vertnum);
  477.       vecxformvec(norms, o->norms, m, o->normnum);
  478.       vertnum=o->vertnum;
  479.       normnum=o->normnum;
  480.       if (o->planes)
  481.         drawplanesbsp(o->planes, clips, sl[i].cuts);
  482.     }
  483.     else
  484.     {
  485.       plane *p=0;
  486.       objdata *o2;
  487.       vertnum=normnum=0;
  488.       for (o2=o; o2; o2=o2->sub)
  489.       {
  490.         matrix m;
  491.         matmul(m, cam, o2->xform);
  492.         vecxform(verts+vertnum, o2->verts, m, o2->vertnum);
  493.         vecxformvec(norms+normnum, o2->norms, m, o2->normnum);
  494.         vertnum+=o2->vertnum;
  495.         normnum+=o2->normnum;
  496.         addlist(p, o2->planes, o2->planenum, vertnum-o2->vertnum, normnum-o2->normnum, clips, sl[i].cuts);
  497.       }
  498.       if (p)
  499.         drawplanesmbsp(p);
  500.     }
  501.   }
  502.  
  503.   planenum=opn;
  504.   vertnum=ovn;
  505.   normnum=onn;
  506.   verts-=vertnum;
  507.   norms-=normnum;
  508. }
  509.  
  510. // view through a mirror, look at the inverted scenery through a small view,
  511. // cut everything outside the mirror away
  512. void viewmirror(const plane &p)
  513. {
  514.   static level=0;
  515.   if (level==1)
  516.     return;
  517.   level++;
  518.  
  519.   long clips[MAXVERT+2][4];
  520.  
  521.   clips[0][0]=-norms[p.nr.n].v[0];
  522.   clips[0][1]=-norms[p.nr.n].v[1];
  523.   clips[0][2]=-norms[p.nr.n].v[2];
  524.   clips[0][3]=vecmul(norms[p.nr.n], verts[p.mid]);
  525.   short i,j;
  526.   long (*cp)[4]=&clips[1];
  527.  
  528.   for (i=0; i<p.num; i++)
  529.   {
  530.     vecxmul(*(vector*)(*cp), verts[p.v[i+1]], verts[p.v[i]]);
  531.     vecnorm(*(vector*)(*cp));
  532.     (*cp++)[3]=0;
  533.   }
  534.  
  535.   matrix m;
  536.   vectsqr(m, *(vector*)clips[0], clips[0][3]);
  537.   for (i=0; i<3; i++)
  538.   {
  539.     for (j=0; j<4; j++)
  540.       m.m[i][j]=-(m.m[i][j]<<1);
  541.     m.m[i][i]+=dtol(1);
  542.   }
  543.  
  544.   (*cp)[0]=(*cp)[2]=0;
  545.   (*cp)[1]=dtol(1);
  546.   (*cp++)[3]=dtol(-0.5);
  547.  
  548.   viewscenery(m, clips, cp-clips);
  549.  
  550.   level--;
  551. }
  552.  
  553. short initscenery(short file)
  554. {
  555.   mainobj=readobject(file);
  556.   verts=new vector[300];
  557.   norms=new vector[300];
  558.   planes=new plane[200];
  559.   return verts&&norms&&planes&&mainobj;
  560. }
  561.  
  562. void closescenery()
  563. {
  564.   delete verts;
  565.   delete norms;
  566.   delete planes;
  567.   delete mainobj;
  568. }
  569.  
  570. void addlight(const vector &pos, long intens)
  571. {
  572.   lights[lightnum].pos=pos;
  573.   lights[lightnum++].intens=intens;
  574. }
  575.  
  576. void addobject(objdata &o)
  577. {
  578.   if (o.id==-1)
  579.   {
  580.     o.next=objlist;
  581.     o.sub=0;
  582.     objlist=&o;
  583.     return;
  584.   }
  585.   objdata **op=&objlist;
  586.   for (op=&objlist; *op; op=&(*op)->next)
  587.     if ((o.id&252)==((*op)->id&252))
  588.       break;
  589.   if (!*op)
  590.   {
  591.     o.next=o.sub=0;
  592.     *op=&o;
  593.     return;
  594.   }
  595.   if ((o.id&3)<=((*op)->id&3))
  596.   {
  597.     o.next=(*op)->next;
  598.     o.sub=*op;
  599.     *op=&o;
  600.     return;
  601.   }
  602.   for (; (*op); op=&(*op)->sub)
  603.     if ((o.id&3)<=((*op)->id&3))
  604.       break;
  605.   o.sub=*op;
  606.   *op=&o;
  607. }
  608.  
  609. // view the scenery through the screen, cut everything outside the screen
  610. // away...
  611. void getscenery()
  612. {
  613.   objlist=0;
  614.   planenum=0;
  615.   vertnum=0;
  616.   normnum=0;
  617.   lightnum=0;
  618.  
  619.   matrix a;
  620.   makematnorm(a);
  621.   mainobj->getobject(a);
  622.  
  623. // also clip screen!!!
  624.   long clips[5][4]={{0, dtol(1), 0, dtol(-0.5)},
  625.                     {dtol(0.908), dtol(0.419), 0, 0},
  626.                     {dtol(-0.908), dtol(0.419), 0, 0},
  627.                     {0, dtol(3.16), dtol(0.95), 0},
  628.                     {0, dtol(3.16), dtol(-0.95), 0}};
  629.  
  630.   makematnorm(a);
  631.   viewscenery(a, clips, 1);
  632. }
  633.