HGE源码分析之图形渲染(一)

HGE是一个开源2D游戏引擎,它最大的特点就是接口简单,易于使用,下面介绍一下他的渲染方法:

HGE使用3Dapi绘制2D图像

这方面的内容这里讲得很清楚:

http://shallway.net/blog/?p=515

hge具体的绘制方法

hge绘制操作由3步完成:

    virtual bool        CALL    Gfx_BeginScene(HTARGET target=0);
virtual void CALL Gfx_EndScene();
virtual void CALL Gfx_Clear(DWORD color);
virtual void CALL Gfx_RenderQuad(const hgeQuad *quad);

  每次渲染以begineScene开始,以endScene结束,在中间进行绘制操作,hge与上面提到的绘制方法有一点区别,下面进行分析

bool CALL HGE_Impl::Gfx_BeginScene(HTARGET targ)
{
.......
if(VertArray)
{
_PostError(
"Gfx_BeginScene: Scene is already being rendered");
return false;
}
.........
pD3DDevice
->BeginScene();
pVB
->Lock( 0, 0, (BYTE**)&VertArray, 0 );

return true;
}

  省略掉了无关代码之后,beginScene做的事是很少的,VertArry是指向顶点缓存的指针,如果不为0说明已经开始渲染,直接返回。然后调用pD3DDevice->BeginScene(),然后锁顶点缓存,以便下一步的绘制操作。

  HGE提供多个绘制函数,下面选择绘制quad的函数进行分析。

  一个quad包含2个三角形,4个顶点,6个索引。

void CALL HGE_Impl::Gfx_RenderQuad(const hgeQuad *quad)
{
if(VertArray)
{
if(CurPrimType!=HGEPRIM_QUADS || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_QUADS || CurTexture!=quad->tex || CurBlendMode!=quad->blend)
{
_render_batch();

CurPrimType
=HGEPRIM_QUADS;
if(CurBlendMode != quad->blend) _SetBlendMode(quad->blend);
if(quad->tex != CurTexture)
{
pD3DDevice
->SetTexture( 0, (LPDIRECT3DTEXTURE8)quad->tex );
CurTexture
= quad->tex;
}
}

memcpy(
&VertArray[nPrim*HGEPRIM_QUADS], quad->v, sizeof(hgeVertex)*HGEPRIM_QUADS);
nPrim
++;
}
}


void HGE_Impl::_render_batch(bool bEndScene)
{
if(VertArray)
{
pVB
->Unlock();

if(nPrim)
{
switch(CurPrimType)
{
case HGEPRIM_QUADS:
pD3DDevice
->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, nPrim<<2, 0, nPrim<<1);
break;

case HGEPRIM_TRIPLES:
pD3DDevice
->DrawPrimitive(D3DPT_TRIANGLELIST, 0, nPrim);
break;

case HGEPRIM_LINES:
pD3DDevice
->DrawPrimitive(D3DPT_LINELIST, 0, nPrim);
break;
}

nPrim
=0;
}

if(bEndScene) VertArray = 0;
else pVB->Lock( 0, 0, (BYTE**)&VertArray, 0 );
}
}

  仔细研究Gfx_RenderQuad(const hgeQuad *quad),发现它并不执行当前的绘制任务,而是将当前的绘制状态(如渲染转台,顶点缓存,nPrim)更新,在下一次调用绘图函数或者EndScene时进行这次的绘制。

  对于其他绘制函数对nPrim的处理有所不同,有兴趣的可以看下源码。

void CALL HGE_Impl::Gfx_EndScene()
{
_render_batch(
true);
pD3DDevice
->EndScene();
if(!pCurTarget) pD3DDevice->Present( NULL, NULL, NULL, NULL );
}

  EndScene调用_render_batch(注意参数为true,保证缓存的unlock状态并置0VertexTray);

  另外可发现,实际调用D3D绘制api的是_render_batch,_render_batch根据参数决定是否将VertexTray置0,HGE绘制函数和endScene会调用_render_batch。

  注意在Gfx_RenderQuad中,只有当绘制条件改变后(如纹理,渲染模式等)Gfx_RenderQuad才会调用_render_batch,如果遇到连续的相同绘制条件的quad对象,Gfx_RenderQuad会把顶点追加到顶点缓存中,然后一起绘制,这样做的原因是缓存的lock与unlock操作很耗时,这样做在遇到大量相同纹理时,可以节约时间,你也可以将许多图片合为一张图片,这样也可以达到相同效果。

  http://shallway.net/blog/?p=515中介绍的改变世界矩阵来避免lock,unlock的方法比HGE中采用的这种方法要好,但是在遇到大量相同纹理,比如粒子系统的时候,HGE的这种方法要优于shallway介绍的方法,但在其它情况下HGE是很慢的,所以HGE的示例程序中绘制2000个quad的时候仍然能够保持较高fps,但如果是2000张不同的图片HGE估计要悲剧。

  有些结论没有经过验证,大家多多指点。

转载于:https://www.cnblogs.com/daoye/archive/2011/07/27/2119027.html

你可能感兴趣的:(游戏)