MF_API MFMatrix *MFAnimation_CalculateMatrices(MFAnimation *pAnimation, MFMatrix *pLocalToWorld)
{
	MFAnimationBone *pAnims = pAnimation->pTemplate->pBones;
	MFModelBone *pBones = pAnimation->pBones;
	MFMatrix *pMats = pAnimation->pMatrices;

	float t = pAnimation->blendLayer.frameTime;
	MFDebug_Assert(t >= pAnimation->pTemplate->startTime && t <= pAnimation->pTemplate->endTime, "Frame time outside animation range...");

	// find the frame number for each bone
	for(uint32 a=0; a<pAnimation->numBones; a++)
	{
		int map = pAnimation->pBoneMap[a];

		if(map != -1)
		{
			float *pTimes = pAnims[map].pTime;
			int lastFrames = pAnims[map].numFrames-1;

			if(t == pTimes[lastFrames])
			{
				pAnimation->blendLayer.pCurFrames[a].tweenStart = lastFrames;
				pAnimation->blendLayer.pCurFrames[a].tweenEnd = lastFrames;
				pAnimation->blendLayer.pCurFrames[a].tween = 0;
			}
			else
			{
				// TODO: change this to a binary search...
				for(int b=0; b<lastFrames; b++)
				{
					float t1 = pTimes[b];
					float t2 = pTimes[b+1];

					if(t >= pTimes[b] && t < pTimes[b+1])
					{
						pAnimation->blendLayer.pCurFrames[a].tweenStart = b;
						pAnimation->blendLayer.pCurFrames[a].tweenEnd = b+1;
						pAnimation->blendLayer.pCurFrames[a].tween = (t-t1) / (t2-t1);
						break;
					}
				}
			}
		}
	}

	// calculate the matrix for each bone
	for(uint32 a=0; a<pAnimation->numBones; a++)
	{
		int map = pAnimation->pBoneMap[a];

		if(map != -1)
		{
			MFMatrix &m1 = pAnims[map].pFrames[pAnimation->blendLayer.pCurFrames[a].tweenStart].key;
			MFMatrix &m2 = pAnims[map].pFrames[pAnimation->blendLayer.pCurFrames[a].tweenEnd].key;

			gWorkingMats[a].Tween(m1, m2, pAnimation->blendLayer.pCurFrames[a].tween);
		}
		else
		{
			gWorkingMats[a] = pBones[a].boneMatrix;
		}
	}

	// build the animation matrix for each bone...
	// TODO: this could be much faster
	for(uint32 a=0; a<pAnimation->numBones; a++)
	{
		MFMatrix boneMat = MFMatrix::identity;

		int b = (int)a;
		do
		{
			boneMat.Multiply(gWorkingMats[b]);
			b = pBones[b].parent;
		}
		while(b != -1);

//		pMats[a].Multiply(boneMat, pBones[a].invWorldMatrix);
		pMats[a].Multiply(pBones[a].invWorldMatrix, boneMat);

		if(pLocalToWorld)
			pMats[a].Multiply(*pLocalToWorld);
	}

	return pAnimation->pMatrices;
}
Beispiel #2
0
const char *ParseFrame(const char *pText, const MFMatrix &mat, int parentID)
{
	char frameName[64];
	const char *pName = GetNextToken(pText, &pText, frameName);

	MFMatrix worldMatrix = mat;

	F3DBone *pBone = NULL;

	if(!MFString_CaseCmpN(pName, "bn_", 3) || !MFString_CaseCmpN(pName, "z_", 2))
	{
		int boneID = pModel->GetSkeletonChunk()->bones.size();
		pBone = &pModel->GetSkeletonChunk()->bones[boneID];

		F3DBone *pParent = parentID == -1 ? NULL : &pModel->GetSkeletonChunk()->bones[parentID];
		parentID = boneID;

		MFString_Copy(pBone->name, pName);
		MFString_Copy(pBone->parentName, pParent ? pParent->name : "");

		pBone->worldMatrix = mat;
	}

	if(MFString_Compare(pName, "{"))
		SkipToken(pText, "{");

	const char *pTok = GetNextToken(pText, &pText);

	while(MFString_Compare(pTok, "}"))
	{
		if(!MFString_Compare(pTok, "Frame"))
		{
			pText = ParseFrame(pText, worldMatrix, parentID);
		}
		else if(!MFString_Compare(pTok, "FrameTransformMatrix"))
		{
			SkipToken(pText, "{");

			MFMatrix localMatrix;
			GetFloatArray(pText, (float*)&localMatrix, 16, &pText);

			worldMatrix.Multiply(localMatrix, worldMatrix);

			if(pBone)
			{
				pBone->boneMatrix = localMatrix;
				pBone->worldMatrix = worldMatrix;
			}

			SkipToken(pText, ";");
			SkipToken(pText, "}");
		}
		else if(!MFString_Compare(pTok, "Mesh"))
		{
			gMeshChunks.push(XMeshChunk::Create(worldMatrix, pText, pName));
			SkipSection(pText);
		}
		else
		{
			MFDebug_Warn(4, MFStr("Unexpected token '%s'\n", pTok));
			SkipSection(pText);
		}

		pTok = GetNextToken(pText, &pText);
	}

	return pText;
}