天行健 君子当自强而不息

创建游戏内核(11)


本篇是 创建游戏内核(10)的续篇,其中涉及到的顶点缓存知识请参阅D3D中基本立体面的绘制


顶点和VERTEX_BUFFER

顶点是一个麻烦的东西,有时对它束手无策,通过提供一种快速创建、设置以及渲染顶点集合的方法,VERTEX_BUFFER类能够减少此烦恼。

来看看VERTEX_BUFFER类的定义:

class VERTEX_BUFFER
{
private:
    GRAPHICS*               _graphics;      
// pointer to graphics object
    IDirect3DVertexBuffer9* _vertex_buffer; // pointer to Direct3D vertex buffer object

    DWORD                   _num_vertices;  
// number of vertex
    DWORD                   _vertex_size;   // vertex size
    DWORD                   _fvf;           // flexible vertex format

    BOOL                    _is_locked;     
// flag indicates if vertex buffer has been locked
    char*                   _ptr;           // pointer to vertex data buffer

public:
    VERTEX_BUFFER();
    ~VERTEX_BUFFER();

    IDirect3DVertexBuffer9* Get_Vertex_buffer_COM();

    unsigned 
long Get_Vertex_Size();
    unsigned 
long Get_Vertex_FVF();
    unsigned 
long Get_Num_Vertices();

    BOOL Create(GRAPHICS* graphics, unsigned 
long num_vertices, unsigned long vertex_size, DWORD fvf);    
    
void Free();

    BOOL Is_Loaded();

    BOOL Set(unsigned 
long first_vertex, unsigned long num_vertices, void* vertex_list);
    BOOL Render(unsigned 
long first_vertex, unsigned long num_primitives, DWORD type);

    BOOL Lock(unsigned 
long first_vertex = 0, unsigned long num_vertices = 0);
    BOOL Unlock();
    
void* Get_Ptr();
};

接着是类VERTEX_BUFFER的实现:
//---------------------------------------------------------------------------
// Constructor, initialize data member.
//---------------------------------------------------------------------------
VERTEX_BUFFER::VERTEX_BUFFER()
{
    _graphics       = NULL;
    _vertex_buffer  = NULL;
    _ptr            = NULL;

    _num_vertices   = 0;
    _fvf            = 0;

    _is_locked      = FALSE;
}

//---------------------------------------------------------------------------
// Destructor, free vertex buffer resource.
//---------------------------------------------------------------------------
VERTEX_BUFFER::~VERTEX_BUFFER()
{
    Free();
}

//---------------------------------------------------------------------------
// Get pointer to vetex buffer.
//---------------------------------------------------------------------------
IDirect3DVertexBuffer9* VERTEX_BUFFER::Get_Vertex_buffer_COM()
{
    
return _vertex_buffer;
}

//---------------------------------------------------------------------------
// Gets the size of a vertex for a flexible vertex format (FVF)
//---------------------------------------------------------------------------
unsigned long VERTEX_BUFFER::Get_Vertex_Size()
{
    
return D3DXGetFVFVertexSize(_fvf);
}

//---------------------------------------------------------------------------
// Get flexible vertex format.
//---------------------------------------------------------------------------
unsigned long VERTEX_BUFFER::Get_Vertex_FVF()
{
    
return _fvf;
}

//---------------------------------------------------------------------------
// Get number of vertex.
//---------------------------------------------------------------------------
unsigned long VERTEX_BUFFER::Get_Num_Vertices()
{
    
return _num_vertices;
}

//---------------------------------------------------------------------------
// Create vertex buffer.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Create(GRAPHICS* graphics, unsigned long num_vertices, unsigned long vertex_size, DWORD fvf)
{
    
// free vertex buffer resource first
    Free();

    
// Check condition

    
if((_graphics = graphics) == NULL)
        
return FALSE;

    
if(_graphics->Get_Device_COM() == NULL)
        
return FALSE;

    
if(!(_num_vertices = num_vertices) || !(_fvf = fvf) || !(_vertex_size = vertex_size))
        
return FALSE;

    
// create vertex buffer now
    if(FAILED(_graphics->Get_Device_COM()->CreateVertexBuffer(
        _num_vertices * _vertex_size, 0, _fvf, D3DPOOL_MANAGED, &_vertex_buffer, NULL)))
        
return FALSE;

    
return TRUE;
}

//---------------------------------------------------------------------------
// Free vertex buffer resource, reset data member.
//---------------------------------------------------------------------------
void VERTEX_BUFFER::Free()
{
    Unlock();

    Release_COM(_vertex_buffer);

    _graphics = NULL;
    _ptr      = NULL;

    _num_vertices = 0;
    _fvf          = 0;

    _is_locked = FALSE;
}

//---------------------------------------------------------------------------
// Copy vertex data from VertexList to vertex buffer.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Set(unsigned long first_vertex, unsigned long num_vertices, void* vertex_list)
{
    
// check condition

    
if(_graphics == NULL || vertex_list == NULL || _vertex_buffer == NULL)
        
return FALSE;

    
if(_graphics->Get_Device_COM() == NULL)
        
return FALSE;

    
// lock the vertex buffer
    if(! Lock(first_vertex, num_vertices))
        
return FALSE;

    
// copy vertices to vertex buffer
    memcpy(_ptr, vertex_list, num_vertices * _vertex_size);

    
// unlock vertex buffer
    return Unlock();
}

//---------------------------------------------------------------------------
// Render vertex buffer into display.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Render(unsigned long first_vertex, unsigned long num_primitives, DWORD type)
{
    
if(_graphics->Get_Device_COM() == NULL || _vertex_buffer == NULL)
        
return FALSE;

    
// binds a vertex buffer to a device data stream
    _graphics->Get_Device_COM()->SetStreamSource(0, _vertex_buffer, 0, _vertex_size);

    
// sets the current vertex stream declaration
    _graphics->Get_Device_COM()->SetFVF(_fvf);

    
// Renders a sequence of nonindexed, geometric primitives of the specified type from the current set 
    // of data input streams.
    _graphics->Get_Device_COM()->DrawPrimitive((D3DPRIMITIVETYPE) type, first_vertex, num_primitives);

    
return TRUE;
}

//---------------------------------------------------------------------------
// Lock vertex buffer from specified position with specified length.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Lock(unsigned long first_vertex, unsigned long num_vertices)
{
    
if(_vertex_buffer == NULL)
        
return FALSE;

    
// locks a range of vertex data and obtains a pointer to the vertex buffer memory
    if(FAILED(_vertex_buffer->Lock(first_vertex * _vertex_size, num_vertices * _vertex_size, (void**)&_ptr, 0)))
        
return FALSE;

    _is_locked = TRUE;

    
return TRUE;
}

//---------------------------------------------------------------------------
// Unlock vertex buffer.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Unlock()
{
    
if(_vertex_buffer == NULL)
        
return FALSE;

    
if(FAILED(_vertex_buffer->Unlock()))
        
return FALSE;

    _is_locked = FALSE;

    
return TRUE;
}

//---------------------------------------------------------------------------
// Check whether vertex buffer has created successfully.
//---------------------------------------------------------------------------
BOOL VERTEX_BUFFER::Is_Loaded()
{
    
return _vertex_buffer ? TRUE : FALSE;
}

//---------------------------------------------------------------------------
// Ger pointer to vertex data.
//---------------------------------------------------------------------------
void* VERTEX_BUFFER::Get_Ptr()
{
    
return (void*)_ptr;
}

首先必须使用VERTEX_BUFFER::Create函数创建顶点缓冲,此函数的参数有GRAPHICS对象、用于分配空间的顶点数、单个顶点的大小(单位是字节)、可变顶点格式(FVF)。由此可以看出,要使用这个类,还需要创建一个顶点结构体。

要记得在处理完类的实例后,调用VERTEX_BUFFER::Free函数释放它。但是,在释放类的实例之前,需要调用 VERTEX_BUFFER::Set函数给缓冲区填充要使用的顶点信息。VERTEX_BUFFER::Set函数的参数包括要设置的第一个顶点的索引、要设置的顶点数目、一个指向自定义顶点结构体数组的指针。

经过以上的准备,就可以使用VERTEX_BUFFER::Render函数渲染多边形了,注意可以指定开始绘制的第一个顶点以及要绘制的图元(多边形的面)的总数目。

type参数的含义如下表所示:

标志 说明
D3DPT_POINTLIST 将顶点通过单独的点集合方式进行渲染。
D3DPT_LINELIST 将顶点通过单独的线段集合方式进行渲染。
D3DPT_LINESTRIP 一连串的线段,每条线段都是从前一个顶点到当前顶点绘制而成。
D3DPT_TRIANGLELIST 三角形列,其中每个三角形都有三个独享的顶点。
D3DPT_TRIANGLESTRIP 三角形带,每个顶点都使用前面两个顶点来形成一个面。
D3DPT_TRIANGLEFAN 三角形扇,每个顶点都使用一个中心顶点和另外两个顶点形成一个面。


其中三角形列、带、扇示意图如下:

下面给出测试代码:


点击下载源码和工程


/*****************************************************************************
PURPOSE:
    Test for class VERTEX_BUFFER.
*****************************************************************************/


#include "Core_Global.h"

#pragma warning(disable : 4996)

//===========================================================================
// Defines class APP which public inherits from class APPLICATION.
//===========================================================================
class APP : public APPLICATION
{
private:
    GRAPHICS  _graphics;
    VERTEX_BUFFER _vertex_buffer;    
    
    
// The 2D vertex format and descriptor
    typedef struct
    {
        
float x, y, z;      // 2D coordinates
        float rhw;          // rhw
        D3DCOLOR diffuse;   // diffuse color component
    } VERTEX;

    
#define VERTEX_FVF   (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
    
public:    
    BOOL Init();
    BOOL Shutdown();
    BOOL Frame();
};

//-----------------------------------------------------------------------------
// Initialize graphics, set display mode, set vertex buffer.
//-----------------------------------------------------------------------------
BOOL APP::Init()
{    
    
// initialize vertex data
    VERTEX verts[] = {
      { 100.0f, 100.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(0,64,128,255) },
      { 300.0f, 100.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(0,64,128,255) },
      { 100.0f, 300.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(0,64,128,255) },
      { 300.0f, 300.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(0,64,128,255) },
      {  50.0f, 150.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(128,0,0,128)  },
      { 350.0f, 150.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(128,0,0,128)  },
      {  50.0f, 350.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(128,0,0,128)  },
      { 350.0f, 350.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(128,0,0,128)  }
    }; 

    
// 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;
    
    
// create the vertex buffer
    _vertex_buffer.Create(&_graphics, 8, sizeof(VERTEX), VERTEX_FVF);
   
    
// Copy vertex data from VertexList to vertex buffer.
    _vertex_buffer.Set(0, 8, verts);

    
return TRUE;
}

//-----------------------------------------------------------------------------
// Release all d3d resource.
//-----------------------------------------------------------------------------
BOOL APP::Shutdown()
{
    
// Free vertex buffer resource, reset data member.
     _vertex_buffer.Free();

    
return TRUE;
}

//-----------------------------------------------------------------------------
// Render a frame.
//-----------------------------------------------------------------------------
BOOL APP::Frame()
{
    
// clear display with specified color
    _graphics.Clear_Display(D3DCOLOR_RGBA(0, 0, 0, 255));

    
// begin scene
    if(_graphics.Begin_Scene())
    {
        
// 1) disable alpha blending first
        _graphics.Enable_Alpha_Blending(FALSE);

        
// Render vertex buffer into display.
        _vertex_buffer.Render(0, 2, D3DPT_TRIANGLESTRIP);

        
// 2) enable alpha blending now
        _graphics.Enable_Alpha_Blending(TRUE);

        
// Render vertex buffer into display.
        _vertex_buffer.Render(4, 2, D3DPT_TRIANGLESTRIP);        

        
// end the scene
        _graphics.End_Scene();       
    }

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

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

    
return app.Run();
}
 
运行截图:
 


posted on 2007-09-03 21:33 lovedday 阅读(344) 评论(0)  编辑 收藏 引用


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


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论