void ParseID3(MFAudioStream *pStream, MFID3 *pID3, int dataSize) { unsigned char *pData = pID3->pID3Data; while(pData - pID3->pID3Data <= dataSize) { if(pID3->major == 2) { // for the moment, to be safe... // MFDebug_Assert(false, "Make this work!!"); return; //int size = (int)pData[5] | ((int)pData[4] << 7) | ((int)pData[3] << 14); //pData += 6 + size; } if(pID3->major > 2) { ID3Chunk *pChunkHeader = (ID3Chunk*)pData; int size = GetSynchSafeInt(pData + 4); if(*pData == 'T') { //uint8 encoding = pData[10]; const char *pString = (const char*)pData + 11; switch(pChunkHeader->id) { case MFMAKEFOURCC('T', 'I', 'T', '2'): MFString_CopyN(pStream->streamInfo.songName, pString, MFMin(size-1, (int)sizeof(pStream->streamInfo.songName)-1)); break; case MFMAKEFOURCC('T', 'A', 'L', 'B'): MFString_CopyN(pStream->streamInfo.albumName, pString, MFMin(size-1, (int)sizeof(pStream->streamInfo.albumName)-1)); break; case MFMAKEFOURCC('T', 'P', 'E', '1'): case MFMAKEFOURCC('T', 'P', 'E', '2'): MFString_CopyN(pStream->streamInfo.artistName, pString, MFMin(size-1, (int)sizeof(pStream->streamInfo.artistName)-1)); break; case MFMAKEFOURCC('T', 'C', 'O', 'N'): MFString_CopyN(pStream->streamInfo.genre, pString, MFMin(size-1, (int)sizeof(pStream->streamInfo.genre)-1)); break; } } pData += 10 + size; } } }
MF_API MFTexture* MFTexture_CreateRenderTarget(const char *pName, int width, int height, MFTextureFormat targetFormat) { MFTexture *pTexture = MFTexture_FindTexture(pName); if(!pTexture) { pTexture = &gTextureBank.Create(pName); if(targetFormat & TexFmt_SelectNicest) { targetFormat = TexFmt_A8R8G8B8; } pTexture->pTemplateData = (MFTextureTemplateData*)MFHeap_AllocAndZero(sizeof(MFTextureTemplateData) + sizeof(MFTextureSurfaceLevel)); pTexture->pTemplateData->pSurfaces = (MFTextureSurfaceLevel*)&pTexture->pTemplateData[1]; pTexture->pTemplateData->magicNumber = MFMAKEFOURCC('F','T','E','X'); pTexture->pTemplateData->imageFormat = targetFormat; pTexture->pTemplateData->mipLevels = 1; pTexture->pTemplateData->flags = TEX_RenderTarget; pTexture->pTemplateData->pSurfaces->width = width; pTexture->pTemplateData->pSurfaces->height = height; pTexture->pTemplateData->pSurfaces->bitsPerPixel = MFTexture_GetBitsPerPixel(pTexture->pTemplateData->imageFormat); pTexture->pTemplateData->pSurfaces->xBlocks = width; pTexture->pTemplateData->pSurfaces->yBlocks = height; pTexture->pTemplateData->pSurfaces->bitsPerBlock = pTexture->pTemplateData->pSurfaces->bitsPerPixel; pTexture->pTemplateData->pSurfaces->pImageData = NULL; pTexture->pTemplateData->pSurfaces->bufferLength = 0; pTexture->pTemplateData->pSurfaces->pPaletteEntries = NULL; pTexture->pTemplateData->pSurfaces->paletteBufferLength = 0; pTexture->refCount = 1; MFString_CopyN(pTexture->name, pName, sizeof(pTexture->name) - 1); pTexture->name[sizeof(pTexture->name) - 1] = 0; D3DFORMAT platformFormat = (D3DFORMAT)MFTexture_GetPlatformFormatID(targetFormat, MFDD_D3D9); HRESULT hr = pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, platformFormat, D3DPOOL_DEFAULT, (IDirect3DTexture9**)&pTexture->pInternalData, NULL); if(hr != D3D_OK) { MFHeap_Free(pTexture->pTemplateData); gTextureBank.DestroyItem(*pTexture); pTexture = NULL; } } else { pTexture->refCount++; } return pTexture; }
MF_API MFIntSound *MFIntSound_CreateFromFile(const char *pFilename) { MFAudioStream *pStream = MFSound_CreateStream(pFilename, MFASF_DecodeOnly | MFASF_QueryLength); if(!pStream) return NULL; MFIntSound *pSound = (MFIntSound*)MFHeap_Alloc(sizeof(MFIntSound)); pSound->pInternal = pStream; pSound->soundTemplate.magic = MFMAKEFOURCC('S', 'N', 'D', '1'); pSound->soundTemplate.format = pStream->streamInfo.bitsPerSample == 8 ? MFWaveFmt_PCM_u8 : (pStream->streamInfo.bitsPerSample == 24 ? MFWaveFmt_PCM_s24 : MFWaveFmt_PCM_s16); pSound->soundTemplate.flags = 0; pSound->soundTemplate.sampleRate = pStream->streamInfo.sampleRate; pSound->soundTemplate.numSamples = 0; pSound->soundTemplate.bitsPerSample = pStream->streamInfo.bitsPerSample; pSound->soundTemplate.numChannels = (uint16)pStream->streamInfo.channels; pSound->soundTemplate.numStreams = 1; return pSound; }
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; }
int main(int argc, char *argv[]) { MFPlatform platform = FP_Unknown; MFWaveFormat targetFormat = MFWF_PCM_s16; char fileName[256] = ""; char outFile[256] = ""; int a; // process command line for(a=1; a<argc; a++) { if(argv[a][0] == '-' || argv[a][0] == '/') { for(int b=0; b<FP_Max; b++) { if(!MFString_CaseCmp(&argv[a][1], MFSystem_GetPlatformString(b))) { platform = (MFPlatform)b; break; } } if(!MFString_CaseCmp(&argv[a][1], "v") || !MFString_CaseCmp(&argv[a][1], "version")) { // print version return 0; } } else { if(!fileName[0]) MFString_Copy(fileName, argv[a]); else if(!outFile[0]) MFString_Copy(outFile, argv[a]); } } if(platform == FP_Unknown) { LOGERROR("No platform specified...\n"); return 1; } if(!fileName[0]) { LOGERROR("No file specified...\n"); return 1; } if(!outFile[0]) { // generate output filename MFString_Copy(outFile, fileName); for(int i=MFString_Length(outFile); --i; ) { if(outFile[i] == '.') { outFile[i] = 0; break; } } MFString_Cat(outFile, ".snd"); } // load image char *pBuffer; FILE *pFile = fopen(fileName, "rb"); if(!pFile) { LOGERROR("Couldnt open source file '%s' for reading.", fileName); return 1; } fseek(pFile, 0, SEEK_END); int bytes = ftell(pFile) + 1; fseek(pFile, 0, SEEK_SET); pBuffer = (char*)malloc(bytes); fread(pBuffer, bytes, 1, pFile); fclose(pFile); FILE *pOutFile = fopen(outFile, "wb"); if(!pOutFile) { LOGERROR("Couldnt open output file '%s' for writing.", outFile); return 2; } // parse the sound file... WAVHeader *pHeader = (WAVHeader*)pBuffer; if(pHeader->RIFF != MFMAKEFOURCC('R', 'I', 'F', 'F') || pHeader->WAVE != MFMAKEFOURCC('W', 'A', 'V', 'E')) { LOGERROR("Source file '%s' is not a wave file.", fileName); return 1; } WAVChunk *pChunk = (WAVChunk*)&pHeader[1]; WAVFormatChunk *pFormat = NULL; WAVDataChunk *pData = NULL; while((char*)pChunk - pBuffer < bytes && bytes - ((char*)pChunk - pBuffer) >= sizeof(WAVChunk)) { if(pChunk->id == MFMAKEFOURCC('f', 'm', 't', ' ')) { pFormat = (WAVFormatChunk*)pChunk; } else if(pChunk->id == MFMAKEFOURCC('d', 'a', 't', 'a')) { pData = (WAVDataChunk*)pChunk; } pChunk = (WAVChunk*)((char*)pChunk + sizeof(WAVChunk) + ((pChunk->size+1) & ~1)); } if(!pFormat || !pData) { LOGERROR("WAVE file '%s' has no format or data chunks.", fileName); return 2; } // we only output 1 stream for now.. int numStreams = 1; int numSamples = ((pData->size*8) / ((pFormat->wBitsPerSample + 7) & ~7)) / pFormat->nChannels; int fileSize = sizeof(MFSoundTemplate) + sizeof(char*)*numStreams + bytesPerSample[targetFormat]*pFormat->nChannels*numSamples*numStreams; char *pSndFile = (char*)MFHeap_Alloc(fileSize); MFSoundTemplate *pTemplate = (MFSoundTemplate*)pSndFile; pTemplate->ppStreams = (char **)&pTemplate[1]; char *pWaveData = (char*)&pTemplate->ppStreams[numStreams]; for(int a=0; a<numStreams; a++) { pTemplate->ppStreams[a] = pWaveData; pWaveData += bytesPerSample[targetFormat]*pFormat->nChannels*numSamples; } pTemplate->magic = MFMAKEFOURCC('S', 'N', 'D', '1'); pTemplate->flags = 0; pTemplate->format = targetFormat; pTemplate->numSamples = numSamples; pTemplate->numStreams = numStreams; pTemplate->numChannels = pFormat->nChannels; pTemplate->bitsPerSample = bytesPerSample[targetFormat]*8; pTemplate->sampleRate = pFormat->nSamplesPerSec; // write wave data into file if(pTemplate->bitsPerSample == pFormat->wBitsPerSample) { for(int a=0; a<pTemplate->numStreams; a++) MFCopyMemory(pTemplate->ppStreams[a], pData->data, bytesPerSample[targetFormat]*pTemplate->numChannels*pTemplate->numSamples); } else { // do a format conversion LOGERROR("Format conversion not written."); return 3; } // fix up template for(int a=0; a<numStreams; a++) MFFixUp(pTemplate->ppStreams[a], pTemplate, false); MFFixUp(pTemplate->ppStreams, pTemplate, false); // write to disk fwrite(pSndFile, fileSize, 1, pOutFile); fclose(pOutFile); printf("> %s\n", outFile); return 0; }
25, // D3DFMT_A1R5G5B5 // TexFmt_A1R5G5B5 0, // // TexFmt_R5G5B5A1 0, // // TexFmt_A1B5G5R5 26, // D3DFMT_A4R4G4B4 // TexFmt_A4R4G4B4 0, // // TexFmt_A4B4G4R4 0, // // TexFmt_R4G4B4A4 113,// D3DFMT_A16B16G16R16F // TexFmt_ABGR_F16 116,// D3DFMT_A32B32G32R32F // TexFmt_ABGR_F32 41, // D3DFMT_P8 // TexFmt_I8 0, // // TexFmt_I4 MFMAKEFOURCC('D', 'X', 'T', '1'), // D3DFMT_DXT1 // TexFmt_DXT1 MFMAKEFOURCC('D', 'X', 'T', '2'), // D3DFMT_DXT2 // TexFmt_DXT2 MFMAKEFOURCC('D', 'X', 'T', '3'), // D3DFMT_DXT3 // TexFmt_DXT3 MFMAKEFOURCC('D', 'X', 'T', '4'), // D3DFMT_DXT4 // TexFmt_DXT4 MFMAKEFOURCC('D', 'X', 'T', '5'), // D3DFMT_DXT5 // TexFmt_DXT5 0, // TexFmt_PSP_DXT1 0, // TexFmt_PSP_DXT3 0, // TexFmt_PSP_DXT5 0, // TexFmt_XB_A8R8G8B8 0, // TexFmt_XB_A8B8G8R8 0, // TexFmt_XB_B8G8R8A8 0, // TexFmt_XB_R8G8B8A8 0, // TexFmt_XB_R5G6B5
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; }