接着上次说
下一个函数
全转换函数(自己起的名。。。)
void CALL HGE_Impl::Gfx_SetTransform(float x, float y, float dx, float dy, float rot, float hscale, float vscale)
{
D3DXMATRIX tmp;
if(vscale==0.0f) D3DXMatrixIdentity(&matView);
else
{
D3DXMatrixTranslation(&matView, -x, -y, 0.0f);
D3DXMatrixScaling(&tmp, hscale, vscale, 1.0f);
D3DXMatrixMultiply(&matView, &matView, &tmp);
D3DXMatrixRotationZ(&tmp, -rot);
D3DXMatrixMultiply(&matView, &matView, &tmp);
D3DXMatrixTranslation(&tmp, x+dx, y+dy, 0.0f);
D3DXMatrixMultiply(&matView, &matView, &tmp);
}
_render_batch();
pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
}
看代码就能看出,这是对DX的矩阵变换函数做了个封装,不管怎么变都用这一个搞定了。
和上一个函数不同的是,这里变的是视图矩阵,就是摄像机的位置,上次那个投影矩阵是摄像机能看到的范围,
在3d世界里,我们感觉到一个东西在动,其实是摄像机在动,因此要有什么变化的话动摄像机就行,方向设相反的,就像这里的-x,-y
函数默认参数是0(vscale垂直变换比例,这个值不可为0,自己用的时候要注意这些值都要有实参),如果有参数为0则将视图矩阵单位化
这里没有做全部判断的检查,自己使用要注意。
开始渲染图像
bool CALL HGE_Impl::Gfx_BeginScene(HTARGET targ)
{
LPDIRECT3DSURFACE8 pSurf=0, pDepth=0;//用法略神奇,dx9已经不这么干了,这里是声明了两个表面,一个用来显示(主缓冲),一个当作Z缓存
D3DDISPLAYMODE Mode;//显示模式 里面有范围,刷新频率,表面格式等等
CRenderTargetList *target=(CRenderTargetList *)targ;//链式结构的渲染目标
HRESULT hr = pD3DDevice->TestCooperativeLevel();//检测设备
if (hr == D3DERR_DEVICELOST) return false;
else if (hr == D3DERR_DEVICENOTRESET)
{
if(bWindowed)
{
if(FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &Mode)) || Mode.Format==D3DFMT_UNKNOWN)
{
_PostError("Can't determine desktop video mode");
return false;
}
//窗口化时的设定,设定后被缓冲格式,位深
d3dppW.BackBufferFormat = Mode.Format;
if(_format_id(Mode.Format) < 4) nScreenBPP=16;
else nScreenBPP=32;
}
//全屏应该是默认有设置所以没有操作
if(!_GfxRestore()) return false;
}
if(VertArray)
{
_PostError("Gfx_BeginScene: Scene is already being rendered");
return false;
}
if(target != pCurTarget)
{
if(target)
{
target->pTex->GetSurfaceLevel(0, &pSurf);//得到一个相应等级的表面,0为最上层,这里因为pSurf是主表面,将要被渲染肯定得在最上层
pDepth=target->pDepth;//直接获得z深度
}
else
{
pSurf=pScreenSurf;
pDepth=pScreenDepth;
}
if(FAILED(pD3DDevice->SetRenderTarget(pSurf, pDepth)))//设置渲染目标,一个是主表面,一个是对应的z深度,现在这种用法dx9已经木有了
{
if(target) pSurf->Release();
_PostError("Gfx_BeginScene: Can't set render target");
return false;
}
if(target)
{
pSurf->Release();//用完释放
if(target->pDepth) pD3DDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
else pD3DDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );//根据判断看要不要开z缓冲
_SetProjectionMatrix(target->width, target->height);
}
else
{ //同上
if(bZBuffer) pD3DDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
else pD3DDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
_SetProjectionMatrix(nScreenWidth, nScreenHeight);
}
pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
D3DXMatrixIdentity(&matView);
pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
pCurTarget=target;
}
pD3DDevice->BeginScene();//开始渲染
pVB->Lock( 0, 0, (BYTE**)&VertArray, 0 );//这里应该起的事一个标记作用,标记已经渲染,只是给VertArray一个初识地址,让它不空,没有锁一点内存
return true;
}
函数用的接口比较老,但是原理还是一样的,把要渲染的内容放在主表面里,然后渲染出来
void CALL HGE_Impl::Gfx_EndScene()
{
_render_batch(true);//后面说这个
pD3DDevice->EndScene();
if(!pCurTarget) pD3DDevice->Present( NULL, NULL, NULL, NULL );//拉一下交换链,把下一个替换上来,NULL参数是剩余所有的表面,这里只开了两个表面
}
结束渲染,直接调用接口就行。
画线函数,在(x1,y1)(x2,y2)之间画一条深度为z的color颜色的线
void CALL HGE_Impl::Gfx_RenderLine(float x1, float y1, float x2, float y2, DWORD color, float z)
{
if(VertArray)
{
if(CurPrimType!=HGEPRIM_LINES || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_LINES || CurTexture || CurBlendMode!=BLEND_DEFAULT)
{
_render_batch();
CurPrimType=HGEPRIM_LINES;
if(CurBlendMode != BLEND_DEFAULT) _SetBlendMode(BLEND_DEFAULT);
if(CurTexture) { pD3DDevice->SetTexture(0, 0); CurTexture=0; }
}
int i=nPrim*HGEPRIM_LINES;
VertArray[i].x = x1; VertArray[i+1].x = x2;
VertArray[i].y = y1; VertArray[i+1].y = y2;
VertArray[i].z = VertArray[i+1].z = z;
VertArray[i].col = VertArray[i+1].col = color;
VertArray[i].tx = VertArray[i+1].tx =
VertArray[i].ty = VertArray[i+1].ty = 0.0f;
nPrim++;
}
}
绘制工作是由dx的函数完成的,HGE有3种基本的图元绘制,除了线之外还有三角形和四边形
具体的绘制工作都是由_render_batch这货完成的,它判断要绘制的内容,完成绘制,还要控制渲染状态(开始和结束)
最后在定点列表里记录下直线的起始和结束点
void CALL HGE_Impl::Gfx_RenderTriple(const hgeTriple *triple)
{
if(VertArray)
{
if(CurPrimType!=HGEPRIM_TRIPLES || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_TRIPLES || CurTexture!=triple->tex || CurBlendMode!=triple->blend)
{
_render_batch();
CurPrimType=HGEPRIM_TRIPLES;
if(CurBlendMode != triple->blend) _SetBlendMode(triple->blend);
if(triple->tex != CurTexture) {
pD3DDevice->SetTexture( 0, (LPDIRECT3DTEXTURE8)triple->tex );
CurTexture = triple->tex;
}
}
memcpy(&VertArray[nPrim*HGEPRIM_TRIPLES], triple->v, sizeof(hgeVertex)*HGEPRIM_TRIPLES);
nPrim++;
}
}
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++;
}
}
其他的两个原始图元都一个德行。
hgeVertex* CALL HGE_Impl::Gfx_StartBatch(int prim_type, HTEXTURE tex, int blend, int *max_prim)
{
if(VertArray)
{
_render_batch();
CurPrimType=prim_type;
if(CurBlendMode != blend) _SetBlendMode(blend);
if(tex != CurTexture)
{
pD3DDevice->SetTexture( 0, (LPDIRECT3DTEXTURE8)tex );
CurTexture = tex;
}
*max_prim=VERTEX_BUFFER_SIZE / prim_type;
return VertArray;
}
else return 0;
}
void CALL HGE_Impl::Gfx_FinishBatch(int nprim)
{
nPrim=nprim;
}
批量绘制图元,还有停止绘制图元,绘制还是依靠_rander_batch,会有一个混合类型判断
用指针传入的int来记录数量,这里的数量指定点缓存里能容纳的最大数量。