Panda3D
|
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 //