Esempio n. 1
0
Matrix4x4f BoneBridgeCAL3D::CalculateBoneSpaceTransform() const
{
   Matrix4x4f boneSpaceTransform = Matrix4x4f::Identity();

   // set up bone space geometry transform
   {
      // transform forward by half the box length
      const Vec3f& dimensions = GetDimensions();
      boneSpaceTransform.SetTranslation(Vec3f(dimensions[Y] / 2.0f, 0.0f, 0.0f));

      // set rotational offset (the inversion of the core bone absolute rotation)
      {
         CalCoreBone* coreBone = mpCalBone->getCoreBone();

         CalQuaternion calRotAbsolute = coreBone->getRotationAbsolute();
         calRotAbsolute.invert();

         Quaternionf kernelRot = ConvertCAL3DtoKernel(calRotAbsolute);

         boneSpaceTransform.SetRotate(kernelRot);
      }
   }

   return boneSpaceTransform;
}
Esempio n. 2
0
void
CalMixer::applyBoneAdjustments()
{
  CalSkeleton * pSkeleton = m_pModel->getSkeleton();
  std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone();
  unsigned int i;
  for( i = 0; i < m_numBoneAdjustments; i++ ) {
    CalMixerBoneAdjustmentAndBoneId * ba = & m_boneAdjustmentAndBoneIdArray[ i ];
    CalBone * bo = vectorBone[ ba->boneId_ ];
    CalCoreBone * cbo = bo->getCoreBone();
    if( ba->boneAdjustment_.flags_ & CalMixerBoneAdjustmentFlagMeshScale ) {
      bo->setMeshScaleAbsolute( ba->boneAdjustment_.meshScaleAbsolute_ );
    }
    if( ba->boneAdjustment_.flags_ & CalMixerBoneAdjustmentFlagPosRot ) {
      const CalVector & localPos = cbo->getTranslation();
      CalVector adjustedLocalPos = localPos;
      CalQuaternion adjustedLocalOri = ba->boneAdjustment_.localOri_;
      static float const scale = 1.0f;
      float rampValue = ba->boneAdjustment_.rampValue_;
      static bool const replace = true;
      static float const unrampedWeight = 1.0f;
      bo->blendState( unrampedWeight, 
        adjustedLocalPos,
        adjustedLocalOri, 
        scale, replace, rampValue );
    }
  }
}
Esempio n. 3
0
void CalCoreBone::calculateState()
{
  if(m_parentId == -1)
  {
    // no parent, this means absolute state == relative state
    m_translationAbsolute = m_translation;
    m_rotationAbsolute = m_rotation;
  }
  else
  {
    // get the parent bone
    CalCoreBone *pParent;
    pParent = m_pCoreSkeleton->getCoreBone(m_parentId);

    // transform relative state with the absolute state of the parent
    m_translationAbsolute = m_translation;
    m_translationAbsolute *= pParent->getRotationAbsolute();
    m_translationAbsolute += pParent->getTranslationAbsolute();

	m_rotationAbsolute = m_rotation;
	m_rotationAbsolute *= pParent->getRotationAbsolute();
  }

  // calculate all child bones
  std::list<int>::iterator iteratorChildId;
  for(iteratorChildId = m_listChildId.begin(); iteratorChildId != m_listChildId.end(); ++iteratorChildId)
  {
    m_pCoreSkeleton->getCoreBone(*iteratorChildId)->calculateState();
  }
}
Esempio n. 4
0
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;
    }
  }
}
Esempio n. 5
0
const std::list<int>& BoneBridgeCAL3D::GetListChildBoneID() const
{
   CalBone*     calBone  = (CalBone*)GetCalBone();
   CalCoreBone* coreBone = calBone->getCoreBone();

   std::list<int>& listChildID = coreBone->getListChildId();

   return listChildID;
}
Esempio n. 6
0
void BoneBridgeCAL3D::ComputeBoundingBox()
{
   CalCoreBone*  coreBone  = mpCalBone->getCoreBone();
   assert(coreBone);
   CalCoreModel* coreModel = mpCalModel->getCoreModel();
   assert(coreModel);

   if (!coreBone->isBoundingBoxPrecomputed())
   {
      coreBone->calculateBoundingBox(coreModel);
      assert(coreBone->isBoundingBoxPrecomputed());
   }
   mpCalBone->calculateBoundingBox();
}
Esempio n. 7
0
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 );
    }
  }
}
Esempio n. 8
0
BoneBridgeCAL3D::BoneBridgeCAL3D(Skeleton& skeleton, CalBone* calBone, CalModel* calModel, int calBoneID)
   : mSkeleton(skeleton)
   , mpCalBone(calBone)
   , mpCalModel(calModel)
   , mCalBoneID(calBoneID)
{
   // create box first
   {
      CalCoreBone* coreBone = mpCalBone->getCoreBone();

      // start by computing our bounding box and our bounding box corners
      ComputeBoundingBox();
      std::vector<Vec3f> corners = ComputeBoundingBoxCorners(coreBone->getBoundingBox());

      Vec3f bbMin = FindMinBoundingBoxXYZ(corners);
      Vec3f bbMax = FindMaxBoundingBoxXYZ(corners);
      BoundingBox<3, float> bbox(bbMin, bbMax - bbMin);

      // don't allow any boxes of no area
      {
         Vec3f dimensions = bbox.GetDimensions();

         const bool no_volume = dimensions[X] <= 0 || dimensions[Y] <= 0 || dimensions[Z] <= 0;
         if (no_volume)
         {
            static const float kThinnest = 0.01f; //0.01f;
            // enforce a volume!
            bbox = BoundingBox<3, float>(bbox.GetMinimum(), Vec3f(
               dimensions[X] > 0 ? dimensions[X] : kThinnest,
               dimensions[Y] > 0 ? dimensions[Y] : kThinnest,
               dimensions[Z] > 0 ? dimensions[Z] : kThinnest));
         }
      }

      SetDimensions(bbox.GetDimensions());
   }
}
//------------------------------------------------------------------------------//
// Export the skeleton from a Maxscript call                                  --//
//------------------------------------------------------------------------------//
bool CMaxInterface::ExportSkeletonFromMaxscriptCall(const std::string& strFilename, bool bShowUI)
{
	// build a skeleton candidate
	CSkeletonCandidate skeletonCandidate;
	if(!skeletonCandidate.CreateFromInterfaceFromMaxScriptCall()) return false;

	//Does the user wants to see the UI and select the bones himself ?
	if (bShowUI)
	{
		// show export wizard sheet
		CSkeletonExportSheet sheet(_T("Cal3D Skeleton Export"), GetMainWnd());
		sheet.SetSkeletonCandidate(&skeletonCandidate);
		sheet.SetWizardMode();
		if(sheet.DoModal() != ID_WIZFINISH) return true;
	}

	// build the selected ids of the bone candidates
	int selectedCount = skeletonCandidate.BuildSelectedId();
	if(selectedCount == 0)
	{
		theExporter.SetLastError("No bones selected to export.", __FILE__, __LINE__);
		return false;
	}

	// create the core skeleton instance
	CalCoreSkeletonPtr coreSkeleton = new CalCoreSkeleton;

        // get bone candidate vector
	std::vector<CBoneCandidate *>& vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate();

	// start the progress info
	StartProgressInfo("Exporting to skeleton file...");

	size_t boneCandidateId;
	int selectedId;
	for(boneCandidateId = 0, selectedId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++)
	{
		// get the bone candidate
		CBoneCandidate *pBoneCandidate;
		pBoneCandidate = vectorBoneCandidate[boneCandidateId];

		// only export selected bone candidates
		if(pBoneCandidate->IsSelected())
		{
			// update the progress info
			SetProgressInfo(int(100.0f * (selectedId + 1) / selectedCount));
			selectedId++;

			// allocate new core bone instance
			CalCoreBone *pCoreBone = new CalCoreBone(pBoneCandidate->GetNode()->GetName());

			// get the parent id of the bone candidate
			int parentId;
			parentId = skeletonCandidate.GetParentSelectedId(boneCandidateId);

			// set the parentId
			pCoreBone->setParentId(parentId);

			// get the translation and the rotation of the bone candidate
			CalVector translation;
			CalQuaternion rotation;

			skeletonCandidate.GetTranslationAndRotation(boneCandidateId, -1.0f, translation, rotation);

			// set the translation and rotation
			pCoreBone->setTranslation(translation);
			pCoreBone->setRotation(rotation);

			// get the bone space translation and the rotation of the bone candidate
			CalVector translationBoneSpace;
			CalQuaternion rotationBoneSpace;
			skeletonCandidate.GetTranslationAndRotationBoneSpace(boneCandidateId, -1.0f, translationBoneSpace, rotationBoneSpace);

			// set the bone space translation and rotation
			pCoreBone->setTranslationBoneSpace(translationBoneSpace);
			pCoreBone->setRotationBoneSpace(rotationBoneSpace);

			// set the core skeleton of the core bone instance
			pCoreBone->setCoreSkeleton(coreSkeleton.get());

			// add the core bone to the core skeleton instance
			int boneId;
			boneId = coreSkeleton->addCoreBone(pCoreBone);

			// adjust child list of parent bone
			if(parentId != -1)
			{
				// get parent core bone
				CalCoreBone *pParentCoreBone;
				pParentCoreBone = coreSkeleton->getCoreBone(parentId);
				if(pParentCoreBone == 0)
				{
					theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__);
					delete pCoreBone;
					StopProgressInfo();
					return false;
				}

				// add this core bone to the child list of the parent bone
				pParentCoreBone->addChildId(boneId);
			}
		}
	}

	// stop the progress info
	StopProgressInfo();

	// save core skeleton to the file
	if(!CalSaver::saveCoreSkeleton(strFilename, coreSkeleton.get()))
	{
		theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__);
		return false;
	}

	return true;
}
Esempio n. 10
0
void IKCharacter::setup( CalSkeleton* cal_skel, bool _auto_root_follow )
{
	skeleton = cal_skel;
	auto_root_follow = _auto_root_follow;
	
	
	// find leaf bones
	deque<int> current;
	vector<int> roots = cal_skel->getCoreSkeleton()->getVectorRootCoreBoneId();
	current.insert( current.begin(), roots.begin(), roots.end() );
	while( !current.empty() )
	{
		CalCoreBone* check = skeleton->getCoreSkeleton()->getCoreBone( current.front() );
		list<int> children = check->getListChildId();
		if ( children.size()==0 )
		{
			// this is a leaf
			leaf_bones.push_back( current.front() );
			printf("found leaf: %s\n", skeleton->getCoreSkeleton()->getCoreBone( leaf_bones.back() )->getName().c_str() );
		}
		else
		{
			// not a leaf
			current.insert( current.end(), children.begin(), children.end() );
		}
		
		// store length
		// default non-zero
		bone_lengths[current.front()] = 0.0001f;
		if ( check->getParentId()!= -1 )
		{
			CalCoreBone* parent = skeleton->getCoreSkeleton()->getCoreBone( check->getParentId() );
			CalVector delta = check->getTranslationAbsolute() - parent->getTranslationAbsolute();
			bone_lengths[check->getParentId()] = delta.length();
		}
	
		// cached rotations
		debug_cached_rotations[current.front()] = CalQuaternion();
		
		current.pop_front();
	}

	// set all weights to default
	vector<CalCoreBone*> all_bones = skeleton->getCoreSkeleton()->getVectorCoreBone();
	for( int i=0; i<all_bones.size() ;i++ )
	{
		weight_centres[all_bones[i]->getId()] = 0.5f;
	}	
	
	// release all leaves
	for ( int i=0; i<leaf_bones.size() ;i++ )
	{
		weight_centres[leaf_bones[i]] = 0;
	}
	// pin all roots
	for ( int i=0; i<roots.size(); i++ )
	{
		weight_centres[roots[i]] = 1;
	}
	
	// fetch world positions from Cal3D model
	pullWorldPositions();
	
	// set targets
	/*
	for ( int i=0; i<leaf_bones.size(); i++ )
	{
		CalVector p = world_positions[leaf_bones[i]];
		setTarget( leaf_bones[i], ofxVec3f(p.x,p.y,p.z) );
	}*/
	
	// 
	setupMagicIgnoringRotationOffsets();
	
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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();
  
  CalCoreSkeletonPtr skel = CalLoader::loadCoreSkeleton(std::string(skeleton));
  if (!skel) {
    MessageBox(
      window, "Loading skeleton file failed",
      "Import Cal3D Animation", MB_OK | MB_ICONERROR);
    return IMPEXP_FAIL;
  }

  CalCoreAnimationPtr anim = CalLoader::loadCoreAnimation(name);
  if (!anim) {
    MessageBox(
      window, "Loading animation file failed",
      "Import Cal3D Animation", MB_OK | MB_ICONERROR);
    return IMPEXP_FAIL;
  }

  // Get the pose information in the animation
  const std::vector<CalTransform>& poses = anim->getPoses();
  unsigned int num_poses = poses.size() / anim->getTrackCount();

  // Calculate the time_per_frame incorrectly since the duration for animations
  // is stored incorrectly.
  float time_per_frame = anim->getDuration() / num_poses;

  // Import each track
  for (unsigned track_id = 0; track_id < anim->getTrackCount(); ++track_id)
  {
    // Get the core bone mapped to the animation
    int bone_id = anim->getBoneAssignment(track_id);
    CalCoreBone* bone = skel->getCoreBone(bone_id);
    if (!bone) continue;

    // Get the max node for the bone
    INode* node = i->GetINodeByName(bone->getName().c_str());
    if (!node) continue;

    SuspendAnimate();
    AnimateOn();

    // Add each pose keyframe in the track
    float keyframe_time = 0.0f;
    for (unsigned keyframe_index = 0; keyframe_index < num_poses; ++keyframe_index)
    {
      // Get the keyframe data
      const CalTransform& pose_coord_sys = poses[(keyframe_index * anim->getTrackCount()) + track_id];
      const CalVector     &kf_v = pose_coord_sys.getTranslation();
      const CalQuaternion &kf_q = pose_coord_sys.getRotation();
      TimeValue time = SecToTicks(keyframe_time);

      // Convert to Max math
      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));

      // Convert the transform to world space
      INode* parent = node->GetParentNode();
      if (parent)
      {
        tm *= parent->GetNodeTM(time);
      }

      // Set the new transform on the node
      node->SetNodeTM(time, tm);

      keyframe_time += time_per_frame;
    }

    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;
}
Esempio n. 13
0
bool CExporter::ExportSkeleton(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;
  if(!skeletonCandidate.CreateFromInterface()) return false;

  // show export wizard sheet
  CSkeletonExportSheet sheet("Cal3D Skeleton Export", m_pInterface->GetMainWnd());
  sheet.SetSkeletonCandidate(&skeletonCandidate);
  sheet.SetWizardMode();
  if(sheet.DoModal() != ID_WIZFINISH) return true;

  // build the selected ids of the bone candidates
  int selectedCount = skeletonCandidate.BuildSelectedId();
  if(selectedCount == 0)
  {
    SetLastError("No bones selected to export.", __FILE__, __LINE__);
    return false;
  }

  // create the core skeleton instance
  CalCoreSkeletonPtr coreSkeleton = new CalCoreSkeleton;

  // get bone candidate vector
  std::vector<CBoneCandidate *> vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate();

  // start the progress info
  m_pInterface->StartProgressInfo("Exporting to skeleton file...");

  size_t boneCandidateId;
  int selectedId;
  for(boneCandidateId = 0, selectedId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++)
  {
    // get the bone candidate
    CBoneCandidate *pBoneCandidate = vectorBoneCandidate[boneCandidateId];

    // only export selected bone candidates
    if(pBoneCandidate->IsSelected())
    {
      // update the progress info
      m_pInterface->SetProgressInfo(int(100.0f * (selectedId + 1) / selectedCount));
      selectedId++;

      // allocate new core bone instance
      CalCoreBone *pCoreBone = new CalCoreBone(pBoneCandidate->GetNode()->GetName());

      // get the parent id of the bone candidate
      int parentId = skeletonCandidate.GetParentSelectedId(boneCandidateId);

      // set the parentId
      pCoreBone->setParentId(parentId);

      // get the translation and the rotation of the bone candidate
      CalVector translation;
      CalQuaternion rotation;
      skeletonCandidate.GetTranslationAndRotation(boneCandidateId, -1.0f, translation, rotation);

      // set the translation and rotation
      pCoreBone->setTranslation(translation);
      pCoreBone->setRotation(rotation);

      // get the bone space translation and the rotation of the bone candidate
      CalVector translationBoneSpace;
      CalQuaternion rotationBoneSpace;
      skeletonCandidate.GetTranslationAndRotationBoneSpace(boneCandidateId, -1.0f, translationBoneSpace, rotationBoneSpace);

      // set the bone space translation and rotation
      pCoreBone->setTranslationBoneSpace(translationBoneSpace);
      pCoreBone->setRotationBoneSpace(rotationBoneSpace);

      // set the core skeleton of the core bone instance
      pCoreBone->setCoreSkeleton(coreSkeleton.get());

      // add the core bone to the core skeleton instance
      int boneId;
      boneId = coreSkeleton->addCoreBone(pCoreBone);

      // adjust child list of parent bone
      if(parentId != -1)
      {
        // get parent core bone
        CalCoreBone *pParentCoreBone;
        pParentCoreBone = coreSkeleton->getCoreBone(parentId);
        if(pParentCoreBone == 0)
        {
          SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__);
          delete pCoreBone;
          m_pInterface->StopProgressInfo();
          return false;
        }

        // add this core bone to the child list of the parent bone
        pParentCoreBone->addChildId(boneId);
      }
    }
  }

  // stop the progress info
  m_pInterface->StopProgressInfo();

  // save core skeleton to the file
  if(!CalSaver::saveCoreSkeleton(strFilename, coreSkeleton.get()))
  {
    SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__);
    return false;
  }

  
  HKEY hk;
  LONG lret=RegCreateKey(HKEY_CURRENT_USER, "Software\\Cal3D\\Exporter", &hk);
  if(lret==ERROR_SUCCESS && NULL!=hk)
  {
    lret=RegSetValueEx(hk,"skeleton",NULL,REG_SZ,(unsigned char *)strFilename.c_str() ,strFilename.length());
    RegCloseKey(hk);
  }


  return true;
}