unsigned int CalCoreAnimation::getTotalNumberOfKeyframes() const { unsigned int nbKeys = 0; for (std::list<CalCoreTrack*>::const_iterator it = m_listCoreTrack.begin(); it != m_listCoreTrack.end(); ++it) { CalCoreTrack *track = *it; nbKeys += track->getCoreKeyframeCount(); } return nbKeys; }
CalCoreAnimation::~CalCoreAnimation() { MyNumCalCoreAnimations--; std::list<CalCoreTrack *>::iterator iteratorCoreTrack; for (iteratorCoreTrack = m_listCoreTrack.begin(); iteratorCoreTrack != m_listCoreTrack.end(); ++iteratorCoreTrack) { CalCoreTrack* pTrack = *iteratorCoreTrack; pTrack->destroy(); delete pTrack; } }
void CalCoreAnimation::fillInvalidTranslations( CalCoreSkeleton * skel ) { std::list<CalCoreTrack *>::iterator iteratorCoreTrack; for(iteratorCoreTrack = m_listCoreTrack.begin(); iteratorCoreTrack != m_listCoreTrack.end(); ++iteratorCoreTrack) { CalCoreTrack * tr = * iteratorCoreTrack; int boneId = tr->getCoreBoneId(); assert( boneId != -1 ); CalCoreBone * bo = skel->getCoreBone( boneId ); if( bo ) { CalVector trans = bo->getTranslation(); tr->fillInvalidTranslations( trans ); } } }
CalCoreTrack *CalCoreAnimation::getCoreTrack(int coreBoneId) { // loop through all core track std::list<CalCoreTrack *>::iterator iteratorCoreTrack; for(iteratorCoreTrack = m_listCoreTrack.begin(); iteratorCoreTrack != m_listCoreTrack.end(); ++iteratorCoreTrack) { // get the core bone CalCoreTrack *pCoreTrack; pCoreTrack = *iteratorCoreTrack; // check if we found the matching core bone if(pCoreTrack->getCoreBoneId() == coreBoneId) return pCoreTrack; } // no match found return 0; }
void CalMixer::updateSkeleton() { // get the skeleton we need to update CalSkeleton *pSkeleton; pSkeleton = m_pModel->getSkeleton(); if(pSkeleton == 0) return; // clear the skeleton state pSkeleton->clearState(); // get the bone vector of the skeleton std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone(); // The bone adjustments are "replace" so they have to go first, giving them // highest priority and full influence. Subsequent animations affecting the same bones, // including subsequent replace animations, will have their incluence attenuated appropriately. applyBoneAdjustments(); // loop through all animation actions std::list<CalAnimationAction *>::iterator itaa; for( itaa = m_listAnimationAction.begin(); itaa != m_listAnimationAction.end(); itaa++ ) { // get the core animation instance CalAnimationAction * aa = * itaa; // Manual animations can be on or off. If they are off, they do not apply // to the bone. if( aa->on() ) { CalCoreAnimation * pCoreAnimation = aa->getCoreAnimation(); // get the list of core tracks of above core animation std::list<CalCoreTrack *>& listCoreTrack = pCoreAnimation->getListCoreTrack(); // loop through all core tracks of the core animation std::list<CalCoreTrack *>::iterator itct; for( itct = listCoreTrack.begin(); itct != listCoreTrack.end(); itct++ ) { // get the appropriate bone of the track CalCoreTrack * ct = * itct; if( ct->getCoreBoneId() >= int(vectorBone.size()) ) { continue; } CalBone * pBone = vectorBone[ ct->getCoreBoneId() ]; // get the current translation and rotation CalVector translation; CalQuaternion rotation; ct->getState( aa->getTime(), translation, rotation); // Replace and CrossFade both blend with the replace function. bool replace = aa->getCompositionFunction() != CalAnimation::CompositionFunctionAverage; float scale = aa->getScale(); pBone->blendState( aa->getWeight(), translation, rotation, scale, replace, aa->getRampValue() ); } } } // === What does lockState() mean? Why do we need it at all? It seems only to allow us // to blend all the animation actions together into a temporary sum, and then // blend all the animation cycles together into a different sum, and then blend // the two sums together according to their relative weight sums. I believe this is mathematically // equivalent of blending all the animation actions and cycles together into a single sum, // according to their relative weights. pSkeleton->lockState(); // let the skeleton calculate its final state pSkeleton->calculateState(); }
int CMaxAnimationImport::DoImport( const TCHAR* name, ImpInterface* ii, Interface* i, BOOL suppressPrompts) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HWND window = i->GetMAXHWnd(); CFileDialog fileDialog(TRUE, "xsf", 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 0, CWnd::FromHandle(window)); if (fileDialog.DoModal() != IDOK) { return IMPEXP_CANCEL; } CString skeleton = fileDialog.GetPathName(); cal3d::RefPtr<CalCoreSkeleton> skel = CalLoader::loadCoreSkeleton(std::string(skeleton)); if (!skel) { MessageBox( window, "Loading skeleton file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } cal3d::RefPtr<CalCoreAnimation> anim = CalLoader::loadCoreAnimation(name); if (!anim) { MessageBox( window, "Loading animation file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } typedef std::list<CalCoreTrack*> CoreTrackList; CoreTrackList& trackList = anim->getListCoreTrack(); for (CoreTrackList::iterator itr = trackList.begin(); itr != trackList.end(); ++itr) { CalCoreTrack* track = *itr; int boneId = track->getCoreBoneId(); CalCoreBone* bone = skel->getCoreBone(boneId); if (!bone) continue; INode* node = i->GetINodeByName(bone->getName().c_str()); if (!node) continue; unsigned kfCount = track->getCoreKeyframeCount(); SuspendAnimate(); AnimateOn(); for (unsigned i = 0; i < kfCount; ++i) { CalCoreKeyframe* kf = track->getCoreKeyframe(i); CalQuaternion kf_q = kf->getRotation(); CalVector kf_v = kf->getTranslation(); TimeValue time = SecToTicks(kf->getTime()); Matrix3 tm; tm.IdentityMatrix(); Quat(kf_q.x, kf_q.y, kf_q.z, kf_q.w).MakeMatrix(tm); tm.SetTrans(Point3(kf_v.x, kf_v.y, kf_v.z)); INode* parent = node->GetParentNode(); if (parent) { tm *= parent->GetNodeTM(time); } node->SetNodeTM(time, tm); } ResumeAnimate(); /* typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); int mapsize = sizeof(keys); int size = keys.size(); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { Point3 p; CalCoreKeyframe* kf = mi->second; p.x = kf->getTranslation().x; p.y = kf->getTranslation().y; p.z = kf->getTranslation().z; pos->SetValue(SecToTicks(mi->first), &p); } */ /* IKeyControl* kc = GetKeyControlInterface(pos); if (!kc) continue; typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); kc->SetNumKeys(keys.size()); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { ITCBPoint3Key key; key.time = SecToTicks(mi->first); key.tens = 0; key.cont = 0; key.bias = 0; key.easeIn = 25.0; key.easeOut = 25.0; key.val.x = mi->second->getTranslation().x; key.val.y = mi->second->getTranslation().y; key.val.z = mi->second->getTranslation().z; kc->SetKey(idx++, &key); } kc->SortKeys(); */ } return IMPEXP_SUCCESS; }
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; }