1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADASaxFrameworkLoader. 5 6 Licensed under the MIT Open Source License, 7 for details please see LICENSE file or the website 8 http://www.opensource.org/licenses/mit-license.php 9 */ 10 11 #include "COLLADASaxFWLStableHeaders.h" 12 #include "COLLADASaxFWLDocumentProcessor.h" 13 14 #include "COLLADAFWNode.h" 15 #include "COLLADAFWIWriter.h" 16 17 18 namespace COLLADASaxFWL 19 { 20 21 //----------------------------- DocumentProcessor(Loader * colladaLoader,SaxParserErrorHandler * saxParserErrorHandler,int objectFlags,int & parsedObjectFlags)22 DocumentProcessor::DocumentProcessor ( Loader* colladaLoader, 23 SaxParserErrorHandler* saxParserErrorHandler, 24 int objectFlags, 25 int& parsedObjectFlags) 26 : mColladaLoader( colladaLoader ) 27 , mCurrentSidTreeNode( colladaLoader->getSidTreeRoot() ) 28 , mIdStringSidTreeNodeMap( colladaLoader->getIdStringSidTreeNodeMap() ) 29 , mVisualScenes( colladaLoader->getVisualScenes() ) 30 , mLibraryNodes( colladaLoader->getLibraryNodes() ) 31 , mEffects( colladaLoader->getEffects() ) 32 , mLights( colladaLoader->getLights() ) 33 , mCameras( colladaLoader->getCameras() ) 34 , mKinematicsIntermediateData( colladaLoader->getKinematicsIntermediateData() ) 35 , mFormulasMap( colladaLoader->getFormulasMap() ) 36 , mAnimationSidAddressBindings( colladaLoader->getAnimationSidAddressBindings() ) 37 , mUniqueIdAnimationListMap( colladaLoader->getUniqueIdAnimationListMap() ) 38 , mObjectFlags( objectFlags ) 39 , mParsedObjectFlags( parsedObjectFlags ) 40 , mSkinDataJointSidsMap( colladaLoader->getSkinDataJointSidsMap() ) 41 , mInstanceControllerDataListMap( colladaLoader->getInstanceControllerDataListMap() ) 42 , mSkinDataSkinSourceMap( colladaLoader->getSkinDataSkinSourceMap() ) 43 , mSkinControllerSet( colladaLoader->getSkinControllerSet() ) 44 , mSaxParserErrorHandler( saxParserErrorHandler ) 45 { 46 47 } 48 //------------------------------ ~DocumentProcessor()49 DocumentProcessor::~DocumentProcessor() 50 { 51 } 52 53 //--------------------------------- addToSidTree(const char * colladaId,const char * colladaSid)54 SidTreeNode* DocumentProcessor::addToSidTree( const char* colladaId, const char* colladaSid ) 55 { 56 mCurrentSidTreeNode = mCurrentSidTreeNode->createAndAddChild( colladaSid ? colladaSid : ""); 57 58 if ( colladaId && *colladaId ) 59 { 60 mIdStringSidTreeNodeMap[colladaId] = mCurrentSidTreeNode; 61 } 62 return mCurrentSidTreeNode; 63 } 64 65 //--------------------------------- moveUpInSidTree()66 void DocumentProcessor::moveUpInSidTree() 67 { 68 COLLADABU_ASSERT(mCurrentSidTreeNode); 69 mCurrentSidTreeNode = mCurrentSidTreeNode->getParent(); 70 } 71 72 //--------------------------------- resolveId(const String & id)73 const SidTreeNode* DocumentProcessor::resolveId( const String& id ) 74 { 75 return findSidTreeNodeByStringId( id ); 76 } 77 78 //--------------------------------- resolveSid(const SidAddress & sidAddress)79 const SidTreeNode* DocumentProcessor::resolveSid( const SidAddress& sidAddress ) 80 { 81 if ( !sidAddress.isValid() ) 82 return 0; 83 84 SidTreeNode* startingPoint = 0; 85 const String& id = sidAddress.getId(); 86 if ( !id.empty() ) 87 { 88 // search for element with id 89 startingPoint = findSidTreeNodeByStringId( id ); 90 } 91 92 if ( !startingPoint ) 93 return 0; 94 95 SidTreeNode* currentNode = startingPoint; 96 const SidAddress::SidList& sids = sidAddress.getSids(); 97 98 size_t i = 0; 99 100 if ( !sids.empty() && (sids.front() == startingPoint->getSid()) ) 101 { 102 // the first one is the start element it self exclude it from recursive search 103 i = 1; 104 } 105 106 for ( size_t count = sids.size(); i < count; ++i) 107 { 108 const String& currentSid = sids[i]; 109 SidTreeNode* childNode = currentNode->findChildBySid( currentSid ); 110 111 if ( !childNode ) 112 { 113 // we could not find the sid as a child of currentNode 114 // lets try if the sid is in an instantiated element 115 return resolveSidInInstance( currentNode, sidAddress, i); 116 } 117 else 118 { 119 currentNode = childNode; 120 } 121 } 122 return currentNode; 123 } 124 125 //--------------------------------- resolveSid(const COLLADABU::URI & id,const String & sid)126 const SidTreeNode* DocumentProcessor::resolveSid( const COLLADABU::URI& id, const String& sid) 127 { 128 SidAddress sidAddress(id, sid); 129 return resolveSid(sidAddress); 130 } 131 132 //--------------------------------- resolveSidInInstance(const SidTreeNode * instancingElement,const SidAddress & sidAddress,size_t firstSidIndex)133 const SidTreeNode* DocumentProcessor::resolveSidInInstance( const SidTreeNode* instancingElement, const SidAddress& sidAddress, size_t firstSidIndex) 134 { 135 // the sid address we use to resolve the sid in the instantiated element 136 const COLLADABU::URI* uri = 0; 137 138 //check if instancingElement instantiates an element 139 switch ( instancingElement->getTargetType() ) 140 { 141 case SidTreeNode::TARGETTYPECLASS_INTERMEDIATETARGETABLE: 142 { 143 IntermediateTargetable* iTargetable = instancingElement->getIntermediateTargetableTarget(); 144 switch ( iTargetable->getClassId() ) 145 { 146 case INTERMEDIATETARGETABLE_TYPE::KINEMATICS_INSTANCE: 147 { 148 KinematicInstance* ki = intermediateTargetableSafeCast<KinematicInstance>(iTargetable); 149 uri = &ki->getUrl(); 150 break; 151 } 152 } 153 154 } 155 // case SidTreeNode::TARGETTYPECLASS_OBJECT: 156 // { 157 // COLLADAFW::Object* iObject = instancingElement->getObjectTarget(); 158 // switch ( iObject->getClassId() ) 159 // { 160 // case COLLADAFW::COLLADA_TYPE::JOINT: 161 // { 162 // KinematicInstance* ki = (KinematicInstance*) iObject; 163 // uri = &ki->getUrl(); 164 // } 165 // } 166 // } 167 default: 168 break; 169 } 170 171 if ( !uri ) 172 { 173 // we could not find an instantiated element 174 return 0; 175 } 176 177 SidAddress newSidAddress( *uri ); 178 const SidAddress::SidList& allSids = sidAddress.getSids(); 179 size_t allSidsCount = allSids.size(); 180 for ( size_t i = firstSidIndex; i < allSidsCount; ++i) 181 { 182 newSidAddress.appendSid( allSids[i] ); 183 } 184 newSidAddress.setFirstIndex( sidAddress.getFirstIndex() ); 185 newSidAddress.setSecondIndex( sidAddress.getSecondIndex() ); 186 newSidAddress.setMemberSelection( sidAddress.getMemberSelection() ); 187 newSidAddress.setMemberSelectionName( sidAddress.getMemberSelectionName() ); 188 return resolveSid( newSidAddress ); 189 } 190 191 192 //----------------------------- findSidTreeNodeByStringId(const String & id)193 SidTreeNode* DocumentProcessor::findSidTreeNodeByStringId( const String& id ) 194 { 195 Loader::IdStringSidTreeNodeMap::iterator it = mIdStringSidTreeNodeMap.find(id); 196 if ( it == mIdStringSidTreeNodeMap.end() ) 197 { 198 return 0; 199 } 200 else 201 { 202 return it->second; 203 } 204 } 205 206 //----------------------------- addToAnimationSidAddressBindings(const AnimationInfo & animationInfo,const SidAddress & targetSidAddress)207 void DocumentProcessor::addToAnimationSidAddressBindings( const AnimationInfo& animationInfo, const SidAddress& targetSidAddress ) 208 { 209 Loader::AnimationSidAddressBinding binding( animationInfo, targetSidAddress); 210 mAnimationSidAddressBindings.push_back(binding); 211 } 212 getAnimationListByUniqueId(const COLLADAFW::UniqueId & animationListUniqueId)213 COLLADAFW::AnimationList*& DocumentProcessor::getAnimationListByUniqueId( const COLLADAFW::UniqueId& animationListUniqueId ) 214 { 215 return mUniqueIdAnimationListMap[animationListUniqueId]; 216 } 217 218 //----------------------------- addSkinDataJointSidsPair(const COLLADAFW::UniqueId & skinDataUniqueId,const StringList & sidsOrIds,bool areIds)219 void DocumentProcessor::addSkinDataJointSidsPair( const COLLADAFW::UniqueId& skinDataUniqueId, const StringList& sidsOrIds, bool areIds ) 220 { 221 Loader::JointSidsOrIds jointSidsOrIds; 222 jointSidsOrIds.sidsOrIds = sidsOrIds; 223 jointSidsOrIds.areIds = areIds; 224 mSkinDataJointSidsMap[skinDataUniqueId]=jointSidsOrIds; 225 } 226 227 //----------------------------- getJointSidsOrIdsBySkinDataUniqueId(const COLLADAFW::UniqueId & skinDataUniqueId) const228 const Loader::JointSidsOrIds& DocumentProcessor::getJointSidsOrIdsBySkinDataUniqueId( const COLLADAFW::UniqueId& skinDataUniqueId ) const 229 { 230 Loader::SkinDataJointSidsMap::const_iterator it = mSkinDataJointSidsMap.find(skinDataUniqueId); 231 if ( it != mSkinDataJointSidsMap.end() ) 232 { 233 return it->second; 234 } 235 else 236 { 237 return Loader::EMPTY_JOINTSIDSORIDS; 238 } 239 } 240 241 //----------------------------- addSkinDataSkinSourcePair(const COLLADAFW::UniqueId & skinDataUniqueId,const COLLADABU::URI & skinSource)242 void DocumentProcessor::addSkinDataSkinSourcePair( const COLLADAFW::UniqueId& skinDataUniqueId, const COLLADABU::URI& skinSource ) 243 { 244 mSkinDataSkinSourceMap[skinDataUniqueId]=skinSource; 245 } 246 247 //----------------------------- getSkinSourceBySkinDataUniqueId(const COLLADAFW::UniqueId & skinDataUniqueId) const248 const COLLADABU::URI* DocumentProcessor::getSkinSourceBySkinDataUniqueId( const COLLADAFW::UniqueId& skinDataUniqueId ) const 249 { 250 Loader::SkinDataSkinSourceMap::const_iterator it = mSkinDataSkinSourceMap.find(skinDataUniqueId); 251 if ( it != mSkinDataSkinSourceMap.end() ) 252 { 253 return &it->second; 254 } 255 else 256 { 257 return 0; 258 } 259 } 260 261 //----------------------------- getInstanceControllerDataListByControllerUniqueId(const COLLADAFW::UniqueId & controllerUniqueId) const262 const Loader::InstanceControllerDataList& DocumentProcessor::getInstanceControllerDataListByControllerUniqueId( const COLLADAFW::UniqueId& controllerUniqueId ) const 263 { 264 Loader::InstanceControllerDataListMap::const_iterator it = mInstanceControllerDataListMap.find(controllerUniqueId); 265 if ( it != mInstanceControllerDataListMap.end()) 266 { 267 return it->second; 268 } 269 else 270 { 271 return Loader::EMPTY_INSTANCE_CONTROLLER_DATALIST; 272 } 273 274 } 275 276 //----------------------------- getInstanceControllerDataListByControllerUniqueId(const COLLADAFW::UniqueId & controllerUniqueId)277 Loader::InstanceControllerDataList& DocumentProcessor::getInstanceControllerDataListByControllerUniqueId( const COLLADAFW::UniqueId& controllerUniqueId ) 278 { 279 return mInstanceControllerDataListMap[controllerUniqueId]; 280 } 281 282 283 284 //----------------------------- setCOLLADAVersion(COLLADAVersion cOLLADAVersion)285 void DocumentProcessor::setCOLLADAVersion( COLLADAVersion cOLLADAVersion ) 286 { 287 mCOLLADAVersion = cOLLADAVersion; 288 mColladaLoader->setCOLLADAVersion(cOLLADAVersion); 289 } 290 291 //----------------------------- createAndWriteSkinController(const Loader::InstanceControllerData & instanceControllerData,const COLLADAFW::UniqueId & controllerDataUniqueId,const COLLADAFW::UniqueId & sourceUniqueId)292 bool DocumentProcessor::createAndWriteSkinController( const Loader::InstanceControllerData& instanceControllerData, 293 const COLLADAFW::UniqueId& controllerDataUniqueId, 294 const COLLADAFW::UniqueId& sourceUniqueId) 295 { 296 if ( !controllerDataUniqueId.isValid() ) 297 return false; 298 const Loader::JointSidsOrIds& sidsOrIds = getJointSidsOrIdsBySkinDataUniqueId( controllerDataUniqueId ); 299 return createAndWriteSkinController( instanceControllerData, controllerDataUniqueId, sourceUniqueId, sidsOrIds.sidsOrIds, sidsOrIds.areIds ); 300 } 301 302 //----------------------------- createAndWriteSkinController(const Loader::InstanceControllerData & instanceControllerData,const COLLADAFW::UniqueId & controllerDataUniqueId,const COLLADAFW::UniqueId & sourceUniqueId,const StringList & sidsOrIds,bool resolveIds)303 bool DocumentProcessor::createAndWriteSkinController( const Loader::InstanceControllerData& instanceControllerData, 304 const COLLADAFW::UniqueId& controllerDataUniqueId, 305 const COLLADAFW::UniqueId& sourceUniqueId, 306 const StringList& sidsOrIds, 307 bool resolveIds) 308 { 309 if ( !controllerDataUniqueId.isValid() ) 310 return false; 311 312 const URIList& skeletonRoots = instanceControllerData.skeletonRoots; 313 314 NodeList joints; 315 316 for ( StringList::const_iterator it = sidsOrIds.begin(); it != sidsOrIds.end(); ++it) 317 { 318 const String sidOrId = *it; 319 320 bool jointFound = false; 321 if ( resolveIds ) 322 { 323 // Joints are referenced by Id 324 const SidTreeNode* joint = resolveId( sidOrId ); 325 if ( joint ) 326 { 327 jointFound = addValidatedJoint(*joint, joints); 328 } 329 } 330 else if ( skeletonRoots.size() == 0 ) 331 { 332 // Joints are referenced by Sid and no <skeleton> entries are defined 333 const SidTreeNode* joint = resolveSid( sidOrId ); 334 if ( joint ) 335 { 336 jointFound = addValidatedJoint(*joint, joints); 337 } 338 } 339 else 340 { 341 // we get the list from the <skeleton> entries 342 for ( URIList::const_iterator skeletonIt = skeletonRoots.begin(); skeletonIt != skeletonRoots.end(); ++skeletonIt) 343 { 344 const COLLADABU::URI& skeletonUri = *skeletonIt; 345 346 SidAddress sidAddress( skeletonUri, sidOrId ); 347 const SidTreeNode* joint = resolveSid( sidAddress ); 348 if ( joint ) 349 { 350 jointFound = addValidatedJoint(*joint, joints); 351 if( jointFound ) 352 { 353 //search for the next joint 354 break; 355 } 356 } 357 } 358 } 359 360 361 if ( !jointFound ) 362 { 363 std::stringstream msg; 364 msg << "Could not resolve " << (resolveIds ? "id" : "sid") << " \""; 365 msg << sidOrId << "\" referenced in skin controller."; 366 if ( handleFWLError( SaxFWLError::ERROR_UNRESOLVED_REFERENCE, msg.str() )) 367 { 368 return false; 369 } 370 } 371 } 372 373 COLLADAFW::SkinController skinController( createUniqueId(COLLADAFW::SkinController::ID())); 374 375 COLLADAFW::UniqueIdArray &jointsUniqueIds = skinController.getJoints(); 376 jointsUniqueIds.allocMemory( joints.size() ); 377 jointsUniqueIds.setCount(joints.size()); 378 379 size_t i = 0; 380 NodeList::const_iterator it = joints.begin(); 381 for ( ; it != joints.end(); ++it, ++i ) 382 { 383 const COLLADAFW::Node* node = *it; 384 jointsUniqueIds[i] = node->getUniqueId(); 385 } 386 387 skinController.setSkinControllerData(controllerDataUniqueId); 388 skinController.setSource(sourceUniqueId); 389 390 bool success = true; 391 // Check if we have already wrote a skin controller that describes the same controller, i.e. has same 392 // source, skin data and joints. If so, do not write it again and reference the previously used in the 393 // scene graph 394 const COLLADAFW::SkinController* skinControllerToWrite = 0; 395 Loader::SkinControllerSet::const_iterator skinControllerIt = mSkinControllerSet.find( skinController ); 396 if ( skinControllerIt == mSkinControllerSet.end() ) 397 { 398 skinControllerToWrite = &skinController; 399 success = writer()->writeController(skinControllerToWrite); 400 mSkinControllerSet.insert( skinController ); 401 } 402 else 403 { 404 skinControllerToWrite = &(*skinControllerIt); 405 } 406 407 instanceControllerData.instanceController->setInstanciatedObjectId( skinControllerToWrite->getUniqueId() ); 408 409 return success; 410 } 411 412 413 //----------------------------- createAndWriteSkinControllers()414 bool DocumentProcessor::createAndWriteSkinControllers() 415 { 416 Loader::InstanceControllerDataListMap::const_iterator mapIt = mInstanceControllerDataListMap.begin(); 417 418 for ( ; mapIt != mInstanceControllerDataListMap.end(); ++mapIt ) 419 { 420 const COLLADAFW::UniqueId& skinDataUniqueId = mapIt->first; 421 const Loader::InstanceControllerDataList& instanceControllerDataList = mapIt->second; 422 423 Loader::InstanceControllerDataList::const_iterator listIt = instanceControllerDataList.begin(); 424 425 for ( ; listIt != instanceControllerDataList.end(); ++listIt) 426 { 427 const Loader::InstanceControllerData& instanceControllerData = *listIt; 428 const COLLADABU::URI* sourceUrl = getSkinSourceBySkinDataUniqueId( skinDataUniqueId ); 429 430 if ( !sourceUrl ) 431 { 432 // TODO handle error 433 continue; 434 } 435 436 const COLLADAFW::UniqueId& sourceUniqueId = getUniqueIdByUrl(*sourceUrl, true); 437 if ( !sourceUniqueId.isValid() ) 438 { 439 // TODO handle error 440 continue; 441 } 442 if ( !createAndWriteSkinController( instanceControllerData, skinDataUniqueId, sourceUniqueId ) ) 443 return false; 444 } 445 } 446 return true; 447 } 448 449 //------------------------------ addValidatedJoint(const SidTreeNode & joint,NodeList & joints)450 bool DocumentProcessor::addValidatedJoint(const SidTreeNode &joint, NodeList &joints) 451 { 452 bool jointValid = false; 453 454 // the joint could be found 455 if ( joint.getTargetType() == SidTreeNode::TARGETTYPECLASS_OBJECT ) 456 { 457 const COLLADAFW::Object* object = joint.getObjectTarget(); 458 459 if ( object->getClassId() == COLLADAFW::Node::ID() ) 460 { 461 joints.push_back( (COLLADAFW::Node*)object ); 462 463 jointValid = true; 464 //search for the next joint 465 } 466 else 467 { 468 // we could resolve the sid, but is not a joint/node 469 } 470 } 471 else 472 { 473 // we could resolve the sid, but is not a joint/node 474 } 475 return jointValid; 476 } 477 478 //------------------------------ addKinematicsScene(KinematicsScene * kinematicsScene)479 void DocumentProcessor::addKinematicsScene( KinematicsScene* kinematicsScene ) 480 { 481 const COLLADABU::URI& uri = kinematicsScene->getUri(); 482 mKinematicsIntermediateData.getKinematicsScenes().insert(std::make_pair(uri, kinematicsScene)); 483 } 484 485 //------------------------------ getKinematicsSceneByUri(const COLLADABU::URI & uri)486 KinematicsScene* DocumentProcessor::getKinematicsSceneByUri( const COLLADABU::URI& uri ) 487 { 488 const KinematicsIntermediateData::KinematicsSceneMap& map = mKinematicsIntermediateData.getKinematicsScenes(); 489 KinematicsIntermediateData::KinematicsSceneMap::const_iterator it = map.find(uri); 490 if ( it != map.end() ) 491 { 492 return it->second; 493 } 494 else 495 { 496 return 0; 497 } 498 } 499 500 //------------------------------ addKinematicsController(KinematicsController * kinematicsController)501 void DocumentProcessor::addKinematicsController( KinematicsController* kinematicsController ) 502 { 503 const COLLADABU::URI& uri = kinematicsController->getUri(); 504 mKinematicsIntermediateData.getKinematicsControllers().insert(std::make_pair(uri, kinematicsController)); 505 } 506 507 //------------------------------ getKinematicsControllerByUri(const COLLADABU::URI & uri)508 KinematicsController* DocumentProcessor::getKinematicsControllerByUri( const COLLADABU::URI& uri ) 509 { 510 const KinematicsIntermediateData::KinematicsControllerMap& map = mKinematicsIntermediateData.getKinematicsControllers(); 511 KinematicsIntermediateData::KinematicsControllerMap::const_iterator it = map.find(uri); 512 if ( it != map.end() ) 513 { 514 return it->second; 515 } 516 else 517 { 518 return 0; 519 } 520 } 521 522 //------------------------------ addKinematicsModel(KinematicsModel * kinematicsModel)523 void DocumentProcessor::addKinematicsModel( KinematicsModel* kinematicsModel ) 524 { 525 const COLLADABU::URI& uri = kinematicsModel->getUrl(); 526 mKinematicsIntermediateData.getKinematicsModels().insert(std::make_pair(uri, kinematicsModel)); 527 } 528 529 //------------------------------ getKinematicsModelByUri(const COLLADABU::URI & uri)530 KinematicsModel* DocumentProcessor::getKinematicsModelByUri( const COLLADABU::URI& uri ) 531 { 532 const KinematicsIntermediateData::KinematicsModelMap& map = mKinematicsIntermediateData.getKinematicsModels(); 533 KinematicsIntermediateData::KinematicsModelMap::const_iterator it = map.find(uri); 534 if ( it != map.end() ) 535 { 536 return it->second; 537 } 538 else 539 { 540 return 0; 541 } 542 } 543 544 //------------------------------ addFormula(COLLADAFW::Formula * formula)545 void DocumentProcessor::addFormula( COLLADAFW::Formula* formula ) 546 { 547 mFormulasMap.insert(std::make_pair(formula->getUniqueId(), formula)); 548 } 549 550 //------------------------------ getFormulaByUniqueId(const COLLADAFW::UniqueId & uniqueId) const551 COLLADAFW::Formula* DocumentProcessor::getFormulaByUniqueId( const COLLADAFW::UniqueId& uniqueId ) const 552 { 553 COLLADAFW::Formula* formula = 0; 554 Loader::UniqueIdFormulaMap::const_iterator it = mFormulasMap.find(uniqueId); 555 if ( it != mFormulasMap.end() ) 556 { 557 formula = it->second; 558 } 559 return formula; 560 } 561 562 563 } // namespace COLLADASaxFWL 564