home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / objsppt.c < prev    next >
C/C++ Source or Header  |  1996-03-19  |  33KB  |  1,303 lines

  1. /* Routines to compute poly normals and bounding sphere
  2. // Object, object list routines
  3. // NEW VR-386 support for composite objects,
  4. // EMM, new recoloring and so on
  5.  
  6. /* Original module written by Bernie Roehl, December 1991 */
  7. // (Massive changes since), mostly by Dave Stampe
  8. // All VR-386 rewrites and integer math by Dave Stampe
  9.  
  10. // This  version support MAP-EMM, and allocates representation memory
  11. // as one large block.  THis requires prescanning of PLG files
  12.  
  13.  
  14. /*
  15.  This code is part of the VR-386 project, created by Dave Stampe.
  16.  VR-386 is a desendent of REND386, created by Dave Stampe and
  17.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  18.  Stampre for VR-386.
  19.  
  20.  Copyright (c) 1994 by Dave Stampe:
  21.  May be freely used to write software for release into the public domain
  22.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  23.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  24.  this software or source code into their products!  Usually there is no
  25.  charge for under 50-100 items for low-cost or shareware products, and terms
  26.  are reasonable.  Any royalties are used for development, so equipment is
  27.  often acceptable payment.
  28.  
  29.  ATTRIBUTION:  If you use any part of this source code or the libraries
  30.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  31.  and any other authors in your documentation, source code, and at startup
  32.  of your program.  Let's keep the freeware ball rolling!
  33.  
  34.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  35.  REND386, improving programmer access by rewriting the code and supplying
  36.  a standard API.  If you write improvements, add new functions rather
  37.  than rewriting current functions.  This will make it possible to
  38.  include you improved code in the next API release.  YOU can help advance
  39.  VR-386.  Comments on the API are welcome.
  40.  
  41.  CONTACT: dstampe@psych.toronto.edu
  42. */
  43.  
  44.  
  45. #include <stdio.h>
  46. #include <alloc.h>
  47. #include <string.h>
  48. #include <math.h>
  49. #include <dos.h>
  50.  
  51. #include "3dstruct.h"
  52. #include "intmath.h"    /* for special sphere test  */
  53. #include "vr_api.h"
  54. #include "segment.h"    // segment operations
  55. #include "renderer.h"
  56. #include "xmem.h"
  57.  
  58.  
  59.  
  60. ///////////////// OBJECT INITIALIZATION /////////////
  61.  
  62. static void find_bounding_sphere(VISOBJ *obj, REP *rep)
  63. {
  64.   int i;
  65.   long minx, maxx, miny, maxy, minz, maxz;
  66.   long r;
  67.  
  68.   accessptr(rep->polys);    // make sure it's accessible
  69.  
  70.   if (rep == NULL) return;
  71.  
  72.   minx = maxx = rep->verts[0].x;
  73.   miny = maxy = rep->verts[0].y;
  74.   minz = maxz = rep->verts[0].z;
  75.  
  76.   for (i = 1; i < rep->nverts; ++i)
  77.     {                     /* find bounding cube */
  78.       if (rep->verts[i].x < minx) minx = rep->verts[i].x;
  79.       if (rep->verts[i].y < miny) miny = rep->verts[i].y;
  80.       if (rep->verts[i].z < minz) minz = rep->verts[i].z;
  81.       if (rep->verts[i].x > maxx) maxx = rep->verts[i].x;
  82.       if (rep->verts[i].y > maxy) maxy = rep->verts[i].y;
  83.       if (rep->verts[i].z > maxz) maxz = rep->verts[i].z;
  84.     }
  85.  
  86.                     /* compute center of cube */
  87.   obj->osphx = obj->sphx = (maxx - minx) /2 + minx;
  88.   obj->osphy = obj->sphy = (maxy - miny) /2 + miny;
  89.   obj->osphz = obj->sphz = (maxz - minz) /2 + minz;
  90.     /* farthest point from center is the radius of the bounding sphere */
  91.  
  92.   r = 0;
  93.   for (i = 0; i < rep->nverts; ++i)
  94.     {
  95.       r = magnitude32((rep->verts[i].x - obj->sphx),
  96.               (rep->verts[i].y - obj->sphy),
  97.               (rep->verts[i].z - obj->sphz) );
  98.       if (r > obj->sphr) obj->sphr = r;
  99.     }
  100. }
  101.  
  102.  
  103. #define NSCALE 536870912     /* 2^29: desired magnitude of normal */
  104.  
  105. static void compute_normal(POLY *p)   /* Compute a polygon's normal */
  106. {                                     /* uses Dave's fast int math  */
  107.   int i = 0;                          /* so it could be used for morphing */
  108.   int j, k;
  109.   long qinx, qiny, qinz;
  110.   long longest = 0;
  111.   long size;
  112.   VERTEX *s,*e, *ls, *le;
  113.  
  114.   p->onormalx = p->normalx = NSCALE;     /* default solution  */
  115.   p->onormaly = p->normaly = 0;
  116.   p->onormalz = p->normalz = 0;
  117.  
  118.   if (p->npoints < 3) return; /* fake it for lines */
  119.  
  120.   if (p->npoints == 3) /* only one solution for triangle: ideal for morphing */
  121.     {
  122.       find_normal(p->points[0]->ox,p->points[0]->oy,p->points[0]->oz,
  123.           p->points[1]->ox,p->points[1]->oy,p->points[1]->oz,
  124.           p->points[2]->ox,p->points[2]->oy,p->points[2]->oz,
  125.           &qinx, &qiny, &qinz );
  126.     p->onormalx = p->normalx = qinx;
  127.     p->onormaly = p->normaly = qiny;
  128.     p->onormalz = p->normalz = qinz;
  129.     return;
  130.     }
  131.  
  132.             /* if more sides: find longest cross product*/
  133.   for (i = 0; i < p->npoints-1; i++)
  134.     {
  135.       s = p->points[i];
  136.       e = p->points[i+1];
  137.       size = big_dist(s->ox, s->oy, s->oz, e->ox, e->oy, e->oz);
  138.       if (size > longest)
  139.     {
  140.       longest = size;
  141.       ls = s;
  142.       le = e;
  143.     }
  144.     }
  145.   s = p->points[i];
  146.   e = p->points[0];
  147.   size = big_dist(s->ox, s->oy, s->oz, e->ox, e->oy, e->oz);
  148.   if (size > longest)
  149.     {
  150.       longest = size;
  151.       ls = s;
  152.       le = e;
  153.     }
  154.  
  155.  if (longest == 0) return;     // degenerate poly
  156.  
  157.  k = -1;         /* now find acceptable point */
  158.  for (i = 0; i < p->npoints; i++)
  159.    {
  160.      s = p->points[i];
  161.      if (s != ls && s != le)
  162.        {
  163.      j = find_normal(ls->ox, ls->oy, ls->oz, le->ox, le->oy, le->oz,
  164.              s->ox, s->oy, s->oz, &qinx, &qiny, &qinz );
  165.  
  166.      if (j > k)     /* longer: more precision */
  167.        {
  168.          p->onormalx = p->normalx = qinx;
  169.          p->onormaly = p->normaly = qiny;
  170.          p->onormalz = p->normalz = qinz;
  171.          k = j;
  172.        }
  173.      if (j > 16) return; /* enough vertices tried already */
  174.        }
  175.    }
  176. }
  177.  
  178.  
  179. /////////////////// REPRESENTATION CONTROL ////////////////
  180.  
  181.  
  182. void lock_current_representation(OBJECT *o, WORD n)  // forces object to use one rep:
  183. {                                // used for morphing animation
  184.   REP *r;
  185.  
  186.   if(!(o=object2visobj(o))) return;    // is a segment!
  187.   if (o)
  188.     {
  189.       o->oflags |= OBJ_REPLOCK;
  190.       if(n==0) return;
  191.       r = o->replist;
  192.       while (n-- && r->next) r = r->next;
  193.       o->current_rep = r;
  194.     }
  195. }
  196.  
  197.  
  198. void unlock_current_representation(OBJECT *o)      // allow rep to be selected by distance again
  199. {
  200.   if(!(o=object2visobj(o))) return;    // is a segment!
  201.   if (o) o->oflags &= ~OBJ_REPLOCK;
  202. }
  203.  
  204.  
  205. static void activate_rep(OBJECT *obj, REP *rep)
  206. {
  207.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  208.   obj->current_rep = rep;      // make rep the current one: used during lock
  209. }
  210.  
  211.  
  212. void select_first_representation(OBJECT *obj)    // make first rep the current one: used during lock
  213. {
  214.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  215.   activate_rep(obj, obj->replist);
  216. }
  217.  
  218.                    // make next rep the current one: used during lock
  219. WORD select_next_representation(OBJECT *obj)      /* return 1 if wrapping back to first */
  220. {
  221.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  222.   if (obj->current_rep == NULL)
  223.         activate_rep(obj, obj->replist);
  224.   else if ((obj->current_rep)->next == NULL)
  225.     {
  226.       activate_rep(obj, obj->replist);
  227.       return 1;
  228.     }
  229.   else
  230.     {
  231.       activate_rep(obj, (obj->current_rep)->next);
  232.       return 0;
  233.     }
  234.   return 1;
  235. }
  236.  
  237.                   // find representation that will be
  238.                   // active at given screen size
  239. void select_representation(OBJECT *obj, WORD size)
  240. {
  241.   REP *p;
  242.  
  243.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  244.   for (p = obj->replist; p; p = p->next)
  245.     if (p->size <= size)
  246.       {
  247.     activate_rep(obj, p);
  248.     break;
  249.       }
  250. }
  251.  
  252.  
  253.                 // set size field of rep
  254. void set_representation_size(OBJECT *obj, WORD size)
  255. {
  256.   REP *rep;
  257.  
  258.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  259.   rep = obj->current_rep;
  260.   if (rep == NULL) return;
  261.   rep->size = size;
  262. }
  263.  
  264.                 // read size field
  265. WORD get_representation_size(OBJECT *obj)
  266. {
  267.   REP *rep;
  268.  
  269.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  270.   rep = obj->current_rep;
  271.   if (rep == NULL) return 0;
  272.   return rep->size;
  273. }
  274.  
  275.  
  276.  
  277. /////////////////// DELETE A REPRESENTATION ///////////////
  278.  
  279. static void del_rep(REP *rep)      // delete rep
  280. {
  281.   if (rep == NULL) return;
  282.  
  283.   if (rep->polys) extfree(rep->polys);   // all memory is one big block
  284.   free(rep);                             // free descriptor too
  285. }
  286.                    // delete current rep of object
  287.         // NOT REALLY SAFE-- LEAVE OUT OF API
  288. void delete_current_representation(OBJECT *obj)    /* needs testing */
  289. {
  290.   REP *rep;
  291.  
  292.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  293.   rep = obj->current_rep;
  294.  
  295.   if (rep == NULL || obj->replist == NULL) return;
  296.   if (rep == obj->replist)
  297.     obj->replist = rep->next;
  298.   else
  299.     {                               // close up the list!
  300.       REP *r;
  301.       for (r = obj->replist; r->next != NULL; r = r->next)
  302.      if (r->next == rep)
  303.        break;
  304.       if (r->next == NULL) return;     /* wasn't in list */
  305.       r->next = rep->next;
  306.     }
  307.   del_rep(rep);
  308. }
  309.  
  310.  
  311. ///////////////// REPRESENTATION CREATE AND LOAD DATA //////////
  312.  
  313.  
  314. static VERTEX **vtxalloc;   // used to allocate mem for vtx ptrs
  315.  
  316.     // this has been reorganized to alloc one block of memory
  317.     // for everything.  This makes banked memory like EMM usable
  318.     // problem is that we don't usually know the total vertices
  319.     // that each poly will have, so the new argument tpverts was added
  320.     // for this.
  321.  
  322. REP *add_representation(OBJECT *obj, WORD size, WORD nv, WORD np, WORD tpverts)
  323. {
  324.   REP *p, *q;
  325.   POLY *pp;
  326.   VERTEX **vpp;
  327.   VERTEX *vp;
  328.   long tmpsize;
  329.  
  330.   if (obj == NULL) return NULL;
  331.   if(!(obj=object2visobj(obj))) return NULL;    // is a segment!
  332.  
  333.   if ((p = malloc(sizeof(REP))) == NULL) return NULL;
  334.   p->size = size;
  335.   p->nverts = 0;
  336.   p->npolys = 0;         /* used as counters when adding */
  337.   p->update_count = 0;
  338.   p->flags = 0;
  339.  
  340.   tmpsize = nv*sizeof(VERTEX) +          // vertices
  341.         tpverts*sizeof(VERTEX *) +   // poly vertex counters
  342.         np*sizeof(POLY);             // polys
  343.  
  344.   pp = (POLY *)extmalloc(tmpsize);       // also makes accessible
  345.   if(pp==NULL)
  346.     {
  347.       free(p);
  348.       return NULL;
  349.     }
  350.   vp = (VERTEX *)(pp+np);
  351.   vtxalloc = (VERTEX **)(vp+nv);  // save these to alloc vertex ptrs to polys
  352.   p->polys = pp;
  353.   p->verts = vp;
  354.  
  355.   activate_rep(obj, p);         // make rep current so we can process it
  356.   if (obj->replist == NULL)     // add to replist of object
  357.     {
  358.       obj->replist = p;
  359.       p->next = NULL;
  360.       return p;
  361.     }
  362.   q = obj->replist;             // insert by switching screen size
  363.   if (q->size <= size)
  364.     {
  365.       p->next = q;
  366.       obj->replist = p;
  367.       return p;
  368.     }
  369.   while (q->next)
  370.     {
  371.       if ((q->next)->size <= size)   break;
  372.       q = q->next;
  373.     }
  374.   p->next = q->next;
  375.   q->next = p;
  376.   return p;
  377. }
  378.  
  379.         // adds poly to rep: still needs vertex list defined
  380. POLY *add_poly(OBJECT *obj, SURFACE color, WORD npoints)
  381. {
  382.   POLY *p;
  383.  
  384.   REP *rep;
  385.  
  386.   if(!(obj=object2visobj(obj))) return NULL;    // is a segment!
  387.   rep = obj->current_rep;
  388.   if (rep == NULL) return NULL;
  389.  
  390.   accessptr(rep->polys);       // ensure access to rep data
  391.  
  392.   p = &(rep->polys[rep->npolys]);  // pointer to current poly (last added)
  393.  
  394.   p->points = vtxalloc;        // "allocate" vertex memory
  395.   vtxalloc += npoints;
  396.  
  397.   p->object = obj;
  398.   p->color = color;
  399.   p->npoints = 0;
  400.   ++rep->npolys;
  401.   return p;
  402. }
  403.  
  404.         // adds vertex to object: these aren't yet hooked to polys
  405. void add_vertex(OBJECT *obj, long x, long y, long z)
  406. {
  407.   REP *rep;
  408.  
  409.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  410.   rep = obj->current_rep;
  411.   if (rep == NULL) return;
  412.  
  413.   accessptr(rep->polys);
  414.  
  415.   rep->verts[rep->nverts].x = rep->verts[rep->nverts].ox = x;
  416.   rep->verts[rep->nverts].y = rep->verts[rep->nverts].oy = y;
  417.   rep->verts[rep->nverts].z = rep->verts[rep->nverts].oz = z;
  418.   ++rep->nverts;
  419. }
  420.  
  421.         // connects vertices to polys thru vertex lists
  422. void add_point(OBJECT *obj, POLY *p, WORD vertnum)
  423. {
  424.   REP *rep;
  425.  
  426.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  427.   rep = obj->current_rep;
  428.   if (rep == NULL) return;
  429.  
  430.   accessptr(rep->polys);
  431.  
  432.   p->points[p->npoints++] = &(rep->verts[vertnum]);
  433. }
  434.  
  435.  
  436.  
  437. ///////////////// OBJECT CREATE AND SUPPORT ///////////
  438.  
  439.                 /* allocate an OBJECT */
  440.                 // also one representation
  441. static OBJECT *new_visobj(int nv, int np, int npverts)
  442. {
  443.   OBJECT *obj;
  444.  
  445.   if ((obj = malloc(sizeof(OBJECT))) == NULL) return NULL;
  446.   obj->oflags = IS_VISOBJ;
  447.   obj->owner = NULL;
  448.   obj->current_rep = obj->replist = NULL;
  449.   if (add_representation(obj, 0, nv, np, npverts) == NULL)
  450.     {
  451.       free(obj);
  452.       return NULL;
  453.     }
  454.   obj->sphx = obj->sphy = obj->sphz = 0;
  455.   obj->osphx = obj->osphy = obj->osphz = 0;
  456.   obj->sphr = 0;
  457.   obj->prev = NULL;
  458.   obj->nnext = NULL;
  459.   obj->update_count = 0;
  460.   return obj;
  461. }
  462.  
  463.  
  464. OBJECT *create_invisible_object()
  465. {
  466.   return new_seg(NULL);
  467. }
  468.  
  469.  
  470. OBJECT *create_fixed_object(WORD nv, WORD np, WORD npverts)
  471. {
  472.   return new_visobj(nv, np, npverts);
  473. }
  474.  
  475.  
  476. void delete_visobj(OBJECT *obj)  // delete an object and all its reps
  477. {
  478.   VISOBJ *v = object2visobj(obj);
  479.   REP *rep,*next;
  480.  
  481.   if(!v) return;
  482.   rep = v->replist;
  483.   while (rep)
  484.     {
  485.       next = rep;
  486.       rep = next->next;
  487.       del_rep(next);
  488.     }
  489.   remove_from_objlist(v);
  490.   if(v->owner) seg_reset_object(v->owner, v);
  491.   free(v);
  492. }
  493.  
  494.  
  495. OBJECT *create_moveable_object(WORD nv, WORD np, WORD npverts)
  496. {
  497.   SEGMENT *s;
  498.   VISOBJ *v = new_visobj(nv, np, npverts);
  499.   if(!v) return NULL;
  500.   s = new_seg(NULL);
  501.   if(!s)
  502.     {
  503.       delete_visobj(v);
  504.       return NULL;
  505.     }
  506.   seg_set_object(s, v);
  507.   return v;
  508. }
  509.  
  510.  
  511. OBJECT *make_fixed_object_moveable(OBJECT *obj, OBJECT *invis)
  512. {
  513.   SEGMENT *s = object2segment(invis);
  514.   VISOBJ  *v = object2visobj(obj);
  515.   if(!v) return NULL;
  516.   if(v->owner) return v->owner;    // already moveable!
  517.   if(!s) s = new_seg(NULL);    // no link supplied
  518.   if(!s)
  519.     {
  520.       delete_visobj(v);
  521.       return NULL;
  522.     }
  523.   seg_set_object(s, v);
  524.   return v;
  525. }
  526.  
  527.     // disconnects visible part of object from
  528.     // invisible object, returns visible part.
  529.     // invisible part is stored in **invis.
  530.     // <preserve> sets whether to leave fixed
  531.     // object in same world positon-- DON'T USE
  532.     // if you are going to make object moveable again!
  533. OBJECT *make_moveable_object_fixed(OBJECT *obj, OBJECT **invis, BOOL preserve)
  534. {
  535.   SEGMENT *s = object2segment(obj);
  536.   VISOBJ  *v = object2visobj(obj);
  537.  
  538.   if(invis) *invis = s;
  539.   if(!v) return NULL;
  540.   if(!s) return v;
  541.   if(preserve)
  542.     {
  543.       REP *r = v->current_rep;
  544.       REP *n = v->replist;
  545.  
  546.       update_segment(s);
  547.       while(n)                // convert all reps to world coords
  548.     {
  549.       v->current_rep = n;
  550.       accessptr(n->polys);
  551.       matmove_rep(n, get_seg_pmatrix(s));
  552.       copy_world_to_object(v);
  553.       n = n->next;
  554.     }
  555.     }
  556.   seg_reset_object(s,v);
  557.   return v;
  558. }
  559.  
  560.  
  561.  
  562. OBJECT *convert_objlist_to_moveable_object(OBJLIST *olist)
  563. {
  564.   VISOBJ *robj, *xobj, *obj = first_in_objlist(olist);
  565.   WORD oflags;
  566.  
  567.   if(!obj) return NULL;        // no objects!
  568.  
  569.   if(!next_in_objlist(obj))    // only one object: make moveable
  570.     {
  571.       return make_fixed_object_moveable(obj,NULL);
  572.     }
  573.   else            // many objects: join together
  574.     {
  575.       robj = create_invisible_object();
  576.       if(!robj) return NULL;
  577.       xobj = make_fixed_object_moveable(obj,NULL);
  578.       naked_attach_object(xobj, robj);          // be sure NOT moved off list!
  579.       while((obj=next_in_objlist(obj))!=NULL)
  580.     {
  581.       xobj = make_fixed_object_moveable(obj,NULL);
  582.       naked_attach_object(xobj, robj);          // be sure NOT moved off list!
  583.     }
  584.     }
  585.   return robj;
  586. }
  587.  
  588.  
  589.     // can delete segments or visobjs, but not if
  590.     // the segment is system owned (camera, light)
  591. void delete_object(OBJECT *obj)
  592. {
  593.   SEGMENT *s = object2segment(obj);    // get parts
  594.   VISOBJ  *v = object2visobj(obj);
  595.  
  596.   if(v) delete_visobj(v);        // delete visobj
  597.   if(s)
  598.     if(!(is_system_owned(s)))    // delete segment if possible
  599.     destroy_segment(s);
  600. }
  601.  
  602.  
  603. /////////////////// OBJECT MANIPULATION ////////////
  604.  
  605.                           // set  object flag bits
  606. void set_obj_flags(OBJECT *obj, unsigned int val)
  607. {
  608.   obj->oflags = (val & OBJ_FLAG_MASK) |
  609.         (obj->oflags & (~OBJ_FLAG_MASK)) | IS_VISOBJ;
  610. }
  611.                           // read object flag bits
  612. unsigned get_obj_flags(OBJECT *obj)
  613. {
  614.   return obj->oflags & OBJ_FLAG_MASK;
  615. }
  616.             // read bounding sphere of object
  617.  
  618. long get_object_bounds(OBJECT *obj, long *x, long *y, long *z)
  619. {
  620.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  621.   if (x) *x = obj->sphx;
  622.   if (y) *y = obj->sphy;
  623.   if (z) *z = obj->sphz;
  624.   return obj->sphr;
  625. }
  626.  
  627.                 // computes renderer data for object
  628. void compute_object(OBJECT *obj)     /* for current rep only! */
  629. {
  630.   int i;
  631.   REP *rep;
  632.  
  633.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  634.  
  635.   rep = obj->current_rep;
  636.   if (rep == NULL) return;
  637.  
  638.   accessptr(rep->polys);        // make sure data is accessible!
  639.  
  640.   for (i = 0; i < rep->npolys; ++i)
  641.     compute_normal(&rep->polys[i]);
  642.  
  643.   find_bounding_sphere(obj, rep);
  644. }
  645.  
  646.                   // computes renderer data for object
  647. void compute_all_object(OBJECT *obj) /* for all reps */
  648. {
  649.   int i;
  650.   REP *rep;
  651.  
  652.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  653.  
  654.   rep = obj->replist;
  655.   if (rep == NULL) return;
  656.   obj->sphr = 0;
  657.   while (rep)
  658.     {
  659.       obj->current_rep = rep;
  660.  
  661.       accessptr(rep->polys);
  662.  
  663.       for (i = 0; i < rep->npolys; ++i)
  664.         compute_normal(&rep->polys[i]);
  665.  
  666.       find_bounding_sphere(obj, rep);
  667.       rep = rep->next;
  668.     }
  669. }
  670.  
  671.  
  672.  
  673. /////////////////  OBJECT LIST MANAGEMENT //////////
  674.  
  675. // NOTES ON OBJECT LIST
  676. //  Why is there an object list with a special header?
  677. // the header serves to terminate the head of the
  678. // double-linked object list, so that the object list
  679. // is easier to add or delete from (the only special
  680. // case is the header, and it just looks like another
  681. // object with a NULL prev ptr.  The double-linked list
  682. // was introduced by Dave to allow the quick insertion
  683. // and deletion of objects from lists, critical since
  684. // moving objects often change object lists when splits
  685. // are used.
  686.  
  687. // OBJECT LISTS contain only VISOBJs, and are used for
  688. // visibility only (in split trees)
  689.  
  690.  
  691. OBJLIST *new_objlist()
  692. {
  693.   OBJLIST *p;
  694.  
  695.   p = malloc(sizeof(OBJLIST));   // allocate a header
  696.   if(p)
  697.     {
  698.       p->nnext  = NULL;          // set to empty
  699.       p->prev   = NULL;
  700.       p->oflags = OBJLIST_HEADER;
  701.     }
  702.   return p;
  703. }
  704.  
  705.  
  706. BOOL on_any_objlist(OBJECT *obj)   // is it currently in a list?
  707. {
  708.   if (obj == NULL) return FALSE;
  709.   if(!(obj=object2visobj(obj))) return FALSE;    // is a segment!
  710.   return (obj->prev!=NULL);
  711. }
  712.  
  713.                // drop from list, needed often
  714. void remove_from_objlist(OBJECT *obj)
  715. {
  716.   if (obj == NULL) return;
  717.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  718.   if (obj->prev == NULL) return; // object list header, or not on objlist
  719.  
  720.   if (obj->nnext != NULL) obj->nnext->prev = obj->prev;
  721.   obj->prev->nnext = obj->nnext;
  722.  
  723.   obj->nnext = obj->prev = NULL;
  724. }
  725.  
  726.  
  727.          // put object at head of list
  728.          // remove if already on any list
  729. void add_to_objlist(OBJLIST *list, OBJECT *obj)
  730. {
  731.   if (list == NULL || obj == NULL) return;
  732.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  733.  
  734.   if(obj->prev) remove_from_objlist(obj);
  735.   if (list->nnext == NULL)
  736.     obj->nnext = NULL;   /* first in empty list */
  737.   else
  738.     {
  739.       list->nnext->prev = obj;   // else add before first
  740.       obj->nnext = list->nnext;
  741.     }
  742.   list->nnext = obj;
  743.   obj->prev = (OBJECT *) list;
  744. }
  745.  
  746.  
  747. void delete_objlist_and_objects(OBJLIST *list)
  748. {
  749.   if (list)                  // delete list, and all objects in it
  750.     {
  751.       while (list->nnext)    // does this work????
  752.     {
  753.       OBJECT *obj;
  754.       obj = list->nnext;
  755.       remove_from_objlist(list->nnext);
  756.       delete_object(obj);
  757.     }
  758.       if(!(list->oflags&SYSTEM_OWNED)) free(list);
  759.     }
  760. }
  761.  
  762. void delete_objlist_keeping_objects(OBJLIST *list)
  763. {
  764.   if (list)                  // delete list, and all objects in it
  765.     {
  766.       while (list->nnext)    // does this work????
  767.     {
  768.       remove_from_objlist(list->nnext);
  769.     }
  770.       if(!(list->oflags&SYSTEM_OWNED)) free(list);
  771.     }
  772. }
  773.  
  774.     // removes all from <from>, adds to start of <to>
  775. void merge_objlists(OBJLIST *from, OBJLIST *to)
  776. {
  777.   VISOBJ *vt = to, *vf = from;
  778.  
  779.   if(!vf->nnext) return;    // none to move
  780.  
  781.   if(!vt->nnext)        // empty to list
  782.     {
  783.       vt->nnext = vf->nnext;    // just move it all
  784.       vf->nnext->prev = vt;
  785.       vf->nnext = NULL;
  786.     }
  787.  
  788.   while(vf->nnext) vf = vf->nnext;    // find end of list
  789.   vt->nnext->prev = vf;            // splice lists
  790.   vf->nnext = vt->nnext;
  791.   vf->nnext->prev = vt;
  792.   vf->nnext = NULL;
  793. }
  794.  
  795.  
  796. OBJLIST *which_objlist(OBJECT *obj)   // look for head of list object is
  797. {                                     // in.  Kinda slow for big lists
  798.   if (obj == NULL) return NULL;
  799.   if(!(obj=object2visobj(obj))) return NULL;    // is a segment!
  800.   for (obj = obj->prev; obj->prev; obj = obj->prev);
  801.   return (OBJLIST *) obj;
  802. }
  803.  
  804.  
  805.  
  806. /* Additional functions suggested by wendellj@microsoft.com */
  807.  
  808. OBJECT *first_in_objlist(OBJLIST *objlist)
  809. {
  810.   return objlist->nnext;
  811. }
  812.  
  813. OBJECT *next_in_objlist(OBJECT *obj)
  814. {
  815.   if(!(obj=object2visobj(obj))) return NULL;    // is a segment!
  816.   return obj->nnext;
  817. }
  818.  
  819. OBJECT *prev_in_objlist(OBJECT *obj)
  820. {
  821.   if(!(obj=object2visobj(obj))) return NULL;    // is a segment!
  822.   return obj->prev;
  823. }
  824.  
  825. BOOL is_first_in_objlist(OBJECT *obj)
  826. {
  827.   if(!(obj=object2visobj(obj))) return FALSE;    // is a segment!
  828.   return obj->prev->prev == NULL;
  829. }
  830.  
  831. BOOL is_last_in_objlist(OBJECT *obj)
  832. {
  833.   if(!(obj=object2visobj(obj))) return FALSE;    // is a segment!
  834.   return obj->nnext == NULL;
  835. }
  836.  
  837.  
  838.            // total number of vertices of all polys NEW NEW NEW
  839. WORD total_object_pverts(OBJECT *obj)
  840. {
  841.   int i,j;
  842.   REP *rep;
  843.  
  844.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  845.   rep = obj->current_rep;
  846.   if (rep == NULL) return 0;
  847.  
  848.   accessptr(rep->polys);
  849.  
  850.   j = 0;
  851.   for(i=0;i<rep->npolys;i++)
  852.     j += rep->polys[i].npoints;
  853.   return j;
  854. }
  855.  
  856.                 // current rep info
  857. void get_obj_info(OBJECT *obj, int *nv, int *np)
  858. {
  859.   REP *rep;
  860.   VISOBJ *v;
  861.  
  862.   if(!(v=object2visobj(obj))) return;    // is a segment!
  863.   rep = v->current_rep;
  864.   if (rep == NULL) return;
  865.  
  866.   if (nv) *nv = rep->nverts;
  867.   if (np) *np = rep->npolys;
  868. }
  869.  
  870.  
  871.  
  872. // This is another useful function.
  873. // You can use it to perform an
  874. // operation on every object in a
  875. // list with one call.  Speed?  What speed?
  876. // this is useful with splits for walking
  877. // all visible objects in the environment
  878.  
  879.  
  880. void walk_objlist(OBJLIST *objlist, void (*fn)(OBJECT *))
  881. {
  882.   OBJECT *obj;
  883.   OBJECT *next;
  884.         /* DS fix: so objects may be deleted by the fn() ! */
  885.   if (objlist == NULL) return;
  886.   obj = objlist->nnext;
  887.   while (obj != NULL)
  888.     {
  889.       next = obj->nnext; /* get ahead of time in case object is modified */
  890.       fn(obj);
  891.       obj = next;
  892.     }
  893. }
  894.  
  895.  
  896. void get_vertex_world_info(OBJECT *obj, WORD vertnum, COORD *x, COORD *y, COORD *z)
  897. {
  898.   REP *rep;
  899.  
  900.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  901.   rep = obj->current_rep;
  902.   if (rep == NULL) return;
  903.  
  904.   accessptr(rep->polys);    // make sure we can acceess data
  905.  
  906.   if (x) *x = rep->verts[vertnum].x;
  907.   if (y) *y = rep->verts[vertnum].y;
  908.   if (z) *z = rep->verts[vertnum].z;
  909. }
  910.  
  911. void get_vertex_info(OBJECT *obj, WORD vertnum, COORD *x, COORD *y, COORD *z)
  912. {
  913.   REP *rep;
  914.  
  915.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  916.   rep = obj->current_rep;
  917.   if (rep == NULL) return;
  918.  
  919.   accessptr(rep->polys);    // make sure we can acceess data
  920.  
  921.   if (x) *x = rep->verts[vertnum].ox;
  922.   if (y) *y = rep->verts[vertnum].oy;
  923.   if (z) *z = rep->verts[vertnum].oz;
  924. }
  925.  
  926. void set_vertex_coords(OBJECT *obj, int vertnum, long x, long y, long z)
  927. {
  928.   REP *rep;
  929.  
  930.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  931.   rep = obj->current_rep;
  932.   if (rep == NULL) return;
  933.  
  934.   accessptr(rep->polys);    // make sure we can acceess data
  935.  
  936.   rep->verts[vertnum].ox = rep->verts[vertnum].x = x;
  937.   rep->verts[vertnum].oy = rep->verts[vertnum].y = y;
  938.   rep->verts[vertnum].oz = rep->verts[vertnum].z = z;
  939. }
  940.  
  941. WORD get_poly_vertex_index(OBJECT *obj, WORD poly, WORD vertex)
  942. {
  943.   int i, n;
  944.   REP *rep;
  945.  
  946.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  947.   rep = obj->current_rep;
  948.   if (rep == NULL) return 0;
  949.  
  950.   accessptr(rep->polys);    // make sure we can acceess data
  951.  
  952.   return (FP_OFF(rep->polys[poly].points[vertex]) -
  953.                 FP_OFF(rep->verts)) /sizeof(VERTEX);
  954. }
  955.  
  956.  
  957.           // get data on poly
  958. void get_poly_info(OBJECT *obj, WORD polynum, SURFACE *color, WORD *nverts)
  959. {
  960.   int i, n;
  961.   REP *rep;
  962.  
  963.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  964.   rep = obj->current_rep;
  965.   if (rep == NULL) return;
  966.  
  967.   accessptr(rep->polys);    // make sure we can acceess data
  968.  
  969.   if (color) *color = rep->polys[polynum].color;
  970.   n = rep->polys[polynum].npoints;
  971.   if (nverts) *nverts = n;
  972. }
  973.  
  974.  
  975. void set_poly_color(OBJECT *obj, WORD polynum, SURFACE color)
  976. {
  977.   REP *rep;
  978.  
  979.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  980.   rep = obj->current_rep;
  981.   if (rep == NULL) return;
  982.  
  983.   accessptr(rep->polys);    // make sure we can acceess data
  984.  
  985.   if (polynum < rep->npolys)
  986.     rep->polys[polynum].color = color;
  987. }
  988.  
  989.  
  990. /////// OBJECT RECOLORING
  991.  
  992.     // very flexible remaps colors of object
  993. void masked_remap_object_surface(OBJECT *obj, SURFACEPAIR map[20], WORD nmap,
  994.               SURFACE sbitmask, SURFACE dbitmask, BOOL all)
  995. {
  996.   REP *rep;
  997.   int i,j;
  998.   SURFACE color;
  999.  
  1000.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1001.   if (all) select_first_representation(obj);
  1002.   do {
  1003.        rep = obj->current_rep;
  1004.        accessptr(rep->polys);
  1005.        for(i=0;i<rep->npolys;i++)
  1006.      {
  1007.        color = rep->polys[i].color;
  1008.        for(j=0;j<nmap;j++)
  1009.          {
  1010.            if((color&sbitmask)==(map[j].old&sbitmask))
  1011.          {
  1012.            color = (color&(~dbitmask))|(map[j].new&dbitmask);
  1013.            break;
  1014.          }
  1015.          }
  1016.        rep->polys[i].color = color;
  1017.      }
  1018.      } while(all && !select_next_representation(obj));
  1019. }
  1020.  
  1021.     // flexible recolo/resurface object
  1022. void masked_recolor_object_surface(OBJECT *obj, SURFACE new,
  1023.                     SURFACE bitmask, BOOL all)
  1024. {
  1025.   REP *rep;
  1026.   int i;
  1027.   SURFACE color;
  1028.  
  1029.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1030.   if (all) select_first_representation(obj);
  1031.   do {
  1032.        rep = obj->current_rep;
  1033.        accessptr(rep->polys);
  1034.        for(i=0;i<rep->npolys;i++)
  1035.      {
  1036.        color = rep->polys[i].color;
  1037.        color = (color&(~bitmask))|(new&bitmask);
  1038.        rep->polys[i].color = color;
  1039.      }
  1040.      } while(all && !select_next_representation(obj));
  1041. }
  1042.  
  1043.  
  1044.     // very flexible remaps colors
  1045.     // does for all objects in objlist
  1046. void objlist_remap_surface(OBJLIST *olist, SURFACEPAIR map[20], WORD nmaps,
  1047.               SURFACE sbitmask, SURFACE dbitmask)
  1048. {
  1049.   OBJECT *obj = first_in_objlist(olist);
  1050.  
  1051.   if(nmaps && obj)
  1052.     {
  1053.       masked_remap_object_surface(obj, map, nmaps, sbitmask, dbitmask, 0);
  1054.       while((obj=next_in_objlist(obj))!=NULL)
  1055.       masked_remap_object_surface(obj, map, nmaps, sbitmask, dbitmask, 0);
  1056.     }
  1057. }
  1058.  
  1059.  
  1060. /* find object that point is closest to center of     */
  1061. /* this is used with the Powerglove to select objects */
  1062.  
  1063. OBJECT *best_collision(OBJLIST *objlist, long x, long y, long z)
  1064. {
  1065.   OBJECT *obj;
  1066.   OBJECT *bestobj = NULL;
  1067.   long mindist = 0x7FFFFFFF;
  1068.   long dist;
  1069.  
  1070.   if (objlist == NULL) return NULL;
  1071.   for (obj = objlist->nnext; obj; obj = obj->nnext)
  1072.     {             /* not selectable... skip */
  1073.       if (obj->oflags & (OBJ_INVIS|OBJ_NONSEL)) continue;
  1074.       if (obj->owner == NULL) continue; /* ignore if no segment */
  1075.       dist = sphere_pretest(obj, x, y, z); /* test object */
  1076.       if (dist < mindist)
  1077.     {
  1078.       mindist = dist; /* better fit: accept */
  1079.       bestobj = obj;
  1080.     }
  1081.     }
  1082.   return bestobj;
  1083. }
  1084.  
  1085.        // set highlight flags in object
  1086. void highlight_object(OBJECT *obj)
  1087. {
  1088.   int i;
  1089.  
  1090.   if (obj == NULL) return;
  1091.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1092.   obj->oflags |= OBJ_HIGHLIGHTED;
  1093. }
  1094.  
  1095.  
  1096. void unhighlight_object(OBJECT *obj)
  1097. {
  1098.   int i;
  1099.  
  1100.   if (obj == NULL) return;
  1101.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1102.   obj->oflags &= ~OBJ_HIGHLIGHTED;
  1103. }
  1104.  
  1105. void make_object_unselectable(OBJECT *obj)
  1106. {
  1107.   int i;
  1108.  
  1109.   if (obj == NULL) return;
  1110.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1111.   obj->oflags |= OBJ_NONSEL;
  1112. }
  1113.  
  1114. void mark_object_invisible(OBJECT *obj)
  1115. {
  1116.   int i;
  1117.  
  1118.   if (obj == NULL) return;
  1119.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1120.   obj->oflags |= OBJ_INVIS;
  1121. }
  1122.  
  1123. void mark_object_visible(OBJECT *obj)
  1124. {
  1125.   int i;
  1126.  
  1127.   if (obj == NULL) return;
  1128.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1129.   obj->oflags &= ~OBJ_INVIS;
  1130. }
  1131.  
  1132.       // set/clear flags in visobj part of object
  1133. void set_object_flags(OBJECT *obj, WORD flagmask, WORD val)
  1134. {
  1135.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1136.   if(val) obj->oflags |= flagmask;
  1137.   else    obj->oflags &= ~flagmask;
  1138. }
  1139.  
  1140.  
  1141.  
  1142.  
  1143. ///////////////////// SCREEN POINT MONITOR SUPPORT //////////////
  1144.  
  1145.  
  1146. // NOTE: the vertex returned by these (and the screen monitor) is
  1147. // the sequential vertex IN THE POLY, NOT the object vertex index.
  1148.  
  1149.     // see what object's on the screen
  1150.     // at the given point <in cursor2d.c>
  1151. extern OBJECT *find_object_on_screen(WORD x, WORD y);
  1152.  
  1153.      // ASSUMES YOU'VE USED DONE A REFRESH WITH MONITOR
  1154.  
  1155. static SWORD screen_obj_poly;    // index of poly in object   (-1 if none)
  1156. static SWORD screen_obj_vert;    // index of vertex in object (-1 if none)
  1157. static SWORD screen_poly_vert;   // index of vertex in poly   (-1 if none)
  1158.  
  1159. void process_screen_monitor()
  1160. {
  1161.   OBJECT *obj;
  1162.   POLY *p;
  1163.   int pi;
  1164.  
  1165.   screen_obj_poly = screen_obj_vert = screen_poly_vert = -1;
  1166.  
  1167.   obj = screen_monitor_object();
  1168.   if (obj)
  1169.     {
  1170.       p = screen_monitor_poly();
  1171.       if (p == NULL) return;
  1172.       screen_obj_poly = (FP_OFF(p) - FP_OFF(obj->current_rep->polys)) /sizeof(POLY);
  1173.       screen_poly_vert = screen_monitor_vertex();
  1174.       if(screen_poly_vert!=-1)
  1175.      screen_obj_vert = get_poly_vertex_index(obj, screen_obj_poly,
  1176.                          screen_poly_vert);
  1177.     }
  1178. }
  1179.  
  1180. OBJECT *screen_found_object()
  1181. {
  1182.   return screen_monitor_object();
  1183. }
  1184.  
  1185. SWORD screen_found_poly()
  1186. {
  1187.   return screen_obj_poly;
  1188. }
  1189.  
  1190. SWORD screen_found_poly_vertex()
  1191. {
  1192.   return screen_poly_vert;
  1193. }
  1194.  
  1195. SWORD screen_found_object_vertex()
  1196. {
  1197.   return screen_obj_vert;
  1198. }
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205. ////////////////// MORE DATA-HIDING ROUTINES //////////
  1206.  
  1207.  
  1208. SEGMENT *object2segment(OBJECT *obj)
  1209. {
  1210.   if(!obj) return NULL;
  1211.   if(is_object_segment(obj)) return obj;
  1212.   return ((VISOBJ *)obj)->owner;
  1213. }
  1214.  
  1215.  
  1216. unsigned get_object_sorting(OBJECT *obj)
  1217. {
  1218.   if(!(obj=object2visobj(obj))) return 0;    // is a segment!
  1219.  
  1220.   return obj->oflags & OBJ_DEPTH_MASK;
  1221. }
  1222.  
  1223. void set_object_sorting(OBJECT *obj, unsigned depth_type)
  1224. {
  1225.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1226.   obj->oflags = (depth_type & OBJ_DEPTH_MASK)
  1227.         | (obj->oflags & (~OBJ_DEPTH_MASK))
  1228.         | IS_VISOBJ;
  1229. }
  1230.  
  1231.  
  1232. /************** MOVE OBJECT COMPLETELY ***********/
  1233.  
  1234. void copy_world_to_object(OBJECT *obj)  // used to "lock" fixed objects
  1235. {                                       // on loading
  1236.   int i;
  1237.   REP *rep;
  1238.  
  1239.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1240.   rep = obj->current_rep;
  1241.   if (rep == NULL) return;
  1242.  
  1243.   accessptr(rep->polys);
  1244.  
  1245.   for (i = 0; i < rep->nverts; ++i)
  1246.     {
  1247.       rep->verts[i].ox = rep->verts[i].x;
  1248.       rep->verts[i].oy = rep->verts[i].y;
  1249.       rep->verts[i].oz = rep->verts[i].z;
  1250.     }
  1251. }
  1252.  
  1253.  
  1254. void scale_object(OBJECT *obj, float sx, float sy, float sz)
  1255. {
  1256.   int i;
  1257.   REP *rep;
  1258.  
  1259.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1260.   rep = obj->current_rep;
  1261.   if (rep == NULL) return;
  1262.  
  1263.   accessptr(rep->polys);
  1264.  
  1265.   for (i = 0; i < rep->nverts; ++i)
  1266.     {
  1267.       rep->verts[i].x = rep->verts[i].ox = rep->verts[i].ox*sx;
  1268.       rep->verts[i].y = rep->verts[i].oy = rep->verts[i].oy*sy;
  1269.       rep->verts[i].z = rep->verts[i].oz = rep->verts[i].oz*sz;
  1270.     }
  1271. }
  1272.  
  1273.  
  1274. void apply_matrix(OBJECT *obj, MATRIX m)  // moves object completely
  1275. {                                         // useful on loading
  1276.   REP *rep;
  1277.  
  1278.   if(!(obj=object2visobj(obj))) return;    // is a segment!
  1279.   rep = obj->current_rep;
  1280.   if(rep==NULL) return;
  1281.  
  1282.   accessptr(rep->polys);
  1283.  
  1284.   matmove_osphere(obj, m);
  1285.   matmove_rep(rep, m);
  1286. }
  1287.  
  1288.  
  1289. void move_rep(VISOBJ *obj)    /* move current rep of object  */
  1290. {                 /* called from renderer itself */
  1291.   REP *rep = obj->current_rep;
  1292.   SEGMENT *s = obj->owner;
  1293.  
  1294.   accessptr(rep->polys);
  1295.  
  1296.   if(s) matmove_rep(rep, get_seg_pmatrix(s));
  1297.  
  1298.   rep->update_count = obj->update_count;    // mark as current
  1299. }
  1300.  
  1301.  
  1302.  
  1303.