open_toontown_panda3d/pandatool/src/maxegg/maxNodeTree.cxx

448 lines
13 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file maxNodeTree.cxx
* @author crevilla
* from mayaNodeTree.cxx created by: drose (06Jun03)
*/
#include "maxEgg.h"
/**
*
*/
MaxNodeTree::
MaxNodeTree() {
_root = new MaxNodeDesc;
_fps = 0.0;
_export_mesh = false;
_egg_data = nullptr;
_egg_root = nullptr;
_skeleton_node = nullptr;
}
/**
* Returns a pointer to the node corresponding to the indicated INode object,
* creating it first if necessary.
*/
MaxNodeDesc *MaxNodeTree::
build_node(INode *max_node) {
MaxNodeDesc *node_desc = r_build_node(max_node);
node_desc->from_INode(max_node);
if (node_desc->is_node_joint()) {
node_desc->_joint_entry = build_joint(max_node, node_desc);
}
return node_desc;
}
/**
* Returns a pointer to the node corresponding to the indicated INode object,
* creating it first if necessary.
*/
MaxNodeDesc *MaxNodeTree::
build_joint(INode *max_node, MaxNodeDesc *node_joint) {
MaxNodeDesc *node_desc = r_build_joint(node_joint, max_node);
node_desc->from_INode(max_node);
node_desc->set_joint(true);
return node_desc;
}
bool MaxNodeTree::node_in_list(ULONG handle, ULONG *list, int len) {
if (!list) return true;
for (int i = 0; i < len; i++)
if (list[i] == handle) return true;
return false;
}
bool MaxNodeTree::is_joint(INode *node) {
Control *c = node->GetTMController();
return (node->GetBoneNodeOnOff() || //joints
(c && //bipeds
((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
(c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
(c->ClassID() == FOOTPRINT_CLASS_ID))));
}
bool MaxNodeTree::
r_build_hierarchy(INode *root, ULONG *selection_list, int len) {
if (node_in_list(root->GetHandle(), selection_list, len))
build_node(root);
// Export children
for ( int i = 0; i < root->NumberOfChildren(); i++ ) {
// *** Should probably be checking the return value of the following line
r_build_hierarchy(root->GetChildNode(i), selection_list, len);
}
return true;
}
/**
* Walks through the complete Max hierarchy and builds up the corresponding
* tree.
*/
bool MaxNodeTree::
build_complete_hierarchy(INode *root, ULONG *selection_list, int len) {
// Get the entire Max scene.
if (root == nullptr) {
// *** Log an error
return false;
}
bool all_ok = true;
r_build_hierarchy(root, selection_list, len);
if (all_ok) {
_root->check_pseudo_joints(false);
}
return all_ok;
}
/**
* Returns the total number of nodes in the hierarchy, not counting the root
* node.
*/
int MaxNodeTree::
get_num_nodes() const {
return _nodes.size();
}
/**
* Returns the nth node in the hierarchy, in an arbitrary ordering.
*/
MaxNodeDesc *MaxNodeTree::
get_node(int n) const {
nassertr(n >= 0 && n < (int)_nodes.size(), nullptr);
return _nodes[n];
}
/**
* Removes all of the references to generated egg structures from the tree,
* and prepares the tree for generating new egg structures.
*/
void MaxNodeTree::
clear_egg(EggData *egg_data, EggGroupNode *egg_root,
EggGroupNode *skeleton_node) {
_root->clear_egg();
_egg_data = egg_data;
_egg_root = egg_root;
_skeleton_node = skeleton_node;
}
/**
* Returns the EggGroupNode corresponding to the group or joint for the
* indicated node. Creates the group node if it has not already been created.
*/
EggGroup *MaxNodeTree::
get_egg_group(MaxNodeDesc *node_desc) {
nassertr(_egg_root != nullptr, nullptr);
if (node_desc->_egg_group == nullptr) {
// We need to make a new group node.
EggGroup *egg_group;
nassertr(node_desc->_parent != nullptr, nullptr);
egg_group = new EggGroup(node_desc->get_name());
if (node_desc->is_joint()) {
egg_group->set_group_type(EggGroup::GT_joint);
}
if (node_desc->_parent == _root) {
// The parent is the root. Set collision properties for the root if it
// has them:
if(!_export_mesh)
{
set_collision_tags(node_desc, egg_group);
}
_egg_root->add_child(egg_group);
} else {
// The parent is another node. if export mesh, the tag should be added
// at the second level
if(_export_mesh)
{
if(node_desc->_parent->_parent == _root)
{
set_collision_tags(node_desc, egg_group);
}
}
EggGroup *parent_egg_group = get_egg_group(node_desc->_parent);
parent_egg_group->add_child(egg_group);
}
node_desc->_egg_group = egg_group;
}
return node_desc->_egg_group;
}
/**
* Returns the EggTable corresponding to the joint for the indicated node.
* Creates the table node if it has not already been created.
*/
EggTable *MaxNodeTree::
get_egg_table(MaxNodeDesc *node_desc) {
nassertr(_skeleton_node != nullptr, nullptr);
nassertr(node_desc->is_joint(), nullptr);
if (node_desc->_egg_table == nullptr) {
// We need to make a new table node.
nassertr(node_desc->_parent != nullptr, nullptr);
EggTable *egg_table = new EggTable(node_desc->get_name());
node_desc->_anim = new EggXfmSAnim("xform",
_egg_data->get_coordinate_system());
node_desc->_anim->set_fps(_fps);
egg_table->add_child(node_desc->_anim);
if (!node_desc->_parent->is_joint()) {
// The parent is not a joint; put it at the top.
_skeleton_node->add_child(egg_table);
} else {
// The parent is another joint.
EggTable *parent_egg_table = get_egg_table(node_desc->_parent);
parent_egg_table->add_child(egg_table);
}
node_desc->_egg_table = egg_table;
}
return node_desc->_egg_table;
}
/**
* Returns the anim table corresponding to the joint for the indicated node.
* Creates the table node if it has not already been created.
*/
EggXfmSAnim *MaxNodeTree::
get_egg_anim(MaxNodeDesc *node_desc) {
get_egg_table(node_desc);
return node_desc->_anim;
}
/**
* The recursive implementation of build_node().
*/
MaxNodeDesc *MaxNodeTree::
r_build_node(INode* max_node) {
// If we have already encountered this pathname, return the corresponding
// MaxNodeDesc immediately.
ULONG node_handle = 0;
if (max_node) {
node_handle = max_node->GetHandle();
}
NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
if (ni != _nodes_by_path.end()) {
return (*ni).second;
}
// Otherwise, we have to create it. Do this recursively, so we create each
// node along the path.
MaxNodeDesc *node_desc;
if (!max_node) {
// This is the top.
node_desc = _root;
} else {
INode *parent_node;
if (max_node->IsRootNode()) {
parent_node = nullptr;
} else {
parent_node = max_node->GetParentNode();
}
MaxNodeDesc *parent_node_desc = r_build_node(parent_node);
node_desc = new MaxNodeDesc(parent_node_desc, max_node);
_nodes.push_back(node_desc);
}
_nodes_by_path.insert(NodesByPath::value_type(node_handle, node_desc));
return node_desc;
}
/**
* The recursive implementation of build_joint().
*/
MaxNodeDesc *MaxNodeTree::
r_build_joint(MaxNodeDesc *node_desc, INode *max_node)
{
MaxNodeDesc *node_joint;
if (node_desc == _root) {
node_joint = new MaxNodeDesc(_root, max_node);
_nodes.push_back(node_joint);
return node_joint;
} else if (node_desc->is_node_joint() && node_desc->_joint_entry) {
node_joint = new MaxNodeDesc(node_desc->_joint_entry, max_node);
_nodes.push_back(node_joint);
return node_joint;
} else {
return r_build_joint(node_desc->_parent, max_node);
}
}
/**
* The recursive implementation of build_node().
*/
MaxNodeDesc *MaxNodeTree::
find_node(INode* max_node) {
// If we have already encountered this pathname, return the corresponding
// MaxNodeDesc immediately.
ULONG node_handle = 0;
if (max_node) {
node_handle = max_node->GetHandle();
}
NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
if (ni != _nodes_by_path.end()) {
return (*ni).second;
}
return nullptr;
}
/**
* The recursive implementation of build_node().
*/
MaxNodeDesc *MaxNodeTree::
find_joint(INode* max_node)
{
MaxNodeDesc *node = find_node(max_node);
if (!node || (is_joint(max_node) && !node->is_node_joint()))
node = build_node(max_node);
return node->_joint_entry;
}
/**
* Sets the corresponding collision tag to the egg_group based on the User
* Defined Tab in the object properties panel
*/
void MaxNodeTree::set_collision_tags(MaxNodeDesc *node_desc, EggGroup *egg_group) {
// Max has huge problems passing strings and bools to Get and SetUserProp
// So instead we have to use Integers. Now we have to check for every
// collide type, then get its collide flags and do some number crunching
// to get the actual flag into the group
int check = 1; //is the value true. This could be anything really
// We have to check each collision type in turn to see if it's true Ugly
// but it works per object, not globaly
if (node_desc->get_max_node()->GetUserPropInt(_T("polyset"), check)) {
// we have a polyset.
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_polyset);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("plane"), check)) {
// plane
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_plane);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("polygon"), check)) {
// polygon
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_polygon);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("sphere"), check)) {
// sphere
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_sphere);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("inv-sphere"), check)) {
// invsphere
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_inv_sphere);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("invsphere"), check)) {
// invsphere (different spelling)
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_inv_sphere);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("tube"), check)) {
// tube
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_tube);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("floor-mesh"), check)) {
// floor-mesh
if (check == 1) {
egg_group->set_collision_name(node_desc->get_name());
egg_group->set_cs_type(EggGroup::CST_floor_mesh);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("descend"), check)) {
if (check == 1) {
// we have the descend flag specified
egg_group->set_collide_flags(EggGroup::CF_descend);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("event"), check)) {
if (check == 1) {
// we have the event flag specified
egg_group->set_collide_flags(EggGroup::CF_event);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("keep"), check)) {
if (check == 1) {
// we have the keep flag specified
egg_group->set_collide_flags(EggGroup::CF_keep);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("solid"), check)) {
if (check == 1) {
// we have the solid flag specified
egg_group->set_collide_flags(EggGroup::CF_solid);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("center"), check)) {
if (check == 1) {
// we have the center flag specified
egg_group->set_collide_flags(EggGroup::CF_center);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("turnstile"), check)) {
if (check == 1) {
// we have the turnstile flag specified
egg_group->set_collide_flags(EggGroup::CF_turnstile);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("level"), check)) {
if (check == 1) {
// we have the level flag specified
egg_group->set_collide_flags(EggGroup::CF_level);
}
}
if (node_desc->get_max_node()->GetUserPropInt(_T("intangible"), check)) {
if (check == 1) {
// we have the intangible flag specified
egg_group->set_collide_flags(EggGroup::CF_intangible);
}
}
return;
}