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; }
// read/write a file to a filesystem MF_API char* MFFileSystem_Load(const char *pFilename, size_t *pBytesRead, size_t extraBytes) { char *pBuffer = NULL; MFFile *hFile = MFFileSystem_Open(pFilename, MFOF_Read|MFOF_Binary); if(hFile) { uint64 size = MFFile_GetSize(hFile); if(size > 0) { #if defined(MF_32BIT) if(size >= 1LL << 32) { MFDebug_Warn(1, MFStr("File is larger than the available address space!", pFilename)); return NULL; } #endif pBuffer = (char*)MFHeap_Alloc((size_t)size + extraBytes); size_t bytesRead = MFFile_Read(hFile, pBuffer, (size_t)size); if(extraBytes > 0) pBuffer[size] = 0; if(pBytesRead) *pBytesRead = bytesRead; } MFFile_Close(hFile); } return pBuffer; }
int F3DFile::ReadOBJ(const char *pFilename) { pModel = this; MFFile *pFile = MFFileSystem_Open(pFilename, MFOF_Read); if(!pFile) { MFDebug_Warn(2, MFStr("Failed to open OBJ file %s", pFilename)); return 1; } uint64 size = MFFile_Seek(pFile, 0, MFSeek_End); MFFile_Seek(pFile, 0, MFSeek_Begin); char *pMem = (char*)MFHeap_Alloc((size_t)size+1); MFFile_Read(pFile, pMem, size); pMem[size] = 0; MFFile_Close(pFile); ParseOBJFile(pMem); MFHeap_Free(pMem); return 0; }
size_t GetWAVSamples(MFAudioStream *pStream, void *pBuffer, size_t bytes) { MFWAVStream *pWS = (MFWAVStream*)pStream->pStreamData; size_t read = MFFile_Read(pWS->pStream, pBuffer, MFMin(bytes, pWS->dataSize - pWS->sampleOffset)); pWS->sampleOffset += read; return read; }
uLong zread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) { return MFFile_Read((MFFile*)stream, buf, size, false); }
MF_API MFAnimation* MFAnimation_Create(const char *pFilename, MFModel *pModel) { MFAnimationTemplate *pTemplate = MFAnimation_FindTemplate(pFilename); if(!pTemplate) { size_t size = 0; pTemplate = (MFAnimationTemplate*)MFModelInternal_PendingAnimationTemplate(&size); if(!pTemplate) { MFFile *hFile = MFFileSystem_Open(MFStr("%s.anm", pFilename), MFOF_Read|MFOF_Binary); if(hFile) { size = (size_t)MFFile_GetSize(hFile); if(size > 0) { char *pTemplateData; // allocate memory and load file pTemplateData = (char*)MFHeap_Alloc(size + MFString_Length(pFilename) + 1); MFFile_Read(hFile, pTemplateData, size); pTemplate = (MFAnimationTemplate*)pTemplateData; // check ID string MFDebug_Assert(pTemplate->hash == MFMAKEFOURCC('A', 'N', 'M', '2'), "Incorrect MFAnimation version."); } MFFile_Close(hFile); } } if(!pTemplate) return NULL; pFilename = MFString_Copy((char*)pTemplate + size, pFilename); MFAnimation_FixUp(pTemplate, true); MFResource_AddResource(pTemplate, MFRT_AnimationTemplate, MFUtil_HashString(pFilename) ^ 0xA010A010, pFilename); } // get the model bone chunk MFModelDataChunk *pBoneChunk = MFModel_GetDataChunk(pModel->pTemplate, MFChunkType_Bones); MFDebug_Assert(pBoneChunk, "Cant apply animation to a model with no skeleton!"); // create and init instance MFAnimation *pAnimation; size_t bytes = MFALIGN16(sizeof(MFAnimation)) + sizeof(MFMatrix)*pBoneChunk->count + sizeof(int)*pBoneChunk->count + sizeof(MFAnimationCurrentFrame)*pBoneChunk->count; pAnimation = (MFAnimation*)MFHeap_Alloc(bytes); pAnimation->pModel = pModel; pAnimation->pTemplate = pTemplate; // add animation to model animation list pModel->pAnimation = pAnimation; // get bones pointer from model (for convenience) pAnimation->pBones = (MFModelBone*)pBoneChunk->pData; pAnimation->numBones = pBoneChunk->count; // set matrices to identity pAnimation->pMatrices = (MFMatrix*)MFALIGN16(&pAnimation[1]); for(int a=0; a<pBoneChunk->count; a++) { pAnimation->pMatrices[a] = MFMatrix::identity; } MFStateConstant_AnimationMatrices animMats; animMats.pMatrices = pAnimation->pMatrices; animMats.numMatrices = pAnimation->numBones; MFStateBlock_SetAnimMatrices(pModel->pEntityState, animMats); // build bone to animation stream mapping pAnimation->pBoneMap = (int*)MFALIGN16(&pAnimation->pMatrices[pBoneChunk->count]); for(int a=0; a<pBoneChunk->count; a++) { const char *pBoneName = MFModel_GetBoneName(pModel, a); // find bone in animation pAnimation->pBoneMap[a] = -1; for(uint32 b=0; b<pTemplate->numBones; b++) { if(!MFString_CaseCmp(pBoneName, pTemplate->pBones[b].pBoneName)) { pAnimation->pBoneMap[a] = b; break; } } } pAnimation->pCustomMatrices = NULL; pAnimation->blendLayer.frameTime = pAnimation->pTemplate->startTime; pAnimation->blendLayer.pCurFrames = (MFAnimationCurrentFrame*)&pAnimation->pBoneMap[pBoneChunk->count]; MFZeroMemory(pAnimation->blendLayer.pCurFrames, sizeof(MFAnimationCurrentFrame)*pBoneChunk->count); return pAnimation; }
// stdio signiture functions (these can be used as a callback to many libs and API's) MF_API size_t MFFile_StdRead(void *pBuffer, size_t size, size_t count, void* fileHandle) { return MFFile_Read((MFFile*)fileHandle, pBuffer, size*count, false); }
MF_API MFModel* MFModel_Create(const char *pFilename) { const char* pOriginalFilename = pFilename; // see if it's already loaded MFModelPool::Iterator it = gModelBank.Get(pOriginalFilename); MFModelTemplate *pTemplate = it ? *it : NULL; if(!pTemplate) { char *pTemplateData = NULL; MFFile *hFile = MFFileSystem_Open(MFStr("%s.mdl", pFilename), MFOF_Read|MFOF_Binary); if(hFile) { int64 size = MFFile_GetSize(hFile); if(size > 0) { // allocate memory and load file pTemplateData = (char*)MFHeap_Alloc((size_t)size + MFString_Length(pFilename) + 1); MFFile_Read(hFile, pTemplateData, (size_t)size); MFFile_Close(hFile); MFString_Copy(&pTemplateData[size], pFilename); pFilename = &pTemplateData[size]; } } else { #if defined(ALLOW_LOAD_FROM_SOURCE_DATA) // try to load from source data const char * const pExt[] = { ".f3d", ".dae", ".x", ".ase", ".obj", ".md2", ".md3", ".me2", NULL }; const char * const *ppExt = pExt; MFIntModel *pIM = NULL; while(!pIM && *ppExt) { MFString tempFilename = MFString::Format("%s%s", pFilename, *ppExt); pIM = MFIntModel_CreateFromFile(tempFilename.CStr()); if(pIM) { pFilename = MFString_Copy((char*)MFHeap_Alloc(tempFilename.NumBytes()+1), tempFilename.CStr()); break; } ++ppExt; } if(pIM) { MFIntModel_Optimise(pIM); size_t size; MFIntModel_CreateRuntimeData(pIM, (void**)&pTemplateData, &size, MFSystem_GetCurrentPlatform()); MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s.mdl", pOriginalFilename), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, pTemplateData, size, false); MFFile_Close(pFile); } MFIntModel_Destroy(pIM); } #endif } if(!pTemplateData) return NULL; // check ID string MFDebug_Assert(*(uint32*)pTemplateData == MFMAKEFOURCC('M', 'D', 'L', '2'), "Incorrect MFModel version."); // store filename for later reference pTemplate = (MFModelTemplate*)pTemplateData; pTemplate->pFilename = pFilename; gModelBank.Add(pOriginalFilename, pTemplate); MFModel_FixUp(pTemplate, true); MFModelDataChunk *pChunk = MFModel_GetDataChunk(pTemplate, MFChunkType_SubObjects); if(pChunk) { MFModelSubObject *pSubobjects = (MFModelSubObject*)pChunk->pData; for(int a=0; a<pChunk->count; a++) { // pSubobjects[a].pMaterial = MFMaterial_Create((char*)pSubobjects[a].pMaterial); for(int b=0; b<pSubobjects[a].numMeshChunks; b++) { MFModel_CreateMeshChunk(MFModel_GetMeshChunkInternal(pTemplate, a, b)); } } } } MFModel *pModel; pModel = (MFModel*)MFHeap_Alloc(sizeof(MFModel)); pModel->worldMatrix = MFMatrix::identity; pModel->modelColour = MFVector::one; pModel->pTemplate = pTemplate; pModel->pAnimation = NULL; ++pTemplate->refCount; return pModel; }
void CreateWAVStream(MFAudioStream *pStream, const char *pFilename) { MFCALLSTACK; // open wav file MFFile* hFile = MFFileSystem_Open(pFilename); if(!hFile) return; // attempt to cache the vorbis stream MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 256*1024; // 256k cache for wav stream should be heaps!! cachedOpen.pBaseFile = hFile; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hFile = pCachedFile; RIFFHeader header; MFFile_Read(hFile, &header, sizeof(header)); if(header.RIFF != MFMAKEFOURCC('R', 'I', 'F', 'F') || header.WAVE != MFMAKEFOURCC('W', 'A', 'V', 'E')) return; // not a .wav file... // if everything's good, and it appears to be a valid wav file MFWAVStream *pWS = (MFWAVStream*)MFHeap_AllocAndZero(sizeof(MFWAVStream)); pStream->pStreamData = pWS; pWS->pStream = hFile; size_t read; size_t fptr = sizeof(header); do { MFFile_Seek(hFile, fptr, MFSeek_Begin); WAVChunk dataChunk; MFZeroMemory(&dataChunk, sizeof(dataChunk)); read = MFFile_Read(hFile, &dataChunk, sizeof(dataChunk)); fptr += sizeof(dataChunk) + dataChunk.size; if(dataChunk.id == MFMAKEFOURCC('f', 'm', 't', ' ')) { read = MFFile_Read(hFile, &pWS->format, dataChunk.size); if(pWS->format.cbSize) read = (size_t)MFFile_Seek(hFile, pWS->format.cbSize, MFSeek_Current); } else if(dataChunk.id == MFMAKEFOURCC('d', 'a', 't', 'a')) { pWS->dataOffset = (size_t)MFFile_Tell(hFile); pWS->dataSize = dataChunk.size; } } while(read); // return to the start of the audio data MFFile_Seek(pWS->pStream, (int)pWS->dataOffset, MFSeek_Begin); // calculate the track length pWS->sampleSize = (pWS->format.nChannels * pWS->format.wBitsPerSample) >> 3; pStream->trackLength = (float)(pWS->dataSize / pWS->sampleSize) / (float)pWS->format.nSamplesPerSec; // fill out the stream info pStream->streamInfo.sampleRate = pWS->format.nSamplesPerSec; pStream->streamInfo.channels = pWS->format.nChannels; pStream->streamInfo.bitsPerSample = pWS->format.wBitsPerSample; pStream->streamInfo.bufferLength = pWS->format.nSamplesPerSec; }