home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 16
/
CD_ASCQ_16_0994.iso
/
news
/
vr386
/
segment.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-09
|
24KB
|
1,015 lines
/* Routines for dealing with segmented figures */
/* Original implementation written by Bernie Roehl, March 1992 */
/* Major paradigm shift to current form: Dave Stampe, Aug. '92 */
// The theoretical basis for segments is that of
// cascading transformation to implement jointed
// objects. The new paradigm goes even further,
// using segments for moving body parts, lights, viewpoints
// and so on. New methods for efficient updating were
// added, and the ability to use matrices to control motion added
// Changes, Jan. '93 by Dave Stampe for Release 5:
// added joint angle caching, fixed up the attach/detach
// so they work properly. Worked out fast automatic updates:
// see statmach.c
// MASSIVE changes for VR-386, including POSE, and multiple
// lists, composite objects... just about everything
// VR-386 changes by Dave Stampe, last as of 9/1/94
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
#include <stdio.h>
#include <alloc.h>
#include <string.h>
#define SEGDEF 1
typedef struct _segment SEGMENT;
#include "3dstruct.h"
#include "vr_api.h"
#include "intmath.h"
#include "segment.h"
struct _segment {
unsigned flags; /* if bit 0 set, segment has been modified */
SEGMENT *parent, *child, *sibling;
MATRIX jmatrix; /* joint relationship */
MATRIX pmatrix; /* world position */
OBJECT *object;
long rx, ry, rz; /* added for animation control */
SEGMENT *root;
SEGMENT *update_next; // used for updating automatically
SEGMENT *update_prev;
char *name;
unsigned fix_count; /* used to fix scale after rel_rotate */
};
//other uses of flags: for segments and object:
#define IS_OBJECT 0x8000 // VROBJECT specifiers
#define IS_SEGMENT 0x0080
#define SYSTEM_OWNED 0x0040 // owned by light, camera, or body
#define HAS_OBJECT 0x0020 // has a visible OBJECT attached
#define IS_MOVEABLE 0x0010 // segment or attached object
#define SEG_MODIFIED 1 // modified position
#define OBJ_MODIFIED 2 // representation only changed
#define ON_UPDATE_LIST 0x0008 // update list status
#define NOT_ON_UPDATE_LIST 0xFFF7
#define UPDATED_MASK 0xFFF0 // used to reset when processed
#define SEG_EXTERNAL_FLAGS_MASK 0xFFFF // what externals can see
static int fix_init = 100;
SEGMENT *new_seg(SEGMENT *parent)
{
SEGMENT *s;
if ((s = malloc(sizeof(SEGMENT))) == NULL) return NULL;
s->parent = parent;
s->child = NULL;
if (parent)
{
s->sibling = parent->child;
parent->child = s;
}
else s->sibling = NULL;
identity_matrix(s->jmatrix);
if (parent) memcpy(&(s->pmatrix), &(parent->pmatrix), sizeof(MATRIX));
else identity_matrix(s->pmatrix);
s->object = NULL;
s->flags = IS_SEGMENT | SEG_MODIFIED | IS_MOVEABLE;
s->name = NULL;
s->root = (parent) ? parent->root : s; // update root
s->rx = s->ry = s->rz = 0;
s->fix_count = fix_init;
s->update_next = NULL;
s->update_prev = NULL;
fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
return s;
}
/////// SEGMENT SUPPORT
void seg_set_object(SEGMENT *s, VISOBJ *obj)
{
s->object = obj;
obj->owner = s;
obj->oflags |= IS_MOVEABLE;
s->flags |= OBJ_MODIFIED | HAS_OBJECT;
update_segment(s); // so object is current
}
void seg_reset_object(SEGMENT *s, VISOBJ *obj)
{
s->object = NULL;
obj->owner = NULL;
obj->oflags &= (~IS_MOVEABLE);
s->flags &= (~HAS_OBJECT);
}
void *seg_get_object(SEGMENT *s)
{
return s->object;
}
char *seg_getname(SEGMENT *s)
{
return s->name;
}
void seg_setname(SEGMENT *s, char *name)
{
s->name = strdup(name);
}
void seg_getpose(SEGMENT *s, POSE *p)
{
p->x = s->jmatrix[3][0];
p->y = s->jmatrix[3][1];
p->z = s->jmatrix[3][2];
p->rx = s->rx;
p->ry = s->ry;
p->rz = s->rz;
}
void seg_getmatpose(SEGMENT *s, POSE *p)
{
p->x = s->jmatrix[3][0];
p->y = s->jmatrix[3][1];
p->z = s->jmatrix[3][2];
matrix_to_angle(s->jmatrix, &p->rx, &p->ry, &p->rz);
s->rx = p->rx;
s->ry = p->ry;
s->rz = p->rz;
}
void seg_getworldpose(SEGMENT *s, POSE *p)
{
p->x = s->pmatrix[3][0];
p->y = s->pmatrix[3][1];
p->z = s->pmatrix[3][2];
matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
}
void seg_setpose(SEGMENT *s, POSE *p)
{
if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
if(p->rx!=DONTCARE) s->rx = p->rx;
if(p->ry!=DONTCARE) s->ry = p->ry;
if(p->rz!=DONTCARE) s->rz = p->rz;
multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
s->flags |= SEG_MODIFIED;
}
void seg_getposang(SEGMENT *s, long *rx, long *ry, long *rz)
{
matrix_to_angle(s->pmatrix, rx, ry, rz);
}
void seg_getjointang(SEGMENT *s, long *rx, long *ry, long *rz)
{
matrix_to_angle(s->jmatrix, rx, ry, rz);
s->rx = *rx;
s->ry = *ry; /* ADDED FOR ANIMATION */
s->rz = *rz;
}
void seg_getrxyz(SEGMENT *s, long *rx, long *ry, long *rz)
{
*rx = s->rx; /* ADDED FOR ANIMATION */
*ry = s->ry;
*rz = s->rz;
}
void seg_getposxyz(SEGMENT *s, long *x, long *y, long *z)
{
if(x) *x = s->pmatrix[3][0];
if(y) *y = s->pmatrix[3][1];
if(z) *z = s->pmatrix[3][2];
}
void seg_getjointxyz(SEGMENT *s, long *x, long *y, long *z)
{
*x = s->jmatrix[3][0];
*y = s->jmatrix[3][1];
*z = s->jmatrix[3][2];
}
void abs_move_segment(SEGMENT *s, long tx, long ty, long tz)
{
s->jmatrix[3][0] = tx;
s->jmatrix[3][1] = ty;
s->jmatrix[3][2] = tz;
s->flags |= SEG_MODIFIED;
}
void rel_move_segment(SEGMENT *s, long tx, long ty, long tz)
{
s->jmatrix[3][0] += tx;
s->jmatrix[3][1] += ty;
s->jmatrix[3][2] += tz;
s->flags |= SEG_MODIFIED;
}
void abs_mat_segment(SEGMENT *s, MATRIX m)
{
memcpy(s->jmatrix, m, sizeof(MATRIX));
s-> flags |= SEG_MODIFIED;
}
void rel_mat_segment(SEGMENT *s, MATRIX m)
{
matrix_product(s->jmatrix, m, s->jmatrix);
s-> flags |= SEG_MODIFIED;
s->fix_count--;
if (s->fix_count == 0)
{
s->fix_count = fix_init;
fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
renormalize_matrix(s->jmatrix);
}
}
void abs_rotmat_segment(SEGMENT *s, MATRIX m)
{
s->jmatrix[0][0] = m[0][0];
s->jmatrix[0][1] = m[0][1];
s->jmatrix[0][2] = m[0][2];
s->jmatrix[1][0] = m[1][0];
s->jmatrix[1][1] = m[1][1];
s->jmatrix[1][2] = m[1][2];
s->jmatrix[2][0] = m[2][0];
s->jmatrix[2][1] = m[2][1];
s->jmatrix[2][2] = m[2][2];
s->flags |= SEG_MODIFIED;
}
void rel_rotmat_segment(SEGMENT *s, MATRIX m)
{
matrix_mult(s->jmatrix, m, s->jmatrix);
s-> flags |= SEG_MODIFIED;
s->fix_count--;
if (s->fix_count == 0)
{
s->fix_count = fix_init;
fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
renormalize_matrix(s->jmatrix);
}
}
#define RXYZ 1 /* matrix rotation orders */
#define RYXZ 0 /* ONLY RYXZ guaranteed to be tested */
#define RXZY 2
#define RZYX 5
#define RZXY 4
#define RYZX 6
void abs_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
{
MATRIX m;
multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
s->rx = rx;
s->ry = ry; /* ADDED FOR ANIMATION */
s->rz = rz;
abs_rotmat_segment(s, m);
}
void rel_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
{
MATRIX m;
multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
rel_rotmat_segment(s, m);
}
extern void split_move_handler(OBJECT *obj); // the default
static void (*move_handler)(OBJECT *) = split_move_handler; /* called when object moved */
void set_move_handler(void (*move_handler_ptr)(OBJECT *))
{
move_handler = move_handler_ptr;
}
void full_update_segment(SEGMENT *seg)
{
SEGMENT *s;
OBJECT *obj;
if(!seg) return;
remove_from_segment_update_list(seg);
seg->flags &= UPDATED_MASK;
if (seg->parent)
matrix_product(seg->parent->pmatrix, seg->jmatrix, seg->pmatrix);
else
memcpy(&(seg->pmatrix), &(seg->jmatrix), sizeof(MATRIX));
if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
{
matmove_osphere(obj, seg->pmatrix);
obj->owner = seg; /* just to be safe... */
if (move_handler) move_handler(obj); /* this moves in split tree */
}
for (s = seg->child; s; s = s->sibling)
{
s->root = seg; // keep root current!
full_update_segment(s);
}
}
void update_segment(SEGMENT *seg) /* scan till update needed */
{
SEGMENT *s;
OBJECT *obj;
if(!seg) return;
remove_from_segment_update_list(seg);
if (seg->flags & SEG_MODIFIED)
full_update_segment(seg);
else if (seg->flags&OBJ_MODIFIED)
{
if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
{
matmove_osphere(obj, seg->pmatrix);
obj->owner = seg; /* just to be safe... */
if (move_handler) move_handler(obj); /* this moves in split tree */
}
}
else
for (s = seg->child; s; s = s->sibling)
{
s->root = seg;
update_segment(s);
}
}
// update object in world only
void update_object(OBJECT *obj)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
s->flags |= OBJ_MODIFIED;
// if (move_handler) move_handler(obj); /* this moves in split tree */
update_segment(s);
}
// moderate update
void physical_update_object(OBJECT *obj)
{
SEGMENT *s = object2segment(obj);
compute_object(obj);
if(!s) return;
s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
update_segment(s);
}
// truly massive update
void global_update_object(OBJECT *obj)
{
SEGMENT *s = object2segment(obj);
compute_all_object(obj);
if(!s) return;
s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
s = find_root_segment(s);
full_update_segment(s);
}
int seg_get_flags(SEGMENT *s)
{
return s->flags & SEG_EXTERNAL_FLAGS_MASK;
}
void seg_set_flags(SEGMENT *s, int f)
{
s->flags = (s->flags&(~SEG_EXTERNAL_FLAGS_MASK))|(f&SEG_EXTERNAL_FLAGS_MASK);
}
SEGMENT *parent_segment(SEGMENT *s)
{
return s->parent;
}
SEGMENT *child_segment(SEGMENT *s)
{
return s->child;
}
SEGMENT *sibling_segment(SEGMENT *s)
{
return s->sibling;
}
MATRIX *get_seg_jmatrix(SEGMENT *s)
{
return &s->jmatrix;
}
MATRIX *get_seg_pmatrix(SEGMENT *s)
{
return &s->pmatrix;
}
void detach_segment(SEGMENT *s, BOOL preserve) /* assumes segment is updated! */
{
SEGMENT *p;
MATRIX n;
if ((p = s->parent) == NULL) return;
s->parent = NULL;
if (preserve)
memcpy(&(s->jmatrix), &(s->pmatrix), sizeof(MATRIX));
s->flags |= SEG_MODIFIED;
if (p->child == s)
{
p->child = s->sibling;
s->sibling = NULL;
s->root = s;
update_segment(s);
return;
}
for (p = p->child; p->sibling; p = p->sibling)
if (p->sibling == s)
{
p->sibling = s->sibling;
s->sibling = NULL;
s->root = s;
update_segment(s);
return;
}
s->root = s;
update_segment(s);
}
void detach_object(OBJECT *obj, BOOL preserve)
{
SEGMENT *p = object2segment(obj);
if(!p) return;
detach_segment(p, preserve);
}
/* assumes parent is updated! */
// preserves world position if flagged
void attach_segment(SEGMENT *s, SEGMENT *to, BOOL preserve)
{
MATRIX m,n;
if (s->parent) detach_segment(s, preserve);
s->parent = to;
s->sibling = to->child;
to->child = s;
s->root = to->root; //find_root_segment(s);
if(preserve) // preserves world position
{
inverse_matrix(to->pmatrix, m);
matrix_product(m, s->pmatrix, s->jmatrix);
}
// to->flags |= SEG_MODIFIED;
s->flags |= SEG_MODIFIED;
update_segment(to); // at least changes roots
}
// used for loading objects, to ensure they don't
// get moved in world or taken off objlist
// be sure to update <to> later!
void naked_attach_object(OBJECT *obj, OBJECT *to)
{
SEGMENT *p, *q;
p = object2segment(obj);
if(!p) return;
q = object2segment(to);
if(!q) return;
p->parent = q;
p->sibling = q->child;
q->child = p;
p->root = q->root; //find_root_segment(q);
p->flags |= SEG_MODIFIED | OBJ_MODIFIED;
}
void attach_object(OBJECT *obj, OBJECT *to, BOOL preserve)
{
SEGMENT *p, *q;
p = object2segment(obj);
if(!p) return;
q = object2segment(to);
if(!q) return;
attach_segment(p, q, preserve);
}
void destroy_segment(SEGMENT *s) // just removes segment
{
SEGMENT *p, *q;
detach_segment(s,1); /* first detach us from our parent */
p = s->child; /* then recursively detach all our child segments */
while (p)
{
q = p->sibling;
detach_segment(p,1);
p = q;
}
remove_from_segment_update_list(s);
free(s);
}
// delete segment, descendents and objects
void delete_object_and_children(OBJECT *obj)
{
SEGMENT *p, *q;
SEGMENT *s = object2segment(obj);
if(!s) return;
detach_segment(s,0); /* first detach us from our parent */
p = s->child; /* then recursively delete all our child segments */
while (p)
{
q = p->sibling;
delete_object_and_children(p);
p = q;
}
if (s->object && (s->flags&HAS_OBJECT) ) // object to delete?
delete_visobj(s->object);
remove_from_segment_update_list(s);
if(!(s->flags&SYSTEM_OWNED)) // delete if not camera/light segment
free(s);
}
// marks segment as protected from recursive deletes
void register_system_segment(SEGMENT *s)
{
s->flags |= SYSTEM_OWNED;
}
/////// SEGMENT AUTO-UPDATE
static SEGMENT *update_list_root = NULL;
// dump entire list
void clear_object_update_list()
{
SEGMENT *sn;
SEGMENT *s = update_list_root;
while(s)
{
sn = s->update_next;
s->flags &= NOT_ON_UPDATE_LIST;
s->update_next = NULL;
s->update_prev = NULL;
s = sn;
}
update_list_root = NULL;
}
void remove_from_segment_update_list(SEGMENT *seg)
{
if(!(seg->flags&ON_UPDATE_LIST)) return;
if(!seg->update_prev) // first in list
{
update_list_root = seg->update_next;
if(update_list_root)
update_list_root->update_prev = NULL; // only one
}
else
{
seg->update_prev->update_next = seg->update_next;
if(seg->update_next)
seg->update_next->update_prev = seg->update_prev;
}
seg->flags &= NOT_ON_UPDATE_LIST;
}
void remove_from_object_update_list(OBJECT *obj)
{
SEGMENT *s = object2segment(obj);
if(s) remove_from_segment_update_list(s);
}
// puts root on update list
void add_to_object_update_list(OBJECT *obj)
{
SEGMENT *s, *seg = object2segment(obj);
if(!seg) return;
s = seg->root;
if(!s) return; // hey! hey!
if(s->flags&ON_UPDATE_LIST) return; // already on list
s->update_next = update_list_root; // add to list
if(update_list_root)
update_list_root->update_prev = s;
s->update_prev = NULL;
update_list_root = s;
s->flags |= ON_UPDATE_LIST;
}
BOOL process_object_update_list()
{
SEGMENT *sn;
SEGMENT *s = update_list_root;
if(!s) return FALSE;
while(s)
{
sn = s->update_next;
update_segment(s);
s->flags &= NOT_ON_UPDATE_LIST;
s->update_next = NULL;
s->update_prev = NULL;
s = sn;
}
update_list_root = NULL;
return TRUE;
}
SEGMENT *find_root_segment(SEGMENT *s) // try to do without
{
SEGMENT *ss = s;
while (s->parent) s = s->parent;
ss->root = s; /* ADDED FOR ANIMATION */
return s;
}
OBJECT *find_root_object(OBJECT *obj) // try to do without
{
SEGMENT *ss = object2segment(obj);
SEGMENT *s = ss;
if(!s) return NULL;
while (s->parent) s = s->parent;
ss->root = s;
return s;
}
SEGMENT *get_root_segment(SEGMENT *s)
{
return s->root; /* ADDED FOR ANIMATION */
}
VISOBJ *object2visobj(OBJECT *obj)
{
if(!obj) return NULL;
if(is_object_visobj(obj)) return obj;
return ((SEGMENT *)obj)->object;
}
//////// RELATIONAL ITEMS
BOOL is_object_child_of(OBJECT *parent, OBJECT *child)
{
SEGMENT *s = object2segment(parent);
SEGMENT *g = object2segment(child);
if(!s || !g) return FALSE;
if(s==g) return TRUE;
while(g->parent)
{
if(g->parent==s) return TRUE;
g = g->parent;
}
return FALSE;
}
BOOL are_objects_related(OBJECT *o1, OBJECT *o2)
{
SEGMENT *p = object2segment(o1);
if(!p) return FALSE;
if(p->root) p = p->root;
return is_object_child_of(p,o2);
}
BOOL is_object_selected(OBJECT *obj)
{
VISOBJ *v = object2visobj(obj);
if(!v) return FALSE;
return ((v->oflags&(OBJ_HIGHLIGHTED|OBJ_INVIS))==OBJ_HIGHLIGHTED);
}
BOOL is_object_visible(OBJECT *obj)
{
VISOBJ *v = object2visobj(obj);
if(!v) return FALSE;
return ((v->oflags&OBJ_INVIS)==0);
}
BOOL is_object_selectable(OBJECT *obj)
{
VISOBJ *v = object2visobj(obj);
if(!v) return FALSE;
return ((v->oflags&OBJ_NONSEL)==0);
}
static void do_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
{
fn(p);
for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
}
static void do_visible_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
{
if(is_object_visible(p)) fn(p);
for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
}
static void do_selected_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
{
if(is_object_selected(p)) fn(p);
for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
}
void do_for_all_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
fn(obj);
if(!p) return;
for (p = p->child; p; p = p->sibling)
do_child_recurse(p, fn);
}
void do_for_visible_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
if (is_object_visible(obj)) fn(obj);
if(!p) return;
for (p = p->child; p; p = p->sibling)
do_visible_child_recurse(p, fn);
}
void do_for_selected_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
if (is_object_selected(obj)) fn(obj);
if(!p) return;
for (p = p->child; p; p = p->sibling)
do_selected_child_recurse(p, fn);
}
void do_for_all_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
if(!p) return;
if(p->root) p = p->root;
do_for_all_child_objects(p, fn);
}
void do_for_visible_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
if(!p) return;
if(p->root) p = p->root;
do_for_visible_child_objects(p, fn);
}
void do_for_selected_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
{
SEGMENT *p = object2segment(obj);
if(!p) return;
if(p->root) p = p->root;
do_for_selected_child_objects(p, fn);
}
///// object pose
void get_object_pose(OBJECT *obj, POSE *p)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
p->x = s->jmatrix[3][0];
p->y = s->jmatrix[3][1];
p->z = s->jmatrix[3][2];
p->rx = s->rx;
p->ry = s->ry;
p->rz = s->rz;
}
void get_object_matrix_pose(OBJECT *obj, POSE *p)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
p->x = s->jmatrix[3][0];
p->y = s->jmatrix[3][1];
p->z = s->jmatrix[3][2];
matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
p->rx = s->rx;
p->ry = s->ry;
p->rz = s->rz;
}
void get_object_world_pose(OBJECT *obj, POSE *p)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
p->x = s->pmatrix[3][0];
p->y = s->pmatrix[3][1];
p->z = s->pmatrix[3][2];
matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
}
void get_object_world_position(OBJECT *obj, long *x, long *y, long *z)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
if(x) *x = s->pmatrix[3][0];
if(y) *y = s->pmatrix[3][1];
if(z) *z = s->pmatrix[3][2];
}
void set_object_pose(OBJECT *obj, POSE *p)
{
SEGMENT *s = object2segment(obj);
if(!s) return;
if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
if(p->rx!=DONTCARE) s->rx = p->rx;
if(p->ry!=DONTCARE) s->ry = p->ry;
if(p->rz!=DONTCARE) s->rz = p->rz;
multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
s->flags |= SEG_MODIFIED;
}
// place object in world, even if attached!
void set_object_world_pose(OBJECT *obj, POSE *p)
{
MATRIX m,n;
POSE po;
SEGMENT *s = object2segment(obj);
if(!s) return;
if(s->parent==NULL) // unattached: EZ
{
set_object_pose(obj,p);
return;
} // else do it the hard way
if(p->rx==DONTCARE || p->ry==DONTCARE || p->rz==DONTCARE)
{
get_object_world_pose(obj, &po); // tough: we need world angles!
}
else // shortcut
{
po.x = s->jmatrix[3][0];
po.y = s->jmatrix[3][1];
po.z = s->jmatrix[3][2];
po.rx = p->rx;
po.ry = p->ry;
po.rz = p->rz;
}
if(p->x!=DONTCARE) po.x = p->x;
if(p->y!=DONTCARE) po.y = p->y;
if(p->z!=DONTCARE) po.z = p->z;
if(p->rx!=DONTCARE) po.rx = p->rx;
if(p->ry!=DONTCARE) po.ry = p->ry;
if(p->rz!=DONTCARE) po.rz = p->rz;
multi_matrix(n, po.rx, po.ry, po.rz, po.x, po.y, po.z, RYXZ);
inverse_matrix(s->parent->pmatrix, m); // find the required joint
matrix_product(m, n, s->jmatrix); // matrix to meet wld pos'n
// and cache it.
matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
s->flags |= SEG_MODIFIED;
}
/////// misc
OBJECT *find_segment_by_name(OBJECT *obj, char *name)
{
SEGMENT *p, *s = object2segment(obj);
if(!s) return NULL;
if (s->name) /* if this segment has a name */
if (!stricmp(s->name, name)) /* and it matches */
return s; /* then we've found the segment with that name */
/* otherwise, recursively check all of our children and their subtrees */
for (p = s->child; p; p = p->sibling)
if ((s = find_segment_by_name(p, name)) != NULL) /* found it! */
return s;
return NULL; /* neither us nor any of our descendants has that name */
}