Working with skeletal animation(8)
As shown in Figure 4.5, the SkeletalAnim mesh demonstrates what you learned in this chapter by loading a skinned mesh (the Tiny.x mesh provided in the DirectX SDK samples) and rendering it to the display.
Figure 4.5: Meet Tiny, Microsoft's woman of skeletal meshes. She is constructed from a single mesh and an underlying hierarchy of invisible bones.
source added into Direct3D.cpp:
//
-------------------------------------------------------------------------------------------
// Declare an internal .X file parser class for loading meshes and frames.
// -------------------------------------------------------------------------------------------
class cXInternalParser
{
public :
// information passed from calling function
IDirect3DDevice9 * m_device;
const char * m_texture_path;
DWORD m_new_fvf;
DWORD m_load_flags;
DWORD m_flags; // flags for which data to load: 1 = mesh, 2 = frames, 3 = both.
// hierarchies used during loading
D3DXMESHCONTAINER_EX * m_root_mesh_container;
D3DXFRAME_EX * m_root_frame;
protected :
void parse_object(ID3DXFileData * xfile_data,
ID3DXFileData * parent_xfile_data,
DWORD depth,
void ** data,
bool force_ref);
void parse_child_object(ID3DXFileData * xfile_data, DWORD depth, void ** data, bool force_ref);
public :
cXInternalParser();
~ cXInternalParser();
bool parse( const char * filename, void ** data);
char * get_name(ID3DXFileData * xfile_data);
};
// ==============================================================================================
// Generic .X parser class code
// ==============================================================================================
cXInternalParser::cXInternalParser()
{
ZeroMemory( this , sizeof ( * this ));
}
cXInternalParser:: ~ cXInternalParser()
{
delete m_root_mesh_container; m_root_mesh_container = NULL;
delete m_root_frame; m_root_frame = NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
bool cXInternalParser::parse( const char * filename, void ** data)
{
if (filename == NULL)
return false ;
ID3DXFile * xfile;
if (FAILED(D3DXFileCreate( & xfile)))
return false ;
// register standard templates
if (FAILED(xfile -> RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
{
xfile -> Release();
return false ;
}
ID3DXFileEnumObject * xfile_enum;
if (FAILED(xfile -> CreateEnumObject(filename, DXFILELOAD_FROMFILE, & xfile_enum)))
{
xfile -> Release();
return false ;
}
SIZE_T num_child;
xfile_enum -> GetChildren( & num_child);
// loop through all top-level objects, breaking on errors.
for (SIZE_T i = 0 ; i < num_child; i ++ )
{
ID3DXFileData * xfile_data;
xfile_enum -> GetChild(i, & xfile_data);
parse_object(xfile_data, NULL, 0 , data, false );
release_com(xfile_data);
}
release_com(xfile_enum);
release_com(xfile);
return true ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cXInternalParser::parse_object(ID3DXFileData * xfile_data,
ID3DXFileData * parent_xfile_data,
DWORD depth, void ** data, bool force_ref)
{
GUID type;
xfile_data -> GetType( & type);
// process templates based on their type
if (type == TID_D3DRMFrame && (m_flags & PARSE_FRAME) && force_ref == false )
{
D3DXFRAME_EX * frame = new D3DXFRAME_EX;
frame -> Name = get_name(xfile_data);
// link frame into hierarchy
if (data == NULL)
{
// link as sibling of root
frame -> pFrameSibling = m_root_frame;
m_root_frame = frame;
frame = NULL;
data = ( void ** ) & m_root_frame;
}
else
{
// link as child of supplied frame
D3DXFRAME_EX * frame_ptr = (D3DXFRAME_EX * ) * data;
frame -> pFrameSibling = frame_ptr -> pFrameFirstChild;
frame_ptr -> pFrameFirstChild = frame;
frame = NULL;
data = ( void ** ) & frame_ptr -> pFrameFirstChild;
}
}
else if (type == TID_D3DRMFrameTransformMatrix && (m_flags & PARSE_FRAME) && data && force_ref == false )
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if (frame)
{
SIZE_T size;
const void * tran_matrix;
xfile_data -> Lock( & size, & tran_matrix);
frame -> TransformationMatrix = * (( const D3DXMATRIX * ) tran_matrix);
frame -> mat_original = frame -> TransformationMatrix;
xfile_data -> Unlock();
}
}
else if (type == TID_D3DRMMesh && (m_flags & PARSE_MESH)) // load a mesh (skinned or regular)
{
if (force_ref == false )
{
D3DXMESHCONTAINER_EX * mesh_container;
load_mesh( & mesh_container, m_device, xfile_data, m_texture_path, m_new_fvf, m_load_flags);
// link mesh to head of list of meshes0
if (mesh_container)
{
mesh_container -> pNextMeshContainer = m_root_mesh_container;
m_root_mesh_container = mesh_container;
mesh_container = NULL;
// link mesh to frame if needed
if (data)
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if ((m_flags & PARSE_FRAME) && frame)
frame -> pMeshContainer = m_root_mesh_container;
}
}
}
else // referenced, then check if wanting to link to frame.
{
if (data)
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if ((m_flags & PARSE_FRAME) && m_root_mesh_container && frame)
{
char * name = get_name(xfile_data);
if (name)
{
frame -> pMeshContainer = m_root_mesh_container -> find(name);
delete[] name;
name = NULL;
}
}
}
}
}
parse_child_object(xfile_data, depth, data, force_ref);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cXInternalParser::parse_child_object(ID3DXFileData * xfile_data,
DWORD depth, void ** data, bool force_ref)
{
SIZE_T num_child;
xfile_data -> GetChildren( & num_child);
// scan for embedded templates
for (SIZE_T i = 0 ; i < num_child; i ++ )
{
ID3DXFileData * child_xfile_data;
xfile_data -> GetChild(i, & child_xfile_data);
if (child_xfile_data -> IsReference())
force_ref = true ;
parse_object(child_xfile_data, xfile_data, depth + 1 , data, force_ref);
release_com(child_xfile_data);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
char * cXInternalParser::get_name(ID3DXFileData * xfile_data)
{
if (xfile_data == NULL)
return NULL;
DWORD size;
if (FAILED(xfile_data -> GetName(NULL, & size)))
return NULL;
char * name = NULL;
if (size > 1 )
{
name = new char [size];
xfile_data -> GetName(name, & size);
}
return name;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT load_mesh(D3DXMESHCONTAINER_EX ** ret_mesh_container,
D3DXFRAME_EX ** ret_frame,
IDirect3DDevice9 * device,
const char * filename,
const char * texture_path,
DWORD new_fvf,
DWORD load_flags)
{
// error checking
if (device == NULL || filename == NULL || texture_path == NULL)
return E_FAIL;
cXInternalParser parser;
// set parser data
parser.m_device = device;
parser.m_texture_path = texture_path;
parser.m_new_fvf = new_fvf;
parser.m_load_flags = load_flags;
parser.m_flags = ((ret_mesh_container == NULL) ? PARSE_NONE : PARSE_MESH) |
((ret_frame == NULL) ? PARSE_NONE : PARSE_FRAME);
// clear mesh and frame pointers
parser.m_root_frame = NULL;
parser.m_root_mesh_container = NULL;
if ( ! parser.parse(filename, NULL))
return E_FAIL;
// 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 (ret_mesh_container && ret_frame && parser.m_root_mesh_container && parser.m_root_frame)
{
// scan through all meshes
D3DXMESHCONTAINER_EX * mesh_container = parser.m_root_mesh_container;
while (mesh_container)
{
// does this mesh use skinning?
if (mesh_container -> pSkinInfo)
{
DWORD num_bones = mesh_container -> pSkinInfo -> GetNumBones();
// allocate the matrix pointers and bone matrices
mesh_container -> frame_combined_matrices = new D3DXMATRIX * [num_bones];
mesh_container -> bone_trans_matrices = new D3DXMATRIX[num_bones];
// match matrix poiners to frames
for (DWORD i = 0 ; i < num_bones; i ++ )
{
const char * bone_name = mesh_container -> pSkinInfo -> GetBoneName(i);
D3DXFRAME_EX * frame = parser.m_root_frame -> find(bone_name);
// match frame to bone
if (frame)
mesh_container -> frame_combined_matrices[i] = & frame -> mat_combined;
else
mesh_container -> frame_combined_matrices[i] = NULL;
}
}
// go to next mesh
mesh_container = (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
}
}
if (ret_mesh_container)
{
// copy the pointer into passed variables
* ret_mesh_container = parser.m_root_mesh_container;
parser.m_root_mesh_container = NULL;
}
else
{
// delete list of meshes in case any were not needed.
delete parser.m_root_mesh_container;
parser.m_root_mesh_container = NULL;
}
if (ret_frame)
{
// assign frame hierarchy pointer
* ret_frame = parser.m_root_frame;
parser.m_root_frame = NULL;
}
else
{
// delete frame hierarchy in case it was loaded and it was not needed.
delete parser.m_root_frame;
parser.m_root_frame = NULL;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT update_skin_mesh(D3DXMESHCONTAINER_EX * mesh_container)
{
if (mesh_container == NULL)
return E_FAIL;
if (mesh_container -> MeshData.pMesh == NULL || mesh_container -> skin_mesh == NULL || mesh_container -> pSkinInfo == NULL)
return E_FAIL;
if (mesh_container -> bone_trans_matrices == NULL || mesh_container -> frame_combined_matrices == NULL)
return E_FAIL;
// copy the bone matrices over (must have been combined before call draw_mesh)
for (DWORD i = 0 ; i < mesh_container -> pSkinInfo -> GetNumBones(); i ++ )
{
// start with bone offset matrix
mesh_container -> bone_trans_matrices[i] = * (mesh_container -> pSkinInfo -> GetBoneOffsetMatrix(i));
// apply frame transformation
if (mesh_container -> frame_combined_matrices[i])
mesh_container -> bone_trans_matrices[i] *= ( * mesh_container -> frame_combined_matrices[i]);
}
void * src_vertices;
void * dest_vertices;
mesh_container -> MeshData.pMesh -> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & src_vertices);
mesh_container -> skin_mesh -> LockVertexBuffer( 0 , ( void ** ) & dest_vertices);
// update the skinned mesh using provided transformations
mesh_container -> pSkinInfo -> UpdateSkinnedMesh(mesh_container -> bone_trans_matrices, NULL, src_vertices, dest_vertices);
mesh_container -> MeshData.pMesh -> UnlockVertexBuffer();
mesh_container -> skin_mesh -> UnlockVertexBuffer();
return S_OK;
}
// Declare an internal .X file parser class for loading meshes and frames.
// -------------------------------------------------------------------------------------------
class cXInternalParser
{
public :
// information passed from calling function
IDirect3DDevice9 * m_device;
const char * m_texture_path;
DWORD m_new_fvf;
DWORD m_load_flags;
DWORD m_flags; // flags for which data to load: 1 = mesh, 2 = frames, 3 = both.
// hierarchies used during loading
D3DXMESHCONTAINER_EX * m_root_mesh_container;
D3DXFRAME_EX * m_root_frame;
protected :
void parse_object(ID3DXFileData * xfile_data,
ID3DXFileData * parent_xfile_data,
DWORD depth,
void ** data,
bool force_ref);
void parse_child_object(ID3DXFileData * xfile_data, DWORD depth, void ** data, bool force_ref);
public :
cXInternalParser();
~ cXInternalParser();
bool parse( const char * filename, void ** data);
char * get_name(ID3DXFileData * xfile_data);
};
// ==============================================================================================
// Generic .X parser class code
// ==============================================================================================
cXInternalParser::cXInternalParser()
{
ZeroMemory( this , sizeof ( * this ));
}
cXInternalParser:: ~ cXInternalParser()
{
delete m_root_mesh_container; m_root_mesh_container = NULL;
delete m_root_frame; m_root_frame = NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
bool cXInternalParser::parse( const char * filename, void ** data)
{
if (filename == NULL)
return false ;
ID3DXFile * xfile;
if (FAILED(D3DXFileCreate( & xfile)))
return false ;
// register standard templates
if (FAILED(xfile -> RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
{
xfile -> Release();
return false ;
}
ID3DXFileEnumObject * xfile_enum;
if (FAILED(xfile -> CreateEnumObject(filename, DXFILELOAD_FROMFILE, & xfile_enum)))
{
xfile -> Release();
return false ;
}
SIZE_T num_child;
xfile_enum -> GetChildren( & num_child);
// loop through all top-level objects, breaking on errors.
for (SIZE_T i = 0 ; i < num_child; i ++ )
{
ID3DXFileData * xfile_data;
xfile_enum -> GetChild(i, & xfile_data);
parse_object(xfile_data, NULL, 0 , data, false );
release_com(xfile_data);
}
release_com(xfile_enum);
release_com(xfile);
return true ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cXInternalParser::parse_object(ID3DXFileData * xfile_data,
ID3DXFileData * parent_xfile_data,
DWORD depth, void ** data, bool force_ref)
{
GUID type;
xfile_data -> GetType( & type);
// process templates based on their type
if (type == TID_D3DRMFrame && (m_flags & PARSE_FRAME) && force_ref == false )
{
D3DXFRAME_EX * frame = new D3DXFRAME_EX;
frame -> Name = get_name(xfile_data);
// link frame into hierarchy
if (data == NULL)
{
// link as sibling of root
frame -> pFrameSibling = m_root_frame;
m_root_frame = frame;
frame = NULL;
data = ( void ** ) & m_root_frame;
}
else
{
// link as child of supplied frame
D3DXFRAME_EX * frame_ptr = (D3DXFRAME_EX * ) * data;
frame -> pFrameSibling = frame_ptr -> pFrameFirstChild;
frame_ptr -> pFrameFirstChild = frame;
frame = NULL;
data = ( void ** ) & frame_ptr -> pFrameFirstChild;
}
}
else if (type == TID_D3DRMFrameTransformMatrix && (m_flags & PARSE_FRAME) && data && force_ref == false )
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if (frame)
{
SIZE_T size;
const void * tran_matrix;
xfile_data -> Lock( & size, & tran_matrix);
frame -> TransformationMatrix = * (( const D3DXMATRIX * ) tran_matrix);
frame -> mat_original = frame -> TransformationMatrix;
xfile_data -> Unlock();
}
}
else if (type == TID_D3DRMMesh && (m_flags & PARSE_MESH)) // load a mesh (skinned or regular)
{
if (force_ref == false )
{
D3DXMESHCONTAINER_EX * mesh_container;
load_mesh( & mesh_container, m_device, xfile_data, m_texture_path, m_new_fvf, m_load_flags);
// link mesh to head of list of meshes0
if (mesh_container)
{
mesh_container -> pNextMeshContainer = m_root_mesh_container;
m_root_mesh_container = mesh_container;
mesh_container = NULL;
// link mesh to frame if needed
if (data)
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if ((m_flags & PARSE_FRAME) && frame)
frame -> pMeshContainer = m_root_mesh_container;
}
}
}
else // referenced, then check if wanting to link to frame.
{
if (data)
{
D3DXFRAME_EX * frame = (D3DXFRAME_EX * ) * data;
if ((m_flags & PARSE_FRAME) && m_root_mesh_container && frame)
{
char * name = get_name(xfile_data);
if (name)
{
frame -> pMeshContainer = m_root_mesh_container -> find(name);
delete[] name;
name = NULL;
}
}
}
}
}
parse_child_object(xfile_data, depth, data, force_ref);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void cXInternalParser::parse_child_object(ID3DXFileData * xfile_data,
DWORD depth, void ** data, bool force_ref)
{
SIZE_T num_child;
xfile_data -> GetChildren( & num_child);
// scan for embedded templates
for (SIZE_T i = 0 ; i < num_child; i ++ )
{
ID3DXFileData * child_xfile_data;
xfile_data -> GetChild(i, & child_xfile_data);
if (child_xfile_data -> IsReference())
force_ref = true ;
parse_object(child_xfile_data, xfile_data, depth + 1 , data, force_ref);
release_com(child_xfile_data);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
char * cXInternalParser::get_name(ID3DXFileData * xfile_data)
{
if (xfile_data == NULL)
return NULL;
DWORD size;
if (FAILED(xfile_data -> GetName(NULL, & size)))
return NULL;
char * name = NULL;
if (size > 1 )
{
name = new char [size];
xfile_data -> GetName(name, & size);
}
return name;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT load_mesh(D3DXMESHCONTAINER_EX ** ret_mesh_container,
D3DXFRAME_EX ** ret_frame,
IDirect3DDevice9 * device,
const char * filename,
const char * texture_path,
DWORD new_fvf,
DWORD load_flags)
{
// error checking
if (device == NULL || filename == NULL || texture_path == NULL)
return E_FAIL;
cXInternalParser parser;
// set parser data
parser.m_device = device;
parser.m_texture_path = texture_path;
parser.m_new_fvf = new_fvf;
parser.m_load_flags = load_flags;
parser.m_flags = ((ret_mesh_container == NULL) ? PARSE_NONE : PARSE_MESH) |
((ret_frame == NULL) ? PARSE_NONE : PARSE_FRAME);
// clear mesh and frame pointers
parser.m_root_frame = NULL;
parser.m_root_mesh_container = NULL;
if ( ! parser.parse(filename, NULL))
return E_FAIL;
// 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 (ret_mesh_container && ret_frame && parser.m_root_mesh_container && parser.m_root_frame)
{
// scan through all meshes
D3DXMESHCONTAINER_EX * mesh_container = parser.m_root_mesh_container;
while (mesh_container)
{
// does this mesh use skinning?
if (mesh_container -> pSkinInfo)
{
DWORD num_bones = mesh_container -> pSkinInfo -> GetNumBones();
// allocate the matrix pointers and bone matrices
mesh_container -> frame_combined_matrices = new D3DXMATRIX * [num_bones];
mesh_container -> bone_trans_matrices = new D3DXMATRIX[num_bones];
// match matrix poiners to frames
for (DWORD i = 0 ; i < num_bones; i ++ )
{
const char * bone_name = mesh_container -> pSkinInfo -> GetBoneName(i);
D3DXFRAME_EX * frame = parser.m_root_frame -> find(bone_name);
// match frame to bone
if (frame)
mesh_container -> frame_combined_matrices[i] = & frame -> mat_combined;
else
mesh_container -> frame_combined_matrices[i] = NULL;
}
}
// go to next mesh
mesh_container = (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
}
}
if (ret_mesh_container)
{
// copy the pointer into passed variables
* ret_mesh_container = parser.m_root_mesh_container;
parser.m_root_mesh_container = NULL;
}
else
{
// delete list of meshes in case any were not needed.
delete parser.m_root_mesh_container;
parser.m_root_mesh_container = NULL;
}
if (ret_frame)
{
// assign frame hierarchy pointer
* ret_frame = parser.m_root_frame;
parser.m_root_frame = NULL;
}
else
{
// delete frame hierarchy in case it was loaded and it was not needed.
delete parser.m_root_frame;
parser.m_root_frame = NULL;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT update_skin_mesh(D3DXMESHCONTAINER_EX * mesh_container)
{
if (mesh_container == NULL)
return E_FAIL;
if (mesh_container -> MeshData.pMesh == NULL || mesh_container -> skin_mesh == NULL || mesh_container -> pSkinInfo == NULL)
return E_FAIL;
if (mesh_container -> bone_trans_matrices == NULL || mesh_container -> frame_combined_matrices == NULL)
return E_FAIL;
// copy the bone matrices over (must have been combined before call draw_mesh)
for (DWORD i = 0 ; i < mesh_container -> pSkinInfo -> GetNumBones(); i ++ )
{
// start with bone offset matrix
mesh_container -> bone_trans_matrices[i] = * (mesh_container -> pSkinInfo -> GetBoneOffsetMatrix(i));
// apply frame transformation
if (mesh_container -> frame_combined_matrices[i])
mesh_container -> bone_trans_matrices[i] *= ( * mesh_container -> frame_combined_matrices[i]);
}
void * src_vertices;
void * dest_vertices;
mesh_container -> MeshData.pMesh -> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & src_vertices);
mesh_container -> skin_mesh -> LockVertexBuffer( 0 , ( void ** ) & dest_vertices);
// update the skinned mesh using provided transformations
mesh_container -> pSkinInfo -> UpdateSkinnedMesh(mesh_container -> bone_trans_matrices, NULL, src_vertices, dest_vertices);
mesh_container -> MeshData.pMesh -> UnlockVertexBuffer();
mesh_container -> skin_mesh -> UnlockVertexBuffer();
return S_OK;
}
WinMain.cpp:
#include
<
windows.h
>
#include < d3d9.h >
#include < d3dx9.h >
#include " Direct3D.h "
IDirect3D9 * g_d3d;
IDirect3DDevice9 * g_device;
D3DXMESHCONTAINER_EX * g_mesh_container;
D3DXFRAME_EX * g_frame;
float g_mesh_radius = 0.0f ; // bounding radius of mesh
const char CLASS_NAME[] = " SkeletalClass " ;
const char CAPTION[] = " Skeletal Demo " ;
////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool do_init(HWND hwnd);
void do_shutdown();
void do_frame();
///////////////////////////////////////////////////////////////////////////////////////////// /
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR, int cmd_show)
{
CoInitialize(NULL); // Initialize the COM system
// Create the window class here and register it
WNDCLASSEX win_class;
win_class.cbSize = sizeof (win_class);
win_class.style = CS_CLASSDC;
win_class.lpfnWndProc = window_proc;
win_class.cbClsExtra = 0 ;
win_class.cbWndExtra = 0 ;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = NULL;
win_class.lpszMenuName = NULL;
win_class.lpszClassName = CLASS_NAME;
win_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if ( ! RegisterClassEx( & win_class))
return - 1 ;
// Create the main window
HWND hwnd = CreateWindow(CLASS_NAME, CAPTION, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
0 , 0 , 640 , 480 , NULL, NULL, inst, NULL);
if (hwnd == NULL)
return - 1 ;
ShowWindow(hwnd, cmd_show);
UpdateWindow(hwnd);
// Call init function and enter message pump
if (do_init(hwnd))
{
MSG msg;
ZeroMemory( & msg, sizeof (MSG));
// Start message pump, waiting for user to exit
while (msg.message != WM_QUIT)
{
if (PeekMessage( & msg, NULL, 0 , 0 , PM_REMOVE))
{
TranslateMessage( & msg);
DispatchMessage( & msg);
}
do_frame(); // Render a single frame
}
}
do_shutdown();
UnregisterClass(CLASS_NAME, inst);
CoUninitialize();
return 0 ;
}
LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Only handle window destruction messages
switch (msg)
{
case WM_DESTROY:
PostQuitMessage( 0 );
break ;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break ;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
bool do_init(HWND hwnd)
{
init_d3d( & g_d3d, & g_device, hwnd, false , false );
if (FAILED(load_mesh( & g_mesh_container, & g_frame, g_device, " ..\\Data\\tiny.x " , " ..\\Data\\ " , 0 , 0 )))
return false ;
// get the bounding radius of the object
g_mesh_radius = 0.0f ;
D3DXMESHCONTAINER_EX * mesh_container = g_mesh_container;
while (mesh_container)
{
ID3DXMesh * mesh = mesh_container -> MeshData.pMesh;
if (mesh)
{
// lock the vertex buffer, get its radius, and unlock buffer.
D3DXVECTOR3 * vertices;
D3DXVECTOR3 center;
float radius;
mesh -> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & vertices);
D3DXComputeBoundingSphere(vertices, mesh -> GetNumVertices(), D3DXGetFVFVertexSize(mesh -> GetFVF()),
& center, & radius);
mesh -> UnlockVertexBuffer();
// update radius
if (radius > g_mesh_radius)
g_mesh_radius = radius;
}
// goto next mesh
mesh_container = (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
}
return true ;
}
void do_shutdown()
{
// free mesh data
delete g_mesh_container; g_mesh_container = NULL;
delete g_frame; g_frame = NULL;
// release D3D objects
release_com(g_device);
release_com(g_d3d);
}
void do_frame()
{
// calculate a view transformation matrix using the mesh's bounding radius to position the viewer
float distance = g_mesh_radius * 3.0f ;
float angle = timeGetTime() / 2000.0f ;
D3DXMATRIX mat_view;
D3DXVECTOR3 eye(cos(angle) * distance, g_mesh_radius, sin(angle) * distance);
D3DXVECTOR3 at( 0.0f , 0.0f , 0.0f );
D3DXVECTOR3 up( 0.0f , 1.0f , 0.0f );
D3DXMatrixLookAtLH( & mat_view, & eye, & at, & up);
g_device -> SetTransform(D3DTS_VIEW, & mat_view);
// rebuild the frame hierarchy transformations
if (g_frame)
g_frame -> update_hierarchy(NULL);
// rebuild the mesh
update_skin_mesh(g_mesh_container);
// clear the device and start drawing the scene
g_device -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 0 , 0 , 64 , 255 ), 1.0f , 0 );
g_device -> BeginScene();
D3DXMATRIX mat_world;
D3DXMatrixIdentity( & mat_world);
g_device -> SetTransform(D3DTS_WORLD, & mat_world);
draw_mesh(g_mesh_container);
g_device -> EndScene();
g_device -> Present(NULL, NULL, NULL, NULL);
}
#include < d3d9.h >
#include < d3dx9.h >
#include " Direct3D.h "
IDirect3D9 * g_d3d;
IDirect3DDevice9 * g_device;
D3DXMESHCONTAINER_EX * g_mesh_container;
D3DXFRAME_EX * g_frame;
float g_mesh_radius = 0.0f ; // bounding radius of mesh
const char CLASS_NAME[] = " SkeletalClass " ;
const char CAPTION[] = " Skeletal Demo " ;
////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool do_init(HWND hwnd);
void do_shutdown();
void do_frame();
///////////////////////////////////////////////////////////////////////////////////////////// /
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR, int cmd_show)
{
CoInitialize(NULL); // Initialize the COM system
// Create the window class here and register it
WNDCLASSEX win_class;
win_class.cbSize = sizeof (win_class);
win_class.style = CS_CLASSDC;
win_class.lpfnWndProc = window_proc;
win_class.cbClsExtra = 0 ;
win_class.cbWndExtra = 0 ;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = NULL;
win_class.lpszMenuName = NULL;
win_class.lpszClassName = CLASS_NAME;
win_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if ( ! RegisterClassEx( & win_class))
return - 1 ;
// Create the main window
HWND hwnd = CreateWindow(CLASS_NAME, CAPTION, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
0 , 0 , 640 , 480 , NULL, NULL, inst, NULL);
if (hwnd == NULL)
return - 1 ;
ShowWindow(hwnd, cmd_show);
UpdateWindow(hwnd);
// Call init function and enter message pump
if (do_init(hwnd))
{
MSG msg;
ZeroMemory( & msg, sizeof (MSG));
// Start message pump, waiting for user to exit
while (msg.message != WM_QUIT)
{
if (PeekMessage( & msg, NULL, 0 , 0 , PM_REMOVE))
{
TranslateMessage( & msg);
DispatchMessage( & msg);
}
do_frame(); // Render a single frame
}
}
do_shutdown();
UnregisterClass(CLASS_NAME, inst);
CoUninitialize();
return 0 ;
}
LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Only handle window destruction messages
switch (msg)
{
case WM_DESTROY:
PostQuitMessage( 0 );
break ;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break ;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
bool do_init(HWND hwnd)
{
init_d3d( & g_d3d, & g_device, hwnd, false , false );
if (FAILED(load_mesh( & g_mesh_container, & g_frame, g_device, " ..\\Data\\tiny.x " , " ..\\Data\\ " , 0 , 0 )))
return false ;
// get the bounding radius of the object
g_mesh_radius = 0.0f ;
D3DXMESHCONTAINER_EX * mesh_container = g_mesh_container;
while (mesh_container)
{
ID3DXMesh * mesh = mesh_container -> MeshData.pMesh;
if (mesh)
{
// lock the vertex buffer, get its radius, and unlock buffer.
D3DXVECTOR3 * vertices;
D3DXVECTOR3 center;
float radius;
mesh -> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & vertices);
D3DXComputeBoundingSphere(vertices, mesh -> GetNumVertices(), D3DXGetFVFVertexSize(mesh -> GetFVF()),
& center, & radius);
mesh -> UnlockVertexBuffer();
// update radius
if (radius > g_mesh_radius)
g_mesh_radius = radius;
}
// goto next mesh
mesh_container = (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
}
return true ;
}
void do_shutdown()
{
// free mesh data
delete g_mesh_container; g_mesh_container = NULL;
delete g_frame; g_frame = NULL;
// release D3D objects
release_com(g_device);
release_com(g_d3d);
}
void do_frame()
{
// calculate a view transformation matrix using the mesh's bounding radius to position the viewer
float distance = g_mesh_radius * 3.0f ;
float angle = timeGetTime() / 2000.0f ;
D3DXMATRIX mat_view;
D3DXVECTOR3 eye(cos(angle) * distance, g_mesh_radius, sin(angle) * distance);
D3DXVECTOR3 at( 0.0f , 0.0f , 0.0f );
D3DXVECTOR3 up( 0.0f , 1.0f , 0.0f );
D3DXMatrixLookAtLH( & mat_view, & eye, & at, & up);
g_device -> SetTransform(D3DTS_VIEW, & mat_view);
// rebuild the frame hierarchy transformations
if (g_frame)
g_frame -> update_hierarchy(NULL);
// rebuild the mesh
update_skin_mesh(g_mesh_container);
// clear the device and start drawing the scene
g_device -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 0 , 0 , 64 , 255 ), 1.0f , 0 );
g_device -> BeginScene();
D3DXMATRIX mat_world;
D3DXMatrixIdentity( & mat_world);
g_device -> SetTransform(D3DTS_WORLD, & mat_world);
draw_mesh(g_mesh_container);
g_device -> EndScene();
g_device -> Present(NULL, NULL, NULL, NULL);
}
download source file