為了方便加載.x文件中的框架和網格模型數據,Direct3D提供了一個ID3DXAllocateHierarchy接口,該接口中有4個純虛函數:用來創建框架的CreateFrame(),創建網格容器的CreateMeshContainer(),銷毀框架的DestroyFrame(),銷毀網格容器的DestroyMeshContainer()。應用程序會在相應的時機自動調用這些對應的函數,以構建或者銷毀對應的框架或網格模型。
This interface is implemented by the application to
allocate or free frame and mesh container objects. Methods on this are called
during loading and destroying frame hierarchies.
Method |
Description |
ID3DXAllocateHierarchy::CreateFrame |
Requests allocation of
a frame object. |
ID3DXAllocateHierarchy::CreateMeshContainer |
Requests allocation of
a mesh container object. |
ID3DXAllocateHierarchy::DestroyFrame |
Requests deallocation
of a frame object. |
ID3DXAllocateHierarchy::DestroyMeshContainer |
Requests deallocation
of a mesh container object. |
ID3DXAllocateHierarchy::CreateFrame
Requests allocation of a frame object.
HRESULT CreateFrame(
LPCSTR Name,
LPD3DXFRAME * ppNewFrame
);
Parameters
- Name
- [in] Name of the frame to be created.
- ppNewFrame
- [out, retval] Returns the created frame object.
Return Values
The return values of this method are implemented by an
application programmer. In general, if no error occurs, program the method to
return D3D_OK. Otherwise, program the method to return an appropriate error
message from D3DERR or D3DXERR, as this will cause D3DXLoadMeshHierarchyFromX to
fail also, and return the error.
ID3DXAllocateHierarchy::CreateMeshContainer
Requests allocation of a mesh container object.
HRESULT CreateMeshContainer(
LPCSTR Name,
CONST D3DXMESHDATA * pMeshData,
CONST D3DXMATERIAL * pMaterials,
CONST D3DXEFFECTINSTANCE * pEffectInstances,
DWORD NumMaterials,
CONST DWORD * pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER * ppNewMeshContainer
);
Parameters
- Name
- [in] Name of the mesh.
- pMeshData
- [in] Pointer to the mesh data structure.
- pMaterials
- [in] Array of materials used in the mesh.
- pEffectInstances
- [in] Array of effect instances used in the mesh.
- NumMaterials
- [in] Number of materials in the materials array.
- pAdjacency
- [in] Adjacency array for the mesh.
- pSkinInfo
- [in] Pointer to the skin mesh object if skin data
is found.
- ppNewMeshContainer
- [out, retval] Returns the created mesh container.
Return Values
The return values of this method are implemented by an
application programmer. In general, if no error occurs, program the method to
return D3D_OK. Otherwise, program the method to return an appropriate error
message from D3DERR or D3DXERR, as this will cause D3DXLoadMeshHierarchyFromX to
fail also, and return the error.
ID3DXAllocateHierarchy::DestroyFrame
Requests deallocation of a frame object.
HRESULT DestroyFrame(
LPD3DXFRAME pFrameToFree
);
Parameters
- pFrameToFree
- [in] Pointer to the frame to be deallocated.
Return Values
The return values of this method are implemented by an
application programmer. In general, if no error occurs, program the method to
return D3D_OK. Otherwise, program the method to return an appropriate error
message from D3DERR or D3DXERR, as this will cause D3DXLoadMeshHierarchyFromX to
fail also, and return the error.
ID3DXAllocateHierarchy::DestroyMeshContainer
Requests deallocation of a mesh container object.
HRESULT DestroyMeshContainer(
LPD3DXMESHCONTAINER pMeshContainerToFree
);
Parameters
- pMeshContainerToFree
- [in] Pointer to the mesh container object to be
deallocated.
Return Values
The return values of this method are implemented by an
application programmer. In general, if no error occurs, program the method to
return D3D_OK. Otherwise, program the method to return an appropriate error
message from D3DERR or D3DXERR, as this will cause D3DXLoadMeshHierarchyFromX to
fail also, and return the error.
cAllocateHierarchy類繼承自ID3DXAllocateHierarchy接口,在cAllocateHierarchy類需要重載這4個純虛函數以實現動畫網格模型數據的加載和釋放。
該類的定義如下:
class cAllocateHierarchy : public ID3DXAllocateHierarchy
{
private:
HRESULT AllocateName(LPCSTR name, LPSTR* ret_name);
public:
STDMETHOD(CreateFrame)(LPCSTR name, LPD3DXFRAME* ret_frame);
STDMETHOD(CreateMeshContainer)(LPCSTR name,
CONST D3DXMESHDATA* mesh_data,
CONST D3DXMATERIAL* xmaterials,
CONST D3DXEFFECTINSTANCE* effect_instances,
DWORD num_materials,
CONST DWORD* adjacency,
LPD3DXSKININFO skin_info,
LPD3DXMESHCONTAINER* ret_mesh_container);
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME frame_to_free);
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER base_mesh_container);
};
函數AllocateFrame()用來為框架生成一個名稱:
HRESULT cAllocateHierarchy::AllocateName(LPCSTR name, LPSTR* ret_name)
{
if(name != NULL)
{
UINT length = (UINT)strlen(name) + 1;
*ret_name = new CHAR[length];
if(*ret_name == NULL)
return E_OUTOFMEMORY;
memcpy(*ret_name, name, length * sizeof(CHAR));
}
else
{
*ret_name = NULL;
}
return S_OK;
}
函數CreateFrame()的作用在于生成一個新的擴展框架,并按照指定的參數為該框架命名:
HRESULT cAllocateHierarchy::CreateFrame(LPCSTR name, LPD3DXFRAME* ret_frame)
{
*ret_frame = NULL;
D3DXFRAME_DERIVED* new_frame = new D3DXFRAME_DERIVED;
if(new_frame == NULL)
return E_OUTOFMEMORY;
HRESULT hr = AllocateName(name, &new_frame->Name);
if(FAILED(hr))
{
delete new_frame;
return hr;
}
D3DXMatrixIdentity(&new_frame->TransformationMatrix);
D3DXMatrixIdentity(&new_frame->CombinedTransformMatrix);
new_frame->pMeshContainer = NULL;
new_frame->pFrameSibling = NULL;
new_frame->pFrameFirstChild = NULL;
*ret_frame = new_frame;
return S_OK;
}
在一個框架創建好后,需要創建該框架的網格容器,這通過函數CreateMeshContainer()來實現:
HRESULT cAllocateHierarchy::CreateMeshContainer(LPCSTR name,
CONST D3DXMESHDATA* mesh_data,
CONST D3DXMATERIAL* xmaterials,
CONST D3DXEFFECTINSTANCE* effect_instances,
DWORD num_materials,
CONST DWORD* adjacency,
LPD3DXSKININFO skin_info,
LPD3DXMESHCONTAINER* ret_mesh_container)
{
*ret_mesh_container = NULL;
if(mesh_data->Type != D3DXMESHTYPE_MESH)
return E_FAIL;
ID3DXMesh* mesh_ptr = mesh_data->pMesh;
DWORD fvf = mesh_ptr->GetFVF();
if(fvf == 0)
return E_FAIL;
// create a mesh container and zero it
D3DXMESHCONTAINER_DERIVED* new_mesh_container = new D3DXMESHCONTAINER_DERIVED;
if(new_mesh_container == NULL)
return E_OUTOFMEMORY;
memset(new_mesh_container, 0, sizeof(D3DXMESHCONTAINER_DERIVED));
// copy mesh name
HRESULT hr = AllocateName(name, &new_mesh_container->Name);
if(FAILED(hr))
{
DestroyMeshContainer(new_mesh_container);
return hr;
}
IDirect3DDevice9* device;
mesh_ptr->GetDevice(&device);
new_mesh_container->MeshData.Type = D3DXMESHTYPE_MESH;
// be sure mesh contain normal
if(!(fvf & D3DFVF_NORMAL))
{
hr = mesh_ptr->CloneMeshFVF(mesh_ptr->GetOptions(), fvf | D3DFVF_NORMAL, device,
&new_mesh_container->MeshData.pMesh);
if(FAILED(hr))
{
release_com(device);
DestroyMeshContainer(new_mesh_container);
return hr;
}
mesh_ptr = new_mesh_container->MeshData.pMesh;
D3DXComputeNormals(mesh_ptr, NULL);
}
else
{
new_mesh_container->MeshData.pMesh = mesh_ptr;
mesh_ptr->AddRef(); // !! important, so DestroyMeshContainer() will not crash.
}
// load materials and textures
UINT num_faces = mesh_ptr->GetNumFaces();
new_mesh_container->NumMaterials = max(1, num_materials);
new_mesh_container->pMaterials = new D3DXMATERIAL[new_mesh_container->NumMaterials];
new_mesh_container->ppTextures = new LPDIRECT3DTEXTURE9[new_mesh_container->NumMaterials];
new_mesh_container->pAdjacency = new DWORD[num_faces * 3];
if((new_mesh_container->pAdjacency == NULL) || (new_mesh_container->pMaterials == NULL) ||
(new_mesh_container->ppTextures == NULL))
{
release_com(device);
DestroyMeshContainer(new_mesh_container);
return E_OUTOFMEMORY;
}
memcpy(new_mesh_container->pAdjacency, adjacency, sizeof(DWORD) * num_faces * 3);
memset(new_mesh_container->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * new_mesh_container->NumMaterials);
D3DXMATERIAL* xmaterials_ptr = new_mesh_container->pMaterials;
if(num_materials > 0)
{
memcpy(xmaterials_ptr, xmaterials, sizeof(D3DXMATERIAL) * num_materials);
xmaterials_ptr->MatD3D.Ambient = xmaterials_ptr->MatD3D.Diffuse;
for(UINT i = 0; i < num_materials; i++)
{
if(xmaterials_ptr[i].pTextureFilename != NULL)
{
WCHAR w_texture_path[MAX_PATH];
WCHAR w_filename[MAX_PATH];
RemovePathFromFileName(xmaterials_ptr[i].pTextureFilename, w_filename);
DXUTFindDXSDKMediaFileCch(w_texture_path, MAX_PATH, w_filename);
if(FAILED( D3DXCreateTextureFromFileW(device, w_texture_path, &new_mesh_container->ppTextures[i]) ))
new_mesh_container->ppTextures[i] = NULL;
}
}
}
else
{
xmaterials_ptr[0].pTextureFilename = NULL;
memset(&xmaterials_ptr[0].MatD3D, 0, sizeof(D3DMATERIAL9));
xmaterials_ptr[0].MatD3D.Diffuse.r = 0.5f;
xmaterials_ptr[0].MatD3D.Diffuse.r = 0.5f;
xmaterials_ptr[0].MatD3D.Diffuse.b = 0.5f;
xmaterials_ptr[0].MatD3D.Specular = xmaterials_ptr[0].MatD3D.Diffuse;
xmaterials_ptr[0].MatD3D.Ambient = xmaterials_ptr[0].MatD3D.Diffuse;
}
release_com(device);
*ret_mesh_container = new_mesh_container;
return S_OK;
}
在此實現的骨骼動畫網格模型中沒有涉及到蒙皮信息,所以在CreateMeshContainer()函數中沒有處理參數skin_info指向的蒙皮信息。
函數DestroyFrame()只有一個參數指向準備釋放的框架對象:
HRESULT cAllocateHierarchy::DestroyFrame(LPD3DXFRAME frame_to_free)
{
SAFE_DELETE_ARRAY(frame_to_free->Name);
SAFE_DELETE(frame_to_free);
return S_OK;
}
函數DestroyMeshContainer()也只有一個參數指向將要釋放的網格容器對象:
HRESULT cAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER base_mesh_container)
{
if(base_mesh_container == NULL)
return S_OK;
D3DXMESHCONTAINER_DERIVED* mesh_container = (D3DXMESHCONTAINER_DERIVED*) base_mesh_container;
SAFE_DELETE_ARRAY(mesh_container->Name);
SAFE_DELETE_ARRAY(mesh_container->pAdjacency);
SAFE_DELETE_ARRAY(mesh_container->pMaterials);
if(mesh_container->ppTextures != NULL)
{
for(UINT i = 0; i < mesh_container->NumMaterials; i++)
release_com(mesh_container->ppTextures[i]);
}
SAFE_DELETE_ARRAY(mesh_container->ppTextures);
SAFE_RELEASE(mesh_container->MeshData.pMesh);
SAFE_RELEASE(mesh_container->pSkinInfo);
SAFE_DELETE(mesh_container);
return S_OK;
}