Panda3D

maxNodeTree.cxx

00001 // Filename: maxNodeTree.cxx
00002 // Created by: crevilla
00003 // from mayaNodeTree.cxx created by:  drose (06Jun03)
00004 //
00005 ////////////////////////////////////////////////////////////////////
00006 //
00007 // PANDA 3D SOFTWARE
00008 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00009 //
00010 // All use of this software is subject to the terms of the revised BSD
00011 // license.  You should have received a copy of this license along
00012 // with this source code in a file named "LICENSE."
00013 //
00014 ////////////////////////////////////////////////////////////////////
00015 
00016 #include "maxEgg.h"
00017 
00018 // 3dsmax versions below 9 don't define this.
00019 #ifndef _M
00020 #define _M(s) (s)
00021 #endif
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: MaxNodeTree::Constructor
00025 //       Access: Public
00026 //  Description: 
00027 ////////////////////////////////////////////////////////////////////
00028 MaxNodeTree::
00029 MaxNodeTree() {
00030   _root = new MaxNodeDesc;
00031   _fps = 0.0;
00032   _export_mesh = false;
00033   _egg_data = (EggData *)NULL;
00034   _egg_root = (EggGroupNode *)NULL;
00035   _skeleton_node = (EggGroupNode *)NULL;
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: MaxNodeTree::build_node
00040 //       Access: Public
00041 //  Description: Returns a pointer to the node corresponding to the
00042 //               indicated INode object, creating it first if
00043 //               necessary.
00044 ////////////////////////////////////////////////////////////////////
00045 MaxNodeDesc *MaxNodeTree::
00046 build_node(INode *max_node) {
00047   MaxNodeDesc *node_desc = r_build_node(max_node);
00048   node_desc->from_INode(max_node);
00049   if (node_desc->is_node_joint())
00050     node_desc->_joint_entry = build_joint(max_node, node_desc);
00051   return node_desc;
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: MaxNodeTree::build_node
00056 //       Access: Public
00057 //  Description: Returns a pointer to the node corresponding to the
00058 //               indicated INode object, creating it first if
00059 //               necessary.
00060 ////////////////////////////////////////////////////////////////////
00061 MaxNodeDesc *MaxNodeTree::
00062 build_joint(INode *max_node, MaxNodeDesc *node_joint) {
00063   MaxNodeDesc *node_desc = r_build_joint(node_joint, max_node);
00064   node_desc->from_INode(max_node);
00065   node_desc->set_joint(true);  
00066   return node_desc;
00067 }
00068 
00069 bool MaxNodeTree::node_in_list(ULONG handle, ULONG *list, int len) {
00070   if (!list) return true;
00071   for (int i = 0; i < len; i++)
00072     if (list[i] == handle) return true;
00073   return false;
00074 }
00075 
00076 bool MaxNodeTree::is_joint(INode *node) {
00077   Control *c = node->GetTMController();
00078   return (node->GetBoneNodeOnOff() ||                    //joints
00079          (c &&                                           //bipeds
00080          ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
00081          (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
00082          (c->ClassID() == FOOTPRINT_CLASS_ID))));
00083 }
00084 
00085 bool MaxNodeTree::
00086 r_build_hierarchy(INode *root, ULONG *selection_list, int len) {
00087   if (node_in_list(root->GetHandle(), selection_list, len))
00088     build_node(root);
00089   // Export children
00090   for ( int i = 0; i < root->NumberOfChildren(); i++ ) {
00091     // *** Should probably be checking the return value of the following line
00092     r_build_hierarchy(root->GetChildNode(i), selection_list, len);
00093   }
00094   return true;
00095 }
00096 ////////////////////////////////////////////////////////////////////
00097 //     Function: MaxNodeTree::build_complete_hierarchy
00098 //       Access: Public
00099 //  Description: Walks through the complete Max hierarchy and builds
00100 //               up the corresponding tree.
00101 ////////////////////////////////////////////////////////////////////
00102 bool MaxNodeTree::
00103 build_complete_hierarchy(INode *root, ULONG *selection_list, int len) {
00104 
00105   // Get the entire Max scene.
00106   if (root == NULL) {
00107     // *** Log an error
00108     return false;
00109   }
00110     
00111   bool all_ok = true;
00112   r_build_hierarchy(root, selection_list, len);
00113 
00114   if (all_ok) {
00115     _root->check_pseudo_joints(false);
00116   }
00117 
00118   return all_ok;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: MaxNodeTree::get_num_nodes
00123 //       Access: Public
00124 //  Description: Returns the total number of nodes in the hierarchy,
00125 //               not counting the root node.
00126 ////////////////////////////////////////////////////////////////////
00127 int MaxNodeTree::
00128 get_num_nodes() const {
00129   return _nodes.size();
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: MaxNodeTree::get_node
00134 //       Access: Public
00135 //  Description: Returns the nth node in the hierarchy, in an
00136 //               arbitrary ordering.
00137 ////////////////////////////////////////////////////////////////////
00138 MaxNodeDesc *MaxNodeTree::
00139 get_node(int n) const {
00140   nassertr(n >= 0 && n < (int)_nodes.size(), NULL);
00141   return _nodes[n];
00142 }
00143 
00144 ////////////////////////////////////////////////////////////////////
00145 //     Function: MaxNodeTree::clear_egg
00146 //       Access: Public
00147 //  Description: Removes all of the references to generated egg
00148 //               structures from the tree, and prepares the tree for
00149 //               generating new egg structures.
00150 ////////////////////////////////////////////////////////////////////
00151 void MaxNodeTree::
00152 clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
00153           EggGroupNode *skeleton_node) {
00154   _root->clear_egg();
00155   _egg_data = egg_data;
00156   _egg_root = egg_root;
00157   _skeleton_node = skeleton_node;
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: MaxNodeTree::get_egg_group
00162 //       Access: Public
00163 //  Description: Returns the EggGroupNode corresponding to the group
00164 //               or joint for the indicated node.  Creates the group
00165 //               node if it has not already been created.
00166 ////////////////////////////////////////////////////////////////////
00167 EggGroup *MaxNodeTree::
00168 get_egg_group(MaxNodeDesc *node_desc) {
00169   nassertr(_egg_root != (EggGroupNode *)NULL, NULL);
00170 
00171   if (node_desc->_egg_group == (EggGroup *)NULL) {
00172     // We need to make a new group node.
00173     EggGroup *egg_group;
00174 
00175     nassertr(node_desc->_parent != (MaxNodeDesc *)NULL, NULL);
00176     egg_group = new EggGroup(node_desc->get_name());
00177     if (node_desc->is_joint()) {
00178       egg_group->set_group_type(EggGroup::GT_joint);
00179     }
00180     if (node_desc->_parent == _root) {
00181       // The parent is the root.
00182       // Set collision properties for the root if it has them:
00183       if(!_export_mesh)
00184       {
00185           set_collision_tags(node_desc, egg_group);
00186       }
00187       _egg_root->add_child(egg_group);
00188 
00189     } else {
00190       // The parent is another node.
00191       // if export mesh, the tag should be added at the second level
00192       if(_export_mesh)
00193       {
00194         if(node_desc->_parent->_parent == _root)
00195         {
00196             set_collision_tags(node_desc, egg_group);
00197         }
00198       }
00199       EggGroup *parent_egg_group = get_egg_group(node_desc->_parent);
00200       parent_egg_group->add_child(egg_group);
00201     }
00202 
00203     node_desc->_egg_group = egg_group;
00204   }
00205 
00206   return node_desc->_egg_group;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: MaxNodeTree::get_egg_table
00211 //       Access: Public
00212 //  Description: Returns the EggTable corresponding to the joint
00213 //               for the indicated node.  Creates the table node if it
00214 //               has not already been created.
00215 ////////////////////////////////////////////////////////////////////
00216 EggTable *MaxNodeTree::
00217 get_egg_table(MaxNodeDesc *node_desc) {
00218   nassertr(_skeleton_node != (EggGroupNode *)NULL, NULL);
00219   nassertr(node_desc->is_joint(), NULL);
00220 
00221   if (node_desc->_egg_table == (EggTable *)NULL) {
00222     // We need to make a new table node.
00223     nassertr(node_desc->_parent != (MaxNodeDesc *)NULL, NULL);
00224 
00225     EggTable *egg_table = new EggTable(node_desc->get_name());
00226     node_desc->_anim = new EggXfmSAnim("xform", 
00227                                        _egg_data->get_coordinate_system());
00228     node_desc->_anim->set_fps(_fps);
00229     egg_table->add_child(node_desc->_anim);
00230 
00231     if (!node_desc->_parent->is_joint()) {
00232       // The parent is not a joint; put it at the top.
00233       _skeleton_node->add_child(egg_table);
00234 
00235     } else {
00236       // The parent is another joint.
00237       EggTable *parent_egg_table = get_egg_table(node_desc->_parent);
00238       parent_egg_table->add_child(egg_table);
00239     }
00240 
00241     node_desc->_egg_table = egg_table;
00242   }
00243 
00244   return node_desc->_egg_table;
00245 }
00246 
00247 ////////////////////////////////////////////////////////////////////
00248 //     Function: MaxNodeTree::get_egg_anim
00249 //       Access: Public
00250 //  Description: Returns the anim table corresponding to the joint
00251 //               for the indicated node.  Creates the table node if it
00252 //               has not already been created.
00253 ////////////////////////////////////////////////////////////////////
00254 EggXfmSAnim *MaxNodeTree::
00255 get_egg_anim(MaxNodeDesc *node_desc) 
00256 {
00257   get_egg_table(node_desc);
00258   return node_desc->_anim;
00259 }
00260 
00261 
00262 ////////////////////////////////////////////////////////////////////
00263 //     Function: MaxNodeTree::r_build_node
00264 //       Access: Private
00265 //  Description: The recursive implementation of build_node().
00266 ////////////////////////////////////////////////////////////////////
00267 MaxNodeDesc *MaxNodeTree::
00268 r_build_node(INode* max_node) 
00269 {
00270   // If we have already encountered this pathname, return the
00271   // corresponding MaxNodeDesc immediately.
00272   
00273   ULONG node_handle = 0;
00274   
00275   if (max_node) {
00276     node_handle = max_node->GetHandle();
00277   }    
00278 
00279   NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
00280   if (ni != _nodes_by_path.end()) {
00281     return (*ni).second;
00282   }
00283 
00284   // Otherwise, we have to create it.  Do this recursively, so we
00285   // create each node along the path.
00286   MaxNodeDesc *node_desc;
00287 
00288   if (!max_node) {
00289     // This is the top.
00290     node_desc = _root;
00291 
00292   } else {
00293     INode *parent_node; 
00294     string local_name = max_node->GetName();
00295     if (max_node->IsRootNode()) {
00296       parent_node = NULL;
00297     } else {
00298       parent_node = max_node->GetParentNode();
00299     }
00300 
00301     MaxNodeDesc *parent_node_desc = r_build_node(parent_node);
00302     node_desc = new MaxNodeDesc(parent_node_desc, local_name);
00303     _nodes.push_back(node_desc);
00304   }
00305 
00306   _nodes_by_path.insert(NodesByPath::value_type(node_handle, node_desc));
00307   return node_desc;
00308 }
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 //     Function: MaxNodeTree::r_build_joint
00312 //       Access: Private
00313 //  Description: The recursive implementation of build_joint().
00314 ////////////////////////////////////////////////////////////////////
00315 MaxNodeDesc *MaxNodeTree::
00316 r_build_joint(MaxNodeDesc *node_desc, INode *max_node) 
00317 {
00318   MaxNodeDesc *node_joint;
00319   if (node_desc == _root) {
00320     node_joint =  new MaxNodeDesc(_root, max_node->GetName());
00321     _nodes.push_back(node_joint);
00322         return node_joint;
00323   }     else if (node_desc->is_node_joint() && node_desc->_joint_entry) {
00324     node_joint =  new MaxNodeDesc(node_desc->_joint_entry, max_node->GetName());
00325     _nodes.push_back(node_joint);
00326         return node_joint;
00327   } else {
00328         return r_build_joint(node_desc->_parent, max_node);
00329   }
00330 }
00331 
00332 ////////////////////////////////////////////////////////////////////
00333 //     Function: MaxNodeTree::find_node
00334 //       Access: Private
00335 //  Description: The recursive implementation of build_node().
00336 ////////////////////////////////////////////////////////////////////
00337 MaxNodeDesc *MaxNodeTree::
00338 find_node(INode* max_node) 
00339 {
00340   // If we have already encountered this pathname, return the
00341   // corresponding MaxNodeDesc immediately.
00342   
00343   ULONG node_handle = 0;
00344   
00345   if (max_node) {
00346     node_handle = max_node->GetHandle();
00347   }    
00348 
00349   NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
00350   if (ni != _nodes_by_path.end()) {
00351     return (*ni).second;
00352   } 
00353 
00354   return NULL;
00355 }
00356 
00357 ////////////////////////////////////////////////////////////////////
00358 //     Function: MaxNodeTree::find_joint
00359 //       Access: Private
00360 //  Description: The recursive implementation of build_node().
00361 ////////////////////////////////////////////////////////////////////
00362 MaxNodeDesc *MaxNodeTree::
00363 find_joint(INode* max_node) 
00364 {
00365   MaxNodeDesc *node = find_node(max_node);
00366   if (!node || (is_joint(max_node) && !node->is_node_joint()))
00367     node = build_node(max_node);
00368   return node->_joint_entry;
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: MaxNodeTree::set_collision_tags
00373 //       Access: Private
00374 //  Description: Sets the corresponding collision tag to the egg_group
00375 //               based on the User Defined Tab in the object properties 
00376 //               panel
00377 ////////////////////////////////////////////////////////////////////
00378 void MaxNodeTree::set_collision_tags(MaxNodeDesc *node_desc, EggGroup *egg_group) {
00379     //Max has huge problems passing strings and bools to Get and SetUserProp
00380     //So instead we have to use Integers. Now we have to check
00381     //for every collide type, then get its collide flags and
00382     //do some number crunching to get the actual flag into the group
00383   
00384     int check = 1; //is the value true. This could be anything really
00385       
00386       //We have to check each collision type in turn to see if it's true
00387       //Ugly but it works per object, not globaly
00388     if (node_desc->get_max_node()->GetUserPropInt(_M("polyset"), check)) {
00389         //we have a polyset.
00390       if (check == 1) {
00391         egg_group->set_collision_name(node_desc->get_name());
00392         egg_group->set_cs_type(EggGroup::CST_polyset);
00393       }
00394     } 
00395     if (node_desc->get_max_node()->GetUserPropInt(_M("plane"), check)) {
00396       //plane
00397       if (check == 1) {
00398         egg_group->set_collision_name(node_desc->get_name());
00399         egg_group->set_cs_type(EggGroup::CST_plane);
00400       }
00401     } 
00402     if (node_desc->get_max_node()->GetUserPropInt(_M("polygon"), check)) {
00403       //polygon
00404       if (check == 1) {
00405         egg_group->set_collision_name(node_desc->get_name());
00406         egg_group->set_cs_type(EggGroup::CST_polygon);
00407       }
00408     }
00409     if (node_desc->get_max_node()->GetUserPropInt(_M("sphere"), check)) {
00410       //sphere
00411       if (check == 1) {
00412         egg_group->set_collision_name(node_desc->get_name());
00413         egg_group->set_cs_type(EggGroup::CST_sphere);
00414       }
00415     } 
00416     if (node_desc->get_max_node()->GetUserPropInt(_M("inv-sphere"), check)) {
00417       //invsphere
00418       if (check == 1) {
00419         egg_group->set_collision_name(node_desc->get_name());
00420         egg_group->set_cs_type(EggGroup::CST_inv_sphere);
00421       }
00422     } 
00423     if (node_desc->get_max_node()->GetUserPropInt(_M("invsphere"), check)) {
00424       //invsphere (different spelling)
00425       if (check == 1) {
00426         egg_group->set_collision_name(node_desc->get_name());
00427         egg_group->set_cs_type(EggGroup::CST_inv_sphere);
00428       }
00429     } 
00430     if (node_desc->get_max_node()->GetUserPropInt(_M("tube"), check)) {
00431       //tube
00432       if (check == 1) {
00433         egg_group->set_collision_name(node_desc->get_name());
00434         egg_group->set_cs_type(EggGroup::CST_tube);
00435       }
00436     } 
00437     if (node_desc->get_max_node()->GetUserPropInt(_M("floor-mesh"), check)) {
00438       //floor-mesh
00439       if (check == 1) {
00440         egg_group->set_collision_name(node_desc->get_name());
00441         egg_group->set_cs_type(EggGroup::CST_floor_mesh);
00442       }
00443     }
00444     
00445     if (node_desc->get_max_node()->GetUserPropInt(_M("descend"), check)) {
00446       if (check == 1) {
00447       //we have the descend flag specified
00448       egg_group->set_collide_flags(EggGroup::CF_descend);
00449       }
00450     } 
00451     if (node_desc->get_max_node()->GetUserPropInt(_M("event"), check)) {
00452       if (check == 1) {
00453       //we have the event flag specified
00454       egg_group->set_collide_flags(EggGroup::CF_event);
00455       }
00456     } 
00457     if (node_desc->get_max_node()->GetUserPropInt(_M("keep"), check)) {
00458       if (check == 1) {
00459       //we have the keep flag specified
00460       egg_group->set_collide_flags(EggGroup::CF_keep);
00461       }
00462     } 
00463     if (node_desc->get_max_node()->GetUserPropInt(_M("solid"), check)) {
00464       if (check == 1) {
00465       //we have the solid flag specified
00466       egg_group->set_collide_flags(EggGroup::CF_solid);
00467       }
00468     } 
00469     if (node_desc->get_max_node()->GetUserPropInt(_M("center"), check)) {
00470       if (check == 1) {
00471       //we have the center flag specified
00472       egg_group->set_collide_flags(EggGroup::CF_center);
00473       }
00474     } 
00475     if (node_desc->get_max_node()->GetUserPropInt(_M("turnstile"), check)) {
00476       if (check == 1) {
00477       //we have the turnstile flag specified
00478       egg_group->set_collide_flags(EggGroup::CF_turnstile);
00479       }
00480     } 
00481     if (node_desc->get_max_node()->GetUserPropInt(_M("level"), check)) {
00482       if (check == 1) {
00483       //we have the level flag specified
00484       egg_group->set_collide_flags(EggGroup::CF_level);
00485       }
00486     } 
00487     if (node_desc->get_max_node()->GetUserPropInt(_M("intangible"), check)) {
00488       if (check == 1) {
00489       //we have the intangible flag specified
00490       egg_group->set_collide_flags(EggGroup::CF_intangible);
00491       }
00492     }
00493     return;
00494 }
 All Classes Functions Variables Enumerations