MF_API MFVertexBuffer *MFVertex_CreateVertexBuffer(const MFVertexDeclaration *pVertexFormat, int numVerts, MFVertexBufferType type, void *pVertexBufferMemory, const char *pName) { int nameLen = pName ? MFString_Length(pName) + 1 : 0; MFVertexBuffer *pVB; if(type == MFVBType_Scratch) pVB = (MFVertexBuffer*)MFRenderer_AllocateScratchMemory(sizeof(MFVertexBuffer) + nameLen); else pVB = (MFVertexBuffer*)MFHeap_Alloc(sizeof(MFVertexBuffer) + nameLen); MFZeroMemory(pVB, sizeof(MFVertexBuffer)); if(pName) pName = MFString_Copy((char*)&pVB[1], pName); pVB->pVertexDeclatation = pVertexFormat; pVB->bufferType = type; pVB->numVerts = numVerts; if(!MFVertex_CreateVertexBufferPlatformSpecific(pVB, pVertexBufferMemory)) { if(type != MFVBType_Scratch) MFHeap_Free(pVB); return NULL; } if(type == MFVBType_Scratch) { // add to a scratch list that will be cleaned up later... pVB->pNextScratchBuffer = gpScratchBufferList; gpScratchBufferList = pVB; } else MFResource_AddResource(pVB, MFRT_VertexBuffer, (uint32)(MFUtil_HashPointer(pVB) & 0xFFFFFFFF), pName); return pVB; }
MF_API MFMaterial* MFMaterial_Create(const char *pName) { MFCALLSTACK; MFMaterial *pMat = MFMaterial_Find(pName); if(!pMat) { pMat = (MFMaterial*)MFHeap_AllocAndZero(sizeof(MFMaterial) + MFString_Length(pName) + 1); pName = MFString_Copy((char*)&pMat[1], pName); MFResource_AddResource(pMat, MFRT_Material, MFUtil_HashString(pName) ^ 0x0a7e01a1, pName); // TODO: how to determine size? pMat->pMaterialState = MFStateBlock_Create(256); pMat->bStateDirty = true; MaterialDefinition *pDef = pDefinitionRegistry; while(pDef) { MFIniLine *pLine = pDef->pIni->GetFirstLine()->FindEntry("section",pName); if (pLine) { MaterialInternal_InitialiseFromDefinition(pDef->pIni, pMat, pName); break; } pDef = pDef->pNextDefinition; } if(!pDef) { // assign material type pMat->pType = MaterialInternal_GetMaterialType("Standard"); pMat->pInstanceData = MFHeap_AllocAndZero(pMat->pType->instanceDataSize); pMat->pType->materialCallbacks.pCreateInstance(pMat); // set diffuse map parameter MFMaterial_SetParameterS(pMat, MFMatStandard_Texture, MFMatStandard_Tex_DifuseMap, pName); } } return pMat; }
MF_API MFIndexBuffer *MFVertex_CreateIndexBuffer(int numIndices, uint16 *pIndexBufferMemory, const char *pName) { int nameLen = pName ? MFString_Length(pName) + 1 : 0; MFIndexBuffer *pIB = (MFIndexBuffer*)MFHeap_AllocAndZero(sizeof(MFIndexBuffer) + nameLen); if(pName) pName = MFString_Copy((char*)&pIB[1], pName); pIB->numIndices = numIndices; if(!MFVertex_CreateIndexBufferPlatformSpecific(pIB, pIndexBufferMemory)) { MFHeap_Free(pIB); return NULL; } MFResource_AddResource(pIB, MFRT_IndexBuffer, (uint32)(MFUtil_HashPointer(pIB) & 0xFFFFFFFF), pName); return pIB; }
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 MFVertexDeclaration *MFVertex_CreateVertexDeclaration(const MFVertexElement *pElementArray, int elementCount) { // assign the auto format components before calculating the hash MFVertexElement elements[16]; MFCopyMemory(elements, pElementArray, sizeof(MFVertexElement)*elementCount); for(int e=0; e<elementCount; ++e) { if(pElementArray[e].format == MFVDF_Auto) elements[e].format = MFVertex_ChoooseVertexDataTypePlatformSpecific(pElementArray[e].type, pElementArray[e].componentCount); } uint32 hash = MFUtil_HashBuffer(elements, sizeof(MFVertexElement)*elementCount); MFVertexDeclaration *pDecl = (MFVertexDeclaration*)MFResource_Find(hash); if(!pDecl) { pDecl = (MFVertexDeclaration*)MFHeap_AllocAndZero(sizeof(MFVertexDeclaration) + (sizeof(MFVertexElement) + sizeof(MFVertexElementData))*elementCount); pDecl->numElements = elementCount; pDecl->pElements = (MFVertexElement*)&pDecl[1]; pDecl->pElementData = (MFVertexElementData*)&pDecl->pElements[elementCount]; MFCopyMemory(pDecl->pElements, elements, sizeof(MFVertexElement)*elementCount); int streamOffsets[16]; MFZeroMemory(streamOffsets, sizeof(streamOffsets)); // set the element data and calculate the strides for(int e=0; e<elementCount; ++e) { pDecl->pElementData[e].offset = streamOffsets[elements[e].stream]; pDecl->pElementData[e].stride = 0; streamOffsets[elements[e].stream] += gVertexDataStride[elements[e].format]; pDecl->streamsUsed |= MFBIT(elements[e].stream); } // set the strides for each component for(int e=0; e<elementCount; ++e) pDecl->pElementData[e].stride = streamOffsets[elements[e].stream]; if(!MFVertex_CreateVertexDeclarationPlatformSpecific(pDecl)) { MFHeap_Free(pDecl); return NULL; } MFResource_AddResource(pDecl, MFRT_VertexDecl, hash); if(pDecl->streamsUsed != 1) { // create the stream declarations... MFVertexElement streamElements[64]; for(int s=0; s<16; ++s) { if(!(pDecl->streamsUsed & (1 << s))) continue; int numStreamElements = 0; for(int e=0; e<elementCount; ++e) { if(elements[e].stream == s) { streamElements[numStreamElements] = elements[e]; streamElements[numStreamElements].stream = 0; ++numStreamElements; } } if(numStreamElements) pDecl->pStreamDecl[s] = MFVertex_CreateVertexDeclaration(streamElements, numStreamElements); } } } return pDecl; }