panda3d/pandatool/src/softegg/softNodeDesc.cxx

727 lines
25 KiB
C++
Executable File

// Filename: softNodeDesc.cxx
// Created by: masad (03Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2003, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "softNodeDesc.h"
TypeHandle SoftNodeDesc::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SoftNodeDesc::
SoftNodeDesc(SoftNodeDesc *parent, const string &name) :
Namable(name),
_parent(parent)
{
_model = (SAA_Elem *)NULL;
_egg_group = (EggGroup *)NULL;
_egg_table = (EggTable *)NULL;
_anim = (EggXfmSAnim *)NULL;
_joint_type = JT_none;
// Add ourselves to our parent.
if (_parent != (SoftNodeDesc *)NULL) {
cout << "parent name " << _parent->get_name();
_parent->_children.push_back(this);
}
vpool = NULL;
fullname = NULL;
numTexLoc = 0;
numTexGlb = 0;
uScale = NULL;
vScale = NULL;
uOffset = NULL;
vOffset = NULL;
valid;
uv_swap;
// SAA_Boolean visible;
textures = NULL;
materials = NULL;
triangles = NULL;
gtype = SAA_GEOM_ORIGINAL;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SoftNodeDesc::
~SoftNodeDesc() {
if (_model != (SAA_Elem *)NULL) {
delete _model;
}
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::set_model
// Access: Public
// Description: Indicates an associated between the SoftNodeDesc and
// some SAA_Elem instance.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
set_model(SAA_Elem *model) {
_model = model;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::set_parent
// Access: Public
// Description: Sometimes, parent is not known at node creation
// As soon as it is known, set the parent
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
set_parent(SoftNodeDesc *parent) {
if (_parent) {
cout << endl;
/*
cout << " expected _parent to be null!?\n";
if (_parent == parent)
cout << " parent already set\n";
else {
cout << " current parent " << _parent->get_name() << " new parent "
<< parent << endl;
}
*/
return;
}
_parent = parent;
cout << " set parent to " << _parent->get_name() << endl;
// Add ourselves to our parent.
_parent->_children.push_back(this);
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::has_model
// Access: Public
// Description: Returns true if a Soft dag path has been associated
// with this node, false otherwise.
////////////////////////////////////////////////////////////////////
bool SoftNodeDesc::
has_model() const {
return (_model != (SAA_Elem *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::get_model
// Access: Public
// Description: Returns the SAA_Elem * associated with this node. It
// is an error to call this unless has_model()
// returned true.
////////////////////////////////////////////////////////////////////
SAA_Elem *SoftNodeDesc::
get_model() const {
nassertr(_model != (SAA_Elem *)NULL, _model);
return _model;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::is_joint
// Access: Private
// Description: Returns true if the node should be treated as a joint
// by the converter.
////////////////////////////////////////////////////////////////////
bool SoftNodeDesc::
is_joint() const {
return _joint_type == JT_joint || _joint_type == JT_pseudo_joint;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::is_junk
// Access: Private
// Description: Returns true if the node should be treated as a junk
// by the converter.
////////////////////////////////////////////////////////////////////
bool SoftNodeDesc::
is_junk() const {
return _joint_type == JT_junk;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::set_joint
// Access: Private
// Description: sets the _joint_type to JT_joint
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
set_joint() {
_joint_type = JT_joint;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::is_joint_parent
// Access: Private
// Description: Returns true if the node is the parent or ancestor of
// a joint.
////////////////////////////////////////////////////////////////////
bool SoftNodeDesc::
is_joint_parent() const {
return _joint_type == JT_joint_parent;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::clear_egg
// Access: Private
// Description: Recursively clears the egg pointers from this node
// and all children.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
clear_egg() {
_egg_group = (EggGroup *)NULL;
_egg_table = (EggTable *)NULL;
_anim = (EggXfmSAnim *)NULL;
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
child->clear_egg();
}
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::mark_joint_parent
// Access: Private
// Description: Indicates that this node has at least one child that
// is a joint or a pseudo-joint.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
mark_joint_parent() {
if (_joint_type == JT_none) {
_joint_type = JT_joint_parent;
cout << " marked parent " << get_name();
}
else
cout << " ?parent " << get_name() << " joint type " << _joint_type;
if (_parent != (SoftNodeDesc *)NULL) {
_parent->mark_joint_parent();
}
cout << endl;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::check_joint_parent
// Access: Private
// Description: Walks the hierarchy, if a node is joint, make
// sure all its parents are marked JT_joint_parent
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
check_joint_parent() {
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
if (child->is_joint()) {
cout << "child " << child->get_name();
mark_joint_parent();
}
child->check_joint_parent();
}
}
///////////////////////////////////////////////////////////////////////
// Function: SoftNodeTree::check_junk
// Access: Public
// Description: check to see if this is a branch we don't want to
// descend - this will prevent creating geometry for
// animation control structures
///////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
check_junk(bool parent_junk) {
const char *name = get_name().c_str();
if (parent_junk) {
_joint_type = JT_junk;
cout << "junk node " << get_name() << endl;
}
if ( (strstr(name, "con-") != NULL) ||
(strstr(name, "con_") != NULL) ||
(strstr(name, "fly_") != NULL) ||
(strstr(name, "fly-") != NULL) ||
(strstr(name, "camRIG") != NULL) ||
(strstr(name, "cam_rig") != NULL) ||
(strstr(name, "bars") != NULL) )
// split
/*
(!_search_prefix || (strstr(name, _search_prefix) != NULL)) )
*/
{
_joint_type = JT_junk;
cout << "junk node " << get_name() << endl;
parent_junk = true;
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
cout << child->get_name() << ",";
}
cout << endl;
}
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
child->check_junk(parent_junk);
}
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::check_pseudo_joints
// Access: Private
// Description: Walks the hierarchy, looking for non-joint nodes that
// are both children and parents of a joint. These
// nodes are deemed to be pseudo joints, since the
// converter must treat them as joints.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
check_pseudo_joints(bool joint_above) {
if (_joint_type == JT_joint_parent && joint_above) {
// This is one such node: it is the parent of a joint
// (JT_joint_parent is set), and it is the child of a joint
// (joint_above is set).
_joint_type = JT_pseudo_joint;
cout << "pseudo " << get_name() << " case1\n";
}
if (_joint_type == JT_joint) {
// If this node is itself a joint, then joint_above is true for
// all child nodes.
joint_above = true;
}
// Don't bother traversing further if _joint_type is none or junk, since
// that means this node has no joint children.
if (_joint_type != JT_none && _joint_type != JT_junk) {
bool any_joints = false;
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
child->check_pseudo_joints(joint_above);
if (child->is_joint()) {
cout << get_name() << " any_joint true by " << child->get_name() << endl;
any_joints = true;
}
}
// If any children qualify as joints, then any sibling nodes that
// are parents of joints are also elevated to joints.
if (any_joints) {
bool all_joints = true;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
if (child->_joint_type == JT_joint_parent) {
child->_joint_type = JT_pseudo_joint;
cout << "pseudo " << child->get_name() << " case2 by parent " << get_name() << "\n";
} else if (child->_joint_type == JT_none || child->_joint_type == JT_junk) {
all_joints = false;
}
}
if (all_joints || any_joints) {
// Finally, if all children or at least one is a joint, then we are too.
if (_joint_type == JT_joint_parent) {
_joint_type = JT_pseudo_joint;
cout << "pseudo " << get_name() << " case3\n";
}
}
}
}
else
cout << "found null joint " << get_name() << endl;
}
////////////////////////////////////////////////////////////////////
// Function: SoftToEggConverter::create_vpool
// Access: Public
// Description: Creates a new vpool for future soft skining,
// this is a one to one reference to external index.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
create_vpool(string vpool_name) {
vpool = new EggVertexPool(vpool_name);
}
////////////////////////////////////////////////////////////////////
// Function: SoftToEggConverter::get_vpool
// Access: Public
// Description: Get vpool
////////////////////////////////////////////////////////////////////
EggVertexPool *SoftNodeDesc::
get_vpool() {
return vpool;
}
////////////////////////////////////////////////////////////////////
// Function: SoftToEggConverter::get_transform
// Access: Private
// Description: Extracts the transform on the indicated Soft node,
// and applies it to the corresponding Egg node.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global) {
// Get the model's matrix
int scale_joint = 0;
/*
if ( strstr( _parent->get_name().c_str(), "scale" ) != NULL ) {
scale_joint = 1;
cout << "scale joint flag set!\n";
}
*/
if (!global && _parent->is_joint() && !stec.flatten && !scale_joint) {
SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL, matrix );
cout << get_name() << " using local matrix :parent ";
} else {
SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL, matrix );
cout << get_name() << " using global matrix :parent ";
}
cout << _parent->get_name() << endl;
cout << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n";
cout << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n";
cout << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n";
cout << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n";
if (!global && is_joint()) {
LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]);
if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
egg_group->set_transform(m4d);
cout << "set transform in egg_group\n";
}
}
return;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::get_joint_transform
// Access: Private
// Description: Extracts the transform on the indicated Soft node,
// as appropriate for a joint in an animated character,
// and applies it to the indicated node. This is
// different from get_transform() in that it does not
// respect the _transform_type flag, and it does not
// consider the relative transforms within the egg file.
// more added functionality: now fills in components of
// anim (EffXfmSAnim) class (masad).
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global) {
// SI_Error result;
SAA_Elem *skeletonPart = _model;
const char *name = get_name().c_str();
if ( skeletonPart != NULL ) {
float i,j,k;
float h,p,r;
float x,y,z;
int scale_joint = 0;
/*
if ( strstr( _parent->get_name().c_str(), "scale" ) != NULL ) {
scale_joint = 1;
cout << "scale joint flag set!\n";
}
*/
cout << "\n\nanimating child " << name << endl;
if (_parent->is_joint() && !stec.flatten && !scale_joint ) {
cout << "using local matrix\n";
//get SAA orientation
SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
&p, &h, &r );
//get SAA translation
SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
&x, &y, &z );
//get SAA scaling
SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL,
&i, &j, &k );
} else {
cout << " using global matrix\n";
//get SAA orientation
SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
&p, &h, &r );
//get SAA translation
SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
&x, &y, &z );
//get SAA scaling
SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
&i, &j, &k );
}
cout << "\nanim data: " << i << " " << j << " " << k << endl;
cout << "\t" << p << " " << h << " " << r << endl;
cout << "\t" << x << " " << y << " " << z << endl;
// make sure the ordering is correct
anim->set_order(anim->get_standard_order());
// Add each component by their names
anim->add_component_data("i", i);
anim->add_component_data("j", j);
anim->add_component_data("k", k);
anim->add_component_data("p", p);
anim->add_component_data("h", h);
anim->add_component_data("r", r);
anim->add_component_data("x", x);
anim->add_component_data("y", y);
anim->add_component_data("z", z);
}
else {
cout << "Cannot build anim table - no skeleton\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::load_model
// Access: Private
// Description: Converts the indicated Soft polyset to a bunch of
// EggPolygons and parents them to the indicated egg
// group.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
load_model(SAA_Scene *scene, SAA_ModelType type) {
SI_Error result;
const char *name = get_name().c_str();
int i;
int id = 0;
// int anim_start;
// int anim_end;
// int anim_rate;
// int pose_frame;
// int verbose;
// int flatten;
// int shift_textures;
// int ignore_tex_offsets;
fullname = name;
// if making a pose - get deformed geometry
if ( stec.make_pose )
gtype = SAA_GEOM_DEFORMED;
// If the model is a NURBS in soft, set its step before tesselating
if ( type == SAA_MNSRF )
SAA_nurbsSurfaceSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
// If the model is a PATCH in soft, set its step before tesselating
else if ( type == SAA_MPTCH )
SAA_patchSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
// Get the number of triangles
result = SAA_modelGetNbTriangles( scene, _model, gtype, id, &numTri);
cout << "triangles: " << numTri << "\n";
if ( result != SI_SUCCESS ) {
cout << "Error: couldn't get number of triangles!\n";
cout << "\tbailing on model: " << name << "\n";
return;
}
// check to see if surface is also skeleton...
SAA_Boolean isSkeleton = FALSE;
SAA_modelIsSkeleton( scene, _model, &isSkeleton );
// check to see if this surface is used as a skeleton
// or is animated via constraint only ( these nodes are
// tagged by the animator with the keyword "joint"
// somewhere in the nodes name)
cout << "is Skeleton? " << isSkeleton << "\n";
/*************************************************************************************/
// model is not a null and has no triangles!
if ( !numTri ) {
cout << "no triangles!\n";
}
else {
// allocate array of triangles
triangles = (SAA_SubElem *) new SAA_SubElem[numTri];
if (!triangles) {
cout << "Not enough Memory for triangles...\n";
exit(1);
}
// triangulate model and read the triangles into array
SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles );
cout << "got triangles\n";
/***********************************************************************************/
// allocate array of materials (Asad: it gives a warning if try to get one triangle
// at a time...investigate later
// read each triangle's material into array
materials = (SAA_Elem*) new SAA_Elem[numTri];
SAA_triangleGetMaterials( scene, _model, numTri, triangles, materials );
if (!materials) {
cout << "Not enough Memory for materials...\n";
exit(1);
}
cout << "got materials\n";
/***********************************************************************************/
// allocate array of textures per triangle
int *numTexTri = new int[numTri];
const void *relinfo;
// find out how many local textures per triangle
for (i = 0; i < numTri; i++) {
result = SAA_materialRelationGetT2DLocNbElements( scene, &materials[i], FALSE,
&relinfo, &numTexTri[i] );
// polytex
if ( result == SI_SUCCESS )
numTexLoc += numTexTri[i];
}
// don't need this anymore...
//free( numTexTri );
// get local textures if present
if ( numTexLoc ) {
cout << "numTexLoc = " << numTexLoc << endl;
// allocate arrays of texture info
uScale = new float[numTri];
vScale = new float[numTri];
uOffset = new float[numTri];
vOffset = new float[numTri];
texNameArray = new char *[numTri];
// ASSUME only one texture per material
textures = new SAA_Elem[numTri];
for ( i = 0; i < numTri; i++ ) {
// and read all referenced local textures into array
SAA_materialRelationGetT2DLocElements( scene, &materials[i],
TEX_PER_MAT , &textures[i] );
// initialize the array value
texNameArray[i] = NULL;
// check to see if texture is present
result = SAA_elementIsValid( scene, &textures[i], &valid );
if ( result != SI_SUCCESS )
cout << "SAA_elementIsValid failed!!!!\n";
// texture present - get the name and uv info
if ( valid ) {
// according to drose, we don't need to convert .pic files to .rgb,
// panda can now read the .pic files.
texNameArray[i] = stec.GetTextureName(scene, &textures[i]);
cout << " tritex[" << i << "] named: " << texNameArray[i] << endl;
SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
if ( uv_swap == TRUE )
cout << " swapping u and v...\n" ;
SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
cout << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl;
cout << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl;
SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat, &vRepeat );
cout << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
}
else {
cout << "Invalid texture...\n";
cout << " tritex[" << i << "] named: (null)\n";
}
}
}
else { // if no local textures, try to get global textures
SAA_modelRelationGetT2DGlbNbElements( scene, _model,
FALSE, &relinfo, &numTexGlb );
if ( numTexGlb ) {
// ASSUME only one texture per model
textures = new SAA_Elem;
// get the referenced texture
SAA_modelRelationGetT2DGlbElements( scene, _model,
TEX_PER_MAT, textures );
cout << "numTexGlb = " << numTexGlb << endl;
// check to see if texture is present
SAA_elementIsValid( scene, textures, &valid );
if ( valid ) { // texture present - get the name and uv info
SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
if ( uv_swap == TRUE )
cout << " swapping u and v...\n";
// according to drose, we don't need to convert .pic files to .rgb,
// panda can now read the .pic files.
texNameArray = new char *[1];
*texNameArray = stec.GetTextureName(scene, textures);
cout << " global tex named: " << *texNameArray << endl;
// allocate arrays of texture info
uScale = new float;
vScale = new float;
uOffset = new float;
vOffset = new float;
SAA_texture2DGetUScale( scene, textures, uScale );
SAA_texture2DGetVScale( scene, textures, vScale );
SAA_texture2DGetUOffset( scene, textures, uOffset );
SAA_texture2DGetVOffset( scene, textures, vOffset );
cout << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl;
cout << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
SAA_texture2DGetRepeats( scene, textures, &uRepeat, &vRepeat );
cout << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
}
else {
cout << "Invalid Texture...\n";
}
}
}
}
cout << "got textures" << endl;
}
//
//
//