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

  1. /* Routines for dealing with segmented figures */
  2.  
  3. /* Original implementation written by Bernie Roehl, March 1992 */
  4.  
  5. /* Major paradigm shift to current form: Dave Stampe, Aug. '92 */
  6.  
  7. // The theoretical basis for segments is that of
  8. // cascading transformation to implement jointed
  9. // objects.  The new paradigm goes even further,
  10. // using segments for moving body parts, lights, viewpoints
  11. // and so on. New methods for efficient updating were
  12. // added, and the ability to use matrices to control motion added
  13.  
  14. // Changes, Jan. '93 by Dave Stampe for Release 5:
  15. // added joint angle caching, fixed up the attach/detach
  16. // so they work properly. Worked out fast automatic updates:
  17. // see statmach.c
  18.  
  19. // MASSIVE changes for VR-386, including POSE, and multiple
  20. // lists, composite objects... just about everything
  21. // VR-386 changes by Dave Stampe, last as of 9/1/94
  22.  
  23. /*
  24.  This code is part of the VR-386 project, created by Dave Stampe.
  25.  VR-386 is a desendent of REND386, created by Dave Stampe and
  26.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  27.  Stampre for VR-386.
  28.  
  29.  Copyright (c) 1994 by Dave Stampe:
  30.  May be freely used to write software for release into the public domain
  31.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  32.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  33.  this software or source code into their products!  Usually there is no
  34.  charge for under 50-100 items for low-cost or shareware products, and terms
  35.  are reasonable.  Any royalties are used for development, so equipment is
  36.  often acceptable payment.
  37.  
  38.  ATTRIBUTION:  If you use any part of this source code or the libraries
  39.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  40.  and any other authors in your documentation, source code, and at startup
  41.  of your program.  Let's keep the freeware ball rolling!
  42.  
  43.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  44.  REND386, improving programmer access by rewriting the code and supplying
  45.  a standard API.  If you write improvements, add new functions rather
  46.  than rewriting current functions.  This will make it possible to
  47.  include you improved code in the next API release.  YOU can help advance
  48.  VR-386.  Comments on the API are welcome.
  49.  
  50.  CONTACT: dstampe@psych.toronto.edu
  51. */
  52.  
  53.  
  54.  
  55. #include <stdio.h>
  56. #include <alloc.h>
  57. #include <string.h>
  58.  
  59. #define SEGDEF 1
  60.  
  61. typedef struct _segment SEGMENT;
  62.  
  63. #include "3dstruct.h"
  64. #include "vr_api.h"
  65. #include "intmath.h"
  66. #include "segment.h"
  67.  
  68.  
  69. struct _segment {
  70.     unsigned flags; /* if bit 0 set, segment has been modified */
  71.     SEGMENT *parent, *child, *sibling;
  72.     MATRIX jmatrix; /* joint relationship */
  73.     MATRIX pmatrix; /* world position     */
  74.     OBJECT *object;
  75.     long rx, ry, rz; /* added for animation control */
  76.     SEGMENT *root;
  77.     SEGMENT *update_next;    // used for updating automatically
  78.     SEGMENT *update_prev;
  79.     char *name;
  80.     unsigned fix_count; /* used to fix scale after rel_rotate      */
  81. };
  82.  
  83. //other uses of flags: for segments and object:
  84.  
  85. #define IS_OBJECT     0x8000    // VROBJECT specifiers
  86. #define IS_SEGMENT    0x0080
  87. #define SYSTEM_OWNED  0x0040    // owned by light, camera, or body
  88. #define HAS_OBJECT    0x0020    // has a visible OBJECT attached
  89. #define IS_MOVEABLE   0x0010    // segment or attached object
  90.  
  91. #define SEG_MODIFIED  1        // modified position
  92. #define OBJ_MODIFIED  2        // representation only changed
  93.  
  94. #define ON_UPDATE_LIST     0x0008   // update list status
  95. #define NOT_ON_UPDATE_LIST 0xFFF7
  96.  
  97. #define UPDATED_MASK  0xFFF0        // used to reset when processed
  98. #define SEG_EXTERNAL_FLAGS_MASK 0xFFFF       // what externals can see
  99.  
  100. static int fix_init = 100;
  101.  
  102.  
  103. SEGMENT *new_seg(SEGMENT *parent)
  104. {
  105.   SEGMENT *s;
  106.  
  107.   if ((s = malloc(sizeof(SEGMENT))) == NULL) return NULL;
  108.   s->parent = parent;
  109.   s->child = NULL;
  110.   if (parent)
  111.     {
  112.       s->sibling = parent->child;
  113.       parent->child = s;
  114.     }
  115.   else s->sibling = NULL;
  116.  
  117.   identity_matrix(s->jmatrix);
  118.   if (parent) memcpy(&(s->pmatrix), &(parent->pmatrix), sizeof(MATRIX));
  119.   else identity_matrix(s->pmatrix);
  120.  
  121.   s->object = NULL;
  122.   s->flags = IS_SEGMENT | SEG_MODIFIED | IS_MOVEABLE;
  123.   s->name = NULL;
  124.   s->root = (parent) ? parent->root : s;  // update root
  125.   s->rx = s->ry = s->rz = 0;
  126.   s->fix_count = fix_init;
  127.   s->update_next = NULL;
  128.   s->update_prev = NULL;
  129.   fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
  130.  
  131.   return s;
  132. }
  133.  
  134.  
  135. /////// SEGMENT SUPPORT
  136.  
  137. void seg_set_object(SEGMENT *s, VISOBJ *obj)
  138. {
  139.   s->object = obj;
  140.   obj->owner = s;
  141.   obj->oflags |= IS_MOVEABLE;
  142.   s->flags |= OBJ_MODIFIED | HAS_OBJECT;
  143.   update_segment(s);    // so object is current
  144. }
  145.  
  146.  
  147. void seg_reset_object(SEGMENT *s, VISOBJ *obj)
  148. {
  149.   s->object = NULL;
  150.   obj->owner = NULL;
  151.   obj->oflags &= (~IS_MOVEABLE);
  152.   s->flags &= (~HAS_OBJECT);
  153. }
  154.  
  155.  
  156. void *seg_get_object(SEGMENT *s)
  157. {
  158.   return s->object;
  159. }
  160.  
  161. char *seg_getname(SEGMENT *s)
  162. {
  163.     return s->name;
  164. }
  165.  
  166. void seg_setname(SEGMENT *s, char *name)
  167. {
  168.     s->name = strdup(name);
  169. }
  170.  
  171. void seg_getpose(SEGMENT *s, POSE *p)
  172. {
  173.   p->x = s->jmatrix[3][0];
  174.   p->y = s->jmatrix[3][1];
  175.   p->z = s->jmatrix[3][2];
  176.   p->rx = s->rx;
  177.   p->ry = s->ry;
  178.   p->rz = s->rz;
  179. }
  180.  
  181. void seg_getmatpose(SEGMENT *s, POSE *p)
  182. {
  183.   p->x = s->jmatrix[3][0];
  184.   p->y = s->jmatrix[3][1];
  185.   p->z = s->jmatrix[3][2];
  186.   matrix_to_angle(s->jmatrix, &p->rx, &p->ry, &p->rz);
  187.   s->rx = p->rx;
  188.   s->ry = p->ry;
  189.   s->rz = p->rz;
  190. }
  191.  
  192.  
  193. void seg_getworldpose(SEGMENT *s, POSE *p)
  194. {
  195.   p->x = s->pmatrix[3][0];
  196.   p->y = s->pmatrix[3][1];
  197.   p->z = s->pmatrix[3][2];
  198.   matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
  199. }
  200.  
  201.  
  202. void seg_setpose(SEGMENT *s, POSE *p)
  203. {
  204.   if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
  205.   if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
  206.   if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
  207.   if(p->rx!=DONTCARE) s->rx = p->rx;
  208.   if(p->ry!=DONTCARE) s->ry = p->ry;
  209.   if(p->rz!=DONTCARE) s->rz = p->rz;
  210.   multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
  211.            s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
  212.   s->flags |= SEG_MODIFIED;
  213. }
  214.  
  215. void seg_getposang(SEGMENT *s, long *rx, long *ry, long *rz)
  216. {
  217.   matrix_to_angle(s->pmatrix, rx, ry, rz);
  218. }
  219.  
  220. void seg_getjointang(SEGMENT *s, long *rx, long *ry, long *rz)
  221. {
  222.   matrix_to_angle(s->jmatrix, rx, ry, rz);
  223.   s->rx = *rx;
  224.   s->ry = *ry; /* ADDED FOR ANIMATION */
  225.   s->rz = *rz;
  226. }
  227.  
  228. void seg_getrxyz(SEGMENT *s, long *rx, long *ry, long *rz)
  229. {
  230.   *rx = s->rx; /* ADDED FOR ANIMATION */
  231.   *ry = s->ry;
  232.   *rz = s->rz;
  233. }
  234.  
  235. void seg_getposxyz(SEGMENT *s, long *x, long *y, long *z)
  236. {
  237.   if(x) *x = s->pmatrix[3][0];
  238.   if(y) *y = s->pmatrix[3][1];
  239.   if(z) *z = s->pmatrix[3][2];
  240. }
  241.  
  242. void seg_getjointxyz(SEGMENT *s, long *x, long *y, long *z)
  243. {
  244.     *x = s->jmatrix[3][0];
  245.     *y = s->jmatrix[3][1];
  246.     *z = s->jmatrix[3][2];
  247. }
  248.  
  249.  
  250. void abs_move_segment(SEGMENT *s, long tx, long ty, long tz)
  251. {
  252.   s->jmatrix[3][0] = tx;
  253.   s->jmatrix[3][1] = ty;
  254.   s->jmatrix[3][2] = tz;
  255.   s->flags |= SEG_MODIFIED;
  256. }
  257.  
  258. void rel_move_segment(SEGMENT *s, long tx, long ty, long tz)
  259. {
  260.   s->jmatrix[3][0] += tx;
  261.   s->jmatrix[3][1] += ty;
  262.   s->jmatrix[3][2] += tz;
  263.   s->flags |= SEG_MODIFIED;
  264. }
  265.  
  266.  
  267. void abs_mat_segment(SEGMENT *s, MATRIX m)
  268. {
  269.   memcpy(s->jmatrix, m, sizeof(MATRIX));
  270.   s-> flags |= SEG_MODIFIED;
  271. }
  272.  
  273.  
  274. void rel_mat_segment(SEGMENT *s, MATRIX m)
  275. {
  276.   matrix_product(s->jmatrix, m, s->jmatrix);
  277.   s-> flags |= SEG_MODIFIED;
  278.   s->fix_count--;
  279.   if (s->fix_count == 0)
  280.     {
  281.       s->fix_count = fix_init;
  282.       fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
  283.       renormalize_matrix(s->jmatrix);
  284.     }
  285. }
  286.  
  287.  
  288. void abs_rotmat_segment(SEGMENT *s, MATRIX m)
  289. {
  290.   s->jmatrix[0][0] = m[0][0];
  291.   s->jmatrix[0][1] = m[0][1];
  292.   s->jmatrix[0][2] = m[0][2];
  293.   s->jmatrix[1][0] = m[1][0];
  294.   s->jmatrix[1][1] = m[1][1];
  295.   s->jmatrix[1][2] = m[1][2];
  296.   s->jmatrix[2][0] = m[2][0];
  297.   s->jmatrix[2][1] = m[2][1];
  298.   s->jmatrix[2][2] = m[2][2];
  299.   s->flags |= SEG_MODIFIED;
  300. }
  301.  
  302.  
  303. void rel_rotmat_segment(SEGMENT *s, MATRIX m)
  304. {
  305.   matrix_mult(s->jmatrix, m, s->jmatrix);
  306.   s-> flags |= SEG_MODIFIED;
  307.   s->fix_count--;
  308.   if (s->fix_count == 0)
  309.     {
  310.       s->fix_count = fix_init;
  311.       fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
  312.       renormalize_matrix(s->jmatrix);
  313.     }
  314. }
  315.  
  316. #define RXYZ 1        /* matrix rotation orders            */
  317. #define RYXZ 0          /* ONLY RYXZ guaranteed to be tested */
  318. #define RXZY 2
  319. #define RZYX 5
  320. #define RZXY 4
  321. #define RYZX 6
  322.  
  323. void abs_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
  324. {
  325.   MATRIX m;
  326.   multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
  327.   s->rx = rx;
  328.   s->ry = ry; /* ADDED FOR ANIMATION */
  329.   s->rz = rz;
  330.   abs_rotmat_segment(s, m);
  331. }
  332.  
  333. void rel_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
  334. {
  335.   MATRIX m;
  336.   multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
  337.   rel_rotmat_segment(s, m);
  338. }
  339.  
  340.  
  341. extern void split_move_handler(OBJECT *obj);    // the default
  342.  
  343. static void (*move_handler)(OBJECT *) = split_move_handler; /* called when object moved */
  344.  
  345. void set_move_handler(void (*move_handler_ptr)(OBJECT *))
  346. {
  347.   move_handler = move_handler_ptr;
  348. }
  349.  
  350.  
  351. void full_update_segment(SEGMENT *seg)
  352. {
  353.   SEGMENT *s;
  354.   OBJECT *obj;
  355.  
  356.   if(!seg) return;
  357.   remove_from_segment_update_list(seg);
  358.   seg->flags &= UPDATED_MASK;
  359.   if (seg->parent)
  360.     matrix_product(seg->parent->pmatrix, seg->jmatrix, seg->pmatrix);
  361.   else
  362.     memcpy(&(seg->pmatrix), &(seg->jmatrix), sizeof(MATRIX));
  363.  
  364.   if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
  365.     {
  366.       matmove_osphere(obj, seg->pmatrix);
  367.       obj->owner = seg;         /* just to be safe...       */
  368.       if (move_handler) move_handler(obj); /* this moves in split tree */
  369.     }
  370.  
  371.   for (s = seg->child; s; s = s->sibling)
  372.     {
  373.       s->root = seg;           // keep root current!
  374.       full_update_segment(s);
  375.     }
  376. }
  377.  
  378.  
  379.  
  380. void update_segment(SEGMENT *seg) /* scan till update needed */
  381. {
  382.   SEGMENT *s;
  383.   OBJECT *obj;
  384.  
  385.   if(!seg) return;
  386.   remove_from_segment_update_list(seg);
  387.   if (seg->flags & SEG_MODIFIED)
  388.     full_update_segment(seg);
  389.   else if (seg->flags&OBJ_MODIFIED)
  390.     {
  391.       if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
  392.     {
  393.       matmove_osphere(obj, seg->pmatrix);
  394.       obj->owner = seg;         /* just to be safe...       */
  395.       if (move_handler) move_handler(obj); /* this moves in split tree */
  396.     }
  397.     }
  398.   else
  399.     for (s = seg->child; s; s = s->sibling)
  400.       {
  401.     s->root = seg;
  402.     update_segment(s);
  403.       }
  404. }
  405.  
  406.     // update object in world only
  407. void update_object(OBJECT *obj)
  408. {
  409.   SEGMENT *s = object2segment(obj);
  410.   if(!s) return;
  411.   s->flags |= OBJ_MODIFIED;
  412. //  if (move_handler) move_handler(obj); /* this moves in split tree */
  413.   update_segment(s);
  414. }
  415.  
  416.        // moderate update
  417. void physical_update_object(OBJECT *obj)
  418. {
  419.   SEGMENT *s = object2segment(obj);
  420.   compute_object(obj);
  421.   if(!s) return;
  422.   s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
  423.   update_segment(s);
  424. }
  425.  
  426.        // truly massive update
  427. void global_update_object(OBJECT *obj)
  428. {
  429.   SEGMENT *s = object2segment(obj);
  430.   compute_all_object(obj);
  431.   if(!s) return;
  432.   s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
  433.   s = find_root_segment(s);
  434.   full_update_segment(s);
  435. }
  436.  
  437.  
  438.  
  439. int seg_get_flags(SEGMENT *s)
  440. {
  441.   return s->flags & SEG_EXTERNAL_FLAGS_MASK;
  442. }
  443.  
  444.  
  445. void seg_set_flags(SEGMENT *s, int f)
  446. {
  447.   s->flags = (s->flags&(~SEG_EXTERNAL_FLAGS_MASK))|(f&SEG_EXTERNAL_FLAGS_MASK);
  448. }
  449.  
  450.  
  451. SEGMENT *parent_segment(SEGMENT *s)
  452. {
  453.     return s->parent;
  454. }
  455.  
  456.  
  457. SEGMENT *child_segment(SEGMENT *s)
  458. {
  459.     return s->child;
  460. }
  461.  
  462.  
  463. SEGMENT *sibling_segment(SEGMENT *s)
  464. {
  465.     return s->sibling;
  466. }
  467.  
  468.  
  469. MATRIX *get_seg_jmatrix(SEGMENT *s)
  470. {
  471.     return &s->jmatrix;
  472. }
  473.  
  474.  
  475. MATRIX *get_seg_pmatrix(SEGMENT *s)
  476. {
  477.     return &s->pmatrix;
  478. }
  479.  
  480.  
  481. void detach_segment(SEGMENT *s, BOOL preserve) /* assumes segment is updated! */
  482. {
  483.   SEGMENT *p;
  484.   MATRIX n;
  485.  
  486.   if ((p = s->parent) == NULL) return;
  487.   s->parent = NULL;
  488.   if (preserve)
  489.       memcpy(&(s->jmatrix), &(s->pmatrix), sizeof(MATRIX));
  490.   s->flags |= SEG_MODIFIED;
  491.  
  492.   if (p->child == s)
  493.     {
  494.       p->child = s->sibling;
  495.       s->sibling = NULL;
  496.       s->root = s;
  497.       update_segment(s);
  498.       return;
  499.     }
  500.   for (p = p->child; p->sibling; p = p->sibling)
  501.     if (p->sibling == s)
  502.       {
  503.     p->sibling = s->sibling;
  504.     s->sibling = NULL;
  505.     s->root = s;
  506.     update_segment(s);
  507.     return;
  508.       }
  509.   s->root = s;
  510.   update_segment(s);
  511. }
  512.  
  513.  
  514. void detach_object(OBJECT *obj, BOOL preserve)
  515. {
  516.  SEGMENT *p = object2segment(obj);
  517.  if(!p) return;
  518.  detach_segment(p, preserve);
  519. }
  520.  
  521.  
  522.      /* assumes parent is updated! */
  523.      // preserves world position if flagged
  524. void attach_segment(SEGMENT *s, SEGMENT *to, BOOL preserve)
  525. {
  526.   MATRIX m,n;
  527.  
  528.   if (s->parent) detach_segment(s, preserve);
  529.   s->parent = to;
  530.   s->sibling = to->child;
  531.   to->child = s;
  532.   s->root = to->root;  //find_root_segment(s);
  533.  
  534.   if(preserve)     // preserves world position
  535.     {
  536.       inverse_matrix(to->pmatrix, m);
  537.       matrix_product(m, s->pmatrix, s->jmatrix);
  538.     }
  539. //  to->flags |= SEG_MODIFIED;
  540.   s->flags |= SEG_MODIFIED;
  541.   update_segment(to);        // at least changes roots
  542. }
  543.  
  544.     // used for loading objects, to ensure they don't
  545.     // get moved in world or taken off objlist
  546.     // be sure to update <to> later!
  547. void naked_attach_object(OBJECT *obj, OBJECT *to)
  548. {
  549.   SEGMENT *p, *q;
  550.   p = object2segment(obj);
  551.   if(!p) return;
  552.   q = object2segment(to);
  553.   if(!q) return;
  554.  
  555.   p->parent = q;
  556.   p->sibling = q->child;
  557.   q->child = p;
  558.   p->root = q->root;   //find_root_segment(q);
  559.  
  560.   p->flags |= SEG_MODIFIED | OBJ_MODIFIED;
  561. }
  562.  
  563.  
  564. void attach_object(OBJECT *obj, OBJECT *to, BOOL preserve)
  565. {
  566.  SEGMENT *p, *q;
  567.  p = object2segment(obj);
  568.  if(!p) return;
  569.  q = object2segment(to);
  570.  if(!q) return;
  571.  attach_segment(p, q, preserve);
  572. }
  573.  
  574.  
  575. void destroy_segment(SEGMENT *s)    // just removes segment
  576. {
  577.   SEGMENT *p, *q;
  578.  
  579.   detach_segment(s,1);   /* first detach us from our parent */
  580.   p = s->child;          /* then recursively detach all our child segments */
  581.   while (p)
  582.     {
  583.       q = p->sibling;
  584.       detach_segment(p,1);
  585.       p = q;
  586.     }
  587.   remove_from_segment_update_list(s);
  588.   free(s);
  589. }
  590.  
  591.  
  592.     // delete segment, descendents and objects
  593. void delete_object_and_children(OBJECT *obj)
  594. {
  595.   SEGMENT *p, *q;
  596.   SEGMENT *s = object2segment(obj);
  597.  
  598.   if(!s) return;
  599.  
  600.   detach_segment(s,0);   /* first detach us from our parent */
  601.   p = s->child;          /* then recursively delete all our child segments */
  602.   while (p)
  603.     {
  604.       q = p->sibling;
  605.       delete_object_and_children(p);
  606.       p = q;
  607.     }
  608.   if (s->object && (s->flags&HAS_OBJECT) )  // object to delete?
  609.       delete_visobj(s->object);
  610.   remove_from_segment_update_list(s);
  611.   if(!(s->flags&SYSTEM_OWNED))            // delete if not camera/light segment
  612.       free(s);
  613. }
  614.  
  615.  
  616.     // marks segment as protected from recursive deletes
  617. void register_system_segment(SEGMENT *s)
  618. {
  619.   s->flags |= SYSTEM_OWNED;
  620. }
  621.  
  622.  
  623.  
  624. /////// SEGMENT AUTO-UPDATE
  625.  
  626.  
  627. static SEGMENT *update_list_root = NULL;
  628.  
  629.  
  630.     // dump entire list
  631. void clear_object_update_list()
  632. {
  633.   SEGMENT *sn;
  634.   SEGMENT *s = update_list_root;
  635.   while(s)
  636.     {
  637.       sn = s->update_next;
  638.       s->flags &= NOT_ON_UPDATE_LIST;
  639.       s->update_next = NULL;
  640.       s->update_prev = NULL;
  641.       s = sn;
  642.     }
  643.   update_list_root = NULL;
  644. }
  645.  
  646.  
  647. void remove_from_segment_update_list(SEGMENT *seg)
  648. {
  649.   if(!(seg->flags&ON_UPDATE_LIST)) return;
  650.   if(!seg->update_prev)                     // first in list
  651.     {
  652.       update_list_root = seg->update_next;
  653.       if(update_list_root)
  654.      update_list_root->update_prev = NULL;   // only one
  655.     }
  656.   else
  657.     {
  658.       seg->update_prev->update_next = seg->update_next;
  659.       if(seg->update_next)
  660.     seg->update_next->update_prev = seg->update_prev;
  661.     }
  662.  
  663.   seg->flags &= NOT_ON_UPDATE_LIST;
  664. }
  665.  
  666.  
  667. void remove_from_object_update_list(OBJECT *obj)
  668. {
  669.   SEGMENT *s = object2segment(obj);
  670.   if(s) remove_from_segment_update_list(s);
  671. }
  672.  
  673.     // puts root on update list
  674. void add_to_object_update_list(OBJECT *obj)
  675. {
  676.   SEGMENT *s, *seg = object2segment(obj);
  677.   if(!seg) return;
  678.   s = seg->root;
  679.   if(!s) return;                        // hey! hey!
  680.   if(s->flags&ON_UPDATE_LIST) return;    // already on list
  681.  
  682.   s->update_next = update_list_root;    // add to list
  683.   if(update_list_root)
  684.      update_list_root->update_prev = s;
  685.   s->update_prev = NULL;
  686.   update_list_root = s;
  687.   s->flags |= ON_UPDATE_LIST;
  688. }
  689.  
  690.  
  691. BOOL process_object_update_list()
  692. {
  693.   SEGMENT *sn;
  694.   SEGMENT *s = update_list_root;
  695.  
  696.   if(!s) return FALSE;
  697.  
  698.   while(s)
  699.     {
  700.       sn = s->update_next;
  701.       update_segment(s);
  702.       s->flags &= NOT_ON_UPDATE_LIST;
  703.       s->update_next = NULL;
  704.       s->update_prev = NULL;
  705.       s = sn;
  706.     }
  707.   update_list_root = NULL;
  708.   return TRUE;
  709. }
  710.  
  711.  
  712. SEGMENT *find_root_segment(SEGMENT *s)    // try to do without
  713. {
  714.     SEGMENT *ss = s;
  715.     while (s->parent) s = s->parent;
  716.     ss->root = s; /* ADDED FOR ANIMATION */
  717.     return s;
  718. }
  719.  
  720.  
  721. OBJECT *find_root_object(OBJECT *obj)    // try to do without
  722. {
  723.   SEGMENT *ss = object2segment(obj);
  724.   SEGMENT *s = ss;
  725.  
  726.   if(!s) return NULL;
  727.   while (s->parent) s = s->parent;
  728.   ss->root = s;
  729.   return s;
  730. }
  731.  
  732.  
  733. SEGMENT *get_root_segment(SEGMENT *s)
  734. {
  735.     return s->root; /* ADDED FOR ANIMATION */
  736. }
  737.  
  738.  
  739.  
  740. VISOBJ *object2visobj(OBJECT *obj)
  741. {
  742.  if(!obj) return NULL;
  743.  if(is_object_visobj(obj)) return obj;
  744.  return ((SEGMENT *)obj)->object;
  745. }
  746.  
  747.  
  748.  
  749.  
  750. //////// RELATIONAL ITEMS
  751.  
  752. BOOL is_object_child_of(OBJECT *parent, OBJECT *child)
  753. {
  754.   SEGMENT *s = object2segment(parent);
  755.   SEGMENT *g = object2segment(child);
  756.  
  757.   if(!s || !g) return FALSE;
  758.   if(s==g) return TRUE;
  759.   while(g->parent)
  760.     {
  761.       if(g->parent==s) return TRUE;
  762.       g = g->parent;
  763.     }
  764.   return FALSE;
  765. }
  766.  
  767.  
  768. BOOL are_objects_related(OBJECT *o1, OBJECT *o2)
  769. {
  770.   SEGMENT *p = object2segment(o1);
  771.  
  772.   if(!p) return FALSE;
  773.   if(p->root) p = p->root;
  774.  
  775.   return is_object_child_of(p,o2);
  776. }
  777.  
  778.  
  779. BOOL is_object_selected(OBJECT *obj)
  780. {
  781.   VISOBJ *v = object2visobj(obj);
  782.   if(!v) return FALSE;
  783.   return ((v->oflags&(OBJ_HIGHLIGHTED|OBJ_INVIS))==OBJ_HIGHLIGHTED);
  784. }
  785.  
  786. BOOL is_object_visible(OBJECT *obj)
  787. {
  788.   VISOBJ *v = object2visobj(obj);
  789.   if(!v) return FALSE;
  790.   return ((v->oflags&OBJ_INVIS)==0);
  791. }
  792.  
  793. BOOL is_object_selectable(OBJECT *obj)
  794. {
  795.   VISOBJ *v = object2visobj(obj);
  796.   if(!v) return FALSE;
  797.   return ((v->oflags&OBJ_NONSEL)==0);
  798. }
  799.  
  800.  
  801. static void do_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
  802. {
  803.   fn(p);
  804.   for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
  805. }
  806.  
  807. static void do_visible_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
  808. {
  809.   if(is_object_visible(p)) fn(p);
  810.   for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
  811. }
  812.  
  813. static void do_selected_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
  814. {
  815.   if(is_object_selected(p)) fn(p);
  816.   for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
  817. }
  818.  
  819.  
  820. void do_for_all_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
  821. {
  822.   SEGMENT *p = object2segment(obj);
  823.   fn(obj);
  824.   if(!p) return;
  825.   for (p = p->child; p; p = p->sibling)
  826.       do_child_recurse(p, fn);
  827. }
  828.  
  829.  
  830. void do_for_visible_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
  831. {
  832.   SEGMENT *p = object2segment(obj);
  833.   if (is_object_visible(obj)) fn(obj);
  834.   if(!p) return;
  835.   for (p = p->child; p; p = p->sibling)
  836.       do_visible_child_recurse(p, fn);
  837. }
  838.  
  839.  
  840. void do_for_selected_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
  841. {
  842.   SEGMENT *p = object2segment(obj);
  843.   if (is_object_selected(obj)) fn(obj);
  844.   if(!p) return;
  845.   for (p = p->child; p; p = p->sibling)
  846.       do_selected_child_recurse(p, fn);
  847. }
  848.  
  849.  
  850. void do_for_all_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
  851. {
  852.   SEGMENT *p = object2segment(obj);
  853.  
  854.   if(!p) return;
  855.   if(p->root) p = p->root;
  856.   do_for_all_child_objects(p, fn);
  857. }
  858.  
  859.  
  860. void do_for_visible_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
  861. {
  862.   SEGMENT *p = object2segment(obj);
  863.  
  864.   if(!p) return;
  865.   if(p->root) p = p->root;
  866.   do_for_visible_child_objects(p, fn);
  867. }
  868.  
  869.  
  870. void do_for_selected_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
  871. {
  872.   SEGMENT *p = object2segment(obj);
  873.  
  874.   if(!p) return;
  875.   if(p->root) p = p->root;
  876.   do_for_selected_child_objects(p, fn);
  877. }
  878.  
  879.  
  880.  
  881. ///// object pose
  882.  
  883. void get_object_pose(OBJECT *obj, POSE *p)
  884. {
  885.   SEGMENT *s = object2segment(obj);
  886.  
  887.   if(!s) return;
  888.   p->x = s->jmatrix[3][0];
  889.   p->y = s->jmatrix[3][1];
  890.   p->z = s->jmatrix[3][2];
  891.   p->rx = s->rx;
  892.   p->ry = s->ry;
  893.   p->rz = s->rz;
  894. }
  895.  
  896.  
  897. void get_object_matrix_pose(OBJECT *obj, POSE *p)
  898. {
  899.   SEGMENT *s = object2segment(obj);
  900.  
  901.   if(!s) return;
  902.   p->x = s->jmatrix[3][0];
  903.   p->y = s->jmatrix[3][1];
  904.   p->z = s->jmatrix[3][2];
  905.   matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
  906.   p->rx = s->rx;
  907.   p->ry = s->ry;
  908.   p->rz = s->rz;
  909. }
  910.  
  911.  
  912. void get_object_world_pose(OBJECT *obj, POSE *p)
  913. {
  914.   SEGMENT *s = object2segment(obj);
  915.  
  916.   if(!s) return;
  917.   p->x = s->pmatrix[3][0];
  918.   p->y = s->pmatrix[3][1];
  919.   p->z = s->pmatrix[3][2];
  920.   matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
  921. }
  922.  
  923. void get_object_world_position(OBJECT *obj, long *x, long *y, long *z)
  924. {
  925.   SEGMENT *s = object2segment(obj);
  926.   if(!s) return;
  927.   if(x) *x = s->pmatrix[3][0];
  928.   if(y) *y = s->pmatrix[3][1];
  929.   if(z) *z = s->pmatrix[3][2];
  930. }
  931.  
  932.  
  933.  
  934. void set_object_pose(OBJECT *obj, POSE *p)
  935. {
  936.   SEGMENT *s = object2segment(obj);
  937.  
  938.   if(!s) return;
  939.  
  940.   if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
  941.   if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
  942.   if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
  943.   if(p->rx!=DONTCARE) s->rx = p->rx;
  944.   if(p->ry!=DONTCARE) s->ry = p->ry;
  945.   if(p->rz!=DONTCARE) s->rz = p->rz;
  946.   multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
  947.            s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
  948.   s->flags |= SEG_MODIFIED;
  949. }
  950.  
  951.  
  952.     // place object in world, even if attached!
  953. void set_object_world_pose(OBJECT *obj, POSE *p)
  954. {
  955.   MATRIX m,n;
  956.   POSE po;
  957.   SEGMENT *s = object2segment(obj);
  958.  
  959.   if(!s) return;
  960.   if(s->parent==NULL)        // unattached: EZ
  961.     {
  962.       set_object_pose(obj,p);
  963.       return;
  964.     }                           // else do it the hard way
  965.  
  966.   if(p->rx==DONTCARE || p->ry==DONTCARE || p->rz==DONTCARE)
  967.     {
  968.       get_object_world_pose(obj, &po);  // tough: we need world angles!
  969.     }
  970.   else         // shortcut
  971.     {
  972.       po.x = s->jmatrix[3][0];
  973.       po.y = s->jmatrix[3][1];
  974.       po.z = s->jmatrix[3][2];
  975.       po.rx = p->rx;
  976.       po.ry = p->ry;
  977.       po.rz = p->rz;
  978.     }
  979.   if(p->x!=DONTCARE) po.x = p->x;
  980.   if(p->y!=DONTCARE) po.y = p->y;
  981.   if(p->z!=DONTCARE) po.z = p->z;
  982.   if(p->rx!=DONTCARE) po.rx = p->rx;
  983.   if(p->ry!=DONTCARE) po.ry = p->ry;
  984.   if(p->rz!=DONTCARE) po.rz = p->rz;
  985.  
  986.   multi_matrix(n, po.rx, po.ry, po.rz, po.x, po.y, po.z, RYXZ);
  987.   inverse_matrix(s->parent->pmatrix, m);     // find the required joint
  988.   matrix_product(m, n, s->jmatrix);          // matrix to meet wld pos'n
  989.                          // and cache it.
  990.   matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
  991.  
  992.   s->flags |= SEG_MODIFIED;
  993. }
  994.  
  995.  
  996.  
  997. /////// misc
  998.  
  999.  
  1000. OBJECT *find_segment_by_name(OBJECT *obj, char *name)
  1001. {
  1002.   SEGMENT *p, *s = object2segment(obj);
  1003.   if(!s) return NULL;
  1004.   if (s->name)                 /* if this segment has a name */
  1005.     if (!stricmp(s->name, name))     /* and it matches */
  1006.         return s;        /* then we've found the segment with that name */
  1007.  
  1008.     /* otherwise, recursively check all of our children and their subtrees */
  1009.   for (p = s->child; p; p = p->sibling)
  1010.     if ((s = find_segment_by_name(p, name)) != NULL) /* found it! */
  1011.         return s;
  1012.   return NULL;             /* neither us nor any of our descendants has that name */
  1013. }
  1014.  
  1015.