http://blog.csdn.net/dotnet90/article/details/6152915
在《Advanced.Animation.with.DirectX》DirectX开发游戏高级动画书中的代码例子都使用了9.0B版本的sdk,现如今的新入行的程序员很少有人再去使用vc6.0 ,大部分人都使用的是9.0c版本的sdk,所以导致编译出现错误:
error C2664: 'D3DXLoadSkinMeshFromXof' : cannot convert parameter 1 from 'IDirectXFileData *' to 'LPD3DXFILEDATA'
要想使用vs2005和9.0c
那么需要修改几个地方:
1、搜索所有的IDirectXFileData 替换成ID3DXFileData,添加D3dx9xof.h
替换所有的
IDirectXFile成ID3DXFile
IDirectXFileEnumObject -- ID3DXFileEnumObject
DirectXFileCreate D3DXFileCreate
但是ID3DXFileData 没有GetData,GetNextObject,AddDataReference等方法.
判断是否引用的改成了IsReference方法.
而获取子信息由原来的一个函数换成了这两个GetChild,GetChildren
下面是我经过改动之后代码......帮那些正在学的人少走一条湾路......
#ifndef _DIRECT3D_H_
#define _DIRECT3D_H_
#include <stdio.h>
#include <windows.h>
#include "d3d9.h"
#include "d3dx9.h"
#include "dxfile.h"
#include "XFile.h"
#include "D3dx9xof.h"
#define ReleaseCOM(x) { if(x!=NULL) x->Release(); x=NULL; }
// Declare an extended version of D3DXFRAME
// that contains a constructor and destructor
// as well as a combined transformation matrix
struct D3DXFRAME_EX : D3DXFRAME
{
D3DXMATRIX matCombined; // Combined matrix
D3DXMATRIX matOriginal; // Original transformation from .X
D3DXFRAME_EX()
{
Name = NULL;
pMeshContainer = NULL;
pFrameSibling = pFrameFirstChild = NULL;
D3DXMatrixIdentity(&matCombined);
D3DXMatrixIdentity(&matOriginal);
D3DXMatrixIdentity(&TransformationMatrix);
}
~D3DXFRAME_EX()
{
delete [] Name; Name = NULL;
delete pFrameSibling; pFrameSibling = NULL;
delete pFrameFirstChild; pFrameFirstChild = NULL;
}
// Function to scan hierarchy for matching frame name
D3DXFRAME_EX *Find(const char *FrameName)
{
D3DXFRAME_EX *pFrame, *pFramePtr;
// Return this frame instance if name matched
if(Name && FrameName && !strcmp(FrameName, Name))
return this;
// Scan siblings
if((pFramePtr = (D3DXFRAME_EX*)pFrameSibling)) {
if((pFrame = pFramePtr->Find(FrameName)))
return pFrame;
}
// Scan children
if((pFramePtr = (D3DXFRAME_EX*)pFrameFirstChild)) {
if((pFrame = pFramePtr->Find(FrameName)))
return pFrame;
}
// Return none found
return NULL;
}
// Reset transformation matrices to originals
void Reset()
{
// Copy original matrix
TransformationMatrix = matOriginal;
// Reset sibling frames
D3DXFRAME_EX *pFramePtr;
if((pFramePtr = (D3DXFRAME_EX*)pFrameSibling))
pFramePtr->Reset();
// Reset child frames
if((pFramePtr = (D3DXFRAME_EX*)pFrameFirstChild))
pFramePtr->Reset();
}
// Function to combine matrices in frame hiearchy
void UpdateHierarchy(D3DXMATRIX *matTransformation = NULL)
{
D3DXFRAME_EX *pFramePtr;
D3DXMATRIX matIdentity;
// Use an identity matrix if none passed
if(!matTransformation) {
D3DXMatrixIdentity(&matIdentity);
matTransformation = &matIdentity;
}
// Combine matrices w/supplied transformation matrix
matCombined = TransformationMatrix * (*matTransformation);
// Combine w/sibling frames
if((pFramePtr = (D3DXFRAME_EX*)pFrameSibling))
pFramePtr->UpdateHierarchy(matTransformation);
// Combine w/child frames
if((pFramePtr = (D3DXFRAME_EX*)pFrameFirstChild))
pFramePtr->UpdateHierarchy(&matCombined);
}
void Count(DWORD *Num)
{
// Error checking
if(!Num)
return;
// Increase count of frames
(*Num)+=1;
// Process sibling frames
D3DXFRAME_EX *pFrame;
if((pFrame=(D3DXFRAME_EX*)pFrameSibling))
pFrame->Count(Num);
// Process child frames
if((pFrame=(D3DXFRAME_EX*)pFrameFirstChild))
pFrame->Count(Num);
}
};
// Declare an extended version of D3DXMESHCONTAINER
// that contains a constructor and destructor
// as well as an array of textures, a mesh object
// that contains the generated skin mesh, and
// matrices that map to the frame hierarchy's and
// for updating bones.
struct D3DXMESHCONTAINER_EX : D3DXMESHCONTAINER
{
IDirect3DTexture9 **pTextures;
ID3DXMesh *pSkinMesh;
D3DXMATRIX **ppFrameMatrices;
D3DXMATRIX *pBoneMatrices;
D3DXMESHCONTAINER_EX()
{
Name = NULL;
MeshData.pMesh = NULL;
pMaterials = NULL;
pEffects = NULL;
NumMaterials = 0;
pAdjacency = NULL;
pSkinInfo = NULL;
pNextMeshContainer = NULL;
pTextures = NULL;
pSkinMesh = NULL;
ppFrameMatrices = NULL;
pBoneMatrices = NULL;
}
~D3DXMESHCONTAINER_EX()
{
if(pTextures && NumMaterials) {
for(DWORD i=0;i<NumMaterials;i++)
ReleaseCOM(pTextures[i]);
}
delete [] pTextures; pTextures = NULL;
NumMaterials = 0;
delete [] Name; Name = NULL;
delete [] pMaterials; pMaterials = NULL;
delete pEffects; pEffects = NULL;
delete [] pAdjacency; pAdjacency = NULL;
delete [] ppFrameMatrices; ppFrameMatrices = NULL;
delete [] pBoneMatrices; pBoneMatrices = NULL;
ReleaseCOM(MeshData.pMesh);
ReleaseCOM(pSkinInfo);
ReleaseCOM(pSkinMesh);
delete pNextMeshContainer; pNextMeshContainer = NULL;
}
D3DXMESHCONTAINER_EX *Find(char *MeshName)
{
D3DXMESHCONTAINER_EX *pMesh, *pMeshPtr;
// Return this mesh instance if name matched
if(Name && MeshName && !strcmp(MeshName, Name))
return this;
// Scan next in list
if((pMeshPtr = (D3DXMESHCONTAINER_EX*)pNextMeshContainer)) {
if((pMesh = pMeshPtr->Find(MeshName)))
return pMesh;
}
// Return none found
return NULL;
}
};
// Declare an internal .X file parser class for loading meshes and frames
class cXInternalParser
{
public:
// Information passed from calling function
IDirect3DDevice9 *m_pD3DDevice;
char *m_TexturePath;
DWORD m_NewFVF;
DWORD m_LoadFlags;
// Flags for which data to load
// 1 = mesh, 2 = frames, 3= both
DWORD m_Flags;
// Hierarchies used during loading
D3DXMESHCONTAINER_EX *m_RootMesh;
D3DXFRAME_EX *m_RootFrame;
protected:
// Function called for every template found
BOOL ParseObject(ID3DXFileData *pDataObj,
ID3DXFileData *pParentDataObj,
DWORD Depth,
void **Data, BOOL Reference);
// Function called to enumerate child templates
BOOL ParseChildObjects(ID3DXFileData *pDataObj,
DWORD Depth, void **Data,
BOOL ForceReference = FALSE);
public:
// Constructor and destructor
cXInternalParser();
~cXInternalParser();
// Function to start parsing an .X file
BOOL Parse(char *Filename, void **Data = NULL);
// Functions to help retrieve template information
const GUID *GetObjectGUID(ID3DXFileData *pDataObj);
char *GetObjectName(ID3DXFileData *pDataObj);
void *GetObjectData(ID3DXFileData *pDataObj, DWORD *Size);
};
// Initialize D3D
HRESULT InitD3D(IDirect3D9 **ppD3D,
IDirect3DDevice9 **ppD3DDevice,
HWND hWnd, BOOL ForceWindowed = FALSE,
BOOL MultiThreaded = FALSE);
// Load a vertex shader
HRESULT LoadVertexShader(IDirect3DVertexShader9 **ppShader,
IDirect3DDevice9 *pDevice,
char *Filename,
D3DVERTEXELEMENT9 *pElements = NULL,
IDirect3DVertexDeclaration9 **ppDecl = NULL);
// Load a single mesh from an .X file (compact multiple meshes into one)
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
IDirect3DDevice9 *pDevice,
char *Filename,
char *TexturePath = ".//",
DWORD NewFVF = 0,
DWORD LoadFlags = D3DXMESH_SYSTEMMEM);
// Load a single mesh (regular or skinned) from a mesh template
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
IDirect3DDevice9 *pDevice,
ID3DXFileData *pDataObj,
char *TexturePath = ".//",
DWORD NewFVF = 0,
DWORD LoadFlags = D3DXMESH_SYSTEMMEM);
// Load all meshes and frames from an .X file
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
D3DXFRAME_EX **ppFrame,
IDirect3DDevice9 *pDevice,
char *Filename,
char *TexturePath = ".//",
DWORD NewFVF = 0,
DWORD LoadFlags = D3DXMESH_SYSTEMMEM);
// Update a skinned mesh
HRESULT UpdateMesh(D3DXMESHCONTAINER_EX *pMesh);
// Draw the first mesh in a linked list of objects
HRESULT DrawMesh(D3DXMESHCONTAINER_EX *pMesh);
// Draw the first mesh in a linked list of objects
// using the specified vertex shader and declaration
HRESULT DrawMesh(D3DXMESHCONTAINER_EX *pMesh,
IDirect3DVertexShader9 *pShader,
IDirect3DVertexDeclaration9 *pDecl);
// Draw all meshes in a linked list of objects
HRESULT DrawMeshes(D3DXMESHCONTAINER_EX *pMesh);
// Draw all meshes in a linked list of objects
// using the specified vertex shader and declaration
HRESULT DrawMeshes(D3DXMESHCONTAINER_EX *pMesh,
IDirect3DVertexShader9 *pShader,
IDirect3DVertexDeclaration9 *pDecl);
#endif
#include "Direct3D.h"
///
//
// Initialize Direct3D function
//
///
HRESULT InitD3D(IDirect3D9 **ppD3D,
IDirect3DDevice9 **ppD3DDevice,
HWND hWnd,
BOOL ForceWindowed,
BOOL MultiThreaded)
{
IDirect3D9 *pD3D = NULL;
IDirect3DDevice9 *pD3DDevice = NULL;
HRESULT hr;
// Error checking
if(!ppD3D || !ppD3DDevice || !hWnd)
return E_FAIL;
// Initialize Direct3D
if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
return E_FAIL;
*ppD3D = pD3D;
// Ask if user wants to run windowed or fullscreen
// or force windowed if flagged to do such
int Mode;
if(ForceWindowed == TRUE)
Mode = IDNO;
else
Mode = MessageBox(hWnd, "Use fullscreen mode? (640x480x16)", "Initialize D3D", MB_YESNO | MB_ICONQUESTION);
// Set the video (depending on windowed mode or fullscreen)
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
// Setup video settings based on choice of fullscreen or not
if(Mode == IDYES) {
//
// Setup fullscreen format (set to your own if you prefer)
//
DWORD Width = 640;
DWORD Height = 480;
D3DFORMAT Format = D3DFMT_R5G6B5;
// Set the presentation parameters (use fullscreen)
d3dpp.BackBufferWidth = Width;
d3dpp.BackBufferHeight = Height;
d3dpp.BackBufferFormat = Format;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.Windowed = FALSE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
} else {
//
// Setup windowed format (set to your own dimensions below)
//
// Get the client and window dimensions
RECT ClientRect, WndRect;
GetClientRect(hWnd, &ClientRect);
GetWindowRect(hWnd, &WndRect);
// Set the width and height (set your dimensions here)
DWORD DesiredWidth = 640;
DWORD DesiredHeight = 480;
DWORD Width = (WndRect.right - WndRect.left) + (DesiredWidth - ClientRect.right);
DWORD Height = (WndRect.bottom - WndRect.top) + (DesiredHeight - ClientRect.bottom);
// Set the window's dimensions
MoveWindow(hWnd, WndRect.left, WndRect.top, Width, Height, TRUE);
// Get the desktop format
D3DDISPLAYMODE d3ddm;
pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
// Set the presentation parameters (use windowed)
d3dpp.BackBufferWidth = DesiredWidth;
d3dpp.BackBufferHeight = DesiredHeight;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
}
// Create the 3-D device
DWORD Flags= D3DCREATE_MIXED_VERTEXPROCESSING;
// DWORD Flags= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if(MultiThreaded == TRUE)
Flags |= D3DCREATE_MULTITHREADED;
if(FAILED(hr = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, hWnd, Flags,
&d3dpp, &pD3DDevice)))
return hr;
// Store the 3-D device object pointer
*ppD3DDevice = pD3DDevice;
// Set the perspective projection
float Aspect = (float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight;
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection, D3DX_PI/4.0f, Aspect, 1.0f, 10000.0f);
pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProjection);
// Set the default render states
pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
// Set the default texture stage states
pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
// Set the default texture filters
pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
return S_OK;
}
///
//
// Load a vertex shader function
//
///
HRESULT LoadVertexShader(IDirect3DVertexShader9 **ppShader,
IDirect3DDevice9 *pDevice,
char *Filename,
D3DVERTEXELEMENT9 *pElements,
IDirect3DVertexDeclaration9 **ppDecl)
{
HRESULT hr;
// Error checking
if(!ppShader || !pDevice || !Filename)
return E_FAIL;
// Load and assemble the shader
ID3DXBuffer *pCode;
if(FAILED(hr=D3DXAssembleShaderFromFile(Filename, NULL, NULL, 0, &pCode, NULL)))
return hr;
if(FAILED(hr=pDevice->CreateVertexShader((DWORD*)pCode->GetBufferPointer(), ppShader)))
return hr;
pCode->Release();
// Create the declaration interface if needed
if(pElements && ppDecl)
pDevice->CreateVertexDeclaration(pElements, ppDecl);
// Return success
return S_OK;
}
///
//
// Load mesh functions
//
///
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
IDirect3DDevice9 *pDevice,
char *Filename,
char *TexturePath,
DWORD NewFVF,
DWORD LoadFlags)
{
ID3DXMesh *pLoadMesh = NULL;
HRESULT hr;
// Error checking
if(!ppMesh || !pDevice || !Filename || !TexturePath)
return E_FAIL;
// Use system memory if converting FVF
DWORD TempLoadFlags = LoadFlags;
if(NewFVF)
TempLoadFlags = D3DXMESH_SYSTEMMEM;
// Load the mesh using D3DX routines
ID3DXBuffer *MaterialBuffer = NULL, *AdjacencyBuffer = NULL;
DWORD NumMaterials;
if(FAILED(hr=D3DXLoadMeshFromX(Filename, TempLoadFlags,
pDevice, &AdjacencyBuffer,
&MaterialBuffer, NULL,
&NumMaterials, &pLoadMesh)))
return hr;
// Convert to new FVF first as needed
if(NewFVF) {
ID3DXMesh *pTempMesh;
// Use CloneMeshFVF to convert mesh
if(FAILED(hr=pLoadMesh->CloneMeshFVF(LoadFlags, NewFVF, pDevice, &pTempMesh))) {
ReleaseCOM(AdjacencyBuffer);
ReleaseCOM(MaterialBuffer);
ReleaseCOM(pLoadMesh);
return hr;
}
// Free prior mesh and store new pointer
ReleaseCOM(pLoadMesh);
pLoadMesh = pTempMesh; pTempMesh = NULL;
}
// Allocate a D3DXMESHCONTAINER_EX structure
D3DXMESHCONTAINER_EX *pMesh = new D3DXMESHCONTAINER_EX();
*ppMesh = pMesh;
// Store mesh name (filename), type, and mesh pointer
pMesh->Name = strdup(Filename);
pMesh->MeshData.Type = D3DXMESHTYPE_MESH;
pMesh->MeshData.pMesh = pLoadMesh; pLoadMesh = NULL;
// Store adjacency buffer
DWORD AdjSize = AdjacencyBuffer->GetBufferSize();
if(AdjSize) {
pMesh->pAdjacency = new DWORD[AdjSize];
memcpy(pMesh->pAdjacency, AdjacencyBuffer->GetBufferPointer(), AdjSize);
}
ReleaseCOM(AdjacencyBuffer);
// Build material list
if(!(pMesh->NumMaterials = NumMaterials)) {
// Create a default material
pMesh->NumMaterials = 1;
pMesh->pMaterials = new D3DXMATERIAL[1];
pMesh->pTextures = new IDirect3DTexture9*[1];
ZeroMemory(pMesh->pMaterials, sizeof(D3DXMATERIAL));
pMesh->pMaterials[0].MatD3D.Diffuse.r = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.g = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.b = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.a = 1.0f;
pMesh->pMaterials[0].MatD3D.Ambient = pMesh->pMaterials[0].MatD3D.Diffuse;
pMesh->pMaterials[0].MatD3D.Specular = pMesh->pMaterials[0].MatD3D.Diffuse;
pMesh->pMaterials[0].pTextureFilename = NULL;
pMesh->pTextures[0] = NULL;
} else {
// Load the materials
D3DXMATERIAL *Materials = (D3DXMATERIAL*)MaterialBuffer->GetBufferPointer();
pMesh->pMaterials = new D3DXMATERIAL[pMesh->NumMaterials];
pMesh->pTextures = new IDirect3DTexture9*[pMesh->NumMaterials];
for(DWORD i=0;i<pMesh->NumMaterials;i++) {
pMesh->pMaterials[i].MatD3D = Materials[i].MatD3D;
pMesh->pMaterials[i].MatD3D.Ambient = pMesh->pMaterials[i].MatD3D.Diffuse;
// Load the texture if one exists
pMesh->pTextures[i] = NULL;
if(Materials[i].pTextureFilename) {
char TextureFile[MAX_PATH];
sprintf(TextureFile, "%s%s", TexturePath,
Materials[i].pTextureFilename);
D3DXCreateTextureFromFile(pDevice,
TextureFile,
&pMesh->pTextures[i]);
}
}
}
ReleaseCOM(MaterialBuffer);
// Optimize the mesh for better attribute access
pMesh->MeshData.pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
// Clear pMesh pointer just in case
pMesh = NULL;
return S_OK;
}
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
IDirect3DDevice9 *pDevice,
ID3DXFileData *pDataObj,
char *TexturePath,
DWORD NewFVF,
DWORD LoadFlags)
{
ID3DXMesh *pLoadMesh = NULL;
ID3DXSkinInfo *pSkin = NULL;
HRESULT hr;
// Error checking
if(!ppMesh || !pDevice || !pDataObj || !TexturePath)
return E_FAIL;
// Use system memory if converting FVF
DWORD TempLoadFlags = LoadFlags;
if(NewFVF)
TempLoadFlags = D3DXMESH_SYSTEMMEM;
// Load the mesh using the D3DX skinned mesh interface
ID3DXBuffer *MaterialBuffer = NULL, *AdjacencyBuffer = NULL;
DWORD NumMaterials;
if(FAILED(hr=D3DXLoadSkinMeshFromXof(pDataObj, TempLoadFlags,
pDevice, &AdjacencyBuffer,
&MaterialBuffer, NULL,
&NumMaterials, &pSkin,
&pLoadMesh)))
return hr;
// Free skin info if no bones
if(pSkin && !pSkin->GetNumBones())
ReleaseCOM(pSkin);
// Convert to new FVF first as needed (not w/skinned models)
if(NewFVF) {
ID3DXMesh *pTempMesh = NULL;
// Use CloneMeshFVF to convert mesh
if(FAILED(hr=pLoadMesh->CloneMeshFVF(LoadFlags, NewFVF, pDevice, &pTempMesh))) {
ReleaseCOM(pLoadMesh);
ReleaseCOM(pSkin);
ReleaseCOM(MaterialBuffer);
ReleaseCOM(AdjacencyBuffer);
return hr;
}
// Free prior mesh and store new pointer
ReleaseCOM(pLoadMesh);
pLoadMesh = pTempMesh; pTempMesh = NULL;
}
// Allocate a D3DXMESHCONTAINER_EX structure
D3DXMESHCONTAINER_EX *pMesh = new D3DXMESHCONTAINER_EX();
*ppMesh = pMesh;
// Store mesh template name, type, and mesh pointers
DWORD Size;
pDataObj->GetName(NULL, &Size);
if(Size) {
pMesh->Name = new char[Size];
pDataObj->GetName(pMesh->Name, &Size);
}
pMesh->MeshData.Type = D3DXMESHTYPE_MESH;
pMesh->MeshData.pMesh = pLoadMesh; pLoadMesh = NULL;
pMesh->pSkinInfo = pSkin; pSkin = NULL;
// Store adjacency buffer
DWORD AdjSize = AdjacencyBuffer->GetBufferSize();
if(AdjSize) {
pMesh->pAdjacency = (DWORD*)new char[AdjSize];
memcpy(pMesh->pAdjacency, AdjacencyBuffer->GetBufferPointer(), AdjSize);
}
ReleaseCOM(AdjacencyBuffer);
// Create a duplicate mesh in case skinning is used
if(pMesh->pSkinInfo)
pMesh->MeshData.pMesh->CloneMeshFVF(0, //D3DXMESH_MANAGED,
pMesh->MeshData.pMesh->GetFVF(),
pDevice, &pMesh->pSkinMesh);
// Build material list
if(!(pMesh->NumMaterials = NumMaterials)) {
// Create a default material
pMesh->NumMaterials = 1;
pMesh->pMaterials = new D3DXMATERIAL[1];
pMesh->pTextures = new IDirect3DTexture9*[1];
ZeroMemory(&pMesh->pMaterials[0], sizeof(D3DXMATERIAL));
pMesh->pMaterials[0].MatD3D.Diffuse.r = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.g = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.b = 1.0f;
pMesh->pMaterials[0].MatD3D.Diffuse.a = 1.0f;
pMesh->pMaterials[0].MatD3D.Ambient = pMesh->pMaterials[0].MatD3D.Diffuse;
pMesh->pMaterials[0].MatD3D.Specular = pMesh->pMaterials[0].MatD3D.Diffuse;
pMesh->pMaterials[0].pTextureFilename = NULL;
pMesh->pTextures[0] = NULL;
} else {
// Load the materials
D3DXMATERIAL *Materials = (D3DXMATERIAL*)MaterialBuffer->GetBufferPointer();
pMesh->pMaterials = new D3DXMATERIAL[pMesh->NumMaterials];
pMesh->pTextures = new IDirect3DTexture9*[pMesh->NumMaterials];
for(DWORD i=0;i<pMesh->NumMaterials;i++) {
pMesh->pMaterials[i].MatD3D = Materials[i].MatD3D;
pMesh->pMaterials[i].MatD3D.Ambient = pMesh->pMaterials[i].MatD3D.Diffuse;
// Load the texture if one exists
pMesh->pTextures[i] = NULL;
if(Materials[i].pTextureFilename) {
char TextureFile[MAX_PATH];
sprintf(TextureFile, "%s%s", TexturePath,
Materials[i].pTextureFilename);
D3DXCreateTextureFromFile(pDevice,
TextureFile,
&pMesh->pTextures[i]);
}
}
}
ReleaseCOM(MaterialBuffer);
// Optimize the mesh for better attribute access
pMesh->MeshData.pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
// Clear pMesh pointer just in case
pMesh = NULL;
return S_OK;
}
HRESULT LoadMesh(D3DXMESHCONTAINER_EX **ppMesh,
D3DXFRAME_EX **ppFrame,
IDirect3DDevice9 *pDevice,
char *Filename,
char *TexturePath,
DWORD NewFVF,
DWORD LoadFlags)
{
cXInternalParser Parser;
// Error checking
if(!pDevice || !Filename || !TexturePath)
return E_FAIL;
// Set parser data
Parser.m_pD3DDevice = pDevice;
Parser.m_TexturePath = TexturePath;
Parser.m_NewFVF = NewFVF;
Parser.m_LoadFlags = LoadFlags;
Parser.m_Flags = ((!ppMesh)?0:1) | ((!ppFrame)?0:2);
// Clear mesh and frame pointers
Parser.m_RootFrame = NULL;
Parser.m_RootMesh = NULL;
// Parse the file
Parser.Parse(Filename);
// Map the matrices to the frames and create an array of bone
// matrices, but only if user passed pointers to receive and
// the loader found some meshes and frames.
if(ppMesh && ppFrame && Parser.m_RootMesh && Parser.m_RootFrame) {
// Scan through all meshes
D3DXMESHCONTAINER_EX *pMesh = Parser.m_RootMesh;
while(pMesh) {
// Does this mesh use skinning?
if(pMesh->pSkinInfo) {
// Get the number of bones
DWORD NumBones = pMesh->pSkinInfo->GetNumBones();
// Allocate the matrix pointers and bone matrices
pMesh->ppFrameMatrices = new D3DXMATRIX*[NumBones];
pMesh->pBoneMatrices = new D3DXMATRIX[NumBones];
// Match matrix pointers to frames
for(DWORD i=0;i<NumBones;i++) {
// Get bone name
const char *BoneName = pMesh->pSkinInfo->GetBoneName(i);
// Find matching name in frames
D3DXFRAME_EX *pFrame = Parser.m_RootFrame->Find(BoneName);
// Match frame to bone
if(pFrame)
pMesh->ppFrameMatrices[i] = &pFrame->matCombined;
else
pMesh->ppFrameMatrices[i] = NULL;
}
}
// Go to next mesh
pMesh = (D3DXMESHCONTAINER_EX*)pMesh->pNextMeshContainer;
}
}
// Copy the pointers into passed variables
if(ppMesh) {
// Assign mesh list pointer
*ppMesh = Parser.m_RootMesh;
Parser.m_RootMesh = NULL;
} else {
// Delete list of meshes in case any were loaded
// and were not needed.
delete Parser.m_RootMesh;
Parser.m_RootMesh = NULL;
}
if(ppFrame) {
// Assign frame hierarchy pointer
*ppFrame = Parser.m_RootFrame;
Parser.m_RootFrame = NULL;
} else {
// Delete frame hierarchy in case it was loaded
// and it was not needed.
delete Parser.m_RootFrame;
Parser.m_RootFrame = NULL;
}
return S_OK;
}
///
//
// Update a skinned mesh
//
///
HRESULT UpdateMesh(D3DXMESHCONTAINER_EX *pMesh)
{
// Error checking
if(!pMesh)
return E_FAIL;
if(!pMesh->MeshData.pMesh || !pMesh->pSkinMesh || !pMesh->pSkinInfo)
return E_FAIL;
if(!pMesh->pBoneMatrices || !pMesh->ppFrameMatrices)
return E_FAIL;
// Copy the bone matrices over (must have been combined before call DrawMesh)
for(DWORD i=0;i<pMesh->pSkinInfo->GetNumBones();i++) {
// Start with bone offset matrix
pMesh->pBoneMatrices[i] = (*pMesh->pSkinInfo->GetBoneOffsetMatrix(i));
// Apply frame transformation
if(pMesh->ppFrameMatrices[i])
pMesh->pBoneMatrices[i] *= (*pMesh->ppFrameMatrices[i]);
}
// Lock the meshes' vertex buffers
void *SrcPtr, *DestPtr;
pMesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&SrcPtr);
pMesh->pSkinMesh->LockVertexBuffer(0, (void**)&DestPtr);
// Update the skinned mesh using provided transformations
pMesh->pSkinInfo->UpdateSkinnedMesh(pMesh->pBoneMatrices, NULL, SrcPtr, DestPtr);
// Unlock the meshes vertex buffers
pMesh->pSkinMesh->UnlockVertexBuffer();
pMesh->MeshData.pMesh->UnlockVertexBuffer();
// Return success
return S_OK;
}
///
//
// Draw mesh functions
//
///
HRESULT DrawMesh(D3DXMESHCONTAINER_EX *pMesh)
{
IDirect3DDevice9 *pD3DDevice;
DWORD LastState, OldAlphaState, OldSrcBlend, OldDestBlend;
// Error checking
if(!pMesh)
return E_FAIL;
if(!pMesh->MeshData.pMesh)
return E_FAIL;
if(!pMesh->NumMaterials || !pMesh->pMaterials)
return E_FAIL;
// Get the device interface
pMesh->MeshData.pMesh->GetDevice(&pD3DDevice);
// Release vertex shader if being used
pD3DDevice->SetVertexShader(NULL);
pD3DDevice->SetVertexDeclaration(NULL);
// Save render states
pD3DDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &OldAlphaState);
pD3DDevice->GetRenderState(D3DRS_SRCBLEND, &OldSrcBlend);
pD3DDevice->GetRenderState(D3DRS_DESTBLEND, &OldDestBlend);
LastState = OldAlphaState;
// Setup pointer for mesh to draw, either regular or skinned
ID3DXMesh *pDrawMesh = (!pMesh->pSkinMesh)?pMesh->MeshData.pMesh:pMesh->pSkinMesh;
// Look through all subsets
for(DWORD i=0;i<pMesh->NumMaterials;i++) {
// Set material and texture
pD3DDevice->SetMaterial(&pMesh->pMaterials[i].MatD3D);
pD3DDevice->SetTexture(0, pMesh->pTextures[i]);
// Enable or disable alpha blending per material
if(pMesh->pMaterials[i].MatD3D.Diffuse.a != 1.0f) {
if(LastState != TRUE) {
LastState = TRUE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);//SRCCOLOR);
pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);
}
} else {
if(LastState != FALSE) {
LastState = FALSE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
// Draw the mesh subset
pDrawMesh->DrawSubset(i);
}
// Restore alpha blending states
if(LastState != OldAlphaState) {
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, OldAlphaState);
pD3DDevice->SetRenderState(D3DRS_SRCBLEND, OldSrcBlend);
pD3DDevice->SetRenderState(D3DRS_DESTBLEND, OldDestBlend);
}
// Make sure to release the device object!
pD3DDevice->Release();
// Return success
return S_OK;
}
HRESULT DrawMesh(D3DXMESHCONTAINER_EX *pMesh,
IDirect3DVertexShader9 *pShader,
IDirect3DVertexDeclaration9 *pDecl)
{
IDirect3DDevice9 *pD3DDevice;
DWORD LastState, OldAlphaState, OldSrcBlend, OldDestBlend;
// Error checking
if(!pMesh || !pShader || !pDecl)
return E_FAIL;
if(!pMesh->MeshData.pMesh)
return E_FAIL;
if(!pMesh->NumMaterials || !pMesh->pMaterials)
return E_FAIL;
// Get the device interface
pMesh->MeshData.pMesh->GetDevice(&pD3DDevice);
// Save render states
pD3DDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &OldAlphaState);
pD3DDevice->GetRenderState(D3DRS_SRCBLEND, &OldSrcBlend);
pD3DDevice->GetRenderState(D3DRS_DESTBLEND, &OldDestBlend);
LastState = OldAlphaState;
// Get mesh buffer pointers
IDirect3DVertexBuffer9 *pVB = NULL;
IDirect3DIndexBuffer9 *pIB = NULL;
pMesh->MeshData.pMesh->GetVertexBuffer(&pVB);
pMesh->MeshData.pMesh->GetIndexBuffer(&pIB);
// Get attribute table
DWORD NumAttributes;
D3DXATTRIBUTERANGE *pAttributes = NULL;
pMesh->MeshData.pMesh->GetAttributeTable(NULL, &NumAttributes);
pAttributes = new D3DXATTRIBUTERANGE[NumAttributes];
pMesh->MeshData.pMesh->GetAttributeTable(pAttributes, &NumAttributes);
// Use the vertex shader interface passed
pD3DDevice->SetFVF(NULL);
pD3DDevice->SetVertexShader(pShader);
pD3DDevice->SetVertexDeclaration(pDecl);
// Set stream sources
pD3DDevice->SetStreamSource(0, pVB, 0, D3DXGetFVFVertexSize(pMesh->MeshData.pMesh->GetFVF()));
pD3DDevice->SetIndices(pIB);
// Go through each attribute group and render
for(DWORD i=0;i<NumAttributes;i++) {
if(pAttributes[i].FaceCount) {
// Get material number
DWORD MatNum = pAttributes[i].AttribId;
// Set texture
pD3DDevice->SetTexture(0, pMesh->pTextures[MatNum]);
// Enable or disable alpha blending per material
if(pMesh->pMaterials[i].MatD3D.Diffuse.a != 1.0f) {
if(LastState != TRUE) {
LastState = TRUE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);//SRCCOLOR);
pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);
}
} else {
if(LastState != FALSE) {
LastState = FALSE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
// Draw the mesh subset
pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
pAttributes[i].VertexStart,
pAttributes[i].VertexCount,
pAttributes[i].FaceStart * 3,
pAttributes[i].FaceCount);
}
}
// Clear stream uses
pD3DDevice->SetStreamSource(0, NULL, 0, 0);
pD3DDevice->SetIndices(NULL);
// Free resources
ReleaseCOM(pVB);
ReleaseCOM(pIB);
delete [] pAttributes;
// Restore alpha blending states
if(LastState != OldAlphaState) {
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, OldAlphaState);
pD3DDevice->SetRenderState(D3DRS_SRCBLEND, OldSrcBlend);
pD3DDevice->SetRenderState(D3DRS_DESTBLEND, OldDestBlend);
}
// Make sure to release the device object!
pD3DDevice->Release();
// Release vertex shader and declaration mapping
pD3DDevice->SetVertexShader(NULL);
pD3DDevice->SetVertexDeclaration(NULL);
return S_OK;
}
HRESULT DrawMeshes(D3DXMESHCONTAINER_EX *pMesh)
{
D3DXMESHCONTAINER_EX *MeshPtr = pMesh;
// Loop through all meshes in list
while(MeshPtr) {
// Draw mesh, returning on error
HRESULT hr = DrawMesh(MeshPtr);
if(FAILED(hr))
return hr;
// Go to next mesh
MeshPtr = (D3DXMESHCONTAINER_EX*)MeshPtr->pNextMeshContainer;
}
// Return success
return S_OK;
}
HRESULT DrawMeshes(D3DXMESHCONTAINER_EX *pMesh,
IDirect3DVertexShader9 *pShader,
IDirect3DVertexDeclaration9 *pDecl)
{
D3DXMESHCONTAINER_EX *MeshPtr = pMesh;
// Loop through all meshes in list
while(MeshPtr) {
// Draw mesh, returning on error
HRESULT hr = DrawMesh(MeshPtr, pShader, pDecl);
if(FAILED(hr))
return hr;
// Go to next mesh
MeshPtr = (D3DXMESHCONTAINER_EX*)MeshPtr->pNextMeshContainer;
}
// Return success
return S_OK;
}
///
//
// Generic .X parser class code
//
///
cXInternalParser::cXInternalParser()
{
m_pD3DDevice = NULL;
m_TexturePath = NULL;
m_Flags = 0;
m_RootMesh = NULL;
m_RootFrame = NULL;
}
cXInternalParser::~cXInternalParser()
{
delete m_RootMesh; m_RootMesh = NULL;
delete m_RootFrame; m_RootFrame = NULL;
}
BOOL cXInternalParser::Parse(char *Filename, void **Data)
{
ID3DXFile *pDXFile = NULL;
ID3DXFileEnumObject *pDXEnum = NULL;
ID3DXFileData *pDXData = NULL;
// Error checking
if(Filename == NULL)
return FALSE;
// Create the file object
if(FAILED(D3DXFileCreate(&pDXFile)))
return FALSE;
// Register the common templates
if(FAILED(pDXFile->RegisterTemplates( /
(LPVOID)D3DRM_XTEMPLATES, /
D3DRM_XTEMPLATE_BYTES))) {
pDXFile->Release();
return FALSE;
}
// Create an enumeration object
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, /
DXFILELOAD_FROMFILE, /
&pDXEnum))) {
pDXFile->Release();
return FALSE;
}
// Loop through all top-level objects, breaking on errors
//BOOL ParseResult;
//while(SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData))) {
// ParseResult = ParseObject(pDXData, NULL, 0, Data, FALSE);
// ReleaseCOM(pDXData);
// if(ParseResult == FALSE)
// break;
//}
SIZE_T num_child;
pDXEnum->GetChildren(&num_child);
BOOL ParseResult;
for(SIZE_T i = 0; i < num_child; i++)
{
if(FAILED(pDXEnum->GetChild(i, &pDXData)))
return NULL;
ParseResult = ParseObject(pDXData, NULL,0,Data,FALSE);
ReleaseCOM(pDXData);
if(ParseResult == FALSE)
break;
}
// Release used COM objects
ReleaseCOM(pDXEnum);
ReleaseCOM(pDXFile);
return TRUE;
}
BOOL cXInternalParser::ParseObject(ID3DXFileData *pDataObj,
ID3DXFileData *pParentDataObj,
DWORD Depth,
void **Data, BOOL Reference)
{
const GUID *Type = GetObjectGUID(pDataObj);
// Process templates based on their type
// Build on to frame hierarchy (ony non-referenced frames)
if(*Type == TID_D3DRMFrame && Reference == FALSE && m_Flags & 2) {
// Allocate a frame
D3DXFRAME_EX *pFrame = new D3DXFRAME_EX();
// Get the frame's name (if any)
pFrame->Name = GetObjectName(pDataObj);
// Link frame into hierarchy
if(Data == NULL) {
// Link as sibling of root
pFrame->pFrameSibling = m_RootFrame;
m_RootFrame = pFrame; pFrame = NULL;
Data = (void**)&m_RootFrame;
} else {
// Link as child of supplied frame
D3DXFRAME_EX *pFramePtr = (D3DXFRAME_EX*)*Data;
pFrame->pFrameSibling = pFramePtr->pFrameFirstChild;
pFramePtr->pFrameFirstChild = pFrame; pFrame = NULL;
Data = (void**)&pFramePtr->pFrameFirstChild;
}
}
// Set a frame transformation matrix
if(*Type == TID_D3DRMFrameTransformMatrix && Reference == FALSE && m_Flags & 2 && Data) {
D3DXFRAME_EX *Frame = (D3DXFRAME_EX*)*Data;
if(Frame) {
Frame->TransformationMatrix = *(D3DXMATRIX*)GetObjectData(pDataObj, NULL);
Frame->matOriginal = Frame->TransformationMatrix;
}
}
// Load a mesh (skinned or regular)
if(*Type == TID_D3DRMMesh && m_Flags & 1) {
// Only load non-referenced skin meshes into memory
if(Reference == FALSE) {
// Load the mesh using the data object load method
D3DXMESHCONTAINER_EX *pMesh = NULL;
LoadMesh(&pMesh, m_pD3DDevice, pDataObj, m_TexturePath, m_NewFVF, m_LoadFlags);
// Link mesh to head of list of meshes
if(pMesh) {
pMesh->pNextMeshContainer = m_RootMesh;
m_RootMesh = pMesh; pMesh = NULL;
// Link mesh to frame if needed
if(Data) {
D3DXFRAME_EX *pFrame = (D3DXFRAME_EX*)*Data;
if(m_Flags & 2 && pFrame)
pFrame->pMeshContainer = m_RootMesh;
}
}
} else {
// If referenced, then check if wanting to link to frame
if(Data) {
D3DXFRAME_EX *pFrame = (D3DXFRAME_EX*)*Data;
if(m_Flags & 2 && m_RootMesh && pFrame) {
// Get name of mesh reference to link to
char *Name = GetObjectName(pDataObj);
if(Name) {
// Find matching mesh by name and store result
pFrame->pMeshContainer = m_RootMesh->Find(Name);
// Clear name
delete [] Name; Name = NULL;
}
}
}
}
}
// Parse child templates
return ParseChildObjects(pDataObj, Depth, Data, Reference);
}
BOOL cXInternalParser::ParseChildObjects(ID3DXFileData *pDataObj,
DWORD Depth, void **Data,
BOOL ForceReference)
{
ID3DXFileData *pSubObj = NULL;
SIZE_T num_child;
BOOL ParseResult = TRUE;
pDataObj->GetChildren(&num_child);
for(SIZE_T j = 0; j < num_child; j++)
{
pDataObj->GetChild(j, &pSubObj);
if(pSubObj->IsReference()){
ForceReference = true;
}
ParseResult = ParseObject(pSubObj,pDataObj,Depth+1, Data,ForceReference);
ReleaseCOM(pSubObj);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
}
IDirectXFileObject *pSubObj = NULL;
ID3DXFileData *pSubData = NULL;
IDirectXFileDataReference *pDataRef = NULL;
BOOL ParseResult = TRUE;
// Scan for embedded templates
while(SUCCEEDED(pDataObj->GetNextObject(&pSubObj))) {
// Process embedded references
if(SUCCEEDED(pSubObj->QueryInterface(
IID_IDirectXFileDataReference,
(void**)&pDataRef))) {
// Resolve the data object
if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {
// Parse the object, remembering the return code
ParseResult = ParseObject(pSubData, pDataObj, Depth+1, Data, TRUE);
ReleaseCOM(pSubData);
}
ReleaseCOM(pDataRef);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
} else
// Process non-referenced embedded templates
if(SUCCEEDED(pSubObj->QueryInterface(
IID_IDirectXFileData,
(void**)&pSubData))) {
// Parse the object, remembering the return code
ParseResult = ParseObject(pSubData, pDataObj, Depth+1, Data, ForceReference);
ReleaseCOM(pSubData);
}
// Release the data object
ReleaseCOM(pSubObj);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
}
return TRUE;
}
const GUID *cXInternalParser::GetObjectGUID(ID3DXFileData *pDataObj)
{
GUID* Type = new GUID;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template type
if(FAILED(pDataObj->GetType(Type)))
return NULL;
return Type;
}
char *cXInternalParser::GetObjectName(ID3DXFileData *pDataObj)
{
char *Name = NULL;
DWORD Size = 0;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template name (if any)
if(FAILED(pDataObj->GetName(NULL, &Size)))
return NULL;
// Allocate a name buffer and retrieve name
if(Size) {
if((Name = new char[Size]) != NULL)
pDataObj->GetName(Name, &Size);
}
return Name;
}
void *cXInternalParser::GetObjectData(ID3DXFileData *pDataObj,
DWORD *Size)
{
void *TemplateData;
SIZE_T TemplateSize=0;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get a data pointer to template
//pDataObj->GetData(NULL, &TemplateSize, (PVOID*)&TemplateData);
pDataObj->Lock(&TemplateSize,(LPCVOID*)(VOID **)&TemplateData);
if (NULL==TemplateData)
{
return NULL;
}
// Save size if needed
if(Size != NULL)
*Size = TemplateSize;
return TemplateData;
}