Heya.
Im playing around with my model loader and I stumbled upon something strange.
Here is the code :
HRESULT AllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER meshContainerBase)
{
// Convert to our extended type. OK as we know for sure it is:
D3DXMESHCONTAINER_EXTENDED* meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase;
if (!meshContainer)
return S_OK;
// name
if (meshContainer->Name)
{
delete []meshContainer->Name;
meshContainer->Name=0;
}
// uncommenting these two crashes in release builds
// dont know why.. they should be released by the vector anyway
//meshContainer->exMaterials.clear();
//meshContainer->exTextures.clear();
// adjacency data
if (meshContainer->pAdjacency)
delete []meshContainer->pAdjacency;
// bone parts
if (meshContainer->exBoneOffsets)
{
delete []meshContainer->exBoneOffsets;
meshContainer->exBoneOffsets=0;
}
// frame matrices
if (meshContainer->exFrameCombinedMatrixPointer)
{
delete []meshContainer->exFrameCombinedMatrixPointer;
meshContainer->exFrameCombinedMatrixPointer=0;
}
// release skin mesh
if (meshContainer->exSkinMesh)
{
meshContainer->exSkinMesh->Release();
meshContainer->exSkinMesh=0;
}
// release the main mesh
if (meshContainer->MeshData.pMesh)
{
meshContainer->MeshData.pMesh->Release();
meshContainer->MeshData.pMesh=0;
}
// release skin information
if (meshContainer->pSkinInfo)
{
meshContainer->pSkinInfo->Release();
meshContainer->pSkinInfo=0;
}
// finally delete the mesh container itself
delete meshContainer;
meshContainer=0;
return S_OK;
}
This is the function used to free meshcontainer for x models.
The x models are loaded with the function D3DXLoadMeshHierarchyFromX and a allocator object is passed to it to allocate the objects.
Here is the creating part of it :
HRESULT AllocateHierarchy::CreateMeshContainer(
LPCSTR Name,
CONST D3DXMESHDATA *meshData,
CONST D3DXMATERIAL *materials,
CONST D3DXEFFECTINSTANCE *effectInstances,
DWORD numMaterials,
CONST DWORD *adjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* retNewMeshContainer)
{
// Create a mesh container structure to fill and initilaise to zero values
// Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h
D3DXMESHCONTAINER_EXTENDED *newMeshContainer = new D3DXMESHCONTAINER_EXTENDED;
ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED));
// Always a good idea to initialise return pointer before proceeding
*retNewMeshContainer = 0;
// The mesh name (may be 0) needs copying over
if (Name && strlen(Name))
{
newMeshContainer->Name = STUtil::DuplicateCharString(Name);
STUtil::DebugString("Added mesh: "+ToString(Name)+"\n");
}
else
{
STUtil::DebugString("Added Mesh: no name given\n");
}
// The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH)
if (meshData->Type!=D3DXMESHTYPE_MESH)
{
// This demo does not handle mesh types other than the standard
// Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh)
DestroyMeshContainer(newMeshContainer);
return E_FAIL;
}
newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
// Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object
DWORD dwFaces = meshData->pMesh->GetNumFaces();
newMeshContainer->pAdjacency = new DWORD[dwFaces*3];
memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3);
// Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it)
LPDIRECT3DDEVICE9 pd3dDevice = 0;
meshData->pMesh->GetDevice(&pd3dDevice);
// Changed 24/09/07 - can just assign pointer and add a ref rather than need to clone
newMeshContainer->MeshData.pMesh=meshData->pMesh;
newMeshContainer->MeshData.pMesh->AddRef();
// Create material and texture arrays. Note that I always want to have at least one
newMeshContainer->NumMaterials = max(numMaterials,1);
newMeshContainer->exMaterials.resize(newMeshContainer->NumMaterials);
newMeshContainer->exTextures.resize(newMeshContainer->NumMaterials);
//newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials];
//newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials];
//ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials);
if (numMaterials>0)
{
// Load all the textures and copy the materials over
for(DWORD i = 0; i < numMaterials; ++i)
{
newMeshContainer->exTextures = 0;
newMeshContainer->exMaterials = (materials.MatD3D);
//set ambient to 0.5f
newMeshContainer->exMaterials.Ambient.r = 0.5f;
newMeshContainer->exMaterials.Ambient.g = 0.5f;
newMeshContainer->exMaterials.Ambient.b = 0.5f;
if(materials.pTextureFilename)
{
std::string texturePath(materials.pTextureFilename);
if (STUtil::FindFile(&texturePath))
{
newMeshContainer->exTextures = m_TextureMngr->addTexture(texturePath);
if(newMeshContainer->exTextures == NULL)
{
std::string errorText = "Couldn't load model texture "+texturePath;
ERRORMSGBOX(NULL,errorText);
}
}
else
{
STUtil::DebugString("Could not find texture: "+ToString(materials.pTextureFilename)+"\n");
}
}
}
}
else
// make a default material in the case where the mesh did not provide one
{
ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) );
newMeshContainer->exMaterials[0].Diffuse.r = 0.5f;
newMeshContainer->exMaterials[0].Diffuse.g = 0.5f;
newMeshContainer->exMaterials[0].Diffuse.b = 0.5f;
newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse;
newMeshContainer->exTextures[0]=0;
}
// If there is skin data associated with the mesh copy it over
if (pSkinInfo)
{
// save off the SkinInfo
newMeshContainer->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();
// Need an array of offset matrices to move the vertices from the figure space to the bone's space
UINT numBones = pSkinInfo->GetNumBones();
newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones];
// Create the arrays for the bones and the frame matrices
newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones];
// get each of the bone offset matrices so that we don't need to get them later
for (UINT i = 0; i < numBones; i++)
newMeshContainer->exBoneOffsets = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i));
STUtil::DebugString("Mesh has skinning info.\n Number of bones is: "+ToString(numBones)+"\n");
// Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare
// the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample
// does not do hardware skinning but instead uses software skinning.
}
else
{
// No skin info so 0 all the pointers
newMeshContainer->pSkinInfo = 0;
newMeshContainer->exBoneOffsets = 0;
newMeshContainer->exSkinMesh = 0;
newMeshContainer->exFrameCombinedMatrixPointer = 0;
}
// When we got the device we caused an internal reference count to be incremented
// So we now need to release it
pd3dDevice->Release();
// The mesh may contain a reference to an effect file
if (effectInstances)
{
if (effectInstances->pEffectFilename)
STUtil::DebugString("This .x file references an effect file. Effect files are not handled by this demo\n");
}
// Set the output mesh container pointer to our newly created one
*retNewMeshContainer = newMeshContainer;
return S_OK;
}
And this is the mesh container class :
struct D3DXMESHCONTAINER_EXTENDED: public D3DXMESHCONTAINER
{
std::vector<TexturePtr> exTextures;
std::vector<D3DMATERIAL9> exMaterials;
//IDirect3DTexture9** exTextures; // Array of texture pointers
//D3DMATERIAL9* exMaterials; // Array of materials
// Skinned mesh variables
ID3DXMesh* exSkinMesh; // The skin mesh
D3DXMATRIX* exBoneOffsets; // The bone matrix Offsets, one per bone
D3DXMATRIX** exFrameCombinedMatrixPointer; // Array of frame matrix pointers
};
If you look through the code you will notice that I replaced the raw pointers exTextures an exMaterials with vectors TexturePtr is CComPtr<IDirect3dTexture9>.
When loading the meshContainer i size these vectors according to the material count and then add materials to the material vector.And use my texture manager to add textures to the texture vector.The texture manager addTexture method returns a TexturePtr too.
The problem is this runs fine on debug but in release mode when i try to use
meshContainer->exMaterials.clear();
meshContainer->exTextures.clear();
in DestroyMeshContainer method it crashes.
I think I don't even need to call clear on the vectors as they will clean themselves up but I'm still curious about what might be wrong.
You can get the whole project from :
Link
Any ideas?