天行健 君子当自强而不息

创建游戏内核(13)


 

本篇是 创建游戏内核(12)的续篇,其中涉及到的网格绘制知识请参阅D3D中网格模型的运用

 

使用MESH加载网格

创建MESH类的目的是为了帮助程序员将那些小守护程序(demon加载到一连串易于使用的类中,然后同其他将网格渲染到显示器上的对象结合起来使用。

点击下载源码和工程

首先定义一个结构体S_MESH来封装ID3DXMesh和ID3DXSkinInfo,以及材质、纹理、变换矩阵等;这个结构体被定位为链表结构。

struct S_MESH
{
public:
    
char*               m_name;             // name of mesh

    ID3DXMesh*          m_mesh;             
// mesh object
    ID3DXMesh*          m_skin_mesh;        // skin mesh object
    ID3DXSkinInfo*      m_skin_info;        // skin mesh information

    DWORD               m_num_materials;    
// number of materials in mesh
    D3DMATERIAL9*       m_materials;        // array of materials
    IDirect3DTexture9** m_textures;         // array of textures

    DWORD               m_num_bones;        
// number of bones
    D3DXMATRIX*         m_matrices;         // bone matrices
    D3DXMATRIX**        m_frame_matrices;   // pointers to frame matrices

    D3DXVECTOR3         m_min, m_max;       
// bounding box
    float               m_radius;           // bounding sphere radius

    S_MESH*              m_next;             
// next mesh in list

    //------------------------------------------------------------------------------------
    // Constructor, initialize all member data.
    //------------------------------------------------------------------------------------
    S_MESH()
    {
        m_name = NULL;
        m_mesh = NULL;
        m_skin_mesh = NULL;
        m_skin_info = NULL;
        m_materials = NULL;
        m_textures  = NULL;
        m_matrices  = NULL;
        m_frame_matrices = NULL;
        m_next           = NULL;

        m_num_materials  = 0;
        m_num_bones      = 0;
        m_radius         = 0.0f;

        m_min.x = m_min.y = m_min.z = m_max.x = m_max.y = m_max.z = 0.0f;
    }

    
//------------------------------------------------------------------------------------
    // Destrcutor, release all resouce.
    //------------------------------------------------------------------------------------
    ~S_MESH()
    {
        Release_COM(m_mesh);
        Release_COM(m_skin_mesh);
        Release_COM(m_skin_info);

        delete[] m_name;
        delete[] m_materials;

        
if(m_textures)
        {
            
for(DWORD i = 0; i < m_num_materials; i++)
                Release_COM(m_textures[i]);

            delete[] m_textures;
        }

        delete[] m_matrices;
        delete[] m_frame_matrices;

        delete m_next;
    }

    
//------------------------------------------------------------------------------------
    // Find mesh object with specified name.
    //------------------------------------------------------------------------------------
    S_MESH* Find_Mesh(char* name)
    {        
        
// return first instance if name is NULL
        if(name == NULL)
            
return this;

        
// compare names and return if exact match
        if(m_name && !strcmp(name, m_name))
            
return this;

        
// search next in list
        if(m_next != NULL)
        {
            S_MESH*  mesh;

            
// recursively call
            if((mesh = m_next->Find_Mesh(name)) != NULL)
                
return mesh;
        }

        
return NULL;
    }

    
//------------------------------------------------------------------------------------
    // Get number of materials.
    //------------------------------------------------------------------------------------
    DWORD Get_Num_Materials()
    {
        
return m_num_materials;
    }

    
//------------------------------------------------------------------------------------
    // Get material object.
    //------------------------------------------------------------------------------------
    D3DMATERIAL9* Get_Material(unsigned long index)
    {
        
if(index >= m_num_materials || m_materials == NULL)
            
return NULL;

        
return &m_materials[index];
    }

    
//------------------------------------------------------------------------------------
    // Get texture object.
    //------------------------------------------------------------------------------------
    IDirect3DTexture9* Get_Texture(unsigned long index)
    {
        
if(index >= m_num_materials || m_textures == NULL)
            
return NULL;

        
return m_textures[index];
    }

    
//------------------------------------------------------------------------------------
    // Copy all matrics from frames to local matrix array.
    //------------------------------------------------------------------------------------
    void Copy_Frame_To_Bone_Matrices()
    {        
        
if(m_num_bones != 0 && m_matrices && m_frame_matrices)
        {
            
for(DWORD i = 0; i < m_num_bones; i++)
            {
                
if(m_frame_matrices[i])
                    
// gets the bone offset matrix and multiply it with frame transformed matrix
                    D3DXMatrixMultiply(&m_matrices[i], m_skin_info->GetBoneOffsetMatrix(i), m_frame_matrices[i]);
                
else
                    D3DXMatrixIdentity(&m_matrices[i]);
            }
        }

        
// process next in list (recursively call)
        if(m_next != NULL)
            m_next->Copy_Frame_To_Bone_Matrices();
    }
};

接着定义一个结构体S_MESH_LIST来封装S_MESH,这个结构体也被定义为链表结构。
 
struct S_MESH_LIST
{
public:
    S_MESH*         m_mesh;
    S_MESH_LIST*    m_next;

    S_MESH_LIST()
    {
        m_mesh = NULL;
        m_next = NULL;
    }
    
    ~S_MESH_LIST()
    {
        delete m_next;
    }
};

再接着定义一个结构体S_FRAME表示框架层次,它也是链表结构,该结构体包含了S_MESH_LIST列表。
 
struct S_FRAME
{
public:
    
char*   m_name;

    S_MESH_LIST*    m_mesh_list;        
// list of meshes attached to this frame

    D3DXMATRIX      m_mat_combined;     
// combined trasnformation matrix
    D3DXMATRIX      m_mat_transformed;  // currently transformed matrix
    D3DXMATRIX      m_mat_original;     // original .x File matrix

    S_FRAME*        m_parent;           
// parent frame
    S_FRAME*        m_child;            // child frame
    S_FRAME*        m_sibling;          // silbling frame

    //------------------------------------------------------------------------------------
    // Constructor, initialize member data.
    //------------------------------------------------------------------------------------
    S_FRAME()
    {
        m_name = NULL;
        m_mesh_list = NULL;

        D3DXMatrixIdentity(&m_mat_combined);
        D3DXMatrixIdentity(&m_mat_transformed);
        D3DXMatrixIdentity(&m_mat_original);

        m_parent = m_sibling = m_child = NULL;           
    }

    
//------------------------------------------------------------------------------------
    // Destructor, release all resource.
    //------------------------------------------------------------------------------------
    ~S_FRAME()
    {
        delete m_name;
        delete m_mesh_list;
        delete m_child;
        delete m_sibling;
    }

    
//------------------------------------------------------------------------------------
    // Find frame with specified name.
    //------------------------------------------------------------------------------------
    S_FRAME* Find_Frame(char* name)
    {        
        
// return this instances if name is NULL
        if(name == NULL)
            
return this;

        
// compare names and return if exact match
        if(m_name && !strcmp(name, m_name))
            
return this;

        S_FRAME* frame;

        
// search child lists, recursively call.
        if(m_child != NULL)
        {
            
if((frame = m_child->Find_Frame(name)) != NULL)
                
return frame;
        }

        
// search sibling lists, recursively call.
        if(m_sibling != NULL)
        {
            
if((frame = m_sibling->Find_Frame(name)) != NULL)
                
return frame;
        }

        
return NULL;
    }

    
//------------------------------------------------------------------------------------
    // Reset transformed matrices to original matrices, recursively call.
    //------------------------------------------------------------------------------------
    void Reset_Matrices()
    {
        m_mat_transformed = m_mat_original;

        
if(m_child != NULL)
            m_child->Reset_Matrices();

        
if(m_sibling != NULL)
            m_sibling->Reset_Matrices();
    }

    
//------------------------------------------------------------------------------------
    // Add mesh into mesh list.
    //------------------------------------------------------------------------------------
    void Add_Mesh(S_MESH* mesh)
    {
        S_MESH_LIST* mesh_list = 
new S_MESH_LIST();

        mesh_list->m_mesh = mesh;
        mesh_list->m_next = m_mesh_list;

        m_mesh_list = mesh_list;
    }
};
 
在以上已经定义好的结构体基础上,我们定义一个类MESH来实现网格文件的加载。

 
class MESH
{
private:
    GRAPHICS*   _graphics;

    
long        _num_meshes;
    S_MESH*      _meshes;

    
long        _num_frames;
    S_FRAME*    _frames;

    D3DXVECTOR3 _min, _max;
    
float       _radius;

    
void _Parse_XFile_Data(ID3DXFileData* xfile_data, S_FRAME* parent_frame, char* texture_path);
    
void _Map_Frames_To_Bones(S_FRAME* frame);

public:
    MESH();
    ~MESH();

    BOOL Is_Loaded();

    
long Get_Num_Frames();
    S_FRAME* Get_Parent_Frame();
    S_FRAME* Get_Frame(
char* name);

    
long Get_Num_Meshes();
    S_MESH* Get_Parent_Mesh();
    S_MESH* Get_Mesh(
char* name);

    
void Get_Bounds(float* min_x, float* min_y, float* min_z, float* max_x, float* max_y, float* max_z, float* radius);

    BOOL Load(GRAPHICS* graphics, 
char* filename, char* texture_path = ".\\");

    
void Free();
};

这是类MESH的实现:
 
//-------------------------------------------------------------------
// Constructor, initialize member data.
//-------------------------------------------------------------------
MESH::MESH()
{
    _graphics   = NULL;
    _meshes     = NULL;
    _frames     = NULL;

    _num_meshes = 0;
    _num_frames = 0;
    _radius     = 0.0f;

    _min.x = _min.y = _min.z = _max.x = _max.y = _max.z = 0.0f;
}

//-------------------------------------------------------------------
// Destructor, release all resource.
//-------------------------------------------------------------------
MESH::~MESH()
{
    Free();
}

//-------------------------------------------------------------------
// Release all resource.
//-------------------------------------------------------------------
void MESH::Free()
{
    _graphics = NULL;

    _num_meshes = 0;
    delete _meshes; _meshes = NULL;

    _num_frames = 0;
    delete _frames; _frames = NULL;

    _min.x = _min.y = _min.z = _max.x = _max.y = _max.z = 0.0f;

    _radius = 0.0f;
}

//-------------------------------------------------------------------
// Load .x File from specified filename.
//-------------------------------------------------------------------
BOOL MESH::Load(GRAPHICS* graphics, char* filename, char* texture_path)
{
    
// free prior mesh object data
    Free();

    
// error checking
    if((_graphics = graphics) == NULL || filename == NULL)
        
return FALSE;

    ID3DXFile* xfile = NULL;

    
// 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;
    }

    ID3DXFileEnumObject* xfile_enum = NULL;

    
// create an enumeration object
    if(FAILED(xfile->CreateEnumObject((LPVOID) filename, DXFILELOAD_FROMFILE, &xfile_enum)))
    {
        xfile->Release();
        
return FALSE;
    }

    
// create a frame
    S_FRAME* frame = new S_FRAME();

    ID3DXFileData* xfile_data = NULL;
    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 frames and meshes
    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, frame, texture_path);

        Release_COM(xfile_data);
    }

    
// release used COM objects
    Release_COM(xfile_enum);
    Release_COM(xfile);

    
// see if we should keep the frame as root
    if(frame->m_mesh_list != NULL)
    {
        _frames = frame;

        _frames->m_name = 
new char[7];
        strcpy(_frames->m_name, "%ROOT%");
    }
    
else
    {
        
// assign the root frame and release frame
        _frames = frame->m_child;
        S_FRAME* frame_ptr = _frames;

        
while(frame_ptr != NULL)
        {
            frame_ptr->m_parent = NULL;
            frame_ptr = frame_ptr->m_sibling;
        }

        frame->m_child = NULL;
        delete frame;
    }

    
// map transformed matrix frames to bones
    _Map_Frames_To_Bones(_frames);

    S_MESH* mesh;

    
// calculate bounding box and sphere
    if((mesh = _meshes) != NULL)
    {
        
while(mesh != NULL)
        {
            _min.x = min(_min.x, mesh->m_min.x);
            _min.y = min(_min.y, mesh->m_min.y);
            _min.z = min(_min.z, mesh->m_min.z);
            _max.x = min(_max.x, mesh->m_max.x);
            _max.y = min(_max.y, mesh->m_max.y);
            _max.z = min(_max.z, mesh->m_max.z);

            _radius = max(_radius, mesh->m_radius);

            mesh = mesh->m_next;
        }
    }

    
return TRUE;
}

//-------------------------------------------------------------------
// Parse specified xfile data, recursive function.
//-------------------------------------------------------------------
void MESH::_Parse_XFile_Data(ID3DXFileData* xfile_data, S_FRAME* parent_frame, char* texture_path)
{
    
// get the template type

    GUID type;

    
// retrieve the globally unique identifier (GUID) of the object's template
    if(FAILED(xfile_data->GetType(&type)))
        
return;

    
// get the template name (if any)

    DWORD size;

    
if(FAILED(xfile_data->GetName(NULL, &size)))
        
return;

    
char* name = NULL;

    
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 frame
    S_FRAME* current_frame = parent_frame;

    
// process the templates

    
if(type == TID_D3DRMFrame)  // it's a frame
    {
        
// create a new frame structure
        S_FRAME* frame = new S_FRAME();

        
// store the name
        frame->m_name = name;
        name = NULL;
        
        
// add to parent frame
        frame->m_parent  = parent_frame;
        frame->m_sibling = parent_frame->m_child;
        parent_frame->m_child = frame;

        
// increase frame count
        _num_frames++;

        
// set current frame with parent frame        
        current_frame = frame;
    }
    
else if(type == TID_D3DRMFrameTransformMatrix)  // it's a frame transformation matrix
    {
        D3DXMATRIX* frame_matrix = NULL;

        
// get frame transformation matrix
        if(FAILED(xfile_data->Lock(&size, (LPCVOID*) &frame_matrix)))
            
return;

        
// set original matrix
        parent_frame->m_mat_original = *frame_matrix;

        xfile_data->Unlock();
    }
    
else if(type == TID_D3DRMMesh)  // it's a mesh
    {
        ID3DXBuffer*    material_buffer = NULL;
        ID3DXBuffer*    adjacency = NULL;
        S_MESH*         mesh = NULL;

        
// see if mesh already loaded
        if(_meshes == NULL || _meshes->Find_Mesh(name) == NULL)
        {
            
// create a new mesh structure
            mesh = new S_MESH();

            
// store the name
            mesh->m_name = name;
            name = NULL;

            
// load mesh data
            if(FAILED(D3DXLoadSkinMeshFromXof(xfile_data, 0, _graphics->Get_Device_COM(),
                &adjacency, &material_buffer, NULL, &mesh->m_num_materials, &mesh->m_skin_info, &mesh->m_mesh)))
            {
                delete[] name;
                delete mesh;
                
return;
            }

            BYTE** ptr;

            
// calculate the bounding box and sphere
            if(SUCCEEDED(mesh->m_mesh->LockVertexBuffer(D3DLOCK_READONLY, (void**) &ptr)))
            {
                
// computes a coordinate-axis oriented bounding box
                D3DXComputeBoundingBox((D3DXVECTOR3*) ptr, mesh->m_mesh->GetNumVertices(),
                    mesh->m_mesh->GetNumBytesPerVertex(), &mesh->m_min, &mesh->m_max);

                
// computes a bounding sphere for the mesh
                D3DXComputeBoundingSphere((D3DXVECTOR3*) ptr, mesh->m_mesh->GetNumVertices(),
                    mesh->m_mesh->GetNumBytesPerVertex(), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &mesh->m_radius);

                mesh->m_mesh->UnlockVertexBuffer();
            }

            
// store number of bones (if any)
            if(mesh->m_skin_info)
                mesh->m_num_bones = mesh->m_skin_info->GetNumBones();

            
// create a matching skinned mesh if bone exist
            if(mesh->m_skin_info != NULL && mesh->m_num_bones != 0)
            {
                
// clones a mesh using a flexible vertex format (FVF) code
                if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), _graphics->Get_Device_COM(),
                                                     &mesh->m_skin_mesh)))
                {
                    Release_COM(mesh->m_skin_info);
                }
                
else    // create an array of matrices to store bone transformations
                {
                    
// create the bone matrix array and clear it out
                    mesh->m_matrices = new D3DXMATRIX[mesh->m_num_bones];

                    
for(DWORD i = 0; i < mesh->m_num_bones; i++)
                        D3DXMatrixIdentity(&mesh->m_matrices[i]);

                    
// create the frame mapping matrix array and clear out
                    mesh->m_frame_matrices = new D3DXMATRIX*[mesh->m_num_bones];

                    
for(DWORD i = 0; i < mesh->m_num_bones; i++)
                        mesh->m_frame_matrices[i] = NULL;
                }
            }
            
            
// load meterials or create a default one if none
            if(mesh->m_num_materials == 0)
            {
                
// create a default one
                mesh->m_materials = new D3DMATERIAL9[1];
                mesh->m_textures  = 
new LPDIRECT3DTEXTURE9[1];

                ZeroMemory(mesh->m_materials, 
sizeof(D3DMATERIAL9));

                mesh->m_materials[0].Diffuse.r = 1.0f;
                mesh->m_materials[0].Diffuse.g = 1.0f;
                mesh->m_materials[0].Diffuse.b = 1.0f;
                mesh->m_materials[0].Diffuse.a = 1.0f;
                mesh->m_materials[0].Ambient   = mesh->m_materials[0].Diffuse;
                mesh->m_materials[0].Specular  = mesh->m_materials[0].Diffuse;

                mesh->m_textures[0] = NULL;

                mesh->m_num_materials = 1;
            }   
            
else
            {
                
// load the materials
                D3DXMATERIAL* materials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();

                mesh->m_materials = 
new D3DMATERIAL9[mesh->m_num_materials];
                mesh->m_textures  = 
new LPDIRECT3DTEXTURE9[mesh->m_num_materials];

                
char path[MAX_PATH];

                
for(DWORD i = 0; i < mesh->m_num_materials; i++)
                {
                    mesh->m_materials[i] = materials[i].MatD3D;
                    mesh->m_materials[i].Ambient = mesh->m_materials[i].Diffuse;

                    
// build a texture path and load it
                    sprintf(path, "%s%s", texture_path, materials[i].pTextureFilename);

                    
if(FAILED(D3DXCreateTextureFromFile(_graphics->Get_Device_COM(), path, &mesh->m_textures[i])))
                        mesh->m_textures[i] = NULL;
                }
            }

            Release_COM(material_buffer);
            Release_COM(adjacency);

            
// link in mesh
            mesh->m_next = _meshes;
            _meshes = mesh;
            _num_meshes++;
        }
        
else
            
// Find mesh in list
            mesh = _meshes->Find_Mesh(name);

        
// add mesh to frame
        if(mesh != NULL)    
            parent_frame->Add_Mesh(mesh);
    } 
// end if(type == TID_D3DRMMesh)
    else if(type == TID_D3DRMAnimationSet || type == TID_D3DRMAnimation || type == TID_D3DRMAnimationKey)
    {
        
// skip animation sets and animations
        delete[] name;
        
return;
    }

    
// release name buffer
    delete[] name;

    ID3DXFileData* child_xfile_data = NULL;
    SIZE_T num_child;

    xfile_data->GetChildren(&num_child);

    
// scan for embedded templates
    for(SIZE_T i = 0; i < num_child; i++)
    {        
        xfile_data->GetChild(i, &child_xfile_data);

        
// process embedded references
        _Parse_XFile_Data(child_xfile_data, current_frame, texture_path);

        Release_COM(child_xfile_data);
    }
}

//-------------------------------------------------------------------
// Map frame transformation matrix to match bone, recursively call.
//-------------------------------------------------------------------
void MESH::_Map_Frames_To_Bones(S_FRAME *frame)
{
    
// return if no more frames to map
    if(frame == NULL || frame->m_name == NULL)
        
return;

    
// scan through meshes looking for bone matches
    S_MESH* mesh = _meshes;

    
while(mesh != NULL)
    {
        
if(mesh->m_skin_info && mesh->m_num_bones && mesh->m_matrices && mesh->m_frame_matrices)
        {
            
for(DWORD i = 0; i < mesh->m_num_bones; i++)
            {
                
if(!strcmp(frame->m_name, mesh->m_skin_info->GetBoneName(i)))
                {
                    mesh->m_frame_matrices[i] = &frame->m_mat_combined;
                    
break;
                }
            }
        }

        mesh = mesh->m_next;
    }

    
// scan through child frames    
    _Map_Frames_To_Bones(frame->m_child);

    
// scan throuogh sibling frames
    _Map_Frames_To_Bones(frame->m_sibling);
}

//-------------------------------------------------------------------
// Judge whether the mesh has been loaded successfully.
//-------------------------------------------------------------------
BOOL MESH::Is_Loaded()
{
    
return (_meshes != NULL && _frames != NULL);
}

//-------------------------------------------------------------------
// Get number of frame.
//-------------------------------------------------------------------
long MESH::Get_Num_Frames()
{
    
return _num_frames;
}

//-------------------------------------------------------------------
// Get root frame.
//-------------------------------------------------------------------
S_FRAME* MESH::Get_Parent_Frame()
{
    
return _frames;
}

//-------------------------------------------------------------------
// Find frame with specified name.
//-------------------------------------------------------------------
S_FRAME* MESH::Get_Frame(char *name)
{
    
if(_frames == NULL)
        
return NULL;

    
return _frames->Find_Frame(name);
}

//-------------------------------------------------------------------
// Get number of mesh.
//-------------------------------------------------------------------
long MESH::Get_Num_Meshes()
{
    
return _num_meshes;
}

//-------------------------------------------------------------------
// Get root mesh.
//-------------------------------------------------------------------
S_MESH* MESH::Get_Mesh(char *name)
{
    
if(_meshes == NULL)
        
return NULL;

    
return _meshes->Find_Mesh(name);
}

//-------------------------------------------------------------------
// Get bound box coordiante and radius.
//-------------------------------------------------------------------
void MESH::Get_Bounds(float *min_x, float *min_y, float *min_z, float *max_x, float *max_y, float *max_z, float *radius)
{
    
if(min_x != NULL)   *min_x = _min.x;
    
if(min_y != NULL)   *min_y = _min.y;
    
if(min_z != NULL)   *min_z = _min.z;

    
if(max_x != NULL)   *max_x = _max.x;
    
if(max_y != NULL)   *max_y = _max.y;
    
if(max_z != NULL)   *max_z = _max.z;

    
if(radius != NULL)  *radius = _radius;
}

接着我们编写一段测试代码来测试MESH类:
/*****************************************************************************
PURPOSE:
    Test for class MESH.
*****************************************************************************/


#include "Core_Global.h"

#pragma warning(disable : 4996)

//===========================================================================
// Defines class APP which public inherits from class APPLICATION.
//===========================================================================
class APP : public APPLICATION
{
private:
    GRAPHICS        _graphics;
    MESH            _mesh;

    BOOL _Draw_Mesh(S_FRAME* frame);
    
public:    
    BOOL Init();
    BOOL Shutdown();
    BOOL Frame();
};

//-----------------------------------------------------------------------------
// Initialize graphics, set display mode, set vertex buffer, load texture file.
//-----------------------------------------------------------------------------
BOOL APP::Init()
{    
    D3DXMATRIX mat_view;

    
// initialize graphics
    if (! _graphics.Init())
        
return FALSE;    

    
// set display mode for graphics
    if(! _graphics.Set_Mode(Get_Hwnd(), TRUE, FALSE, 400, 400, 16))
        
return FALSE;

    
// disable D3D lighting
    _graphics.Enable_Lighting(FALSE);

    
// set perspective projection transform matrix.
    _graphics.Set_Perspective(D3DX_PI/4.0f, 1.33333f, 1.0f, 1000.0f);

    
// 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));

    _graphics.Get_Device_COM()->SetTransform(D3DTS_VIEW, &mat_view);

    
// load mesh
    if(! _mesh.Load(&_graphics, "warrior.x"))
        
return FALSE;

    
return TRUE;
}

//-----------------------------------------------------------------------------
// Release all d3d resource.
//-----------------------------------------------------------------------------
BOOL APP::Shutdown()
{
    
return TRUE;
}

//-----------------------------------------------------------------------------
// Render a frame.
//-----------------------------------------------------------------------------
BOOL APP::Frame()
{
    D3DXMATRIX mat_world;

    
// clear display with specified color
    _graphics.Clear_Display(D3DCOLOR_RGBA(0, 0, 0, 255));

    
// begin scene
    if(_graphics.Begin_Scene())
    {
        
// create and set the world transformation matrix
        // rotate object along z-axis
        D3DXMatrixRotationY(&mat_world, (float) (timeGetTime() / 1000.0));

        _graphics.Get_Device_COM()->SetTransform(D3DTS_WORLD, &mat_world);        

        
// get root frame
        S_FRAME* root_frame = _mesh.Get_Parent_Frame();

        
// draw mesh
        _Draw_Mesh(root_frame);
        
        
// end the scene
        _graphics.End_Scene();       
    }

    
// display video buffer
    _graphics.Display();
    
    
return TRUE;
}

//-----------------------------------------------------------------------------
// Draw mesh, call recursively.
//-----------------------------------------------------------------------------
BOOL APP::_Draw_Mesh(S_FRAME* frame)
{
    D3DXMATRIX* matrices = NULL;
    ID3DXMesh*  mesh_to_draw;  
    S_MESH* mesh;
    
    
// return if no frame
    if(frame == NULL)
        
return FALSE;

    
if(frame->m_mesh_list != NULL)
    {
        
// draw meshes if any in frame
        if((mesh = frame->m_mesh_list->m_mesh) != NULL)
        {
            
// setup pointer to mesh to draw
            mesh_to_draw = mesh->m_mesh;

            
// generate mesh from skinned mesh to draw with
            if(mesh->m_skin_mesh != NULL && mesh->m_skin_info != NULL)
            {
                DWORD num_bones = mesh->m_skin_info->GetNumBones();

                
// allocate an array of matrices to orient bones
                matrices = new D3DXMATRIX[num_bones];

                
// set all bones orientation to identity
                for(DWORD i = 0; i < num_bones; i++)
                    D3DXMatrixIdentity(&matrices[i]);

                
// lock source and destination vertex buffers

                
void* source = NULL;
                
void* dest = NULL;

                
// locks a vertex buffer and obtains a pointer to the vertex buffer memory
                mesh->m_mesh->LockVertexBuffer(0, &source);
                mesh->m_skin_mesh->LockVertexBuffer(0, &dest);

                
// Update skinned mesh, applies software skinning to the target vertices based on the current matrices.
                mesh->m_skin_info->UpdateSkinnedMesh(matrices, NULL, source, dest);

                
// unlock buffers
                mesh->m_mesh->UnlockVertexBuffer();
                mesh->m_skin_mesh->UnlockVertexBuffer();
                
                
// pointer to skin mesh to draw
                mesh_to_draw = mesh->m_skin_mesh;
            }

            
// render the mesh
            for(DWORD i = 0; i < mesh->Get_Num_Materials(); i++)
            {
                
// set the materials properties for the device            
                _graphics.Get_Device_COM()->SetMaterial(&mesh->m_materials[i]);

                
// assign a texture to a stage for a device
                _graphics.Get_Device_COM()->SetTexture(0, mesh->m_textures[i]);

                
// draw a subset of a mesh
                mesh_to_draw->DrawSubset(i);
            }

            
// free array of matrices
            delete[] matrices;
            matrices = NULL;
        }
    }
    
    
// draw child frames, recursively call.
    _Draw_Mesh(frame->m_child);

    
return TRUE;
}


int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    APP app;

    
return app.Run();
}

运行截图:
 


posted on 2007-09-09 01:50 lovedday 阅读(515) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论