MF_API bool MFAsset_ConvertModelAndAnimationFromFile(const char *pFilename, void **ppMesh, size_t *pMeshSize, void **ppAnimation, size_t *pAnimationSize, MFPlatform platform, size_t extraBytes) { // should this request be forewarded to the file server, or should we do it locally? //... todo if(!MFIntAsset_ConvertModelAndAnimationFromFile(pFilename, ppMesh, pMeshSize, ppAnimation, pAnimationSize, platform, extraBytes)) return false; if(ppMesh && *ppMesh) { MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s.mdl", pFilename), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, *ppMesh, *pMeshSize, false); MFFile_Close(pFile); } } if(ppAnimation && *ppAnimation) { MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s.anm", pFilename), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, *ppAnimation, *pAnimationSize, false); MFFile_Close(pFile); } } return true; }
// 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; }
MF_API bool MFAsset_ConvertAssetFromFile(const char *pFilename, void **ppOutput, size_t *pSize, MFPlatform platform, size_t extraBytes) { // should this request be forewarded to the file server, or should we do it locally? //... todo size_t size; if(!MFIntAsset_ConvertAssetFromFile(pFilename, ppOutput, &size, platform, extraBytes) || !*ppOutput) return false; if(pSize) *pSize = size; const char *pExt = MFString_GetFileExtension(pFilename); const char *pCacheExt = NULL; if(!MFString_CaseCmp(pExt, ".mfx")) pCacheExt = ".bfx"; else if(!MFString_CaseCmp(pExt, ".fnt")) pCacheExt = ".fft"; else if(!MFAsset_IsSoundFile(pExt)) pCacheExt = ".snd"; else if(!MFAsset_IsImageFile(pExt)) pCacheExt = ".tex"; else if(!MFAsset_IsGeometryFile(pExt)) pCacheExt = ".mdl"; else if(!MFAsset_IsShaderFile(pExt)) pCacheExt = ".fsh"; MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s%s", pFilename, pCacheExt), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, *ppOutput, size, false); MFFile_Close(pFile); } return true; }
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; }
// returns true if the file can be found within the mounted filesystem stack MF_API bool MFFileSystem_Exists(const char *pFilename) { MFCALLSTACK; bool exists = false; MFFile *hFile = MFFileSystem_Open(pFilename, MFOF_Read|MFOF_Binary|MFOF_TryOpen); if(hFile) { exists = true; MFFile_Close(hFile); } return exists; }
// if file does not exist, GetSize returns 0, however, a zero length file can also return 0 use 'Exists' to confirm MF_API uint64 MFFileSystem_GetSize(const char *pFilename) { MFCALLSTACK; uint64 size = 0; MFFile *hFile = MFFileSystem_Open(pFilename, MFOF_Read|MFOF_Binary); if(hFile) { size = MFFile_GetSize(hFile); MFFile_Close(hFile); } return size; }
MF_API size_t MFFileSystem_Save(const char *pFilename, const char *pBuffer, size_t size) { MFDebug_Log(5, MFStr("Call: MFFileSystem_Save(\"%s\")", pFilename)); size_t bytesWritten = 0; MFFile *hFile = MFFileSystem_Open(pFilename, MFOF_Write|MFOF_Truncate|MFOF_Binary|MFOF_CreateDirectory); if(hFile) { bytesWritten = MFFile_Write(hFile, pBuffer, size, false); MFFile_Close(hFile); } return bytesWritten; }
MF_API bool MFAsset_ConvertShaderFromFile(const char *pFilename, void **ppOutput, size_t *pSize, MFPlatform platform, MFShaderType shaderType, MFShaderMacro *pMacros, MFRendererDrivers renderDriver, MFShaderLanguage language) { // should this request be forewarded to the file server, or should we do it locally? //... todo if(!MFIntAsset_ConvertShaderFromFile(pFilename, ppOutput, pSize, platform, shaderType, pMacros, renderDriver, language)) return false; MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s.fsh", pFilename), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, *ppOutput, *pSize, false); MFFile_Close(pFile); } return true; }
MF_API bool MFAsset_ConvertTextureFromFile(const char *pFilename, void **ppOutput, size_t *pSize, MFPlatform platform, uint32 flags, MFImageFormat targetFormat, size_t extraBytes) { // should this request be forewarded to the file server, or should we do it locally? //... todo if(!MFIntAsset_ConvertTextureFromFile(pFilename, ppOutput, pSize, platform, flags, targetFormat, extraBytes)) return false; MFFile *pFile = MFFileSystem_Open(MFStr("cache:%s.tex", pFilename), MFOF_Write | MFOF_Binary); if(pFile) { MFFile_Write(pFile, *ppOutput, *pSize, false); MFFile_Close(pFile); } return true; }
void MFFileSystem_DeinitModule() { GET_MODULE_DATA(MFFileSystemState); if(pModuleData->hDataArchive) { MFFile_Close(pModuleData->hDataArchive); } MFFileSystemHTTP_DeinitModule(); MFFileSystemZipFile_DeinitModule(); MFFileSystemCachedFile_DeinitModule(); MFFileSystemMemory_DeinitModule(); MFFileSystemNative_DeinitModule(); MFHeap_Free(pModuleData->ppFileSystemList); pModuleData->gFileSystems.Deinit(); pModuleData->gOpenFiles.Deinit(); pModuleData->gFinds.Deinit(); }
MF_API const char *MFFileSystem_ResolveSystemPath(const char *pFilename, bool bAbsolute) { MFFile *pFile = MFFileSystem_Open(pFilename, MFOF_Read|MFOF_Binary); const char *pPath = NULL; if(pFile) { GET_MODULE_DATA(MFFileSystemState); // TODO: support other filesystems that forward to the native filesystem (like cache filesystem?) if(pFile->filesystem == pModuleData->hNativeFileSystem) pPath = MFStr(pFile->fileIdentifier); MFFile_Close(pFile); } // convert to absolute... if(bAbsolute) pPath = MFFileNative_MakeAbsolute(pPath); return pPath; }
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; }
MF_API int MFFile_StdClose(void* fileHandle) { return MFFile_Close((MFFile*)fileHandle); }
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 DestroyWAVStream(MFAudioStream *pStream) { MFWAVStream *pWS = (MFWAVStream*)pStream->pStreamData; MFFile_Close(pWS->pStream); MFHeap_Free(pWS); }