Alright. Here is my cpp file (it's not completed yet):
// X-File Loader// Sirius Engine#include "stdafx.h"#include "Log.h"#include "GMain.h"#include "XFileLoader.h"enum XFileMethod{ D3DNONINDEXED, D3DINDEXED, SOFTWARE, D3DINDEXEDVS, D3DINDEXEDHLSLVS, NONE};struct D3DXFRAME_DERIVED : public D3DXFRAME{ D3DXMATRIXA16 CombinedTransformationMatrix;};struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER{ LPDIRECT3DTEXTURE9 * TextureArray; LPD3DXMESH OriginalMesh; LPD3DXATTRIBUTERANGE AttributeTable; DWORD AttributeGroupCount; DWORD InflCount; LPD3DXBUFFER BoneCombinationBuffer; D3DXMATRIX ** BoneMatrixPointers; D3DXMATRIX * BoneOffsetMatrices; DWORD PaletteEntryCount; BOOL UseSoftwareVP; DWORD AttributeSW; // used for non-indexed skinning};BOOL AllocateName(LPCTSTR Name, LPTSTR * NewName){ UINT Length; if(Name != NULL){ Length = lstrlen(Name) + 1; *NewName = new TCHAR[Length]; if(*NewName == NULL) return FALSE; memcpy(*NewName, Name, Length * sizeof(TCHAR)); }else *NewName = NULL; return TRUE;}HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR Name, LPD3DXFRAME * NewFrame){ D3DXFRAME_DERIVED * Frame; Frame = new D3DXFRAME_DERIVED; *NewFrame = NULL; if(Frame == NULL){ delete Frame; return E_FAIL; } if(FAILED(AllocateName(Name, &Frame->Name))){ delete Frame; return E_FAIL; } // Initialize other data members of the frame D3DXMatrixIdentity(&Frame->TransformationMatrix); D3DXMatrixIdentity(&Frame->CombinedTransformationMatrix); Frame->pMeshContainer = NULL; Frame->pFrameSibling = NULL; Frame->pFrameFirstChild = NULL; *NewFrame = Frame; Frame = NULL; delete Frame; return S_OK;}HRESULT CAllocateHierarchy::CreateMeshContainer(LPCTSTR Name, LPD3DXMESHDATA MeshData, LPD3DXMATERIAL Materials, LPD3DXEFFECTINSTANCE EffectInstances, DWORD MaterialCount, DWORD * Adjacency, LPD3DXSKININFO SkinInfo, LPD3DXMESHCONTAINER * NewMeshContainer){ D3DXMESHCONTAINER_DERIVED * MeshContainer = NULL; UINT FaceCount; UINT Material; UINT Bone, Bones; LPD3DXMESH Mesh = NULL; LPDIRECT3DDEVICE9 Device = NULL; *NewMeshContainer = NULL; if(MeshData->Type != D3DXMESHTYPE_MESH){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } Mesh = MeshData->pMesh; if(Mesh->GetFVF() == NULL){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } MeshContainer = new D3DXMESHCONTAINER_DERIVED; if(MeshContainer == NULL){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_OUTOFMEMORY; } memset(MeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED)); if(!AllocateName(Name, &MeshContainer->Name)){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } Mesh->GetDevice(&Device); FaceCount = Mesh->GetNumFaces(); // if no normals are in the mesh, add them if(!(Mesh->GetFVF() & D3DFVF_NORMAL)){ MeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; if(FAILED(Mesh->CloneMeshFVF(Mesh->GetOptions(), Mesh->GetFVF() | D3DFVF_NORMAL, Device, &MeshContainer->MeshData.pMesh))){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } Mesh = MeshContainer->MeshData.pMesh; D3DXComputeNormals(pMesh, NULL); }else{ MeshContainer->MeshData.pMesh = Mesh; MeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; Mesh->AddRef(); } // Allocate memory to contain the material information. MeshContainer->NumMaterials = max(1, MaterialCount); MeshContainer->pMaterials = new D3DXMATERIAL[MeshContainer->NumMaterials]; MeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[MeshContainer->NumMaterials]; MeshContainer->pAdjacency = new DWORD[FaceCount * 3]; if((MeshContainer->pAdjacency == NULL) || (MeshContainer->pMaterials == NULL)){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } memcpy(MeshContainer->pAdjacency, Adjacency, sizeof(DWORD) * FaceCount * 3); memcpy(MeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * MeshContainer->NumMaterials); // Copy materials if they are present if(MaterialCount > 0){ memcpy(MeshContainer->pMaterials, Materials, sizeof(D3DXMATERIAL) * MaterialCount); for(Material = 0; Material < MaterialCount; Material++){ if(MeshContainer->pMaterials[Material].pTextureFilename != NULL){ TCHAR TexturePath[MAX_PATH] = _T(""); DXUtil_FindMediaFileCb(TexturePath, sizeof(TexturePath), MeshContainer->pMaterials[Material].pTextureFilename); if(FAILED(D3DXCreateTextureFromFile(Device, TexturePath, &MeshContainer->ppTextures[Material]))) MeshContainer->ppTextures[Material] = NULL; // Don't remember a pointer into dynamic memory, just forget the name after loading MeshContainer->pMaterials[Material].pTextureFilename = NULL; } } }else{ // No materials provided, use a default white one instead MeshContainer->pMaterials[0].pTextureFilename = NULL; memset(&MeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); MeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; MeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; MeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; MeshContainer->pMaterials[0].MatD3D.Specular = MeshContainer->pMaterials[0].MatD3D.Diffuse; } // If there is skinning information, save it and setup for HW skinning if(SkinInfo != NULL){ // First save SkinInfo and original mesh data MeshContainer->pSkinInfo = SkinInfo; SkinInfo->AddRef(); MeshContainer->OriginalMesh = Mesh; Mesh->AddRef(); // We will need an array of offset matrices to move the vertices from the figure space to the bone's space Bones = SkinInfo->GetNumBones(); MeshContainer->BoneOffsetMatrices = new D3DXMATRIX[Bones]; if(MeshContainer->BoneOffsetMatrices == NULL){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } // Get each one of the bone offset matrices so that we don't need to get them later for(Bone = 0; Bone < Bones; Bone++) MeshContainer->BoneOffsetMatrices[Bone] = *(MeshContainer->pSkinInfo->GetBoneOffsetMatrix(Bone)); // GenerateSkinMesh will take the general skinning information and transform it into a HW friendly version if(FAILED(m_XFile->GenerateSkinnedMesh(MeshContainer, m_D3DCaps, Device, m_XFile->GetSkinningMethod()))){ RCOM(Device); DestroyMeshContainer(MeshContainer); return E_FAIL; } } *NewMeshContainer = MeshContainer; MeshContainer = NULL; return S_OK;}HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME FrameToFree){ SAFE_DELETE_ARRAY(FrameToFree->Name); SAFE_DELETE(FrameToFree); return S_OK;}HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER MeshContainerBase){ UINT Material; D3DXMESHCONTAINER_DERIVED * MeshContainer = (D3DXMESHCONTAINER_DERIVED*) MeshContainerBase; SAFE_DELETE_ARRAY(MeshContainer->Name); SAFE_DELETE_ARRAY(MeshContainer->pAdjacency); SAFE_DELETE_ARRAY(MeshContainer->pMaterials); SAFE_DELETE_ARRAY(MeshContainer->BoneOffsetMatrices); // Release all allocated textures if(MeshContainer->ppTextures != NULL){ for(Material = 0; Material < MeshContainer->NumMaterials; Material++) SAFE_RELEASE(MeshContainer->ppTextures[Material]); } SAFE_DELETE_ARRAY(MeshContainer->ppTextures); SAFE_DELETE_ARRAY(MeshContainer->BoneMatrixPointers); SAFE_RELEASE(MeshContainer->BoneCombinationBuffer); SAFE_RELEASE(MeshContainer->MeshData.pMesh); SAFE_RELEASE(MeshContainer->pSkinInfo); SAFE_RELEASE(MeshContainer->OriginalMesh); SAFE_DELETE(MeshContainer); return S_OK;}CXFile::CXFile(){ m_AnimCtrl = NULL; m_FrameRoot = NULL; m_SkinningMethod = D3DNONINDEXED; m_BoneMatrices = NULL; m_BoneMatrixMax = NULL;}BOOL CXFile::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED * MeshContainer, D3DCAPS9 D3DCaps, XFileMethod SkinningMethod){ if(MeshContainer->pSkinInfo == NULL) return FALSE; SAFE_RELEASE(MeshContainer->MeshData.pMesh); SAFE_RELEASE(MeshContainer->BoneCombinationBuffer); switch(SkinningMethod){ case D3DNONINDEXED:{ // Use ConvertToBlendedMesh to generate drawable mesh if(FAILED(MeshContainer->pSkinInfo->ConvertToBlendedMesh(MeshContainer->OriginalMesh, D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE, MeshContainer->pAdjacency, NULL, NULL, NULL, &MeshContainer->InflCount, &MeshContainer->AttributeGroupCount, &MeshContainer->BoneCombinationBuffer, &MeshContainer->MeshData.pMesh))) return FALSE; /* If the device can only do two matrix blends, ConvertToBlendedMesh cannot approximate all meshes to it. So we split the mesh into two parts: The one that uses at most 2 matrices and the rest. The first is drawn using the device's HW vertex processing and the rest is drawn using SW vertex processing */ LPD3DXBONECOMBINATION BoneCombinations = reinterpret_cast<LPD3DXBONECOMBINATION>(MeshContainer->BoneCombinationBuffer->GetBufferPointer()); // Look for any set of bone combinations that do not fit the caps for(MeshContainer->AttributeSW = 0; MeshContainer->AttributeSW < MeshContainer->AttributeGroupCount; MeshContainer->AttributeSW++){ DWORD i = 0; for(DWORD j = 0; j < MeshContainer->InflCount; j++){ if(BoneCombinations[MeshContainer->AttributeSW].BoneId[j] != UINT_MAX) i++; } if(i > D3DCaps.MaxVertexBlendMatrices) break; } // If there is both HW and SW, add the Software Processing flag if(MeshContainer->AttributeSW < MeshContainer->AttributeGroupCount){ LPD3DXMESH TempMesh; if(FAILED(MeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING | MeshContainer->MeshData.pMesh->GetOptions(), MeshContainer->MeshData.pMesh->GetFVF(), m_Graphics->GetDevice(), &TempMesh))) return FALSE; MeshContainer->MeshData.pMesh->Release(); MeshContainer->MeshData.pMesh = TempMesh; TempMesh = NULL; } } break; case D3DINDEXED:{ // Use ConvertToIndexedBlendedMesh to generate drawable mesh DWORD MaxFaceInflCount; DWORD Flags = D3DXMESHOPT_VERTEXCACHE; LPDIRECT3DINDEXBUFFER9 IB; if(FAILED(MeshContainer->OriginalMesh->GetIndexBuffer(&IB))) return FALSE; if(FAILED(MeshContainer->pSkinInfo->GetMaxFaceInfluences(IB, MeshContainer->OriginalMesh->GetNumFaces(), &MaxFaceInflCount))) return FALSE; // 12 entry palette guarentees that any triangle (4 independant influences per vertex of a triangle) // can be handled MaxFaceInflCount = min(MaxFaceInflCount, 12); if(D3DCaps.MaxVertexBlendMatrixIndex + 1 < MaxFaceInflCount){ // HW does not support indexed vertex blending. Use SW instead MeshContainer->PaletteEntryCount = min(256, MeshContainer->pSkinInfo->GetNumBones()); MeshContainer->UseSoftwareVP = TRUE; Flags |= D3DXMESH_SYSTEMMEM; }else{ /* Using hardware - determine palette size from caps and number of bones. If normals are present in the vertex data that need to be blended for lighting, then the number of matricies is half the number specified by MaxVertexBlendMatrixIndex. */ MeshContainer->PaletteEntryCount = min((D3DCaps.MaxVertexBlendMatrixIndex + 1) / 2, MeshContainer->pSkinInfo->GetNumBones()); MeshContainer->UseSoftwareVP = FALSE; Flags |= D3DXMESH_MANAGED; } if(FAILED(MeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh(MeshContainer->OriginalMesh, Flags, MeshContainer->PaletteEntryCount, MeshContainer->pAdjacency, NULL, NULL, NULL, &MeshContainer->InflCount, &MeshContainer->AttributeGroupCount, &MeshContainer->BoneCombinationBuffer, &MeshContainer->MeshData.pMesh))) return FALSE; } break; case (D3DINDEXEDVS || D3DINDEXEDHLSLVS):{ // Get palette size. First 9 constants are used for other data. Each 4x3 matrix takes up 3 constants. // (96 - 9) / 3 i.e. Maximum constants count - used constants UINT MaxMatrices = 26; MeshContainer->PaletteEntryCount = min(MaxMatrices, MeshContainer->pSkinInfo->GetNumBones()); DWORD Flags = D3DXMESHOPT_VERTEXCACHE; if(D3DCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1)){ MeshContainer->UseSoftwareVP = FALSE; Flags |= D3DXMESH_MANAGED; }else{ MeshContainer->UseSoftwareVP = TRUE; Flags |= D3DXMESH_SYSTEMMEM; } SAFE_RELEASE(MeshContainer->MeshData.pMesh); if(FAILED(MeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh(MeshContainer->OriginalMesh, Flags, MeshContainer->PaletteEntryCount, MeshContainer->pAdjacency, NULL, NULL, NULL, &MeshContainer->InflCount, &MeshContainer->AttributeGroupCount, &MeshContainer->BoneCombinationBuffer, &MeshContainer->MeshData.pMesh))) return FALSE; DWORD NewFVF = (MeshContainer->MeshData.pMesh->GetFVF() & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL |D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4; if(NewFVF != MeshContainer->MeshData.pMesh->GetFVF()){ LPD3DXMESH Mesh; if(SUCCEEDED(MeshContainer->MeshData.pMesh->CloneMeshFVF(MeshContainer->MeshData.pMesh->GetOptions(), NewFVF, m_Graphics->GetDevice(), &Mesh))){ MeshContainer->MeshData.pMesh->Release(); MeshContainer->MeshData.pMesh = Mesh; Mesh = NULL; } } D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE]; LPD3DVERTEXELEMENT9 DeclareCur; if(FAILED(MeshContainer->MeshData.pMesh->GetDeclaration(Declaration))) return FALSE; // The vertex shader is expecting to interpret the UBYTE4 as a D3DCOLOR, so update the type // NOTE: This cannot be done with CloneMesh, that would convert the UBYTE4 data to float and then to D3DCOLOR // This is more of a "cast" operation. DeclareCur = Declaration; while(DeclareCur->Stream != 0xff){ if((DeclareCur->Usage == D3DDECLUSAGE_BLENDINDICES) && (DeclareCur->UsageIndex == 0)) DeclareCur->Type = D3DDECLTYPE_D3DCOLOR; DeclareCur++; } if(FAILED(MeshContainer->MeshData.pMesh->UpdateSemantics(Declaration))) return FALSE; // Allocate a buffer for bone matrices, but only if another // mesh has not allocated one for the same size or larger if(m_BoneMatrixMax < MeshContainer->pSkinInfo->GetNumBones()){ m_BoneMatrixMax = MeshContainer->pSkinInfo->GetNumBones(); // Allocate space for blend matrices delete [] m_BoneMatrices; m_BoneMatrices = new D3DXMATRIXA16[m_BoneMatrixMax]; if(m_BoneMatrices == NULL) return FALSE; } } break; case SOFTWARE:{ // If software skinning selected, use GenerateSkinnedMesh to create // a mesh that can be used with UpdateSkinMesh if(FAILED(MeshContainer->OriginalMesh->CloneMeshFVF(D3DXMESH_MANAGED, MeshContainer->OriginalMesh->GetFVF(), m_Graphics->GetDevice(), &MeshContainer->MeshData.pMesh))) return FALSE; if(FAILED(MeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &MeshContainer->AttributeGroupCount))) return FALSE; delete[] MeshContainer->AttributeTable; MeshContainer->AttributeTable = new D3DXATTRIBUTERANGE[MeshContainer->AttributeGroupCount]; if(MeshContainer->AttributeTable == NULL) return FALSE; if(FAILED(MeshContainer->MeshData.pMesh->GetAttributeTable(MeshContainer->AttributeTable, NULL))) return FALSE; // Allocate a buffer for bone matrices, but only if another mesh has not allocated one // of the same size or larger if(m_BoneMatrixMax < MeshContainer->pSkinInfo->GetNumBones()){ m_BoneMatrixMax = MeshContainer->pSkinInfo->GetNumBones(); // Allocate space for blend matrices delete[] m_BoneMatrices; m_BoneMatrices = new D3DXMATRIXA16[m_BoneMatrixMax]; if(m_BoneMatrices == NULL) return FALSE; } } break; default: return FALSE; } return TRUE;}void CXFile::DrawMeshContainer(LPD3DXMESHCONTAINER MeshContainerBase, LPD3DXFRAME FrameBase, D3DCAPS9 D3DCaps, D3DXMATRIXA16 ViewMatrix){ D3DXMESHCONTAINER_DERIVED * MeshContainer = (D3DXMESHCONTAINER_DERIVED*)MeshContainerBase; D3DXFRAME_DERIVED * Frame = (D3DXFRAME_DERIVED*)FrameBase; UINT Material, BlendCount, Attribute, PrevAttributeId; LPD3DXBONECOMBINATION BoneComb; UINT MaterialIndex; UINT PaletteEntry; D3DXMATRIXA16 TempMatrix; // Check for skinning if(MeshContainer->pSkinInfo != NULL){ if(m_SkinningMethod != NULL) return; }}
If this is too hard to look at, you can download it here:
XFileLoader.cppXFileLoader.h Thanks again for all your help! randomZ, I havn't found any indication that the author was using a different compiler, but thanks for suggesting it. I'll have to look through it more just to be sure.
¬_¬
[edited by - Fuzztrek on January 26, 2003 1:16:53 PM]