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