bool CSkeletonCandidate::AddNode(CalCoreSkeleton *pCoreSkeleton, CalCoreBone *pCoreBone, int parentId) { // check if the core skeleton and core bone are valid if((pCoreSkeleton == 0) || (pCoreBone == 0)) { theExporter.SetLastError("Invalid handle!", __FILE__, __LINE__); return false; } // find the node with the name of the core bone CBaseNode *pNode = theExporter.GetInterface()->GetNode(pCoreBone->getName()); if(pNode == 0) { theExporter.SetLastError("Skeleton assignment failed!", __FILE__, __LINE__); return false; } // check if the node is a candidate //we want to export all types of nodes as bones /*if(!theExporter.GetInterface()->IsBone(pNode) && !theExporter.GetInterface()->IsDummy(pNode)) { delete pNode; theExporter.SetLastError("Invalid node types in skeleton!", __FILE__, __LINE__); return false; } */ // allocate a new bone candidate CBoneCandidate *pBoneCandidate = new CBoneCandidate; if(pBoneCandidate == 0) { delete pNode; theExporter.SetLastError("Memory allocation failed!", __FILE__, __LINE__); return false; } // create the bone candidate if(!pBoneCandidate->Create(m_vectorBoneCandidate.size(), parentId, pNode)) { delete pBoneCandidate; return false; } // insert node element into hierarchy m_vectorBoneCandidate.push_back(pBoneCandidate); // insert node element id into parent node element if(parentId == -1) { // no parent -> this is a root node m_listRootBoneCandidateId.push_back(pBoneCandidate->GetId()); } else { // valid parent -> this is a child node m_vectorBoneCandidate[parentId]->AddChildId(pBoneCandidate->GetId()); } // get core bone vector std::vector<CalCoreBone *>& vectorCoreBone = pCoreSkeleton->getVectorCoreBone(); // handle all children of the core bone std::list<int>::iterator iteratorChildId; for(iteratorChildId = pCoreBone->getListChildId().begin(); iteratorChildId != pCoreBone->getListChildId().end(); ++iteratorChildId) { if(!AddNode(pCoreSkeleton, vectorCoreBone[*iteratorChildId], pBoneCandidate->GetId())) return false; } return true; }
bool CSkeletonCandidate::AddNode(CBaseNode *pNode, int parentId) { // check if the node is valid if(pNode == 0) { theExporter.SetLastError("Invalid handle!", __FILE__, __LINE__); return false; } // Don't add any nodes that have already been added. for (size_t i = 0; i < m_vectorBoneCandidate.size(); ++i) { if (*m_vectorBoneCandidate[i]->GetNode() == *pNode) { delete pNode; return true; } } // if the node does not get used, we have to delete it! bool bDeleteNode = true; // Check if the node is a candidate //We want to be able to export all type of nodes as bones... //if(theExporter.GetInterface()->IsBone(pNode) || theExporter.GetInterface()->IsDummy(pNode)) { // allocate a new bone candidate CBoneCandidate *pBoneCandidate = new CBoneCandidate; if(pBoneCandidate == 0) { delete pNode; theExporter.SetLastError("Memory allocation failed!", __FILE__, __LINE__); return false; } // create the bone candidate if(!pBoneCandidate->Create(m_vectorBoneCandidate.size(), parentId, pNode)) { delete pBoneCandidate; return false; } //when the node is a dummy, it's not selected, so select it anyway... pBoneCandidate->SetSelected(true); // insert node element into hierarchy m_vectorBoneCandidate.push_back(pBoneCandidate); // insert node element id into parent node element if(parentId == -1) { // no parent -> this is a root node m_listRootBoneCandidateId.push_back(pBoneCandidate->GetId()); } else { // valid parent -> this is a child node m_vectorBoneCandidate[parentId]->AddChildId(pBoneCandidate->GetId()); } // set parent id for the children parentId = pBoneCandidate->GetId(); bDeleteNode = false; } // handle all children of the node for(int childId = 0; childId < pNode->GetChildCount(); childId++) { if(!AddNode(pNode->GetChild(childId), parentId)) { // free the node of needed if(bDeleteNode) { delete pNode; } return false; } } // free the node of needed if(bDeleteNode) { delete pNode; } return true; }
bool CExporter::ExportAnimation(const std::string& strFilename) { // check if a valid interface is set if(m_pInterface == 0) { SetLastError("Invalid handle.", __FILE__, __LINE__); return false; } // build a skeleton candidate CSkeletonCandidate skeletonCandidate; // show export wizard sheet CAnimationExportSheet sheet("Cal3D Animation Export", m_pInterface->GetMainWnd()); sheet.SetSkeletonCandidate(&skeletonCandidate); sheet.SetAnimationTime(m_pInterface->GetStartFrame(), m_pInterface->GetEndFrame(), m_pInterface->GetCurrentFrame(), m_pInterface->GetFps()); sheet.SetWizardMode(); if(sheet.DoModal() != ID_WIZFINISH) return true; // get the number of selected bone candidates int selectedCount; selectedCount = skeletonCandidate.GetSelectedCount(); if(selectedCount == 0) { SetLastError("No bones selected to export.", __FILE__, __LINE__); return false; } // create the core animation instance cal3d::RefPtr<CalCoreAnimation> coreAnimation = new CalCoreAnimation(); // set the duration of the animation float duration; duration = (float)(sheet.GetEndFrame() - sheet.GetStartFrame()) / (float)m_pInterface->GetFps(); coreAnimation->setDuration(duration); // get bone candidate vector std::vector<CBoneCandidate *>& vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate(); size_t boneCandidateId; for(boneCandidateId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++) { // get the bone candidate CBoneCandidate *pBoneCandidate; pBoneCandidate = vectorBoneCandidate[boneCandidateId]; // only create tracks for the selected bone candidates if(pBoneCandidate->IsSelected()) { // allocate new core track instance CalCoreTrack *pCoreTrack; pCoreTrack = new CalCoreTrack(); if(pCoreTrack == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); theExporter.GetInterface()->StopProgressInfo(); return false; } // create the core track instance if(!pCoreTrack->create()) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreTrack; theExporter.GetInterface()->StopProgressInfo(); return false; } // set the core bone id pCoreTrack->setCoreBoneId(boneCandidateId); // add the core track to the core animation instance if(!coreAnimation->addCoreTrack(pCoreTrack)) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreTrack; theExporter.GetInterface()->StopProgressInfo(); return false; } } } // start the progress info theExporter.GetInterface()->StartProgressInfo("Exporting to animation file..."); // calculate the end frame int endFrame; endFrame = (int)(duration * (float)sheet.GetFps() + 0.5f); // calculate the displaced frame int displacedFrame; displacedFrame = (int)(((float)sheet.GetDisplacement() / (float)m_pInterface->GetFps()) * (float)sheet.GetFps() + 0.5f) % endFrame; // calculate the possible wrap frame int wrapFrame; wrapFrame = (displacedFrame > 0) ? 1 : 0; float wrapTime; wrapTime = 0.0f; int frame; int outputFrame; for(frame = 0, outputFrame = 0; frame <= (endFrame + wrapFrame); frame++) { // update the progress info m_pInterface->SetProgressInfo(int(100.0f * (float)frame / (float)(endFrame + wrapFrame + 1))); // calculate the time in seconds float time; time = (float)sheet.GetStartFrame() / (float)m_pInterface->GetFps() + (float)displacedFrame / (float)sheet.GetFps(); /* DEBUG CString str; str.Format("frame=%d, endframe=%d, disframe=%d, ouputFrame=%d (%f), time=%f\n", frame, endFrame, displacedFrame, outputFrame, (float)outputFrame / (float)sheet.GetFps() + wrapTime, time); OutputDebugString(str); */ for(boneCandidateId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++) { // get the bone candidate CBoneCandidate *pBoneCandidate; pBoneCandidate = vectorBoneCandidate[boneCandidateId]; // only export keyframes for the selected bone candidates if(pBoneCandidate->IsSelected()) { // allocate new core keyframe instance CalCoreKeyframe *pCoreKeyframe; pCoreKeyframe = new CalCoreKeyframe(); if(pCoreKeyframe == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); theExporter.GetInterface()->StopProgressInfo(); return false; } // create the core keyframe instance if(!pCoreKeyframe->create()) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreKeyframe; theExporter.GetInterface()->StopProgressInfo(); return false; } // set the frame time pCoreKeyframe->setTime((float)outputFrame / (float)sheet.GetFps() + wrapTime); // get the translation and the rotation of the bone candidate CalVector translation; CalQuaternion rotation; skeletonCandidate.GetTranslationAndRotation(boneCandidateId, time, translation, rotation); // set the translation and rotation pCoreKeyframe->setTranslation(translation); pCoreKeyframe->setRotation(rotation); // get the core track for this bone candidate CalCoreTrack *pCoreTrack; pCoreTrack = coreAnimation->getCoreTrack(pBoneCandidate->GetId()); if(pCoreTrack == 0) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreKeyframe; theExporter.GetInterface()->StopProgressInfo(); return false; } // add this core keyframe to the core track pCoreTrack->addCoreKeyframe(pCoreKeyframe); } } // calculate the next displaced frame and its frame time if(wrapFrame > 0) { if(displacedFrame == endFrame) { wrapTime = 0.0001f; displacedFrame = 0; } else { wrapTime = 0.0f; outputFrame++; displacedFrame++; } } else { outputFrame++; displacedFrame++; } } // stop the progress info theExporter.GetInterface()->StopProgressInfo(); // save core animation to the file if(!CalSaver::saveCoreAnimation(strFilename, coreAnimation.get())) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); return false; } return true; }