Panda3D

softNodeTree.cxx

00001 // Filename: softNodeTree.cxx
00002 // Created by:  masad (26Sep03)
00003 // 
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 ////////////////////////////////////////////////////////////////////
00016 // Includes
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "softNodeTree.h"
00020 #include "softEggGroupUserData.h"
00021 #include "config_softegg.h"
00022 #include "eggGroup.h"
00023 #include "eggTable.h"
00024 #include "eggXfmSAnim.h"
00025 #include "eggData.h"
00026 #include "softToEggConverter.h"
00027 #include "dcast.h"
00028 
00029 #include <SAA.h>
00030 
00031 ////////////////////////////////////////////////////////////////////
00032 //     Function: SoftNodeTree::Constructor
00033 //       Access: Public
00034 //  Description: 
00035 ////////////////////////////////////////////////////////////////////
00036 SoftNodeTree::
00037 SoftNodeTree() {
00038   _root = new SoftNodeDesc(NULL, "----root");
00039   _root->fullname = "----root";
00040   _fps = 0.0;
00041   _use_prefix = 0;
00042   _search_prefix = NULL;
00043   _egg_data = (EggData *)NULL;
00044   _egg_root = (EggGroupNode *)NULL;
00045   _skeleton_node = (EggGroupNode *)NULL;
00046 }
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: GetName
00049 //       Access: Public
00050 //  Description: Given an element, return a copy of the element's 
00051 //                 name WITHOUT prefix. 
00052 ////////////////////////////////////////////////////////////////////
00053 char *SoftNodeTree::
00054 GetName( SAA_Scene *scene, SAA_Elem *element ) {
00055   int nameLen;
00056   char *name;
00057   
00058   // get the name
00059   SAA_elementGetNameLength( scene, element, &nameLen ); 
00060   name = new char[++nameLen];
00061   SAA_elementGetName( scene, element, nameLen, name );
00062 
00063   return name;
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: GetFullName
00068 //       Access: Public
00069 //  Description: Given an element, return a copy of the element's 
00070 //                 name complete with prefix. 
00071 ////////////////////////////////////////////////////////////////////
00072 char *SoftNodeTree::
00073 GetFullName( SAA_Scene *scene, SAA_Elem *element )
00074 {
00075   int nameLen, prefixLen;
00076   char *name, *prefix;
00077 
00078   // get the name length
00079   SAA_elementGetNameLength( scene, element, &nameLen );
00080   // get the prefix length
00081   SAA_elementGetPrefixLength( scene, element, &prefixLen );
00082   // allocate the array to hold name
00083   name = new char[++nameLen];
00084   // allocate the array to hold prefix and length + hyphen
00085   prefix = new char[++prefixLen + nameLen + 4];
00086   // get the name
00087   SAA_elementGetName( scene, element, nameLen, name );
00088   // get the prefix
00089   SAA_elementGetPrefix( scene, element, prefixLen, prefix );
00090   // add 'em together
00091   strcat(prefix, "-");
00092   strcat(prefix, name);
00093 
00094   // return string
00095   return prefix;
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: GetModelNoteInfo
00100 //       Access: Public
00101 //  Description: Given an element, return a string containing the
00102 //               contents of its MODEL NOTE entry 
00103 ////////////////////////////////////////////////////////////////////
00104 char *SoftNodeTree::
00105 GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) {
00106   int size;
00107   char *modelNote = NULL;
00108   SAA_Boolean bigEndian;
00109 
00110   SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
00111 
00112   if ( size != 0 ) {
00113     // allocate modelNote string
00114     modelNote = new char[size + 1];
00115     
00116     // get ModelNote data from this model
00117     SAA_elementGetUserData( scene, model, "MNOT", size,
00118                             &bigEndian, (void *)modelNote );
00119     
00120     //strip off newline, if present
00121     char *eol = (char *)memchr( modelNote, '\n', size );
00122     if ( eol != NULL)
00123       *eol = '\0';
00124     else
00125       modelNote[size] = '\0';
00126 
00127     softegg_cat.spam() << "\nmodelNote = " << modelNote << endl;
00128   }
00129   
00130   return modelNote;
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //     Function: GetRootName
00135 //       Access: Public
00136 //  Description: Given a string, return a copy of the string up to
00137 //                 the first occurence of '-'. 
00138 ////////////////////////////////////////////////////////////////////
00139 char *SoftNodeTree::
00140 GetRootName( const char *name ) {
00141   const char *hyphen;
00142   char *root;
00143   int len;
00144   
00145   hyphen = strchr( name, '-' );
00146   len = hyphen-name;
00147   
00148   if ( (hyphen != NULL) && len ) {
00149     root = new char[len+1];
00150     strncpy( root, name, len );
00151     root[len] = '\0';
00152   }
00153   else {
00154     root = new char[strlen(name)+1];
00155     strcpy( root, name );
00156   }
00157   return( root );
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: SoftNodeTree::build_complete_hierarchy
00162 //       Access: Public
00163 //  Description: Walks through the complete Soft hierarchy and builds
00164 //               up the corresponding tree.
00165 ////////////////////////////////////////////////////////////////////
00166 bool SoftNodeTree::
00167 build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database) {
00168   SI_Error status;
00169   SoftNodeDesc *node;
00170 
00171   // Get the entire Soft scene.
00172   int numModels;
00173   SAA_Elem *models;
00174 
00175   SAA_sceneGetNbModels( &scene, &numModels ); 
00176   softegg_cat.spam() << "Scene has " << numModels << " model(s)...\n";
00177   
00178   // This while loop walks through the entire Soft hierarchy, one
00179   // node at a time. 
00180   bool all_ok = true;
00181   if ( numModels ) {
00182     // allocate array of models
00183     models = (SAA_Elem *) new SAA_Elem[numModels];
00184     if ( models != NULL ) {
00185       if ((status = SAA_sceneGetModels( &scene, numModels, models )) != SI_SUCCESS) {
00186         return false;
00187       }
00188       for ( int i = 0; i < numModels; i++ ) {
00189         int level;
00190         status = SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
00191         softegg_cat.spam() << "model[" << i << "]" << endl;
00192         softegg_cat.spam() << " level " << level << endl;
00193         softegg_cat.spam() << " status is " << status << "\n";
00194 
00195         node = build_node(&scene, &models[i]);
00196         if (!level && node)
00197           node->set_parent(_root);
00198       }
00199     }
00200   }
00201 
00202   softegg_cat.spam() << "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n";
00203 
00204   // check the nodes that are junk for animation/artist control purposes
00205   _root->check_junk(false);
00206 
00207   softegg_cat.spam() << "jpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjp\n";
00208 
00209   // check the nodes that are parent of ancestors of a joint
00210   _root->check_joint_parent();
00211 
00212   softegg_cat.spam() << "pppppppppppppppppppppppppppppppppppppppppppppppppppppppp\n";
00213 
00214   // check the nodes that are pseudo joints
00215   _root->check_pseudo_joints(false);
00216 
00217   softegg_cat.spam() << "========================================================\n";
00218 
00219   // find _parentJoint for each node
00220   _root->set_parentJoint(&scene, NULL);
00221 
00222   return all_ok;
00223 }
00224 #if 0
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: SoftNodeTree::build_selected_hierarchy
00227 //       Access: Public
00228 //  Description: Walks through the selected subset of the Soft
00229 //               hierarchy (or the complete hierarchy, if nothing is
00230 //               selected) and builds up the corresponding tree.
00231 ////////////////////////////////////////////////////////////////////
00232 bool SoftNodeTree::
00233 build_selected_hierarchy(char *scene_name) {
00234   MStatus status;
00235 
00236   MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
00237   if (!status) {
00238     status.perror("MItDag constructor");
00239     return false;
00240   }
00241 
00242   // Get only the selected geometry.
00243   MSelectionList selection;
00244   status = MGlobal::getActiveSelectionList(selection);
00245   if (!status) {
00246     status.perror("MGlobal::getActiveSelectionList");
00247     return false;
00248   }
00249   
00250   // Get the selected geometry only if the selection is nonempty;
00251   // otherwise, get the whole scene anyway.
00252   if (selection.isEmpty()) {
00253     softegg_cat.info()
00254       << "Selection list is empty.\n";
00255     return build_complete_hierarchy();
00256   }
00257 
00258   bool all_ok = true;
00259   unsigned int length = selection.length();
00260   for (unsigned int i = 0; i < length; i++) {
00261     MDagPath root_path;
00262     status = selection.getDagPath(i, root_path);
00263     if (!status) {
00264       status.perror("MSelectionList::getDagPath");
00265     } else {
00266       // Now traverse through the selected dag path and all nested
00267       // dag paths.
00268       dag_iterator.reset(root_path);
00269       while (!dag_iterator.isDone()) {
00270         MDagPath dag_path;
00271         status = dag_iterator.getPath(dag_path);
00272         if (!status) {
00273           status.perror("MItDag::getPath");
00274         } else {
00275           build_node(dag_path);
00276         }
00277         
00278         dag_iterator.next();
00279       }
00280     }
00281   }
00282 
00283   if (all_ok) {
00284     _root->check_pseudo_joints(false);
00285   }
00286 
00287   return all_ok;
00288 }
00289 #endif
00290 ////////////////////////////////////////////////////////////////////
00291 //     Function: SoftNodeTree::get_num_nodes
00292 //       Access: Public
00293 //  Description: Returns the total number of nodes in the hierarchy,
00294 //               not counting the root node.
00295 ////////////////////////////////////////////////////////////////////
00296 int SoftNodeTree::
00297 get_num_nodes() const {
00298   return _nodes.size();
00299 }
00300 
00301 ////////////////////////////////////////////////////////////////////
00302 //     Function: SoftNodeTree::get_node
00303 //       Access: Public
00304 //  Description: Returns the nth node in the hierarchy, in an
00305 //               arbitrary ordering.
00306 ////////////////////////////////////////////////////////////////////
00307 SoftNodeDesc *SoftNodeTree::
00308 get_node(int n) const {
00309   nassertr(n >= 0 && n < (int)_nodes.size(), NULL);
00310   return _nodes[n];
00311 }
00312 
00313 ////////////////////////////////////////////////////////////////////
00314 //     Function: SoftNodeTree::get_node
00315 //       Access: Public
00316 //  Description: Returns the node named 'name' in the hierarchy, in
00317 //               an arbitrary ordering.
00318 ////////////////////////////////////////////////////////////////////
00319 SoftNodeDesc *SoftNodeTree::
00320 get_node(string name) const {
00321   NodesByName::const_iterator ni = _nodes_by_name.find(name);
00322   if (ni != _nodes_by_name.end())
00323     return (*ni).second;
00324   return NULL;
00325 }
00326 
00327 ////////////////////////////////////////////////////////////////////
00328 //     Function: SoftNodeTree::clear_egg
00329 //       Access: Public
00330 //  Description: Removes all of the references to generated egg
00331 //               structures from the tree, and prepares the tree for
00332 //               generating new egg structures.
00333 ////////////////////////////////////////////////////////////////////
00334 void SoftNodeTree::
00335 clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
00336           EggGroupNode *skeleton_node) {
00337   _root->clear_egg();
00338   _egg_data = egg_data;
00339   _egg_root = egg_root;
00340   _skeleton_node = skeleton_node;
00341 }
00342 
00343 ////////////////////////////////////////////////////////////////////
00344 //     Function: SoftNodeTree::get_egg_group
00345 //       Access: Public
00346 //  Description: Returns the EggGroupNode corresponding to the group
00347 //               or joint for the indicated node.  Creates the group
00348 //               node if it has not already been created.
00349 ////////////////////////////////////////////////////////////////////
00350 EggGroup *SoftNodeTree::
00351 get_egg_group(SoftNodeDesc *node_desc) {
00352   nassertr(_egg_root != (EggGroupNode *)NULL, NULL);
00353 
00354   // lets print some relationship
00355   softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")";
00356   if (node_desc->_parent)
00357     softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")";
00358   else
00359     softegg_cat.spam() << " parent " << node_desc->_parent;
00360   softegg_cat.spam() << endl;
00361 
00362   if (node_desc->_egg_group == (EggGroup *)NULL) {
00363     // We need to make a new group node.
00364     EggGroup *egg_group;
00365     
00366     egg_group = new EggGroup(node_desc->get_name());
00367     if (node_desc->is_joint()) {
00368       egg_group->set_group_type(EggGroup::GT_joint);
00369     }
00370 
00371     if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) {
00372       // The parent is the root.
00373       softegg_cat.spam() << "came hereeeee\n";
00374       _egg_root->add_child(egg_group);
00375     } else {
00376       // The parent is another node.
00377       EggGroup *parent_egg_group = get_egg_group(node_desc->_parentJoint);
00378       parent_egg_group->add_child(egg_group);
00379     }
00380 
00381     node_desc->_egg_group = egg_group;
00382   }
00383   
00384   return node_desc->_egg_group;
00385 }
00386 
00387 ////////////////////////////////////////////////////////////////////
00388 //     Function: SoftNodeTree::get_egg_table
00389 //       Access: Public
00390 //  Description: Returns the EggTable corresponding to the joint
00391 //               for the indicated node.  Creates the table node if it
00392 //               has not already been created.
00393 ////////////////////////////////////////////////////////////////////
00394 EggTable *SoftNodeTree::
00395 get_egg_table(SoftNodeDesc *node_desc) {
00396   nassertr(_skeleton_node != (EggGroupNode *)NULL, NULL);
00397   nassertr(node_desc->is_joint(), NULL);
00398   
00399   // lets print some relationship
00400   softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")";
00401   if (node_desc->_parent)
00402     softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")";
00403   else
00404     softegg_cat.spam() << " parent " << node_desc->_parent;
00405   softegg_cat.spam() << endl;
00406 
00407   if (node_desc->_egg_table == (EggTable *)NULL) {
00408     softegg_cat.spam() << "creating a new table\n";
00409     // We need to make a new table node.
00410     //    nassertr(node_desc->_parent != (SoftNodeDesc *)NULL, NULL);
00411     
00412     EggTable *egg_table = new EggTable(node_desc->get_name());
00413     node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system());
00414     node_desc->_anim->set_fps(_fps);
00415     egg_table->add_child(node_desc->_anim);
00416     
00417     if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) {
00418       //    if (!node_desc->_parent->is_joint()) {
00419       // The parent is not a joint; put it at the top.
00420       _skeleton_node->add_child(egg_table);
00421     } else {
00422       // The parent is another joint.
00423       EggTable *parent_egg_table = get_egg_table(node_desc->_parentJoint);
00424       parent_egg_table->add_child(egg_table);
00425     }
00426 
00427     node_desc->_egg_table = egg_table;
00428   }
00429   
00430   return node_desc->_egg_table;
00431 }
00432 
00433 ////////////////////////////////////////////////////////////////////
00434 //     Function: SoftNodeTree::get_egg_anim
00435 //       Access: Public
00436 //  Description: Returns the anim table corresponding to the joint
00437 //               for the indicated node.  Creates the table node if it
00438 //               has not already been created.
00439 ////////////////////////////////////////////////////////////////////
00440 EggXfmSAnim *SoftNodeTree::
00441 get_egg_anim(SoftNodeDesc *node_desc) {
00442   get_egg_table(node_desc);
00443   return node_desc->_anim;
00444 }
00445 
00446 ////////////////////////////////////////////////////////////////////
00447 //     Function: SoftNodeTree::handle_null
00448 //       Access: Public
00449 //  Description: Sets joint information for MNILL node
00450 ////////////////////////////////////////////////////////////////////
00451 void SoftNodeTree::
00452 handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name) {
00453   const char *name = node_name;
00454   SAA_AlgorithmType    algo;
00455   SAA_Elem *model = node_desc->get_model();
00456   
00457   SAA_modelGetAlgorithm( scene, model, &algo );
00458   softegg_cat.spam() << " null algorithm: " << algo << endl;
00459   
00460   if ( algo == SAA_ALG_INV_KIN ) {
00461     //    MakeJoint( &scene, lastJoint, lastAnim,  model, name );
00462     node_desc->set_joint();
00463     softegg_cat.spam() << " encountered IK root: " << name << endl;
00464   }
00465   else if ( algo == SAA_ALG_INV_KIN_LEAF ) {
00466     //    MakeJoint( &scene, lastJoint, lastAnim, model, name );
00467     node_desc->set_joint();
00468     softegg_cat.spam() << " encountered IK leaf: " << name << endl;
00469   }
00470   else if ( algo == SAA_ALG_STANDARD ) {
00471     SAA_Boolean isSkeleton = FALSE;
00472     softegg_cat.spam() << " encountered Standard null: " << name << endl;
00473 
00474     SAA_modelIsSkeleton( scene, model, &isSkeleton );
00475 
00476     // check to see if this NULL is used as a skeleton
00477     // or is animated via constraint only ( these nodes are
00478     // tagged by the animator with the keyword "joint"
00479     // somewhere in the nodes name)
00480     if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) {
00481       //      MakeJoint( &scene, lastJoint, lastAnim, model, name );
00482       node_desc->set_joint();
00483       softegg_cat.spam() << " animating Standard null!!!\n";
00484       softegg_cat.spam() << "isSkeleton: " << isSkeleton << endl;
00485     }
00486   }
00487   else
00488     softegg_cat.spam() << " encountered some other NULL: " << algo << endl;
00489 }
00490 
00491 ////////////////////////////////////////////////////////////////////
00492 //     Function: SoftNodeTree::build_node
00493 //       Access: Public
00494 //  Description: Returns a pointer to the node corresponding to the
00495 //               indicated dag_path object, creating it first if
00496 //               necessary.
00497 ////////////////////////////////////////////////////////////////////
00498 SoftNodeDesc *SoftNodeTree::
00499 build_node(SAA_Scene *scene, SAA_Elem *model) {
00500   char *name, *fullname;
00501   string node_name;
00502   int numChildren;
00503   int thisChild;
00504   SAA_Elem *children;
00505   SAA_ModelType type;
00506   SAA_Boolean isSkeleton = FALSE;
00507 
00508   fullname = GetFullName(scene, model);
00509   if (_use_prefix)
00510     name = fullname;
00511   else
00512     name = GetName(scene, model);
00513 
00514   node_name = name;
00515 
00516   SoftNodeDesc *node_desc = r_build_node(NULL, node_name);
00517 
00518   node_desc->fullname = fullname;
00519   node_desc->set_model(model);
00520   SAA_modelIsSkeleton( scene, model, &isSkeleton );
00521 
00522   // find out what type of node we're dealing with
00523   SAA_modelGetType( scene, node_desc->get_model(), &type );
00524   
00525   if (type == SAA_MJNT || isSkeleton || (strstr(node_desc->get_name().c_str(), "joint") != NULL))
00526     node_desc->set_joint();
00527   
00528   // treat the MNILL differently, because it needs to detect and set some joints
00529   if (type == SAA_MNILL)
00530     handle_null(scene, node_desc, name);
00531 
00532   if (node_desc->is_joint())
00533     softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl;
00534 
00535   // get to the children
00536   SAA_modelGetNbChildren( scene, model, &numChildren );
00537   softegg_cat.spam() << " Model " << node_name << " children: " << numChildren << endl;
00538   
00539   if ( numChildren ) {
00540     children = new SAA_Elem[numChildren];
00541     SAA_modelGetChildren( scene, model, numChildren, children );
00542     if (!children)
00543       softegg_cat.info() << "Not enough Memory for children...\n";
00544     
00545     for ( thisChild = 0; thisChild < numChildren; thisChild++ ) {
00546       fullname = GetFullName(scene, &children[thisChild]);
00547       if (_use_prefix)
00548         node_name = fullname;
00549       else
00550         node_name = GetName(scene, &children[thisChild]);
00551       
00552       softegg_cat.spam() << " building child " << thisChild << "...";
00553       
00554       SoftNodeDesc *node_child = r_build_node(node_desc, node_name);
00555 
00556       node_child->fullname = fullname;
00557       node_child->set_model(&children[thisChild]);
00558       SAA_modelIsSkeleton( scene, &children[thisChild], &isSkeleton );
00559 
00560       // find out what type of node we're dealing with
00561       SAA_modelGetType( scene, node_child->get_model(), &type );
00562       
00563       if (type == SAA_MJNT || isSkeleton || (strstr(node_child->get_name().c_str(), "joint") != NULL))
00564         node_child->set_joint();
00565 
00566       // treat the MNILL differently, because it needs to detect and set some joints
00567       if (type == SAA_MNILL)
00568         handle_null(scene, node_child, node_name.c_str());
00569 
00570       if (node_child->is_joint())
00571         softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl;
00572     }
00573   }
00574   return node_desc;
00575 }
00576 
00577 ////////////////////////////////////////////////////////////////////
00578 //     Function: SoftNodeTree::r_build_node
00579 //       Access: Private
00580 //  Description: The recursive implementation of build_node().
00581 ////////////////////////////////////////////////////////////////////
00582 SoftNodeDesc *SoftNodeTree::
00583 r_build_node(SoftNodeDesc *parent_node, const string &name) {
00584   SoftNodeDesc *node_desc;
00585 
00586   // If we have already encountered this pathname, return the
00587   // corresponding SoftNodeDesc immediately.
00588   NodesByName::const_iterator ni = _nodes_by_name.find(name);
00589   if (ni != _nodes_by_name.end()) {
00590     softegg_cat.spam() << "  already built node " << (*ni).first;
00591     node_desc = (*ni).second;
00592     node_desc->set_parent(parent_node);
00593     return node_desc;
00594   }
00595 
00596   // Otherwise, we have to create it.  Do this recursively, so we
00597   // create each node along the path.
00598   node_desc = new SoftNodeDesc(parent_node, name);
00599 
00600   softegg_cat.spam() << " node name : " << name << endl;
00601   _nodes.push_back(node_desc);
00602 
00603   _nodes_by_name.insert(NodesByName::value_type(name, node_desc));
00604 
00605   return node_desc;
00606 }
00607 
00608 //
00609 //
00610 //
 All Classes Functions Variables Enumerations