void CalCoreTrack::translationCompressibility( bool * transRequiredResult, bool * transDynamicResult, bool * highRangeRequiredResult, float threshold, float highRangeThreshold, CalCoreSkeleton * skel ) { * transRequiredResult = false; * transDynamicResult = false; * highRangeRequiredResult = false; unsigned int numFrames = m_keyframes.size(); CalCoreBone * cb = skel->getCoreBone( m_coreBoneId ); const CalVector & cbtrans = cb->getTranslation(); CalVector trans0; float t2 = threshold * threshold; unsigned int i; for( i = 0; i < numFrames; i++ ) { CalCoreKeyframe * keyframe = m_keyframes[ i ]; const CalVector & kftrans = keyframe->getTranslation(); if( fabsf( kftrans.x ) >= highRangeThreshold || fabsf( kftrans.y ) >= highRangeThreshold || fabsf( kftrans.z ) >= highRangeThreshold ) { * highRangeRequiredResult = true; } if( i == 0 ) { trans0 = keyframe->getTranslation(); } else { float d2 = DistanceSquared( trans0, kftrans ); if( d2 > t2 ) { * transDynamicResult = true; } } float d2 = DistanceSquared( cbtrans, kftrans ); if( d2 > t2 ) { * transRequiredResult = true; } } }
void CalCoreTrack::fillInvalidTranslations( CalVector const & trans ) { unsigned int numFrames = m_keyframes.size(); for( unsigned int i = 0; i < numFrames; i++ ) { CalCoreKeyframe * keyframe = m_keyframes[ i ]; const CalVector & kftrans = keyframe->getTranslation(); if( TranslationInvalid( kftrans ) ) { keyframe->setTranslation( trans ); } } }
void CalCoreTrack::destroy() { // destroy all core keyframes rde::sorted_vector<float, CalCoreKeyframe *>::iterator iteratorCoreKeyframe; for(iteratorCoreKeyframe = m_mapCoreKeyframe.begin(); iteratorCoreKeyframe != m_mapCoreKeyframe.end(); ++iteratorCoreKeyframe) { CalCoreKeyframe *pCoreKeyframe; pCoreKeyframe = iteratorCoreKeyframe->second; pCoreKeyframe->destroy(); delete pCoreKeyframe; } m_mapCoreKeyframe.clear(); m_coreBoneId = -1; }
bool CalCoreTrack::getState(float time, CalVector& translation, CalQuaternion& rotation) const { std::vector<CalCoreKeyframe*>::const_iterator iteratorCoreKeyframeBefore; std::vector<CalCoreKeyframe*>::const_iterator iteratorCoreKeyframeAfter; // get the keyframe after the requested time iteratorCoreKeyframeAfter = getUpperBound(time); // check if the time is after the last keyframe if(iteratorCoreKeyframeAfter == m_keyframes.end()) { // return the last keyframe state --iteratorCoreKeyframeAfter; rotation = (*iteratorCoreKeyframeAfter)->getRotation(); translation = (*iteratorCoreKeyframeAfter)->getTranslation(); return true; } // check if the time is before the first keyframe if(iteratorCoreKeyframeAfter == m_keyframes.begin()) { // return the first keyframe state rotation = (*iteratorCoreKeyframeAfter)->getRotation(); translation = (*iteratorCoreKeyframeAfter)->getTranslation(); return true; } // get the keyframe before the requested one iteratorCoreKeyframeBefore = iteratorCoreKeyframeAfter; --iteratorCoreKeyframeBefore; // get the two keyframe pointers CalCoreKeyframe *pCoreKeyframeBefore; pCoreKeyframeBefore = *iteratorCoreKeyframeBefore; CalCoreKeyframe *pCoreKeyframeAfter; pCoreKeyframeAfter = *iteratorCoreKeyframeAfter; // calculate the blending factor between the two keyframe states float blendFactor; blendFactor = (time - pCoreKeyframeBefore->getTime()) / (pCoreKeyframeAfter->getTime() - pCoreKeyframeBefore->getTime()); // blend between the two keyframes translation = pCoreKeyframeBefore->getTranslation(); translation.blend(blendFactor, pCoreKeyframeAfter->getTranslation()); rotation = pCoreKeyframeBefore->getRotation(); rotation.blend(blendFactor, pCoreKeyframeAfter->getRotation()); return true; }
bool CalCoreTrack::getState(float time, CalVector& translation, CalQuaternion& rotation) { rde::sorted_vector<float, CalCoreKeyframe *>::iterator iteratorCoreKeyframeBefore; rde::sorted_vector<float, CalCoreKeyframe *>::iterator iteratorCoreKeyframeAfter; // get the keyframe after the requested time iteratorCoreKeyframeAfter = m_mapCoreKeyframe.upper_bound(time); // check if the time is after the last keyframe if(iteratorCoreKeyframeAfter == m_mapCoreKeyframe.end()) { // return the last keyframe state --iteratorCoreKeyframeAfter; rotation = (iteratorCoreKeyframeAfter->second)->getRotation(); translation = (iteratorCoreKeyframeAfter->second)->getTranslation(); return true; } // check if the time is before the first keyframe if(iteratorCoreKeyframeAfter == m_mapCoreKeyframe.begin()) { // return the first keyframe state rotation = (iteratorCoreKeyframeAfter->second)->getRotation(); translation = (iteratorCoreKeyframeAfter->second)->getTranslation(); return true; } // get the keyframe before the requested one iteratorCoreKeyframeBefore = iteratorCoreKeyframeAfter; --iteratorCoreKeyframeBefore; // get the two keyframe pointers CalCoreKeyframe *pCoreKeyframeBefore; pCoreKeyframeBefore = iteratorCoreKeyframeBefore->second; CalCoreKeyframe *pCoreKeyframeAfter; pCoreKeyframeAfter = iteratorCoreKeyframeAfter->second; // calculate the blending factor between the two keyframe states float blendFactor; blendFactor = (time - pCoreKeyframeBefore->getTime()) / (pCoreKeyframeAfter->getTime() - pCoreKeyframeBefore->getTime()); // blend between the two keyframes translation = pCoreKeyframeBefore->getTranslation(); translation.blend(blendFactor, pCoreKeyframeAfter->getTranslation()); rotation = pCoreKeyframeBefore->getRotation(); rotation.blend(blendFactor, pCoreKeyframeAfter->getRotation()); return true; }
// Returns true if rounding took place and they were not exactly equal. bool CalCoreTrack::roundTranslation( CalCoreKeyframe const * prevp, CalCoreKeyframe * p, double transTolerance ) { CalCoreKeyframe * prev = const_cast< CalCoreKeyframe * >( prevp ); CalVector translation; assert( prev && p ); // blend between the two keyframes translation = prev->getTranslation(); CalVector const ppos = p->getTranslation(); float dist = Distance( translation, ppos ); // Identical returns false. if( dist == 0 ) return false; // Compare with tolerance. if( dist < transTolerance ) { // equal case handled above. p->setTranslation( translation ); return true; } else { return false; } }
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; }