panda3d/pandatool/src/softegg/softNodeDesc.cxx
2003-12-03 01:11:40 +00:00

1378 lines
48 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"
#include "config_softegg.h"
#include "eggGroup.h"
#include "eggXfmSAnim.h"
#include "eggSAnimData.h"
#include "softToEggConverter.h"
#include "dcast.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) {
softegg_cat.spam() << "parent name " << _parent->get_name();
_parent->_children.push_back(this);
}
// set the _parentJoint to Null
_parentJoint = NULL;
fullname = NULL;
numTexLoc = 0;
numTexGlb = 0;
uScale = NULL;
vScale = NULL;
uOffset = NULL;
vOffset = NULL;
valid;
uv_swap;
// SAA_Boolean visible;
numTexTri = NULL;
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) {
softegg_cat.spam() << endl;
/*
softegg_cat.spam() << " expected _parent to be null!?\n";
if (_parent == parent)
softegg_cat.spam() << " parent already set\n";
else {
softegg_cat.spam() << " current parent " << _parent->get_name() << " new parent "
<< parent << endl;
}
*/
return;
}
_parent = parent;
softegg_cat.spam() << " set parent to " << _parent->get_name() << endl;
// Add ourselves to our parent.
_parent->_children.push_back(this);
}
////////////////////////////////////////////////////////////////////
// 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::
force_set_parent(SoftNodeDesc *parent) {
if (_parent)
softegg_cat.spam() << " current parent " << _parent->get_name();
_parent = parent;
if (_parent)
softegg_cat.spam() << " new parent " << _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;
return _joint_type == JT_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;
softegg_cat.spam() << " marked parent " << get_name();
}
else
softegg_cat.spam() << " ?parent " << get_name() << " joint type " << _joint_type;
if (_parent != (SoftNodeDesc *)NULL) {
_parent->mark_joint_parent();
}
softegg_cat.spam() << 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()) {
softegg_cat.spam() << "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;
softegg_cat.spam() << "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) )
{
_joint_type = JT_junk;
softegg_cat.spam() << "junk node " << get_name() << endl;
parent_junk = true;
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
softegg_cat.spam() << child->get_name() << ",";
}
softegg_cat.spam() << endl;
}
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
child->check_junk(parent_junk);
}
}
///////////////////////////////////////////////////////////////////////
// Function: SoftNodeTree::is_partial
// Access: Public
// Description: check to see if this is a selected branch we want to
// descend - this will prevent creating geometry for
// other parts
///////////////////////////////////////////////////////////////////////
bool SoftNodeDesc::
is_partial(char *search_prefix) {
const char *name = fullname;
// if no search prefix then return false
if (!search_prefix)
return false;
// if name is search_prefix, return false
if (strstr(name, search_prefix) != NULL) {
softegg_cat.debug() << "matched " << name << " ";
return false;
}
// if name is not search_prefix, look in its parent
if (strstr(name, search_prefix) == NULL) {
softegg_cat.debug() << "node " << name << " ";
if (_parent)
return _parent->is_partial(search_prefix);
}
// neither name nor its parent is search_prefix
return true;
}
///////////////////////////////////////////////////////////////////////
// Function: SoftNodeTree::set_parentJoint
// Access: Public
// Description: Go through the ancestors and figure out who is the
// immediate _parentJoint of this node
///////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint) {
if (is_junk())
return;
//set its parent joint to the lastJoint
_parentJoint = lastJoint;
softegg_cat.spam() << get_name() << ": parent joint set to :" << lastJoint;
if (lastJoint)
softegg_cat.spam() << "(" << lastJoint->get_name() << ")";
softegg_cat.spam() << endl;
// is this node a joint?
SAA_Boolean isSkeleton = false;
if (has_model())
SAA_modelIsSkeleton( scene, get_model(), &isSkeleton );
// if already a joint or name has "joint" in it
const char *name = get_name().c_str();
if (is_joint() || isSkeleton || strstr(name, "joint") != NULL) {
lastJoint = this;
}
if ( _parentJoint && strstr( _parentJoint->get_name().c_str(), "scale" ) != NULL ) {
_parentJoint = NULL;
// _parentJoint = lastJoint = NULL;
softegg_cat.spam() << "scale joint flag set!\n";
}
// look in the children
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
SoftNodeDesc *child = (*ci);
child->set_parentJoint(scene, lastJoint);
}
}
////////////////////////////////////////////////////////////////////
// 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;
softegg_cat.debug() << "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()) {
softegg_cat.spam() << 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;
softegg_cat.debug() << "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;
softegg_cat.debug() << "pseudo " << get_name() << " case3\n";
}
}
}
}
else
softegg_cat.spam() << "found null joint " << get_name() << endl;
}
////////////////////////////////////////////////////////////////////
// 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 (!global && _parentJoint && !stec.flatten && !scale_joint) {
SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL, matrix );
softegg_cat.debug() << get_name() << " using local matrix :parent ";
} else {
SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL, matrix );
softegg_cat.debug() << get_name() << " using global matrix :parent ";
}
if (_parentJoint && !stec.flatten)
softegg_cat.debug() << _parentJoint->get_name() << endl;
else
softegg_cat.debug() << _parentJoint << endl;
softegg_cat.spam() << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n";
softegg_cat.spam() << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n";
softegg_cat.spam() << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n";
softegg_cat.spam() << "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);
softegg_cat.spam() << "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;
softegg_cat.spam() << "\n\nanimating child " << name << endl;
if (_parentJoint && !stec.flatten && !scale_joint ) {
softegg_cat.debug() << "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 {
softegg_cat.debug() << " 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 );
}
softegg_cat.spam() << "\nanim data: " << i << " " << j << " " << k << endl;
softegg_cat.spam() << "\t" << p << " " << h << " " << r << endl;
softegg_cat.spam() << "\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 {
softegg_cat.debug() << "Cannot build anim table - no skeleton\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::load_poly_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_poly_model(SAA_Scene *scene, SAA_ModelType type) {
SI_Error result;
const char *name = get_name().c_str();
int i;
int id = 0;
// if making a pose - get deformed geometry
if ( stec.make_pose )
gtype = SAA_GEOM_DEFORMED;
// 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);
softegg_cat.spam() << "triangles: " << numTri << "\n";
if ( result != SI_SUCCESS ) {
softegg_cat.spam() << "Error: couldn't get number of triangles!\n";
softegg_cat.debug() << "\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)
softegg_cat.spam() << "is Skeleton? " << isSkeleton << "\n";
/*************************************************************************************/
// model is not a null and has no triangles!
if ( !numTri ) {
softegg_cat.spam() << "no triangles!\n";
}
else {
// allocate array of triangles
triangles = (SAA_SubElem *) new SAA_SubElem[numTri];
if (!triangles) {
softegg_cat.info() << "Not enough Memory for triangles...\n";
exit(1);
}
// triangulate model and read the triangles into array
SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles );
softegg_cat.spam() << "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) {
softegg_cat.info() << "Not enough Memory for materials...\n";
exit(1);
}
softegg_cat.spam() << "got materials\n";
/***********************************************************************************/
// allocate array of textures per triangle
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 ) {
softegg_cat.spam() << "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;
// see if this triangle has texture info
if (numTexTri[i] == 0)
continue;
// check to see if texture is present
result = SAA_elementIsValid( scene, &textures[i], &valid );
if ( result != SI_SUCCESS )
softegg_cat.spam() << "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]);
softegg_cat.spam() << " tritex[" << i << "] named: " << texNameArray[i] << endl;
SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
if ( uv_swap == TRUE )
softegg_cat.spam() << " 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] );
softegg_cat.spam() << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl;
softegg_cat.spam() << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl;
SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat, &vRepeat );
softegg_cat.spam() << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
}
else {
softegg_cat.spam() << "Invalid texture...\n";
softegg_cat.spam() << " 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 );
softegg_cat.spam() << "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 )
softegg_cat.spam() << " 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);
softegg_cat.spam() << " 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 );
softegg_cat.spam() << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl;
softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
SAA_texture2DGetRepeats( scene, textures, &uRepeat, &vRepeat );
softegg_cat.spam() << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
}
else {
softegg_cat.spam() << "Invalid Texture...\n";
}
}
}
}
softegg_cat.spam() << "got textures" << endl;
}
////////////////////////////////////////////////////////////////////
// Function: SoftNodeDesc::load_nurbs_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_nurbs_model(SAA_Scene *scene, SAA_ModelType type) {
SI_Error result;
const char *name = get_name().c_str();
// 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 );
// get the materials
/***********************************************************************************/
const void *relinfo;
SAA_modelRelationGetMatNbElements( scene, get_model(), FALSE, &relinfo,
&numNurbMats );
softegg_cat.spam() << "nurbs surf has " << numNurbMats << " materials\n";
if ( numNurbMats ) {
materials = new SAA_Elem[numNurbMats];
if (!materials) {
softegg_cat.info() << "Out Of Memory on allocating materials\n";
exit(1);
}
SAA_modelRelationGetMatElements( scene, get_model(), relinfo,
numNurbMats, materials );
softegg_cat.spam() << "got materials\n";
// get the textures
/***********************************************************************************/
numNurbTexLoc = 0;
numNurbTexGlb = 0;
// find out how many local textures per NURBS surface
// ASSUME it only has one material
SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], FALSE, &relinfo, &numNurbTexLoc );
// if present, get local textures
if ( numNurbTexLoc ) {
softegg_cat.spam() << name << " had " << numNurbTexLoc << " local tex\n";
nassertv(numNurbTexLoc == 1);
textures = new SAA_Elem[numNurbTexLoc];
// get the referenced texture
SAA_materialRelationGetT2DLocElements( scene, &materials[0], TEX_PER_MAT, &textures[0] );
}
// if no locals, try to get globals
else {
SAA_modelRelationGetT2DGlbNbElements( scene, get_model(), FALSE, &relinfo, &numNurbTexGlb );
if ( numNurbTexGlb ) {
softegg_cat.spam() << name << " had " << numNurbTexGlb << " global tex\n";
nassertv(numNurbTexGlb == 1);
textures = new SAA_Elem[numNurbTexGlb];
// get the referenced texture
SAA_modelRelationGetT2DGlbElements( scene, get_model(), TEX_PER_MAT, &textures[0] );
}
}
if ( numNurbTexLoc || numNurbTexGlb) {
// allocate the texture name array
texNameArray = new char *[1];
// allocate arrays of texture info
uScale = new float;
vScale = new float;
uOffset = new float;
vOffset = new float;
// check to see if texture is present
result = SAA_elementIsValid( scene, &textures[0], &valid );
if ( result != SI_SUCCESS )
softegg_cat.spam() << "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[0] = stec.GetTextureName(scene, &textures[0]);
softegg_cat.spam() << " tritex[0] named: " << texNameArray[0] << endl;
SAA_texture2DGetUVSwap( scene, &textures[0], &uv_swap );
if ( uv_swap == TRUE )
softegg_cat.spam() << " swapping u and v...\n" ;
SAA_texture2DGetUScale( scene, &textures[0], &uScale[0] );
SAA_texture2DGetVScale( scene, &textures[0], &vScale[0] );
SAA_texture2DGetUOffset( scene, &textures[0], &uOffset[0] );
SAA_texture2DGetVOffset( scene, &textures[0], &vOffset[0] );
softegg_cat.spam() << "tritex[0] uScale: " << uScale[0] << " vScale: " << vScale[0] << endl;
softegg_cat.spam() << " uOffset: " << uOffset[0] << " vOffset: " << vOffset[0] << endl;
SAA_texture2DGetRepeats( scene, &textures[0], &uRepeat, &vRepeat );
softegg_cat.spam() << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
}
else {
softegg_cat.spam() << "Invalid texture...\n";
softegg_cat.spam() << " tritex[0] named: (null)\n";
}
}
softegg_cat.spam() << "got textures\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: find_shape_vert
// Access: Public
// Description: given a vertex, find its corresponding shape vertex
// and return its index.
////////////////////////////////////////////////////////////////////
int SoftNodeDesc::
find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert) {
int i, found = 0;
for (i = 0; i < numVert && !found ; i++) {
if ((p3d[0] == vertices[i].x) &&
(p3d[1] == vertices[i].y) &&
(p3d[2] == vertices[i].z)) {
found = 1;
softegg_cat.spam() << "found shape vert at index " << i << endl;
}
}
if (!found )
i = -1;
else
i--;
return i;
}
////////////////////////////////////////////////////////////////////
// Function: make_vertex_offsets
// Access: Public
// Description: Given a scene, a model , the vertices of its original
// shape and its name find the difference between the
// geometry of its key shapes and the models original
// geometry and add morph vertices to the egg data to
// reflect these changes.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
make_vertex_offsets(int numShapes) {
int i, j;
int offset;
int numCV;
char tableName[_MAX_PATH];
SAA_DVector *shapeVerts = NULL;
SAA_DVector *uniqueVerts = NULL;
SAA_Elem *model = get_model();
SAA_Scene *scene = &stec.scene;
EggVertexPool *vpool = NULL;
string vpool_name = get_name() + ".verts";
EggNode *t = stec._tree.get_egg_root()->find_child(vpool_name);
if (t)
DCAST_INTO_V(vpool, t);
int numOrigVert = (int) vpool->size();
EggVertexPool::iterator vi;
if ((type == SAA_MNSRF) && stec.make_nurbs)
SAA_nurbsSurfaceSetStep( scene, model, stec.nurbs_step, stec.nurbs_step );
SAA_modelGetNbVertices( scene, model, &numCV );
// get the shape verts
uniqueVerts = new SAA_DVector[numCV];
SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
numCV, uniqueVerts );
softegg_cat.spam() << numCV << " CV's\n";
for ( i = 0; i < numCV; i++ )
// convert vertices to global
_VCT_X_MAT( uniqueVerts[i], uniqueVerts[i], matrix);
softegg_cat.spam() << "uniqueVerts[" << i << "] = " << uniqueVerts[i].x << " " << uniqueVerts[i].y
<< " " << uniqueVerts[i].z << " " << uniqueVerts[i].w << endl;
// iterate through for each key shape (except original)
for ( i = 1; i < numShapes; i++ ) {
sprintf(tableName, "%s.%d", get_name().c_str(), i);
softegg_cat.spam() << "\nMaking geometry offsets for " << tableName << "...\n";
if ((type == SAA_MNSRF) && stec.make_nurbs)
softegg_cat.spam() << "calculating NURBS morphs...\n";
else
softegg_cat.spam() << "calculating triangle morphs...\n";
// get the shape verts
shapeVerts = new SAA_DVector[numCV];
SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, numCV, shapeVerts );
for ( j=0; j < numCV; j++ ) {
// convert vertices to global
_VCT_X_MAT( shapeVerts[j], shapeVerts[j], matrix);
softegg_cat.spam() << "shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
<< shapeVerts[j].y << " " << shapeVerts[j].z << endl;
}
softegg_cat.spam() << endl;
// for every original vertex, compare to the corresponding
// key shape vertex and see if a vertex offset is needed
j = 0;
for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++j) {
double dx, dy, dz;
EggVertex *vert = (*vi);
LPoint3d p3d = vert->get_pos3();
softegg_cat.spam() << "oVert[" << j << "] = " << p3d[0] << " " << p3d[1] << " " << p3d[2] << endl;
if ((type == SAA_MNSRF) && stec.make_nurbs) {
dx = shapeVerts[j].x - p3d[0];
dy = shapeVerts[j].y - p3d[1];
dz = shapeVerts[j].z - p3d[2];
softegg_cat.spam() << "global shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
<< shapeVerts[j].y << " " << shapeVerts[j].z << " " << shapeVerts[j].w << endl;
}
else {
// we need to map from original vertices
// to triangle shape vertices here
offset = find_shape_vert(p3d, uniqueVerts, numCV);
dx = shapeVerts[offset].x - p3d[0];
dy = shapeVerts[offset].y - p3d[1];
dz = shapeVerts[offset].z - p3d[2];
softegg_cat.spam() << "global shapeVerts[" << offset << "] = " << shapeVerts[offset].x << " "
<< shapeVerts[offset].y << " " << shapeVerts[offset].z << endl;
}
softegg_cat.spam() << j << ": dx = " << dx << ", dy = " << dy << ", dz = " << dz << endl;
// if change isn't negligible, make a morph vertex entry
double total = fabs(dx)+fabs(dy)+fabs(dz);
if ( total > 0.00001 ) {
if ( vpool != NULL ) {
// create offset
LVector3d p(dx, dy, dz);
EggMorphVertex *dxyz = new EggMorphVertex(tableName, p);
// add the offset to the vertex
vert->_dxyzs.insert(*dxyz);
}
else
softegg_cat.spam() << "Error: couldn't find vertex pool " << vpool_name << endl;
} // if total
} //for j
} //for i
}
////////////////////////////////////////////////////////////////////
// Function: make_morph_table
// Access: Public
// Description: Given a scene, a model, a name and a frame time,
// determine what type of shape interpolation is
// used and call the appropriate function to extract
// the shape weight info for this frame...
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
make_morph_table( float time ) {
int numShapes;
SAA_Elem *model = NULL;
SAA_AnimInterpType type;
SAA_Scene *scene = &stec.scene;
if (has_model())
model = get_model();
else
return;
// Get the number of key shapes
SAA_modelGetNbShapes( scene, model, &numShapes );
if ( numShapes <= 0 ) {
return;
}
stec.has_morph = true;
softegg_cat.spam() << "make_morph_table: " << get_name() << " : num shapes: " << numShapes << endl;
SAA_modelGetShapeInterpolation( scene, model, &type );
if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) {
softegg_cat.spam() << "linear morph" << endl;
make_linear_morph_table( numShapes, time );
}
else { // must be weighted...
// check first for expressions
softegg_cat.spam() << "expression morph" << endl;
make_expression_morph_table( numShapes, time );
}
}
////////////////////////////////////////////////////////////////////
// Function: make_linear_morph_table
// Access: Public
// Description: Given a scene, a model, its name, and the time,
// get the shape fcurve for the model and determine
// the shape weights for the given time and use them
// to populate the morph table.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
make_linear_morph_table(int numShapes, float time) {
int i;
float curveVal;
char tableName[_MAX_PATH];
SAA_Elem fcurve;
//SAnimTable *thisTable;
EggSAnimData *anim;
SAA_Elem *model = get_model();
SAA_Scene *scene = &stec.scene;
softegg_cat.spam() << "linear interp, getting fcurve\n";
SAA_modelFcurveGetShape( scene, model, &fcurve );
SAA_fcurveEval( scene, &fcurve, time, &curveVal );
softegg_cat.spam() << "at time " << time << ", fcurve for " << get_name() << " = " << curveVal << endl;
float nextVal = 0.0f;
// populate morph table values for this frame
for ( i = 1; i < numShapes; i++ ) {
// derive table name from the model name
sprintf(tableName, "%s.%d", get_name().c_str(), i);
softegg_cat.spam() << "Linear: looking for table '" << tableName << "'\n";
//find the morph table associated with this key shape
anim = stec.find_morph_table(tableName);
if ( anim != NULL ) {
if ( i == (int)curveVal ) {
if ( curveVal - i == 0 ) {
anim->add_data(1.0f );
softegg_cat.spam() << "adding element 1.0f\n";
}
else {
anim->add_data(1.0f - (curveVal - i));
nextVal = curveVal - i;
softegg_cat.spam() << "adding element " << 1.0f - (curveVal - i) << endl;
}
}
else {
if ( nextVal ) {
anim->add_data(nextVal );
nextVal = 0.0f;
softegg_cat.spam() << "adding element " << nextVal << endl;
}
else {
anim->add_data(0.0f);
softegg_cat.spam() << "adding element 0.0f\n";
}
}
softegg_cat.spam() <<" to '" << tableName << "'\n";
}
else
softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: make_weighted_morph_table
// Access: Public
// Description: Given a scene, a model, a list of all models in the
// scene, the number of models in the scece, the number
// of key shapes for this model, the name of the model
// and the current time, determine what method of
// controlling the shape weights is used and call the
// appropriate routine.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
make_weighted_morph_table(int numShapes, float time) {
float curveVal;
SI_Error result;
char tableName[_MAX_PATH];
SAA_Elem *weightCurves;
//SAnimTable *thisTable;
EggSAnimData *anim;
SAA_Elem *model = get_model();
SAA_Scene *scene = &stec.scene;
// allocate array of weight curves (one for each shape)
weightCurves = new SAA_Elem[numShapes];
result = SAA_modelFcurveGetShapeWeights(scene, model, numShapes, weightCurves);
if ( result == SI_SUCCESS ) {
for ( int i = 1; i < numShapes; i++ ) {
SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );
// make sure soft gave us a reasonable number
//if (!isNum(curveVal))
//curveVal = 0.0f;
softegg_cat.spam() << "at time " << time << ", weightCurve[" << i << "] for " << get_name() << " = " << curveVal << endl;
// derive table name from the model name
sprintf(tableName, "%s.%d", get_name().c_str(), i);
// find and populate shape table
softegg_cat.spam() << "Weight: looking for table '" << tableName << "'\n";
//find the morph table associated with this key shape
anim = stec.find_morph_table(tableName);
if ( anim != NULL ) {
anim->add_data(curveVal);
softegg_cat.spam() << "adding element " << curveVal << endl;
}
else
softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: make_expression_morph_table
// Access: Public
// Description: Given a scene, a model and its number of key shapes
// generate a morph table describing transitions btwn
// the key shapes by evaluating the positions of the
// controlling sliders.
////////////////////////////////////////////////////////////////////
void SoftNodeDesc::
make_expression_morph_table(int numShapes, float time)
{
//int j;
int numExp;
char *track;
//float expVal;
//float sliderVal;
//char *tableName;
//char *sliderName;
//SAnimTable *thisTable;
SAA_Elem *expressions;
SI_Error result;
SAA_Elem *model = get_model();
SAA_Scene *scene = &stec.scene;
// populate morph table values for this frame
// compose track name
track = NULL;
// find how many expressions for this shape
SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
softegg_cat.spam() << get_name() << " has " << numExp << " RHS expressions\n";
if ( numExp ) {
// get the expressions for this shape
expressions = new SAA_Elem[numExp];
softegg_cat.spam() << "getting " << numExp << " RHS expressions...\n";
result = SAA_elementGetExpressions( scene, model, track, FALSE,
numExp, expressions );
/*
if ( !result ) {
for ( j = 1; j < numExp; j++ ) {
if ( verbose >= 2 )
{
// debug see what we got
int numvars;
SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
int *varnamelen;
int *varstrlen;
int expstrlen;
varnamelen = (int *)malloc(sizeof(int)*numvars);
varstrlen = (int *)malloc(sizeof(int)*numvars);
SAA_expressionGetStringLengths( scene, &expressions[j],
numvars, varnamelen, varstrlen, &expstrlen );
int *varnamesizes;
int *varstrsizes;
varnamesizes = (int *)malloc(sizeof(int)*numvars);
varstrsizes = (int *)malloc(sizeof(int)*numvars);
for ( int k = 0; k < numvars; k++ )
{
varnamesizes[k] = varnamelen[k] + 1;
varstrsizes[k] = varstrlen[k] + 1;
}
int expstrsize = expstrlen + 1;
char **varnames;
char **varstrs;
varnames = (char **)malloc(sizeof(char *)*numvars);
varstrs = (char **)malloc(sizeof(char *)*numvars);
for ( k = 0; k < numvars; k++ )
{
varnames[k] = (char *)malloc(sizeof(char)*
varnamesizes[k]);
varstrs[k] = (char *)malloc(sizeof(char)*
varstrsizes[k]);
}
char *expstr = (char *)malloc(sizeof(char)* expstrsize );
SAA_expressionGetStrings( scene, &expressions[j], numvars,
varnamesizes, varstrsizes, expstrsize, varnames,
varstrs, expstr );
if ( verbose >= 2 )
{
fprintf( outStream, "expression = '%s'\n", expstr );
fprintf( outStream, "has %d variables\n", numvars );
}
} //if verbose
if ( verbose >= 2 )
fprintf( outStream, "evaling expression...\n" );
SAA_expressionEval( scene, &expressions[j], time, &expVal );
if ( verbose >= 2 )
fprintf( outStream, "time %f: exp val %f\n",
time, expVal );
// derive table name from the model name
tableName = MakeTableName( name, j );
if ( verbose >= 2 )
fprintf( outStream, "Exp: looking for table '%s'\n",
tableName );
//find the morph table associated with this key shape
anim = (SAnimTable *)
(morphRoot->FindDescendent( tableName ));
if ( anim != NULL )
{
anim->AddElement( expVal );
if ( verbose >= 1 )
fprintf( outStream, "%d: adding element %f to %s\n",
j, expVal, tableName );
fflush( outStream );
}
else
{
fprintf( outStream, "%d: Couldn't find table '%s'", j,
tableName );
fprintf( outStream, " for value %f\n", expVal );
}
}
}
else
fprintf( outStream, "couldn't get expressions!!!\n" );
*/
}
else {
softegg_cat.spam() << "weighted morph" << endl;
// no expression, use weight curves
make_weighted_morph_table(numShapes, time );
}
}
//
//
//