示例#1
0
bool CMilkBoneNode::Create(msBone *pIBone)
{
	// check if the internal bone is valid
	if(pIBone == 0)
	{
		theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
		return false;
	}

	m_pIBone = pIBone;

  // get the internal model
  msModel *pIModel;
  pIModel = dynamic_cast<CMilkInterface *>(theExporter.GetInterface())->GetIModel();
  if(pIModel == 0)
  {
		theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
		return false;
  }

  // get the name of this bone
  std::string strName;
  strName = pIBone->szName;

    // search for children of this bone and create them
  int boneId;
  for(boneId = 0; boneId < msModel_GetBoneCount(pIModel); boneId++)
  {
    // get the name of the bone
    std::string strParentName;
    strParentName = msModel_GetBoneAt(pIModel, boneId)->szParentName;

    // check if it is a child
    if(strName == strParentName)
    {
      // add the child id to the child id vector
      m_vectorChildId.push_back(boneId);
    }
  }

	return true;
}
示例#2
0
CBaseNode *CMilkBoneNode::GetChild(int childId)
{
	// check if the internal bone is valid
	if(m_pIBone == 0) return 0;

	// check if the given node id is valid
	if((childId < 0) || (childId >= (int)m_vectorChildId.size()))
	{
		theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
		return 0;
	}

  // get the internal model
  msModel *pIModel;
  pIModel = dynamic_cast<CMilkInterface *>(theExporter.GetInterface())->GetIModel();
  if(pIModel == 0)
  {
		theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
		return 0;
  }

	// allocate a new milk bone node instance
	CMilkBoneNode *pNode;
	pNode = new CMilkBoneNode();
	if(pNode == 0)
	{
		theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__);
		return false;
	}

  // create the milk bone node
	if(!pNode->Create(msModel_GetBoneAt(pIModel, m_vectorChildId[childId])))
	{
		delete pNode;
		return 0;
	}

	return pNode;
}
void MilkshapePlugin::doExportAnimations(msModel* pModel, Ogre::SkeletonPtr& ogreskel)
{

    Ogre::LogManager& logMgr = Ogre::LogManager::getSingleton();
    std::vector<SplitAnimationStruct> splitInfo;
    Ogre::String msg;

    int numFrames = msModel_GetTotalFrames(pModel);
	msg = "Number of frames: " + Ogre::StringConverter::toString(numFrames);
    logMgr.logMessage(msg);

    if (splitAnimations)
    {
        // Explain
        msg = "You have chosen to create multiple discrete animations by splitting up the frames in "
			"the animation sequence. In order to do this, you must supply a simple text file "
            "describing the separate animations, which has a single line per animation in the format: \n\n" 
            "startFrame,endFrame,animationName\n\nFor example: \n\n"
            "1,20,Walk\n21,35,Run\n36,40,Shoot\n\n" 
            "..creates 3 separate animations (the frame numbers are inclusive)."
			"You must browse to this file in the next dialog.";
        MessageBox(0,msg.c_str(), "Splitting Animations",MB_ICONINFORMATION | MB_OK);
        // Prompt for a file which contains animation splitting info
        OPENFILENAME ofn;
        memset (&ofn, 0, sizeof (OPENFILENAME));
        
        char szFile[MS_MAX_PATH];
        char szFileTitle[MS_MAX_PATH];
        char szDefExt[32] = "skeleton";
        char szFilter[128] = "All Files (*.*)\0*.*\0\0";
        szFile[0] = '\0';
        szFileTitle[0] = '\0';

        ofn.lStructSize = sizeof (OPENFILENAME);
        ofn.lpstrDefExt = szDefExt;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFile;
        ofn.nMaxFile = MS_MAX_PATH;
        ofn.lpstrFileTitle = szFileTitle;
        ofn.nMaxFileTitle = MS_MAX_PATH;
        ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        ofn.lpstrTitle = "Open animation split configuration file";

        if (!::GetOpenFileName (&ofn))
        {
            msg = "Splitting aborted, generating a single animation called 'Default'";
            MessageBox(0, msg.c_str(), "Info", MB_OK | MB_ICONWARNING);
            SplitAnimationStruct split;
            split.start = 1;
            split.end = numFrames;
            split.name = "Default";
            splitInfo.push_back(split);
        }
        else
        {
            // Read file
            Ogre::String sline;
            char line[256];
            SplitAnimationStruct newSplit;

            std::ifstream istr;
            istr.open(szFile);

            while (!istr.eof())
            {
                istr.getline(line, 256);
                sline = line;

                // Ignore blanks & comments
                if (sline == "" || sline.substr(0,2) == "//")
                    continue;

                // Split on ','
				std::vector<Ogre::String> svec = Ogre::StringUtil::split(line, ",\n");

                // Basic validation on number of elements
                if (svec.size() != 3)
                {
                    MessageBox(0, "Warning: corrupt animation details in file. You should look into this. ",
                        "Corrupt animations file", MB_ICONWARNING | MB_OK);
                    continue;
                }
                // Remove any embedded spaces
				Ogre::StringUtil::trim(svec[0]);
                Ogre::StringUtil::trim(svec[1]);
                Ogre::StringUtil::trim(svec[2]);
                // Create split info
                newSplit.start = atoi(svec[0].c_str());
                newSplit.end = atoi(svec[1].c_str());
                newSplit.name = svec[2];
                splitInfo.push_back(newSplit);

            }


        }

    }
    else
    {
        // No splitting
        SplitAnimationStruct split;
        split.start = 1;
        split.end = numFrames;
        split.name = "Default";
        splitInfo.push_back(split);
    }

    // Get animation length
    // Map frames -> seconds, this can be changed in speed of animation anyway



    int numBones = msModel_GetBoneCount(pModel);
    unsigned int frameTime;
    float realTime;

    std::vector<SplitAnimationStruct>::iterator animsIt;
    for (animsIt = splitInfo.begin(); animsIt != splitInfo.end(); ++animsIt)
    {
        SplitAnimationStruct& currSplit = *animsIt;

        // Create animation
        frameTime = currSplit.end - currSplit.start;
        realTime = frameTime / fps;
		Ogre::LogManager::getSingleton().stream()
			<< "Trying to create Animation object for animation "
			<<  currSplit.name << " For Frames " << currSplit.start << " to "
            << currSplit.end << " inclusive. ";

		Ogre::LogManager::getSingleton().stream()
			<< "Frame time = "
			<< frameTime << ", Seconds = " << realTime;

        Ogre::Animation *ogreanim =
            ogreskel->createAnimation(currSplit.name, realTime);
        logMgr.logMessage("Animation object created.");

        int i;
        // Create all the animation tracks
        for (i = 0; i < numBones; ++i)
        {

            msBone* bone = msModel_GetBoneAt(pModel, i);
            Ogre::Bone* ogrebone = ogreskel->getBone(bone->szName);

            // Create animation tracks
			msg = "Creating AnimationTrack for bone " + Ogre::StringConverter::toString(i);
            logMgr.logMessage(msg);

            Ogre::NodeAnimationTrack *ogretrack = ogreanim->createNodeTrack(i, ogrebone);
            logMgr.logMessage("Animation track created.");

            // OGRE uses keyframes which are both position and rotation
            // Milkshape separates them, but never seems to use the ability to
            // have a different # of pos & rot keys

            int numKeys = msBone_GetRotationKeyCount(bone);

            msg = "Number of keyframes: " + Ogre::StringConverter::toString(numKeys);
            logMgr.logMessage(msg);

            int currKeyIdx;
            msPositionKey* currPosKey;
            msRotationKey* currRotKey;
            for (currKeyIdx = 0; currKeyIdx < numKeys; ++currKeyIdx )
            {
                currPosKey = msBone_GetPositionKeyAt(bone, currKeyIdx);
                currRotKey = msBone_GetRotationKeyAt(bone, currKeyIdx);

                // Make sure keyframe is in current time frame (for splitting)
                if (currRotKey->fTime >= currSplit.start && currRotKey->fTime <= currSplit.end)
                {

                    msg = "Creating KeyFrame #" + Ogre::StringConverter::toString(currKeyIdx)
                        + " for bone #" + Ogre::StringConverter::toString(i);
                    logMgr.logMessage(msg);
                    // Create keyframe
                    // Adjust for start time, and for the fact that frames are numbered from 1
                    frameTime = currRotKey->fTime - currSplit.start;
                    realTime = frameTime / fps;
                    Ogre::TransformKeyFrame *ogrekey = ogretrack->createNodeKeyFrame(realTime);
                    logMgr.logMessage("KeyFrame created");

					Ogre::Vector3 kfPos;
					// Imported milkshape animations may not have positions 
					// for all rotation keys
					if ( currKeyIdx < bone->nNumPositionKeys ) {
						kfPos.x = currPosKey->Position[0];
						kfPos.y = currPosKey->Position[1];
						kfPos.z = currPosKey->Position[2];
					}
					else {
						kfPos.x = bone->Position[0];
						kfPos.y = bone->Position[1];
						kfPos.z = bone->Position[2];
					}
                    Ogre::Quaternion qx, qy, qz, kfQ;

					// Milkshape translations are local to own orientation, not parent
					kfPos = ogrebone->getOrientation() * kfPos;

                    ogrekey->setTranslate(kfPos);
                    qx.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[0]), Ogre::Vector3::UNIT_X);
                    qy.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[1]), Ogre::Vector3::UNIT_Y);
                    qz.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[2]), Ogre::Vector3::UNIT_Z);
                    kfQ = qz * qy * qx;
                    ogrekey->setRotation(kfQ);

					Ogre::LogManager::getSingleton().stream()
						<< "KeyFrame details: Adjusted Frame Time=" << frameTime
						<< " Seconds: " << realTime << " Position=" << kfPos << " " 
						<< "Ms3d Rotation= {" << currRotKey->Rotation[0] << ", " 
						<< currRotKey->Rotation[1] << ", " << currRotKey->Rotation[2] 
						<< "} " << "Orientation=" << kfQ;
                } // keyframe creation

            } // keys
        } //Bones
    } // Animations




}
Ogre::SkeletonPtr MilkshapePlugin::doExportSkeleton(msModel* pModel, Ogre::MeshPtr& mesh)
{
    Ogre::LogManager &logMgr = Ogre::LogManager::getSingleton();
    Ogre::String msg;

    //
    // choose filename
    //
    OPENFILENAME ofn;
    memset (&ofn, 0, sizeof (OPENFILENAME));

    char szFile[MS_MAX_PATH];
    char szFileTitle[MS_MAX_PATH];
    char szDefExt[32] = "skeleton";
    char szFilter[128] = "OGRE .skeleton Files (*.skeleton)\0*.skeleton\0All Files (*.*)\0*.*\0\0";
    szFile[0] = '\0';
    szFileTitle[0] = '\0';

    ofn.lStructSize = sizeof (OPENFILENAME);
    ofn.lpstrDefExt = szDefExt;
    ofn.lpstrFilter = szFilter;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = MS_MAX_PATH;
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = MS_MAX_PATH;
    ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
    ofn.lpstrTitle = "Export to OGRE Skeleton";

    if (!::GetSaveFileName (&ofn))
        return Ogre::SkeletonPtr();

    // Strip off the path
    Ogre::String skelName = szFile;
    size_t lastSlash = skelName.find_last_of("\\");
    skelName = skelName.substr(lastSlash+1);

    // Set up
    logMgr.logMessage("Trying to create Skeleton object");
    Ogre::SkeletonPtr ogreskel = Ogre::SkeletonManager::getSingleton().create(skelName, 
        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    logMgr.logMessage("Skeleton object created");

    // Complete the details

    // Do the bones
    int numBones = msModel_GetBoneCount(pModel);
	msg = "Number of bones: " + Ogre::StringConverter::toString(numBones);
    logMgr.logMessage(msg);

    int i;
    // Create all the bones in turn
    for (i = 0; i < numBones; ++i)
    {
        msBone* bone = msModel_GetBoneAt(pModel, i);
        Ogre::Bone* ogrebone = ogreskel->createBone(bone->szName);

        msVec3 msBonePos, msBoneRot;
        msBone_GetPosition(bone, msBonePos);
        msBone_GetRotation(bone, msBoneRot);

        Ogre::Vector3 bonePos(msBonePos[0], msBonePos[1], msBonePos[2]);
        ogrebone->setPosition(bonePos);
        // Hmm, Milkshape has chosen a Euler angle representation of orientation which is not smart
        // Rotation Matrix or Quaternion would have been the smarter choice
        // Might we have Gimbal lock here? What order are these 3 angles supposed to be applied?
        // Grr, we'll try our best anyway...
        Ogre::Quaternion qx, qy, qz, qfinal;
        qx.FromAngleAxis(Ogre::Radian(msBoneRot[0]), Ogre::Vector3::UNIT_X);
        qy.FromAngleAxis(Ogre::Radian(msBoneRot[1]), Ogre::Vector3::UNIT_Y);
        qz.FromAngleAxis(Ogre::Radian(msBoneRot[2]), Ogre::Vector3::UNIT_Z);

        // Assume rotate by x then y then z
        qfinal = qz * qy * qx;
        ogrebone->setOrientation(qfinal);

		Ogre::LogManager::getSingleton().stream()
			<< "Bone #" << i << ": " <<
            "Name='" << bone->szName << "' " <<
            "Position: " << bonePos << " " <<
            "Ms3d Rotation: {" << msBoneRot[0] << ", " << msBoneRot[1] << ", " << msBoneRot[2] << "} " <<
            "Orientation: " << qfinal;


    }
    // Now we've created all the bones, link them up
    logMgr.logMessage("Establishing bone hierarchy..");
    for (i = 0; i < numBones; ++i)
    {
        msBone* bone = msModel_GetBoneAt(pModel, i);

        if (strlen(bone->szParentName) == 0)
        {
            // Root bone
            msg = "Root bone detected: Name='" + Ogre::String(bone->szName) + "' Index=" 
				+ Ogre::StringConverter::toString(i);
            logMgr.logMessage(msg);
        }
        else
        {
            Ogre::Bone* ogrechild = ogreskel->getBone(bone->szName);
            Ogre::Bone* ogreparent = ogreskel->getBone(bone->szParentName);

            if (ogrechild == 0)
            {
                msg = "Error: could not locate child bone '" +
					Ogre::String(bone->szName) + "'";
                logMgr.logMessage(msg);
                continue;
            }
            if (ogreparent == 0)
            {
                msg = "Error: could not locate parent bone '"
					+ Ogre::String(bone->szParentName) + "'";
                logMgr.logMessage(msg);
                continue;
            }
            // Make child
            ogreparent->addChild(ogrechild);
        }


    }
    logMgr.logMessage("Bone hierarchy established.");

    // Create the Animation(s)
    doExportAnimations(pModel, ogreskel);



    // Create skeleton serializer & export
    Ogre::SkeletonSerializer serializer;
    msg = "Exporting skeleton to " + Ogre::String(szFile);
    logMgr.logMessage(msg);
    serializer.exportSkeleton(ogreskel.getPointer(), szFile);
    logMgr.logMessage("Skeleton exported");


    msg = "Linking mesh to skeleton file '" + skelName + "'";
    Ogre::LogManager::getSingleton().logMessage(msg);

    mesh->_notifySkeleton(ogreskel);

    return ogreskel;

}