home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / PCGLOVE / GLOVE / OBJGLV.ZIP / SRC / DEMO4B / INT / 3DSUPP.CPP next >
C/C++ Source or Header  |  1993-05-02  |  18KB  |  791 lines

  1. /* Routines to compute poly normals and bounding sphere and lots more */
  2.  
  3. /* Written by Bernie Roehl, December 1991 */
  4. /* updated 10/1/91 D. Stampe (for render first stage clip) */
  5. /* now supports integers where needed */
  6.  
  7. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  8.    May be freely used to write software for release into the public domain;
  9.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  10.    for permission to incorporate any part of this software into their
  11.    products!
  12.  */
  13.  
  14. /* Contact: broehl@sunee.waterloo.edu or dstampe@sunee.waterloo.edu */
  15.  
  16. #include <stdio.h>
  17. #include <alloc.h>
  18. #include <string.h>
  19. #include <math.h>
  20. #include <dos.h>
  21.  
  22. #include "3dstruct.hpp"
  23. #include "intmath.h"        /* for special sphere test */
  24.  
  25. #include "demo4.hpp"
  26.  
  27. static unsigned default_depth_sort = DEEPEST ;
  28.  
  29. unsigned get_default_depth_sort()
  30.     {
  31.     return default_depth_sort;
  32.     }
  33.  
  34. void set_default_depth_sort(unsigned value)
  35.     {
  36.     default_depth_sort = value;
  37.     }
  38.  
  39. static void find_bounding_sphere(OBJECT *obj)
  40. {
  41.     int i;
  42.  
  43.     REP *rep = obj->replist;
  44.     float minx, maxx, miny, maxy, minz, maxz;
  45.  
  46.     if (rep == NULL) return;
  47.  
  48.     minx = maxx = rep->verts[0].x;
  49.     miny = maxy = rep->verts[0].y;
  50.     minz = maxz = rep->verts[0].z;
  51.  
  52.     for (i = 1; i < rep->nverts; ++i)
  53.     { /* find bounding cube */
  54.         if (rep->verts[i].x < minx) minx = rep->verts[i].x;
  55.         if (rep->verts[i].y < miny) miny = rep->verts[i].y;
  56.         if (rep->verts[i].z < minz) minz = rep->verts[i].z;
  57.         if (rep->verts[i].x > maxx) maxx = rep->verts[i].x;
  58.         if (rep->verts[i].y > maxy) maxy = rep->verts[i].y;
  59.         if (rep->verts[i].z > maxz) maxz = rep->verts[i].z;
  60.     }
  61.  
  62.     /* compute center of cube */
  63.     obj->osphx = obj->sphx = (maxx - minx) /2 + minx;
  64.     obj->osphy = obj->sphy = (maxy - miny) /2 + miny;
  65.     obj->osphz = obj->sphz = (maxz - minz) /2 + minz;
  66.  
  67.     /* farthest point from center is the radius of the bounding sphere */
  68.     obj->sphr = 0.0;
  69.  
  70.     for (i = 0; i < rep->nverts; ++i)
  71.     {
  72.         float r;
  73.  
  74.      r = (float)(rep->verts[i].x - obj->sphx) * (float)(rep->verts[i].x - obj->sphx) +
  75.              (float)(rep->verts[i].y - obj->sphy) * (float)(rep->verts[i].y - obj->sphy) +
  76.              (float)(rep->verts[i].z - obj->sphz) * (float)(rep->verts[i].z - obj->sphz);
  77.      r = sqrt(r);
  78.      if (r > obj->sphr) obj->sphr = r;
  79.     }
  80. }
  81.  
  82.  
  83. #define NSCALE 536870912     /* 2^29: desired magnitude of normal */
  84. static void compute_normal(POLY *p)    /* Compute a polygon's normal */
  85. {
  86.     int i = 0;
  87.     int j,k;
  88.     long qinx, qiny, qinz;
  89.     long longest = 0;
  90.     long size;
  91.     VERTEX *s,*e, *ls, *le;
  92.  
  93.     p->onormalx = p->normalx = NSCALE;  /* default solution  */
  94.     p->onormaly = p->normaly = 0;
  95.     p->onormalz = p->normalz = 0;
  96.  
  97.     if (p->npoints<3) return;           /* fake it for lines */
  98.  
  99.     if(p->npoints==3)   /* only one solution for triangle */
  100.      {
  101.         find_normal(p->points[0]->ox,p->points[0]->oy,p->points[0]->oz,
  102.               p->points[1]->ox,p->points[1]->oy,p->points[1]->oz,
  103.                     p->points[2]->ox,p->points[2]->oy,p->points[2]->oz,
  104.               &qinx, &qiny, &qinz );
  105.         p->onormalx = p->normalx = qinx;
  106.         p->onormaly = p->normaly = qiny;
  107.         p->onormalz = p->normalz = qinz;
  108.       return;
  109.      }
  110.  
  111.                             /* if more sides: find longest */
  112.     for(i=0;i<p->npoints-1;i++)
  113.      {
  114.         s = p->points[i];
  115.         e = p->points[i+1];
  116.         size = big_dist(s->ox, s->oy, s->oz, e->ox, e->oy, e->oz);
  117.         if(size>longest)
  118.          {
  119.         longest = size;
  120.             ls = s;
  121.             le = e;
  122.          }
  123.      }
  124.     s = p->points[i];
  125.     e = p->points[0];
  126.     size = big_dist(s->ox, s->oy, s->oz, e->ox, e->oy, e->oz);
  127.     if(size>longest)
  128.      {
  129.         longest = size;
  130.         ls = s;
  131.         le = e;
  132.      }
  133.  
  134.     if(longest==0) return;
  135.  
  136.     k = -1;               /* now find acceptable point */
  137.     for(i=0;i<p->npoints;i++)
  138.      {
  139.         s = p->points[i];
  140.  
  141.         if(s!=ls && s!=le)
  142.          {
  143.             j = find_normal(ls->ox, ls->oy, ls->oz, le->ox, le->oy, le->oz,
  144.                     s->ox, s->oy, s->oz, &qinx, &qiny, &qinz );
  145.             if(j>k)                           /* more precision */
  146.              {
  147.                 p->onormalx = p->normalx = qinx;
  148.                 p->onormaly = p->normaly = qiny;
  149.                 p->onormalz = p->normalz = qinz;
  150.                 k = j;
  151.              }
  152.             if (j>16) return;                 /* enough already */
  153.          }
  154.      }
  155. }
  156.  
  157.  
  158. static void activate_rep(OBJECT *obj, REP *rep)
  159. {
  160.     obj->current_rep = rep;
  161. }
  162.  
  163. void first_rep(OBJECT *obj)
  164. {
  165.     activate_rep(obj, obj->replist);
  166. }
  167.  
  168. void next_rep(OBJECT *obj)
  169. {
  170.     if (obj->current_rep == NULL)
  171.         activate_rep(obj, obj->replist);
  172.     else if ((obj->current_rep)->next == NULL)
  173.         activate_rep(obj, obj->replist);
  174.     else
  175.         activate_rep(obj, (obj->current_rep)->next);
  176. }
  177.  
  178. REP *add_representation(OBJECT *obj, long size, int nv, int np)
  179. {
  180.     REP *p, *q;
  181.     if (obj == NULL) return NULL;
  182.     if ((p = (REP *)malloc(sizeof(REP))) == NULL) return NULL;
  183.     p->size = size;
  184.     p->nverts = 0;
  185.     p->npolys = 0; /* used as counters when adding */
  186.     p->update_count = 0;
  187.     p->flags = 0;
  188.     if ((p->verts = (VERTEX *)calloc(nv, sizeof(VERTEX))) == NULL) {
  189.         free(p);
  190.         return NULL;
  191.     }
  192.     if ((p->polys = (POLY *)calloc(np, sizeof(POLY))) == NULL) {
  193.         free(p->verts);
  194.         free(p);
  195.         return NULL;
  196.     }
  197.     activate_rep(obj, p);
  198.     if (obj->replist == NULL) {
  199.         obj->replist = p;
  200.         p->next = NULL;
  201.         return p;
  202.     }
  203.     q = obj->replist;
  204.     if (q->size <= size) {
  205.         p->next = q;
  206.         obj->replist = p;
  207.         return p;
  208.     }
  209.     while (q->next) {
  210.         if ((q->next)->size <= size)
  211.             break;
  212.         q = q->next;
  213.     }
  214.     p->next = q->next;
  215.     q->next = p;
  216.     return p;
  217. }
  218.  
  219. void select_representation(OBJECT *obj, long size)
  220. {
  221.     REP *p;
  222.     for (p = obj->replist; p; p = p->next)
  223.         if (p->size <= size) {
  224.             activate_rep(obj, p);
  225.             break;
  226.         }
  227. }
  228.  
  229. void set_rep_size(OBJECT *obj, long size)
  230. {
  231.     REP *rep = obj->current_rep;
  232.     if (rep == NULL) return;
  233.     rep->size = size;
  234. }
  235.  
  236.  
  237. long get_rep_size(OBJECT *obj)
  238. {
  239.     REP *rep = obj->current_rep;
  240.     if (rep == NULL) return 0;
  241.     return rep->size;
  242. }
  243.  
  244.  
  245. /* allocate an OBJECT */
  246. #pragma argsused
  247. OBJECT *new_obj(int type, int nv, int np)
  248. {
  249.     OBJECT *obj;
  250.  
  251.     if ((obj = (OBJECT *)malloc(sizeof(OBJECT))) == NULL) return NULL;
  252.     obj->oflags = IS_OBJECT | default_depth_sort;
  253.     obj->owner = NULL;
  254.     obj->current_rep = obj->replist = NULL;
  255.     if (add_representation(obj, 0, nv, np) == NULL)
  256.     {
  257.         free(obj);
  258.         return NULL;
  259.     }
  260.     obj->sphx = obj->sphy = obj->sphz = 0;
  261.     obj->osphx = obj->osphy = obj->osphz = 0;
  262.     obj->sphr = 0;
  263.     obj->prev = NULL;
  264.     obj->nnext = NULL;
  265.     obj->update_count = 0;
  266.     return obj;
  267. }
  268.  
  269. void add_vertex(OBJECT *obj, long x, long y, long z)
  270. {
  271.     REP *rep = obj->current_rep;
  272.     if (rep == NULL) return;
  273.  
  274.     rep->verts[rep->nverts].x = rep->verts[rep->nverts].ox = x;
  275.     rep->verts[rep->nverts].y = rep->verts[rep->nverts].oy = y;
  276.     rep->verts[rep->nverts].z = rep->verts[rep->nverts].oz = z;
  277.     ++rep->nverts;
  278. }
  279.  
  280. POLY *add_poly(OBJECT *obj, unsigned color, int npoints)
  281. {
  282.     POLY *p;
  283.     REP *rep = obj->current_rep;
  284.     if (rep == NULL) return NULL;
  285.  
  286.     p = &(rep->polys[rep->npolys]);
  287.     if ((p->points = (VERTEX **)calloc(npoints, sizeof(VERTEX *))) == NULL) return NULL;
  288.     p->object = obj;
  289.     p->color = color;
  290.     p->npoints = 0;
  291.     ++rep->npolys;
  292.     return p;
  293. }
  294.  
  295. void add_point(OBJECT *obj, POLY *p, int vertnum)
  296. {
  297.     REP *rep = obj->current_rep;
  298.     if (rep == NULL) return;
  299.  
  300.     p->points[p->npoints++] = &(rep->verts[vertnum]);
  301. }
  302.  
  303.  
  304. static void del_rep(REP *rep)
  305. {
  306.     if (rep == NULL) return;
  307.  
  308.     while (rep->npolys--)
  309.         if (rep->polys[rep->npolys].points)
  310.             free(rep->polys[rep->npolys].points);
  311.     if (rep->polys) free(rep->polys);
  312.     if (rep->verts) free(rep->verts);
  313.     free(rep);
  314. }
  315.  
  316. void delete_rep(OBJECT *obj)  /* needs testing */
  317. {
  318.     REP *rep = obj->current_rep;
  319.  
  320.     if (rep == NULL || obj->replist == NULL) return;
  321.     if (rep == obj->replist)
  322.         obj->replist = rep->next;
  323.     else
  324.     {
  325.         REP *r;
  326.         for (r = obj->replist; r->next != NULL; r = r->next)
  327.             if (r->next == rep)
  328.                 break;
  329.         if (r->next == NULL) return;  /* wasn't in list */
  330.         r->next = rep->next;
  331.     }
  332.     del_rep(rep);
  333. }
  334.  
  335. void delete_obj(OBJECT *obj)
  336. {
  337.     REP *rep = obj->replist;
  338.     REP *next;
  339.  
  340.     while (rep)
  341.     {
  342.         next = rep;
  343.         rep = next->next;
  344.         del_rep(next);
  345.     }
  346.     free(obj);
  347. }
  348.  
  349. void set_obj_flags(OBJECT *obj, unsigned int val)
  350. {
  351.     obj->oflags = (val & OBJ_FLAG_MASK)
  352.                 | (obj->oflags & (~OBJ_FLAG_MASK))
  353.                 | IS_OBJECT;
  354. }
  355.  
  356. unsigned get_obj_flags(OBJECT *obj)
  357. {
  358.     return obj->oflags & OBJ_FLAG_MASK;
  359. }
  360.  
  361. long get_object_bounds(OBJECT *obj, long *x, long *y, long *z)
  362. {
  363.     if (x) *x = obj->sphx; 
  364.     if (y) *y = obj->sphy; 
  365.     if (z) *z = obj->sphz;
  366.     return obj->sphr;
  367. }
  368.  
  369.  
  370. void compute_obj(OBJECT *obj) /* for current rep only! */
  371. {
  372.     int i;
  373.  
  374.     REP *rep = obj->current_rep;
  375.     if (rep == NULL) return;
  376.  
  377.     for (i = 0; i < rep->npolys; ++i)
  378.         compute_normal(&rep->polys[i]);
  379.  
  380.     find_bounding_sphere(obj);
  381. }
  382.  
  383.  
  384. /* object list management routines */
  385.  
  386. OBJLIST *new_objlist()
  387. {
  388.     OBJLIST *p;
  389.  
  390.     p = (OBJLIST *)malloc(sizeof(OBJLIST));
  391.     if (p)
  392.     {
  393.         p->prev = p->nnext = NULL;
  394.         p->oflags = OBJLIST_HEADER;
  395.     }
  396.     return p;
  397. }
  398.  
  399. void add_to_objlist(OBJLIST *list, OBJECT *obj)
  400. {
  401.     if (list == NULL || obj == NULL) return;
  402.     if (list->nnext == NULL) /* first in list */
  403.         obj->nnext = NULL;
  404.     else
  405.     {
  406.         list->nnext->prev = obj;
  407.         obj->nnext = list->nnext;
  408.     }
  409.     list->nnext = obj;
  410.     obj->prev = (OBJECT *) list;
  411. }
  412.  
  413. void remove_from_objlist(OBJECT *obj)
  414. {
  415.     if (obj == NULL) return;
  416.     if (obj->nnext != NULL) obj->nnext->prev = obj->prev;
  417.     obj->prev->nnext = obj->nnext;
  418.  
  419.     obj->nnext = obj->prev = NULL;
  420. }
  421.  
  422. void del_objlist(OBJLIST *list)
  423. {
  424.     if (list)
  425.     {
  426.         while (list->nnext) {
  427.             OBJECT *obj;
  428.             obj = list->nnext;
  429.             remove_from_objlist(list->nnext);
  430.             delete_obj(obj);
  431.             }
  432.         free(list);
  433.     }
  434. }
  435.  
  436. OBJLIST *on_objlist(OBJECT *obj)
  437. {
  438.     if (obj == NULL) return NULL;
  439.     for (obj = obj->prev; obj->prev; obj = obj->prev);
  440.     return (OBJLIST *) obj;
  441. }
  442.  
  443.  
  444. /* Additional functions suggested by wendellj@microsoft.com */
  445.  
  446. OBJECT *first_in_objlist(OBJLIST *objlist)
  447. {
  448.     return objlist->nnext;
  449. }
  450.  
  451. OBJECT *next_in_objlist(OBJECT *obj)
  452. {
  453.     return obj->nnext;
  454. }
  455.  
  456. OBJECT *prev_in_objlist(OBJECT *obj)
  457. {
  458.     return obj->prev;
  459. }
  460.  
  461. int is_first_in_objlist(OBJECT *obj)
  462. {
  463.     return obj->prev->prev == NULL;
  464. }
  465.  
  466. int is_last_in_objlist(OBJECT *obj)
  467. {
  468.     return obj->nnext == NULL;
  469. }
  470.  
  471. void get_obj_info(OBJECT *obj, int *nv, int *np)
  472. {
  473.     REP *rep = obj->current_rep;
  474.     if (rep == NULL) return;
  475.  
  476.     if (nv) *nv = rep->nverts;
  477.     if (np) *np = rep->npolys;
  478. }
  479.  
  480. void walk_objlist(OBJLIST *objlist, void (*fn)(OBJECT *))
  481. {
  482.  OBJECT *obj;
  483.  OBJECT *next;
  484.                                                             /* be changed by the fn() ! */
  485.  if(objlist==NULL) return;
  486.  obj=objlist->nnext;
  487.  while(obj!=NULL)
  488.     {
  489.         next = obj->nnext;  /* get ahead of time in case object is modified */
  490.         fn(obj);
  491.         obj = next;
  492.     }
  493. }
  494.  
  495. void get_vertex_world_info(OBJECT *obj, int vertnum, long *x, long *y, long *z)
  496. {
  497.     REP *rep = obj->current_rep;
  498.     if (rep == NULL) return;
  499.  
  500.     if (x) *x = rep->verts[vertnum].x;
  501.     if (y) *y = rep->verts[vertnum].y;
  502.     if (z) *z = rep->verts[vertnum].z;
  503. }
  504.  
  505. void get_vertex_info(OBJECT *obj, int vertnum, long *x, long *y, long *z)
  506. {
  507.     REP *rep = obj->current_rep;
  508.     if (rep == NULL) return;
  509.  
  510.     if (x) *x = rep->verts[vertnum].ox;
  511.     if (y) *y = rep->verts[vertnum].oy;
  512.     if (z) *z = rep->verts[vertnum].oz;
  513. }
  514.  
  515.  
  516. void get_poly_info(OBJECT *obj, int polynum,
  517.     unsigned *color, int *nverts,
  518.     int *verts, int maxverts)
  519. {
  520.     int i, n;
  521.     REP *rep = obj->current_rep;
  522.     if (rep == NULL) return;
  523.  
  524.     if (color) *color = rep->polys[polynum].color;
  525.     n = rep->polys[polynum].npoints;
  526.     if (nverts) *nverts = n;
  527.     if (verts)
  528.         for (i = 0; i < n && i < maxverts; ++i)
  529.             verts[i] = (FP_OFF(rep->polys[polynum].points[i]) -
  530.                 FP_OFF(rep->verts)) /sizeof(VERTEX);
  531. }
  532.  
  533.  
  534. void set_poly_color(OBJECT *obj, int polynum, unsigned color)
  535. {
  536.     REP *rep = obj->current_rep;
  537.     if (rep == NULL) return;
  538.  
  539.     if (polynum < rep->npolys)
  540.         rep->polys[polynum].color = color;
  541. }
  542.  
  543. static long sqr(long x)
  544. {
  545.     return x*x;
  546. }
  547.  
  548. /* find nearest object and vertex to [x,y,z] -- return distance */
  549.  
  550. long where_pt(OBJLIST *objlist, long x, long y, long z,
  551.     OBJECT **wobj, int *wvert)
  552. {
  553.     OBJECT *obj;
  554.     long distance; /* the next best thing to being there!  :-) */
  555.     REP *rep;
  556.  
  557.     if (wobj) *wobj = NULL;
  558.     if (wvert) *wvert = 0;
  559.     distance = 0;
  560.     for (obj = objlist->nnext; obj; obj = obj->nnext)
  561.     {
  562.         int i;
  563.  
  564.         if (obj->oflags & (OBJ_INVIS|OBJ_NONSEL)) continue; /* invisible... skip */
  565.         if (labs(x-obj->sphx) > obj->sphr) continue; /* outside of box */
  566.         if (labs(y-obj->sphy) > obj->sphr) continue;
  567.         if (labs(z-obj->sphz) > obj->sphr) continue;
  568.         if (sqr(x-obj->sphx)+sqr(y-obj->sphy)+sqr(z-obj->sphz) >
  569.             sqr(obj->sphr)) continue;
  570.         rep = obj->current_rep;
  571.         if (rep == NULL) continue;
  572.         for (i = 0; i < rep->nverts; ++i)
  573.         {
  574.             long d;
  575.  
  576.             d = sqr(x-rep->verts[i].x)+sqr(y-rep->verts[i].y)+sqr(z-rep->verts[i].z);
  577.             if (d < distance || distance == 0)
  578.             {
  579.                 distance = d;
  580.                 if (wobj) *wobj = obj;
  581.                 if (wvert) *wvert = i;
  582.             }
  583.         }
  584.     }
  585.     return (long) floor(sqrt((double) distance));
  586. }
  587.  
  588.  
  589. /* find object that point is closest to center of */
  590.  
  591. OBJECT *best_collision(OBJLIST *objlist, long x, long y, long z)
  592. {
  593.     OBJECT *obj;
  594.     OBJECT *bestobj = NULL;
  595.     long mindist = 0x7FFFFFFF;
  596.     long dist;
  597.  
  598.     if (objlist == NULL) return NULL;
  599.     for (obj = objlist->nnext; obj; obj = obj->nnext)
  600.     {   /* not selectable... skip */
  601.         if (obj->oflags & (OBJ_INVIS|OBJ_NONSEL)) continue;
  602.         if (obj->owner == NULL) continue; /* ignore if no segment */
  603.         dist = sphere_pretest(obj, x, y, z); /* test object */
  604.         if (dist < mindist)
  605.         {
  606.             mindist = dist; /* better fit: accept */
  607.             bestobj = obj;
  608.         }
  609.     }
  610.     return bestobj;
  611. }
  612.  
  613.  
  614. /* check collision of object (full) */
  615.  
  616. int test_collision(OBJECT *obj, long x, long y, long z)
  617. {
  618.     if (obj->oflags & OBJ_INVIS) return 0; /* invisible... skip */
  619.     if (sphere_pretest(obj, x, y, z) == 0x7FFFFFFF) return 0;  /* test object sphere; */
  620.     if (obj->coll_eval) return obj->coll_eval(obj, x, y, z);
  621.     return 1;
  622. }
  623.  
  624.  
  625. void highlight_obj(OBJECT *obj)
  626. {
  627.     int i;
  628.     REP *p;
  629.  
  630.     if (obj == NULL) return;
  631.     for (p = obj->replist; p; p = p->next)
  632.     {
  633.         for (i = 0; i < p->npolys; ++i) p->polys[i].color |= 0x8000;
  634.     }
  635.     obj->oflags |= OBJ_HIGHLIGHTED;
  636. }
  637.  
  638.  
  639. void unhighlight_obj(OBJECT *obj)
  640. {
  641.     int i;
  642.     REP *p;
  643.  
  644.     if (obj == NULL) return;
  645.     for (p = obj->replist; p; p = p->next)
  646.     {
  647.         for (i = 0; i < p->npolys; ++i) p->polys[i].color &= 0x7FFF;
  648.     }
  649.     obj->oflags &= ~OBJ_HIGHLIGHTED;
  650. }
  651.  
  652.  
  653. extern DSORT *vispolys; /* an array of pointers to visible polygons */
  654.  
  655. extern int npols;
  656.  
  657. static pt_in_poly(NPOLY *p, int x, int y)
  658. {
  659.     int i, v, have_left = 0, have_right = 0;
  660.     NVERTEX **pp = (NVERTEX **)(p+1); /* pointers at end of struct */
  661.  
  662.     v = 0;
  663.     for (i = 0; i < p->npoints; ++i) /* find if point in poly */
  664.     {
  665.         if (pp[i]->xs <= x) v |= 1;
  666.         else if (pp[i]->xs >= x) v |= 2;
  667.         if (pp[i]->ys <= y) v |= 4;
  668.         else if (pp[i]->ys >= y) v |= 8;
  669.         if (v == 15) break;
  670.     }
  671.     if (v != 15) return 0;
  672.     for (i = 0; i < p->npoints; ++i)
  673.     {
  674.         float m, c;
  675.  
  676.         int n = (i == p->npoints-1) ? 0 : (i + 1); /* index of 'next' point */
  677.  
  678.         if (pp[i]->ys < y && pp[n]->ys < y) continue; /* above */
  679.         if (pp[i]->ys > y && pp[n]->ys > y) continue; /* below */
  680.         if (pp[i]->ys == y && pp[n]->ys == y) /* on same line */
  681.         {
  682.             if (pp[i]->xs < x && pp[n]->xs < x) return 0; /* left */
  683.             if (pp[i]->xs > x && pp[n]->xs > x) return 0; /* right */
  684.             return 1; /* [x,y] is on same line as an edge */
  685.         }
  686.         if (pp[n]->ys == y) continue; /* skip shared vtx-- bug fix */
  687.  
  688.         /* otherwise, this line crosses the scanline containing [x,y] */
  689.         /* fast L/R pretest */
  690.         if (pp[i]->xs < x && pp[n]->xs < x)
  691.         {
  692.             if (have_left) return 0; /* we're to the right */
  693.             if (have_right) return 1; /* we're in between */
  694.             have_left = 1;
  695.             continue;
  696.         }
  697.         if (pp[i]->xs > x && pp[n]->xs > x)
  698.         {
  699.             if (have_right) return 0; /* we're to the right */
  700.             if (have_left) return 1; /* we're in between */
  701.             have_right = 1;
  702.             continue;
  703.         }
  704.         /* check which side of line */
  705.         m = ((float) (pp[n]->xs - pp[i]->xs)) /
  706.             ((float) (pp[n]->ys - pp[i]->ys));
  707.         c = m*(y - pp[i]->ys) + pp[i]->xs;
  708.         if (c < x)
  709.         {
  710.             if (have_left) return 0; /* we're to the right */
  711.             if (have_right) return 1; /* we're in between */
  712.             have_left = 1;
  713.         }
  714.         else if (c > x)
  715.         {
  716.             if (have_right) return 0; /* we're to the right */
  717.             if (have_left) return 1; /* we're in between */
  718.             have_right = 1;
  719.         }
  720.         else return 1; /* on it! */
  721.     }
  722.     return 0;
  723. }
  724.  
  725. OBJECT *where_screen_pt(int *pol, int *vert, int x, int y)
  726.     {
  727.     OBJECT *obj;
  728.     POLY *p;
  729.     set_screen_monitor(x, y);
  730.     refresh_display();
  731.     p = read_screen_monitor();
  732.     if (p == NULL) return NULL;
  733.     obj = p->object;
  734.     if (obj == NULL) return NULL;
  735.     if (pol) *pol = (FP_OFF(p) - FP_OFF(obj->current_rep->polys)) /sizeof(POLY);
  736.     if (vert) *vert = 0;
  737.     return obj;
  738.     }
  739.  
  740. OBJECT *locate_screen_pt(int *pol, int *vert)
  741. {
  742.     OBJECT *obj;
  743.     POLY *p;
  744.     int i;
  745.  
  746.     p = read_screen_monitor();
  747.     if (p == NULL) return NULL;
  748.  
  749.     obj = p->object;
  750.     if (pol) *pol = (FP_OFF(p) - FP_OFF(obj->current_rep->polys)) /sizeof(POLY);
  751.     if (vert) *vert = 0;
  752.     return obj;
  753. }
  754.  
  755.  
  756. void *get_object_owner(OBJECT *obj)
  757. {
  758.     return obj->owner;
  759. }
  760.  
  761. void set_object_owner(OBJECT *obj, void *owner)
  762. {
  763.     obj->owner = owner;
  764. }
  765.  
  766. void copy_world_to_object(OBJECT *obj)
  767. {
  768.     int i;
  769.     REP *rep = obj->current_rep;
  770.     if (rep == NULL) return;
  771.  
  772.     for (i = 0; i < rep->nverts; ++i)
  773.     {
  774.         rep->verts[i].ox = rep->verts[i].x;
  775.         rep->verts[i].oy = rep->verts[i].y;
  776.         rep->verts[i].oz = rep->verts[i].z;
  777.     }
  778. }
  779.  
  780. unsigned get_object_sorting(OBJECT *obj)
  781. {
  782.     return obj->oflags & OBJ_DEPTH_MASK;
  783. }
  784.  
  785. void set_object_sorting(OBJECT *obj, unsigned depth_type)
  786. {
  787.     obj->oflags = (depth_type & OBJ_DEPTH_MASK)
  788.                   | (obj->oflags & (~OBJ_DEPTH_MASK))
  789.                   | IS_OBJECT;
  790. }
  791.