Further to my recent 2D in D3D thread:
If anyone has a couple of minutes, would you mind having a quick glance at my (very simple) D3D8 wrapper. All it does at the moment is batch drawing white quads, with a view to adding textures etc later on to make a nice, simple sprite library.
I'm after any pointers on using D3D and batching more efficiently (although any other criticism is, of course, always welcome). I am aware of the lack of solid error checking code at this stage.
[EDIT] I've also now noticed, after two hours of swearing last night when I came to add textures, that I'm not setting a value to the rhw's in the CVertexBuffer::Add function either [smile].
draw.h
#ifndef draw_H
#define draw_H
#include <windows.h>
#include <sdk\d3d8.h>
struct CVertex
{
float x,y,z,rhw;
D3DCOLOR color;
};
class CVertexBuffer
{
private:
friend class CDevice;
IDirect3DVertexBuffer8 *Ptr;
IDirect3DIndexBuffer8 *Ind;
int Max,No; CVertex *Vtx;
public:
CVertexBuffer() : Ptr(0),Ind(0),Max(0),No(0),Vtx(0) { }
bool Acquire(int N);
bool Release();
void Begin();
void End();
bool Add(int X,int Y,int W,int H);
};
class CDevice
{
public:
CDevice();
bool Acquire(HWND Hw,int W,int H);
bool Release();
void BeginScene();
void EndScene();
void Clear(D3DCOLOR C);
void Present();
void Draw(CVertexBuffer &B);
};
#endif
draw.cpp
#include "draw.h"
#define sqrtf (float)sqrt // this is a workaround for Borland compiler
#include <sdk\d3dx8.h>
namespace
{
IDirect3DDevice8 *Dev=0;
void CreateParams(D3DPRESENT_PARAMETERS &P,HWND Hw,int W,int H);
void CreateIndices(IDirect3DIndexBuffer8 *Ind,int Max);
const DWORD D3DFVF_CVERTEX=(D3DFVF_XYZRHW|D3DFVF_DIFFUSE);
}
bool CVertexBuffer::Acquire(int N)
{
HRESULT R; Max=N*4;
R=Dev->CreateVertexBuffer(Max*sizeof(CVertex),
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
D3DFVF_CVERTEX,D3DPOOL_DEFAULT,&Ptr);
if(FAILED(R)){ Ptr=0; return false; }
R=Dev->CreateIndexBuffer(Max*3,D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,
D3DPOOL_MANAGED,&Ind);
if(FAILED(R)){ Ptr->Release(); Ptr=0; Ind=0; return false; }
CreateIndices(Ind,Max);
return true;
}
bool CVertexBuffer::Release()
{
if(Ptr){ Ptr->Release(); Ptr=0; }
if(Ind){ Ind->Release(); Ind=0; }
return true;
}
void CVertexBuffer::Begin()
{
No=0; Ptr->Lock(0,Max*sizeof(CVertex),(UCHAR**)&Vtx,D3DLOCK_DISCARD);
}
void CVertexBuffer::End()
{
Ptr->Unlock();
}
bool CVertexBuffer::Add(int X,int Y,int W,int H)
{
if(No==Max) return false;
Vtx[No].color=D3DCOLOR_ARGB(255,255,255,255);
Vtx[No].x=X;
Vtx[No].y=Y;
Vtx[No].z=1.0f;
Vtx[No+1].color=D3DCOLOR_ARGB(255,255,255,255);
Vtx[No+1].x=X+W-1;
Vtx[No+1].y=Y;
Vtx[No+1].z=1.0f;
Vtx[No+2].color=D3DCOLOR_ARGB(255,255,255,255);
Vtx[No+2].x=X+W-1;
Vtx[No+2].y=Y+H-1;
Vtx[No+2].z=1.0f;
Vtx[No+3].color=D3DCOLOR_ARGB(255,255,255,255);
Vtx[No+3].x=X;
Vtx[No+3].y=Y+H-1;
Vtx[No+3].z=1.0f;
No+=4; return true;
}
CDevice::CDevice()
{
}
bool CDevice::Acquire(HWND Hw,int W,int H)
{
IDirect3D8 *D=Direct3DCreate8(D3D_SDK_VERSION); if(!D) return false;
D3DPRESENT_PARAMETERS Pm; CreateParams(Pm,Hw,W,H);
HRESULT R=D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,Hw,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,&Pm,&Dev);
D->Release(); if(FAILED(R) || !Dev) return false;
Dev->SetVertexShader(D3DFVF_CVERTEX);
return true;
}
bool CDevice::Release()
{
if(Dev){ Dev->Release(); Dev=0; } return true;
}
void CDevice::BeginScene()
{
Dev->BeginScene();
}
void CDevice::EndScene()
{
Dev->EndScene();
}
void CDevice::Clear(D3DCOLOR C)
{
Dev->Clear(0,NULL,D3DCLEAR_TARGET,C,1.0f,0);
}
void CDevice::Present()
{
Dev->Present(NULL,NULL,NULL,NULL);
}
void CDevice::Draw(CVertexBuffer &B)
{
Dev->SetStreamSource(0,B.Ptr,sizeof(CVertex));
Dev->SetIndices(B.Ind,0);
Dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,B.No,0,B.No/2);
}
namespace
{
void CreateParams(D3DPRESENT_PARAMETERS &P,HWND Hw,int W,int H)
{
P.BackBufferWidth=W;
P.BackBufferHeight=H;
P.BackBufferFormat=D3DFMT_A8R8G8B8;
P.BackBufferCount=1;
P.MultiSampleType=D3DMULTISAMPLE_NONE;
P.SwapEffect=D3DSWAPEFFECT_FLIP;
P.hDeviceWindow=Hw;
P.Windowed=false;
P.EnableAutoDepthStencil=false;
P.AutoDepthStencilFormat=D3DFMT_UNKNOWN;
P.Flags=0;
P.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
P.FullScreen_PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
}
void CreateIndices(IDirect3DIndexBuffer8 *Ind,int Max)
{
int I=0; short *Ptr=NULL;
Ind->Lock(0,Max*3,(UCHAR**)&Ptr,0);
for(int V=0;V<Max;V+=4)
{
Ptr=V;
Ptr[I+1]=V+2;
Ptr[I+2]=V+3;
Ptr[I+3]=V;
Ptr[I+4]=V+1;
Ptr[I+5]=V+2;
I+=6;
}
Ind->Unlock();
}
}
And used in the main loop a bit like (example only):
CDevice Dev;
CVertexBuffer Ver;
bool CEngine::OnAcquire()
{
if(!Dev.Acquire(Hw,Wt,Ht)) return false;
if(!Ver.Acquire(100)) return false;
return true;
}
void CEngine::OnCycle()
{
Dev.Clear(D3DCOLOR_ARGB(255,0,0,64));
Dev.BeginScene();
Ver.Begin();
for(int i=1;i<=20;++i)
{
Ver.Add(i*20,i*20,i*10,i*10);
}
Ver.End();
Dev.Draw(Ver);
Dev.EndScene();
Dev.Present();
}
This is based on various tutorials from this site and a lot of good advice from the forums. If anyone can see anyway to improve basic performance of the D3D bits of this, I'd appreciate you letting me know.
Thanks in advance.
Paul
[Edited by - EasilyConfused on July 27, 2006 8:37:22 AM]