Can you see why my pFrameRoot->pmeshContainer remains NULL?
Source.cpp
#include "Utilities.h"
#include "allocatehierarchy.h"
char* filename = "tiny.x";
//globals
LPDIRECT3D9 d3dObject=NULL;
LPDIRECT3DDEVICE9 d3dDevice;
LPDIRECTINPUT8 din; // the pointer to our DirectInput interface
LPDIRECTINPUTDEVICE8 dinkeyboard; // the pointer to the keyboard device
BYTE keystate[256]; // the storage for the key-information
LPD3DXFRAME pFrameRoot;
LPD3DXANIMATIONCONTROLLER pAnimController;
//declare functions
void initDInput(HINSTANCE hInstance, HWND hWnd); // sets up and initializes DirectInput
void Render();
void DrawFrame(LPD3DXFRAME frame);
void DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase);
void detect_input(void); // gets the current input state
void cleanDInput(void); // closes DirectInput and releases memory
void Load()
{
CMeshHierarchy Alloc;
D3DXLoadMeshHierarchyFromX(
"tiny.x",
D3DXMESH_MANAGED,
d3dDevice,
&Alloc,
NULL,
&pFrameRoot,
&pAnimController );
//Set Breakpoint to check value of pFrameRoot
if (pFrameRoot)
;
}
HRESULT InitD3D( HWND hWnd )
{
//create D3D Object
if( NULL == ( d3dObject=Direct3DCreate9(D3D_SDK_VERSION) ) )
return E_FAIL;
//setup structure for parameters for D3D Device
D3DPRESENT_PARAMETERS presParams;
ZeroMemory(&presParams,sizeof(presParams));
presParams.Windowed=TRUE;
presParams.SwapEffect=D3DSWAPEFFECT_DISCARD;
presParams.BackBufferFormat=D3DFMT_UNKNOWN;
presParams.PresentationInterval=D3DPRESENT_INTERVAL_ONE;
//create D3D Device
if( FAILED (d3dObject->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice) ) )
{
return E_FAIL;
}
// Turn on ambient lighting
d3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );
return S_OK;
}
VOID SetupMatrices()
{
// Set up world matrix
D3DXMATRIXA16 matWorld;
D3DXMATRIX mtranslate;
// index+=0.03f;
static float index = 0.0f;
if(keystate[DIK_LEFT] & 0x80)
index += 0.06f;
if(keystate[DIK_RIGHT] & 0x80)
index -= 0.06f;
//rotate model
D3DXMatrixRotationY( &matWorld, index );
//translate model
D3DXMatrixTranslation(&mtranslate, index, 0.0f, 0.0f);
d3dDevice->SetTransform( D3DTS_WORLD, &(matWorld * mtranslate) );
// Set up our view matrix. A view matrix can be defined given an eye point,
// a point to lookat, and a direction for which way is up. Here, we set the
// eye five units back along the z-axis and up three units, look at the
// origin, and define "up" to be in the y-direction.
D3DXVECTOR3 vEyePt( 0.0f, 150.0f, 130.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 0.0f, 1.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
d3dDevice->SetTransform( D3DTS_VIEW, &matView );
// For the projection matrix, we set up a perspective transform (which
// transforms geometry from 3D view space to 2D viewport space, with
// a perspective divide making objects smaller in the distance). To build
// a perpsective transform, we need the field of view (1/4 pi is common),
// the aspect ratio, and the near and far clipping planes (which define at
// what distances geometry should be no longer be rendered).
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
d3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
void Render()
{
//clear buffer
d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,50,100),1.0f,0);
//begin scene
d3dDevice->BeginScene();
DrawFrame(pFrameRoot);
SetupMatrices();
//end scene
d3dDevice->EndScene();
//present screen
d3dDevice->Present( NULL, NULL, NULL, NULL );
}
void DrawFrame(LPD3DXFRAME frame)
{
// Draw all mesh containers in this frame
LPD3DXMESHCONTAINER meshContainer = frame->pMeshContainer;
while (meshContainer)
{
DrawMeshContainer(meshContainer, frame);
meshContainer = meshContainer->pNextMeshContainer;
}
// Recurse for sibblings
if (frame->pFrameSibling != NULL)
DrawFrame(frame->pFrameSibling);
// Recurse for children
if (frame->pFrameFirstChild != NULL)
DrawFrame(frame->pFrameFirstChild);
}
void DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase)
{
// Cast to our extended frame type
D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameBase;
// Cast to our extended mesh container
D3DXMESHCONTAINER_EXTENDED *meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase;
// Loop through all the materials in the mesh rendering each subset
for (unsigned int iMaterial = 0; iMaterial < meshContainer->NumMaterials; iMaterial++)
{
// use the material in our extended data rather than the one in meshContainer->pMaterials[iMaterial].MatD3D
d3dDevice->SetMaterial( &meshContainer->exMaterials[iMaterial] );
d3dDevice->SetTexture( 0, meshContainer->exTextures[iMaterial] );
// Select the mesh to draw, if there is skin then use the skinned mesh else the normal one
LPD3DXMESH pDrawMesh = meshContainer->MeshData.pMesh;
// Finally Call the mesh draw function
pDrawMesh->DrawSubset(iMaterial);
}
}
void initDInput(HINSTANCE hInstance, HWND hWnd)
{
// create the DirectInput interface
DirectInput8Create(hInstance, // the handle to the application
DIRECTINPUT_VERSION, // the compatible version
IID_IDirectInput8, // the DirectInput interface version
(void**)&din, // the pointer to the interface
NULL); // COM stuff, so we'll set it to NULL
// create the keyboard device
din->CreateDevice(GUID_SysKeyboard, // the default keyboard ID being used
&dinkeyboard, // the pointer to the device interface
NULL); // COM stuff, so we'll set it to NULL
// set the data format to keyboard format
dinkeyboard->SetDataFormat(&c_dfDIKeyboard);
// set the control we will have over the keyboard
dinkeyboard->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
}
// this is the function that gets the latest input data
void detect_input(void)
{
// get access if we don't have it already
dinkeyboard->Acquire();
// get the input data
dinkeyboard->GetDeviceState(256, (LPVOID)keystate);
}
// this is the function that closes DirectInput
void cleanDInput(void)
{
dinkeyboard->Unacquire(); // make sure the keyboard is unacquired
din->Release(); // close DirectInput before exiting
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//case WM_COMMAND:
// handle menu selections etc.
//break;
//case WM_PAINT:
// draw our window - note: you must paint something here or not trap it!
//break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// We do not want to handle this message so pass back to Windows
// to handle it in a default way
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= (WNDPROC)WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= 0;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= 0;
wcex.lpszClassName= "MyWindowClass";
wcex.hIconSm= 0;
// Now we can go ahead and register our new window class
RegisterClassEx(&wcex);
HWND hWnd = CreateWindow("MyWindowClass", "Poop", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
//call initD3D
InitD3D(hWnd);
initDInput(hInstance, hWnd); // initialize DirectInput
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//enter main loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
Load();
Render();
}
return (int)msg.wParam;
}
AllocateHierarchy.h
#include "Utilities.h"
//Derived Structs
struct D3DXFRAME_EXTENDED: public D3DXFRAME
{
D3DXMATRIX exCombinedTransformationMatrix;
};
struct D3DXMESHCONTAINER_EXTENDED: public D3DXMESHCONTAINER
{
// The base D3DXMESHCONTAINER has a pMaterials member which is a D3DXMATERIAL structure
// that contains a texture filename and material data. It is easier to ignore this and
// instead store the data in arrays of textures and materials in this extended structure:
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
};
class CMeshHierarchy : public ID3DXAllocateHierarchy
{
public:
// callback to create a D3DXFRAME extended object and initialize it
STDMETHOD( CreateFrame )(LPCSTR Name, LPD3DXFRAME *retNewFrame );
// callback to create a D3DXMESHCONTAINER extended object and initialize it
STDMETHOD( CreateMeshContainer )(LPCSTR Name, CONST D3DXMESHDATA * meshData,
CONST D3DXMATERIAL * materials, CONST D3DXEFFECTINSTANCE * effectInstances,
DWORD numMaterials, CONST DWORD * adjacency, LPD3DXSKININFO skinInfo,
LPD3DXMESHCONTAINER * retNewMeshContainer );
// callback to release a D3DXFRAME extended object
STDMETHOD( DestroyFrame )(LPD3DXFRAME frameToFree );
// callback to release a D3DXMESHCONTAINER extended object
STDMETHOD( DestroyMeshContainer )(LPD3DXMESHCONTAINER meshContainerToFree );
};
HRESULT CMeshHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *retNewFrame)
{
// Always a good idea to initialise a return pointer before proceeding
*retNewFrame = 0;
// Create a new frame using the derived version of the structure
D3DXFRAME_EXTENDED *newFrame = new D3DXFRAME_EXTENDED;
ZeroMemory(newFrame,sizeof(D3DXFRAME_EXTENDED));
// Now fill in the data members in the frame structure
// Now initialize other data members of the frame to defaults
D3DXMatrixIdentity(&newFrame->TransformationMatrix);
D3DXMatrixIdentity(&newFrame->exCombinedTransformationMatrix);
newFrame->pMeshContainer = 0;
newFrame->pFrameSibling = 0;
newFrame->pFrameFirstChild = 0;
// Assign the return pointer to our newly created frame
*retNewFrame = newFrame;
// The frame name (note: may be 0 or zero length)
if (Name != NULL)
{
newFrame->Name = new char[strlen(Name) + 1];
strcpy(newFrame->Name, Name);
}
return S_OK;
}
/**
* \brief callback called when a mesh data is encountered during the .x file load
* \param Name - name of the Mesh (const char*)
* \param meshData - the mesh data
* \param materials - material array
* \param effectInstances - effect files / settings for the mesh
* \param numMaterials - number of materials in the mesh
* \param adjacency - adjacency array
* \param pSkinInfo - skin info.
* \param retNewMeshContainer - output pointer to assign our newly created mesh container
* \return success code
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::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 != NULL)
{
newMeshContainer->Name = new char[strlen(Name) + 1];
strcpy(newMeshContainer->Name, Name);
}
// 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];
if (adjacency)
{
memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3);
}
else
{
// Added 24/08/10: previously did not detect null adjacency
if(FAILED( newMeshContainer->MeshData.pMesh->GenerateAdjacency( 1e-6f, (DWORD*)(void*)newMeshContainer->pAdjacency ) ) )
FillMemory((void*)newMeshContainer->pAdjacency, dwFaces*3, 0xFF );
}
// 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 = 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;
if(materials.pTextureFilename)
{
D3DXCreateTextureFromFile(pd3dDevice, materials.pTextureFilename,
&newMeshContainer->exTextures);
}
}
}
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));
// 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)
MessageBox(NULL, "Effect Instance", "Model Load Error", MB_OK);
}
// Set the output mesh container pointer to our newly created one
*retNewMeshContainer = newMeshContainer;
return S_OK;
}
/**
* \brief callback called to deallocate the frame data
* \param the frame to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::DestroyFrame(LPD3DXFRAME frameToFree)
{
// Convert to our extended type. OK to do this as we know for sure it is:
D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameToFree;
delete []frame->Name;
delete frame;
return S_OK;
}
/**
* \brief callback called to deallocate the mesh container data
* \param the mesh data to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::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
delete []meshContainer->Name;
meshContainer->Name=0;
// material array
delete []meshContainer->exMaterials;
meshContainer->exMaterials=0;
// release the textures before deleting the array
if(meshContainer->exTextures)
{
for(UINT i = 0; i < meshContainer->NumMaterials; ++i)
{
if (meshContainer->exTextures)
meshContainer->exTextures->Release();
}
}
// texture array
delete []meshContainer->exTextures;
// adjacency data
delete []meshContainer->pAdjacency;
// bone parts
delete []meshContainer->exBoneOffsets;
// frame matrices
delete []meshContainer->exFrameCombinedMatrixPointer;
// release skin mesh
if (meshContainer->exSkinMesh)
meshContainer->exSkinMesh->Release();
// release the main mesh
if (meshContainer->MeshData.pMesh)
meshContainer->MeshData.pMesh->Release();
// release skin information
if (meshContainer->pSkinInfo)
meshContainer->pSkinInfo->Release();
// finally delete the mesh container itself
delete meshContainer;
meshContainer=0;
return S_OK;
}