本篇是创建游戏内核(14)【OO改良版】的续篇,关于该内核的细节说明请参阅创建游戏内核(15)。
接口:
//================================================================================
// Defines for structure, these structures are used for class ANIAMTION.
//================================================================================
typedef struct XFILE_ROTATE_KEY
{
DWORD time;
DWORD floats;
float w;
float x;
float y;
float z;
} *XFILE_ROTATE_KEY_PTR;
typedef struct XFILE_SCALE_KEY
{
DWORD time;
DWORD floats;
D3DXVECTOR3 scale;
} *XFILE_SCALE_KEY_PTR;
typedef struct XFILE_POSITION_KEY
{
DWORD time;
DWORD floats;
D3DXVECTOR3 pos;
} *XFILE_POSITION_KEY_PTR;
typedef struct XFILE_MATRIX_KEY
{
DWORD time;
DWORD floats;
D3DXMATRIX matrix;
} *XFILE_MATRIX_KEY_PTR;
//================================================================================
// Defines for class ANIMATION.
//================================================================================
typedef class ANIMATION
{
public:
ANIMATION();
~ANIMATION();
BOOL load(const char* filename, MESH* map_mesh);
void free();
BOOL is_loaded();
long get_num_anim_set();
ANIM_INFO_SET_PTR get_anim_info_set(const char* name);
ulong get_time_length(const char* name);
BOOL map_to_mesh(MESH* mesh);
BOOL set_loop(BOOL is_loop, const char* name);
private:
void _parse_xfile_data(ID3DXFileData* xfile_data,
ANIM_INFO_SET_PTR anim_set_to_parse, ANIM_INFO_PTR anim_to_parse);
private:
long m_num_anim_info_set;
ANIM_INFO_SET_PTR m_anim_info_set;
} *ANIMATION_PTR;
实现:
//-------------------------------------------------------------------
// Constructor, initialize member data.
//-------------------------------------------------------------------
ANIMATION::ANIMATION()
{
memset(this, 0, sizeof(*this));
}
//-------------------------------------------------------------------
// Destructor, free resource.
//-------------------------------------------------------------------
ANIMATION::~ANIMATION()
{
free();
}
//-------------------------------------------------------------------
// free resource.
//-------------------------------------------------------------------
void ANIMATION::free()
{
delete m_anim_info_set;
m_anim_info_set = NULL;
}
//-------------------------------------------------------------------
// load animation information from specified file and map mesh.
//-------------------------------------------------------------------
BOOL ANIMATION::load(const char* filename, MESH* map_mesh)
{
ID3DXFile* _xfile = NULL;
ID3DXFileEnumObject* _xfile_enum = NULL;
ID3DXFileData* _xfile_data = NULL;
// free a prior animation
free();
// error checking
if(filename == NULL)
return FALSE;
// create the file object
if(FAILED(D3DXFileCreate(&_xfile)))
return FALSE;
// register the templates
if(FAILED(_xfile->RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
{
_xfile->Release();
return FALSE;
}
// create an enumeration object
if(FAILED(_xfile->CreateEnumObject((LPVOID) filename, DXFILELOAD_FROMFILE, &_xfile_enum)))
{
_xfile->Release();
return FALSE;
}
SIZE_T _num_child;
// retrieve the number of children in this file data object
_xfile_enum->GetChildren(&_num_child);
// loop through all objects looking for the animation
for(SIZE_T i = 0; i < _num_child; i++)
{
if(FAILED(_xfile_enum->GetChild(i, &_xfile_data)))
return FALSE;
// parse _xfile data
_parse_xfile_data(_xfile_data, NULL, NULL);
release_com(_xfile_data);
}
release_com(_xfile_enum);
release_com(_xfile);
// map the animation to the supplied mesh (if any)
if(map_mesh != NULL)
map_to_mesh(map_mesh);
return TRUE;
}
//-------------------------------------------------------------------
// Parse xfile data object which type is animation or animation set,
// call recursively.
//-------------------------------------------------------------------
void ANIMATION::_parse_xfile_data(ID3DXFileData* xfile_data,
ANIM_INFO_SET_PTR anim_info_set_to_parse, ANIM_INFO_PTR anim_info_to_parse)
{
GUID _type;
DWORD _size;
char* _name = NULL;
// get the template _type
if(FAILED(xfile_data->GetType(&_type)))
return;
// get the template _name (if any)
if(FAILED(xfile_data->GetName(NULL, &_size)))
return;
if(_size != 0)
{
if((_name = new char[_size]) != NULL)
xfile_data->GetName(_name, &_size);
}
// give template a default name if none found
if(_name == NULL)
{
if((_name = new char[9]) == NULL)
return;
strcpy(_name, "$NoName$");
}
// set current animation set and current animation
ANIM_INFO_SET_PTR _cur_anim_info_set = anim_info_set_to_parse;
ANIM_INFO_PTR _cur_anim_info = anim_info_to_parse;
// process the templates
ANIM_INFO_PTR _new_anim_info = NULL;
ANIM_INFO_SET_PTR _new_anim_info_set = NULL;
PBYTE _data_ptr;
DWORD _time;
XFILE_ROTATE_KEY_PTR _xfile_rot_keys;
XFILE_SCALE_KEY_PTR _xfile_scale_keys;
XFILE_POSITION_KEY_PTR _xfile_pos_keys;
XFILE_MATRIX_KEY_PTR _xfile_mat_keys;
ROTATE_KEY_PTR _anim_rot_keys;
SCALE_KEY_PTR _anim_scale_keys;
POSITION_KEY_PTR _anim_pos_keys;
MATRIX_KEY_PTR _anim_mat_keys;
if(_type == TID_D3DRMAnimationSet) // process an animation set
{
// create an animation set object
if((_new_anim_info_set = new ANIM_INFO_SET()) == NULL)
return;
// set the name
_new_anim_info_set->m_name = _name;
_name = NULL;
// link into the animation set list
_new_anim_info_set->m_next = m_anim_info_set;
m_anim_info_set = _new_anim_info_set;
// set new animation information set as current animation information set
_cur_anim_info_set = _new_anim_info_set;
}
else if(_type == TID_D3DRMAnimation && _cur_anim_info_set != NULL) // process an animtion
{
// create an animation structure
if((_new_anim_info = new ANIM_INFO()) == NULL)
return;
// set the name
_new_anim_info->m_name = _name;
_name = NULL;
// link into current animation information set
_new_anim_info->m_next = _cur_anim_info_set->m_anim_info;
_cur_anim_info_set->m_anim_info = _new_anim_info;
_cur_anim_info = _new_anim_info;
}
else if(_type == TID_D3DRMAnimationKey && _cur_anim_info != NULL) // process an animation key
{
// load in this animation's key data
if(FAILED(xfile_data->Lock(&_size, (LPCVOID*) &_data_ptr)))
return;
DWORD _key_type = ((DWORD*) _data_ptr)[0];
DWORD _num_keys = ((DWORD*) _data_ptr)[1];
switch(_key_type)
{
case 0: // rotate key type
delete[] _cur_anim_info->m_rotate_keys;
if((_cur_anim_info->m_rotate_keys = new ROTATE_KEY[_num_keys]) == NULL)
return;
_cur_anim_info->m_num_rotate_keys = _num_keys;
_anim_rot_keys = _cur_anim_info->m_rotate_keys;
_xfile_rot_keys = (XFILE_ROTATE_KEY_PTR) ((char*) _data_ptr + sizeof(DWORD) * 2);
// translate rotate key information from xfile to animation
for(DWORD i = 0; i < _num_keys; i++)
{
_cur_anim_info->m_rotate_keys[i].time = _xfile_rot_keys->time;
_cur_anim_info->m_rotate_keys[i].quat.x = -_xfile_rot_keys->x;
_cur_anim_info->m_rotate_keys[i].quat.y = -_xfile_rot_keys->y;
_cur_anim_info->m_rotate_keys[i].quat.z = -_xfile_rot_keys->z;
_cur_anim_info->m_rotate_keys[i].quat.w = -_xfile_rot_keys->w;
if(_xfile_rot_keys->time > _cur_anim_info_set->m_time_length)
_cur_anim_info_set->m_time_length = _xfile_rot_keys->time;
_xfile_rot_keys += 1;
}
break;
case 1: // scale key type
delete[] _cur_anim_info->m_scale_keys;
if((_cur_anim_info->m_scale_keys = new SCALE_KEY[_num_keys]) == NULL)
return;
_cur_anim_info->m_num_scale_keys = _num_keys;
_anim_scale_keys = _cur_anim_info->m_scale_keys;
_xfile_scale_keys = (XFILE_SCALE_KEY_PTR) ((char*) _data_ptr + sizeof(DWORD) * 2);
// translate scale key information from xfile to animtion
for(DWORD i = 0; i < _num_keys; i++)
{
_anim_scale_keys[i].time = _xfile_scale_keys->time;
_anim_scale_keys[i].scale = _xfile_scale_keys->scale;
if(_xfile_scale_keys->time > _cur_anim_info_set->m_time_length)
_cur_anim_info_set->m_time_length = _xfile_scale_keys->time;
_xfile_scale_keys += 1;
}
// calculate the interpolation values
if(_num_keys > 1)
{
for(DWORD i = 0; i < _num_keys -1; i++)
{
_time = _anim_scale_keys[i+1].time - _anim_scale_keys[i].time;
if(_time == 0)
_time = 1;
_anim_scale_keys[i].scale_inter =
(_anim_scale_keys[i+1].scale - _anim_scale_keys[i].scale) / (float)_time;
}
}
break;
case 2: // position key _type
delete[] _cur_anim_info->m_position_keys;
if((_cur_anim_info->m_position_keys = new POSITION_KEY[_num_keys]) == NULL)
return;
_cur_anim_info->m_num_position_keys = _num_keys;
_anim_pos_keys = _cur_anim_info->m_position_keys;
_xfile_pos_keys = (XFILE_POSITION_KEY_PTR) ((char*) _data_ptr + sizeof(DWORD) * 2);
// translate position key informaton from xfile to animtion
for(DWORD i = 0; i < _num_keys; i++)
{
_anim_pos_keys[i].time = _xfile_pos_keys->time;
_anim_pos_keys[i].pos = _xfile_pos_keys->pos;
if(_xfile_pos_keys->time > _cur_anim_info_set->m_time_length)
_cur_anim_info_set->m_time_length = _xfile_pos_keys->time;
_xfile_pos_keys += 1;
}
// calculate the interpolation values
if(_num_keys > 1)
{
for(DWORD i = 0;i < _num_keys - 1; i++)
{
_time = _anim_pos_keys[i+1].time - _anim_pos_keys[i].time;
if(_time == 0)
_time = 1;
_anim_pos_keys[i].pos_inter = (_anim_pos_keys[i+1].pos - _anim_pos_keys[i].pos) / (float)_time;
}
}
break;
case 4: // matrix key _type
delete[] _cur_anim_info->m_matrix_keys;
if((_cur_anim_info->m_matrix_keys = new MATRIX_KEY[_num_keys]) == NULL)
return;
_cur_anim_info->m_num_matrix_keys = _num_keys;
_anim_mat_keys = _cur_anim_info->m_matrix_keys;
_xfile_mat_keys = (XFILE_MATRIX_KEY_PTR) ((char*) _data_ptr + sizeof(DWORD) * 2);
// translate matrix key information from xfile to animation
for(DWORD i = 0; i < _num_keys; i++)
{
_anim_mat_keys[i].time = _xfile_mat_keys->time;
_anim_mat_keys[i].matrix = _xfile_mat_keys->matrix;
if(_xfile_mat_keys->time > _cur_anim_info_set->m_time_length)
_cur_anim_info_set->m_time_length = _xfile_mat_keys->time;
_xfile_mat_keys += 1;
}
// calculate the interpolation matrices
if(_num_keys > 1)
{
for(DWORD i = 0; i < _num_keys - 1; i++)
{
_time = _anim_mat_keys[i+1].time - _anim_mat_keys[i].time;
if(_time == 0)
_time = 1;
_anim_mat_keys[i].mat_inter =
(_anim_mat_keys[i+1].matrix - _anim_mat_keys[i].matrix) / (float)_time;
}
}
break;
}
xfile_data->Unlock();
}
else if(_type == TID_D3DRMAnimationOptions && _cur_anim_info != NULL) // process animation options
{
// load in this animation's options
if(FAILED(xfile_data->Lock(&_size, (LPCVOID*) &_data_ptr)))
return;
// process looping information
if(((DWORD*) _data_ptr)[0] == 0)
_cur_anim_info->m_is_loop = TRUE;
else
_cur_anim_info->m_is_loop = FALSE;
// process linear information
if(((DWORD*) _data_ptr)[1] == 0)
_cur_anim_info->m_is_linear = FALSE;
else
_cur_anim_info->m_is_linear = TRUE;
xfile_data->Unlock();
}
else if(_type == TID_D3DRMFrame && _cur_anim_info != NULL) // process a frame reference
{
_cur_anim_info->m_frame_name = _name;
_name = NULL;
// don't enumerate child templates
return;
}
// release _name buffer
delete[] _name;
SIZE_T _num_child;
ID3DXFileData* _child_xfile_data = NULL;
xfile_data->GetChildren(&_num_child);
// scan for embeded templates
for(SIZE_T i = 0; i < _num_child; i++)
{
xfile_data->GetChild(i, &_child_xfile_data);
// parse child xfile data
_parse_xfile_data(_child_xfile_data, _cur_anim_info_set, _cur_anim_info);
release_com(_child_xfile_data);
}
}
//-------------------------------------------------------------------
// Judge whether animation set has beed loaded.
//-------------------------------------------------------------------
BOOL ANIMATION::is_loaded()
{
return (m_anim_info_set != NULL);
}
//-------------------------------------------------------------------
// Map all frames in all animation sets to mesh's frames.
//-------------------------------------------------------------------
BOOL ANIMATION::map_to_mesh(MESH* mesh)
{
ANIM_INFO_SET_PTR _anim_info_set;
ANIM_INFO_PTR _anim_info;
// make sure there is a mesh to work with
if(mesh == NULL)
return FALSE;
// assign links to frames by name
if((_anim_info_set = m_anim_info_set) == NULL)
return FALSE;
// scan through all animation sets
while(_anim_info_set)
{
// scan through all animations in current animation set
_anim_info = _anim_info_set->m_anim_info;
while(_anim_info)
{
// find the matching frame from mesh
_anim_info->m_frame_info = mesh->get_frame_info(_anim_info->m_frame_name);
_anim_info = _anim_info->m_next;
}
_anim_info_set = _anim_info_set->m_next;
}
return TRUE;
}
//-------------------------------------------------------------------
// Get number of animations.
//-------------------------------------------------------------------
long ANIMATION::get_num_anim_set()
{
return m_num_anim_info_set;
}
//-------------------------------------------------------------------
// Get animation set which match specified name.
//-------------------------------------------------------------------
ANIM_INFO_SET_PTR ANIMATION::get_anim_info_set(const char* name)
{
if(m_anim_info_set == NULL)
return NULL;
return m_anim_info_set->find_anim_info_set(name);
}
//-------------------------------------------------------------------
// set loop flag of all animations in the animation set which match
// specified name.
//-------------------------------------------------------------------
BOOL ANIMATION::set_loop(BOOL is_loop, const char* name)
{
ANIM_INFO_SET_PTR _anim_info_set;
if((_anim_info_set = get_anim_info_set(name)) == NULL)
return FALSE;
ANIM_INFO_PTR _anim_info = _anim_info_set->m_anim_info;
while(_anim_info)
{
_anim_info->m_is_loop = is_loop;
_anim_info = _anim_info->m_next;
}
return TRUE;
}
//-------------------------------------------------------------------
// Get time length of animation set which match specified name.
//-------------------------------------------------------------------
ulong ANIMATION::get_time_length(const char* name)
{
ANIM_INFO_SET_PTR _anim_info_set;
if((_anim_info_set = get_anim_info_set(name)) == NULL)
return 0;
return _anim_info_set->m_time_length;
}
测试代码:
/*****************************************************************************
PURPOSE:
Test for class ANIMATION.
*****************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_graphics.h"
#pragma warning(disable : 4996)
//===========================================================================
// Defines class APP which public inherits from class APPLICATION.
//===========================================================================
class APP : public FRAMEWORK
{
public:
BOOL init();
BOOL frame();
BOOL shutdown();
private:
MESH m_mesh;
OBJECT m_object;
ANIMATION m_animation;
DWORD m_last_anim_time;
BOOL m_is_first_render;
};
//-----------------------------------------------------------------------------
// Initialize graphics, set display mode, set vertex buffer, load texture file.
//-----------------------------------------------------------------------------
BOOL APP::init()
{
// Create Direct3D and Direct3DDevice object
if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, FALSE))
return FALSE;
// set perspective projection transform matrix
set_perspective(D3DX_PI/4.0f, 1.33333f, 1.0f, 1000.0f);
D3DXMATRIX _mat_view;
// create and set the view matrix
D3DXMatrixLookAtLH(&_mat_view,
&D3DXVECTOR3(0.0, 50.0, -150.0),
&D3DXVECTOR3(0.0, 50.0, 0.0),
&D3DXVECTOR3(0.0, 1.0, 0.0));
g_d3d_device->SetTransform(D3DTS_VIEW, &_mat_view);
const char* xfilename = "Walk.x";
// load mesh
if(! m_mesh.load(xfilename, ".\\"))
return FALSE;
// load animation
if(! m_animation.load(xfilename, &m_mesh))
return FALSE;
// play loop
m_animation.set_loop(TRUE, NULL);
// create object to draw
if(! m_object.create(&m_mesh))
return FALSE;
// attach animation to object
m_object.set_anim_info_set(&m_animation, NULL, timeGetTime());
m_last_anim_time = timeGetTime();
m_is_first_render = TRUE;
return TRUE;
}
//-----------------------------------------------------------------------------
// Release all d3d resource.
//-----------------------------------------------------------------------------
BOOL APP::shutdown()
{
return TRUE;
}
//-----------------------------------------------------------------------------
// render a frame.bbbb
//-----------------------------------------------------------------------------
BOOL APP::frame()
{
D3DXMATRIX _mat_world;
// clear display with specified color
clear_display_buffer(D3DCOLOR_RGBA(0, 0, 0, 255));
// begin scene
if(g_d3d_device->BeginScene())
{
// rotate object along x-axis, y-axis.
m_object.rotate(0, (float) (timeGetTime() / 1000.0), 0);
if(timeGetTime() - m_last_anim_time > 300 || m_is_first_render)
{
// update animation
m_object.update_anim_info_set(timeGetTime(), TRUE);
// update last animation time
m_last_anim_time = timeGetTime();
m_is_first_render = FALSE;
}
// draw object
m_object.render();
// end the scene
g_d3d_device->EndScene();
}
// display video buffer
present_display();
return TRUE;
}
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
APP app;
if(! build_window(inst, "MainClass", "MainWindow", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480))
return -1;
app.run();
return 0;
}