int PreCacheFrameOffsets(MFMADDecoder *pDecoder) { MP3Header header; unsigned char headerBuffer[10]; int sampleRate = 0; uint32 filePos = MFFile_Tell(pDecoder->pFile); while(MFFile_Read(pDecoder->pFile, headerBuffer, 4)) { int validHeader = ReadMP3Header(&header, headerBuffer); sampleRate = header.samplerate; if(validHeader != 1) { if(pDecoder->frameCount >= pDecoder->numFrameOffsetsAllocated) { pDecoder->numFrameOffsetsAllocated *= 2; pDecoder->pFrameOffsets = (uint32*)MFHeap_Realloc(pDecoder->pFrameOffsets, sizeof(uint32) * pDecoder->numFrameOffsetsAllocated); } pDecoder->pFrameOffsets[pDecoder->frameOffsetCount++] = filePos; ++pDecoder->frameCount; MFFile_Seek(pDecoder->pFile, header.frameSize-4, MFSeek_Current); } else { // check if we have some other header.. ID3? if(!MFString_CaseCmpN((char*)headerBuffer, "TAG", 3)) { // read ID3 v1? ... // skip past it for now... MFFile_Seek(pDecoder->pFile, 128-4, MFSeek_Current); } else if(!MFString_CaseCmpN((char*)headerBuffer, "ID3", 3)) { // ID3 v2... MFFile_Read(pDecoder->pFile, headerBuffer + 4, 6); uint32 size = GetSynchSafeInt(headerBuffer + 6); // skip ID3 v2 data MFFile_Seek(pDecoder->pFile, size, MFSeek_Current); } else { // lost sync? :/ return 0; } } filePos = MFFile_Tell(pDecoder->pFile); } return sampleRate; }
void GotoSection(int cancel, const char *pString) { if(cancel || !*pString) return; const char *pTest = pString; while(*pTest && (MFIsNumeric(*pTest) || *pTest == '.')) ++pTest; int res = gEditor.pSong->GetRes(); if(pTest > pString) { if(!*pTest) { OffsetToMeasureAndBeat((int)((float)atof(pString) * res), &gEditor.measure, &gEditor.beat); return; } if(!MFString_CaseCmp(pTest, "s")) { float time = (float)atof(pString); OffsetToMeasureAndBeat(gEditor.pSong->CalculateTickAtTime((int64)(time*1000000.0f)), &gEditor.measure, &gEditor.beat); return; } else if(!MFString_CaseCmp(pTest, "ms")) { float time = (float)atof(pString); OffsetToMeasureAndBeat(gEditor.pSong->CalculateTickAtTime((int64)(time*1000.0f)), &gEditor.measure, &gEditor.beat); return; } } // find section by name size_t len = MFString_Length(pString); GHEvent *pSE = gEditor.pSong->events.First(); while(pSE) { if(!MFString_CaseCmpN(pSE->GetString(), "section ", 8) && !MFString_CaseCmpN(&pSE->GetString()[8], pString, len)) { OffsetToMeasureAndBeat(pSE->tick, &gEditor.measure, &gEditor.beat); return; } pSE = pSE->Next(); } }
void ParseXFile(char *pFilePtr) { if(MFString_CaseCmpN(pFilePtr, "xof ", 4)) { MFDebug_Warn(4, "File is not an .x file\n"); return; } if(!MFString_CaseCmpN(&pFilePtr[8], "txt ", 4)) { pFilePtr += 16; LoadTextXFile(pFilePtr); } else if(!MFString_CaseCmpN(&pFilePtr[8], "bin ", 4)) { MFDebug_Warn(4, "Binary .x files not yet supported...\n"); } else { MFDebug_Warn(4, "Not a valid .x file...\n"); } }
char* ReadGeomChunk(char *pFilePtr, char *pToken) { if(!MFString_CaseCmp(pToken, "*NODE_NAME")) { char *pNodeName; pFilePtr = GetString(pFilePtr, &pNodeName); if(!MFString_CaseCmpN(pNodeName, "z_", 2)) { // node is bone nodeType = 2; } else if(!MFString_CaseCmpN(pNodeName, "r_", 2)) { // node is refPoint nodeType = 4; } else { // node is mesh nodeType = 1; } // if exporting geometry, add a subobject if(nodeType & 1) { pSub = &pModel->GetMeshChunk()->subObjects.push(); if(MFString_Length(pNodeName) > 63) { MFDebug_Warn(3, MFStr("Error: More than 64 characters in mesh name, \"%s\"", pNodeName)); } else pSub->name = pNodeName; } // if exporting a bone, add a bone if(nodeType & 2) { pBone = &pModel->GetSkeletonChunk()->bones.push(); } // if exporting a refPoint, add a refPoint if(nodeType & 4) { pRefPoint = &pModel->GetRefPointChunk()->refPoints.push(); if(MFString_Length(pNodeName) > 63) { MFDebug_Warn(3, MFStr("Error: More than 64 characters in refPoint name, \"%s\"", pNodeName)); } else pRefPoint->name = pNodeName; } } else if(!MFString_CaseCmp(pToken, "*NODE_PARENT")) { if(nodeType & 2) { char *pParentName; pFilePtr = GetString(pFilePtr, &pParentName); if(MFString_Length(pParentName) > 63) { MFDebug_Warn(3, MFStr("Error: More than 64 characters in bone parent name, \"%s\"", pParentName)); return pFilePtr; } pBone->parentName = pParentName; } } else if(!MFString_CaseCmp(pToken, "*NODE_TM")) { if(nodeType & 2) { pFilePtr = ProcessBlock(pFilePtr, "*NODE_TM", ReadBone); } } else if(!MFString_CaseCmp(pToken, "*MESH")) { if(nodeType & 1) { pFilePtr = ProcessBlock(pFilePtr, "*MESH", ReadMesh); } } else if(!MFString_CaseCmp(pToken, "*MATERIAL_REF")) { if(nodeType & 1) { pFilePtr = GetInt(pFilePtr, &pSub->matSubobjects[0].materialIndex); } } else { MFDebug_Warn(3, MFStr("Unknown token: %s", pToken)); } return pFilePtr; }
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; }
const char *ParseAnimation(const char *pText) { const char *pAnimName = GetNextToken(pText, &pText); if(MFString_Compare(pAnimName, "{")) SkipToken(pText, "{"); char bone[64]; int numFrames = 0; float *pFrameTimes = NULL; MFQuaternion *pQuats = NULL; MFVector *pScale = NULL; MFVector *pTrans = NULL; MFMatrix *pMats = NULL; MFVector tQuat; const char *pTok = GetNextToken(pText, &pText); while(MFString_Compare(pTok, "}")) { if(!MFString_Compare(pTok, "AnimationKey")) { SkipToken(pText, "{"); int type = GetInt(pText, &pText); numFrames = GetInt(pText, &pText); pFrameTimes = (float*)MFHeap_Alloc(sizeof(float)*numFrames); switch(type) { case KT_Quat: pQuats = (MFQuaternion*)MFHeap_Alloc(sizeof(MFQuaternion)*numFrames); break; case KT_Scale: pScale = (MFVector*)MFHeap_Alloc(sizeof(MFVector)*numFrames); break; case KT_Translation: pTrans = (MFVector*)MFHeap_Alloc(sizeof(MFVector)*numFrames); break; case KT_Matrix: pMats = (MFMatrix*)MFHeap_Alloc(sizeof(MFMatrix)*numFrames); break; } // read data for(int a=0; a<numFrames; a++) { int frame = GetInt(pText, &pText); pFrameTimes[a] = (float)frame; int numComponents = GetInt(pText, &pText); switch(type) { case KT_Quat: MFDebug_Assert(numComponents == 4, "Required 4 components for a quaternion."); GetFloatArray(pText, tQuat, numComponents, &pText); ((MFVector&)pQuats[a]).Swizzle(tQuat, SW_Y|SW_NEG, SW_Z|SW_NEG, SW_W|SW_NEG, SW_X|SW_NEG); break; case KT_Scale: MFDebug_Assert(numComponents == 3, "Required 3 components for a scale."); GetFloatArray(pText, (float*)&pScale[a], numComponents, &pText); break; case KT_Translation: MFDebug_Assert(numComponents == 3, "Required 3 components for a translation."); GetFloatArray(pText, (float*)&pTrans[a], numComponents, &pText); break; case KT_Matrix: MFDebug_Assert(numComponents == 16, "Required 16 components for a matrix."); GetFloatArray(pText, (float*)&pMats[a], numComponents, &pText); break; } SkipToken(pText, ";"); if(a < numFrames-1) SkipToken(pText, ","); } SkipToken(pText, ";"); SkipToken(pText, "}"); } else if(!MFString_Compare(pTok, "{")) { GetNextToken(pText, &pText, bone); SkipToken(pText, "}"); } else { MFDebug_Warn(4, MFStr("Unexpected token '%s'\n", pTok)); SkipSection(pText); } pTok = GetNextToken(pText, &pText); } if(!MFString_CaseCmpN(bone, "bn_", 3) || !MFString_CaseCmpN(bone, "z_", 2)) { // copy data to bone F3DAnimation &anim = pModel->GetAnimationChunk()->anims.push(); anim.boneID = pModel->GetSkeletonChunk()->FindBone(bone); if(anim.boneID == -1) { MFDebug_Warn(4, MFStr("Bone '%s' not found..\n", bone)); return pText; } anim.minTime = pFrameTimes[0]; anim.maxTime = pFrameTimes[numFrames-1]; for(int a=0; a<numFrames; a++) { anim.keyframes[a].time = pFrameTimes[a]; if(pMats) { anim.keyframes[a].key = pMats[a]; // anim.keyframes[a].scale = MakeVector(pMats[a].GetXAxis().Magnitude3(), pMats[a].GetYAxis().Magnitude3(), pMats[a].GetZAxis().Magnitude3(), 1.0f); // pMats[a].Normalise(); // anim.keyframes[a].rotation = pMats[a].GetRotationQ(); // anim.keyframes[a].translation = pMats[a].GetTrans(); } else { anim.keyframes[a].key.SetRotationQ(pQuats ? pQuats[a] : MFQuaternion::identity); if(pScale) anim.keyframes[a].key.Scale(pScale[a]); anim.keyframes[a].key.SetTrans3(pTrans ? pTrans[a] : MFVector::identity); // anim.keyframes[a].rotation = pQuats ? pQuats[a] : MFQuaternion::identity; // anim.keyframes[a].scale = pScale ? pScale[a] : MFVector::one; // anim.keyframes[a].translation = pTrans ? pTrans[a] : MFVector::identity; } } } return pText; }
const char *ParseMesh(const char *pText, const MFMatrix &mat, const char *pFrameName) { // read name char meshName[64]; const char *pMeshName = GetNextToken(pText, &pText, meshName); if(!MFString_Compare(pMeshName, "{")) pMeshName = pFrameName; else SkipToken(pText, "{"); if(MFString_CaseCmpN(pMeshName, "m_", 2)) { // not a mesh! SkipSection(pText); return pText; } F3DMeshChunk *pMesh = pModel->GetMeshChunk(); F3DSubObject &sub = pMesh->subObjects.push(); MFString_Copy(sub.name, pMeshName); // get num positions int numPositions = GetInt(pText, &pText); sub.positions.resize(numPositions); // read positions for(int a=0; a<numPositions; a++) { sub.positions[a].x = GetFloat(pText, &pText); sub.positions[a].y = GetFloat(pText, &pText); sub.positions[a].z = GetFloat(pText, &pText); sub.positions[a] = ApplyMatrixH(sub.positions[a], mat); if(a < numPositions-1) SkipToken(pText, ","); } SkipToken(pText, ";"); // get num faces int numFaces = GetInt(pText, &pText); // see if we have a material face mapping int *pMatFaces = ParseMaterialList(pText, sub, numFaces); // read faces int face[16], numVerts[16], numTris[16]; MFZeroMemory(numVerts, sizeof(numVerts)); MFZeroMemory(numTris, sizeof(numTris)); for(int a=0; a<numFaces; a++) { int matSub = pMatFaces ? pMatFaces[a] : 0; F3DMaterialSubobject &matsub = sub.matSubobjects[matSub]; int numPoints = GetInt(pText, &pText); MFDebug_Assert(numPoints < 16, "Exceeded maximum 16 points per face..."); GetIntArray(pText, face, numPoints, &pText); int firstVert = numVerts[matSub]; numVerts[matSub] += numPoints; if(matsub.vertices.size() < numVerts[matSub]) matsub.vertices.resize(numVerts[matSub]); int firstTri = numTris[matSub]; numTris[matSub] += numPoints-2; if(matsub.triangles.size() < numTris[matSub]) matsub.triangles.resize(numTris[matSub]); for(int b=0; b<numPoints; b++) matsub.vertices[firstVert+b].position = face[b]; for(int b=0; b<numPoints-2; b++) { matsub.triangles[firstTri+b].v[0] = firstVert+0; matsub.triangles[firstTri+b].v[1] = firstVert+b+1; matsub.triangles[firstTri+b].v[2] = firstVert+b+2; } if(a < numFaces-1) SkipToken(pText, ","); } SkipToken(pText, ";"); const char *pTok = GetNextToken(pText, &pText); while(MFString_Compare(pTok, "}")) { if(!MFString_Compare(pTok, "MeshMaterialList")) { SkipSection(pText); } else if(!MFString_Compare(pTok, "MeshNormals")) { pText = ParseNormals(pText, sub, mat, numFaces, pMatFaces); } else if(!MFString_Compare(pTok, "MeshTextureCoords")) { pText = ParseTexCoords(pText, sub, numPositions); } else if(!MFString_Compare(pTok, "MeshVertexColors")) { pText = ParseColours(pText, sub, numPositions); } else if(!MFString_Compare(pTok, "XSkinMeshHeader")) { SkipToken(pText, "{"); // get num positions int nMaxSkinWeightsPerVertex = GetInt(pText, &pText); int nMaxSkinWeightsPerFace = GetInt(pText, &pText); int nBones = GetInt(pText, &pText); // not yet sure how this helps... /* for(int m=0; m<sub.matSubobjects.size(); m++) { sub.matSubobjects[m].numBones = nBones; } */ SkipToken(pText, "}"); } else if(!MFString_Compare(pTok, "SkinWeights")) { pText = ParseSkinWeights(pText, sub, numPositions); } else if(!MFString_Compare(pTok, "DeclData")) { SkipSection(pText); } else { MFDebug_Warn(4, MFStr("Unknown token '%s'\n", pTok)); SkipSection(pText); } pTok = GetNextToken(pText, &pText); } // we should order the bone weights into the most to least weighting. return pText; }