#ifdef USE_D3D9
D3D9GraphicsDevice::D3D9GraphicsDevice()
{
_type = GD_D3D9;
_assetsReleased = false;
_d3d = NULL;
_device = NULL;
_windowSurface = NULL;
_desktopSurface = NULL;
}
D3D9GraphicsDevice::~D3D9GraphicsDevice()
{
FreeMemory();
}
void D3D9GraphicsDevice::FreeMemory()
{
if(_device)
{
_device->Release();
_device = 0;
}
if(_d3d)
{
_d3d->Release();
_d3d = 0;
}
}
void D3D9GraphicsDevice::LoadPresentParameters(D3DPRESENT_PARAMETERS &PresentParameters, HWND Window, UINT Width, UINT Height)
{
ZeroMemory( &PresentParameters, sizeof(PresentParameters) );
PresentParameters.BackBufferWidth = Width;
PresentParameters.BackBufferHeight = Height;
PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8;
PresentParameters.BackBufferCount = 1;
PresentParameters.MultiSampleQuality = 0;
PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
PresentParameters.hDeviceWindow = Window;
if(_parameters.MultisampleCount <= 1)
{
PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
PresentParameters.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
}
else
{
PresentParameters.MultiSampleType = D3DMULTISAMPLE_TYPE(_parameters.MultisampleCount);
}
PresentParameters.Windowed = TRUE;
PresentParameters.EnableAutoDepthStencil = TRUE;
PresentParameters.AutoDepthStencilFormat = D3DFMT_D24S8;
PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
if(_parameters.WaitForVSync)
{
PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
}
else
{
PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
}
}
void D3D9GraphicsDevice::InitializeStateMachine()
{
D3DXMATRIXA16 matIdentity;
D3DXMatrixIdentity(&matIdentity);
_device->SetTransform(D3DTS_WORLD, &matIdentity);
_device->SetTransform(D3DTS_VIEW, &matIdentity);
_device->SetTransform(D3DTS_PROJECTION, &matIdentity);
_device->SetRenderState(D3DRS_LIGHTING, FALSE);
_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
_device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
_device->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
_device->SetSamplerState(0,D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
_device->SetSamplerState(0,D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
_device->SetSamplerState(0,D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
_device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
_device->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
_device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
}
void D3D9GraphicsDevice::Init(const GraphicsDeviceParameters ¶meters, ApplicationWindow &window)
{
Init(parameters, window.Handle(), window.Width(), window.Height());
}
void D3D9GraphicsDevice::Init(const GraphicsDeviceParameters ¶meters, HWND window, UINT width, UINT height)
{
FreeMemory();
_parameters = parameters;
if(_parameters.MainFontName.Length() == 0)
{
_parameters.MainFontName = "Verdana";
}
_d3d = Direct3DCreate9( D3D_SDK_VERSION );
Assert(_d3d != NULL, "Direct3DCreate9 failed");
D3DPRESENT_PARAMETERS d3dpp;
LoadPresentParameters(d3dpp, window, width, height);
HRESULT hr = _d3d->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL,
window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp,
&_device );
if(_device == NULL)
{
_parameters.MultisampleCount = 1;
LoadPresentParameters(d3dpp, window, width, height);
hr = _d3d->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL,
window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp,
&_device );
}
if(_device == NULL)
{
hr = _d3d->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL,
window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,
&_device );
}
PersistentAssert(_device != NULL, "CreateDevice failed. This application requires a DirectX 9.0c or better graphics card.");
_assetsReleased = false;
InitializeStateMachine();
}
bool D3D9GraphicsDevice::StartRender()
{
if(!_device)
{
return false;
}
RGBColor ScreenColor = _parameters.ScreenColor;
_device->Clear( 0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, D3DCOLOR_ARGB(ScreenColor.a, ScreenColor.r, ScreenColor.g, ScreenColor.b), 1.0f, 0 );
HRESULT CoopLevel = _device->TestCooperativeLevel();
if(CoopLevel == D3D_OK)
{
_device->BeginScene();
return true;
}
else
{
return false;
}
}
void D3D9GraphicsDevice::FinishRender(ApplicationWindow &window, GraphicsDeviceCallbacks &callbacks)
{
if(!_device)
{
return;
}
HRESULT CoopLevel = _device->TestCooperativeLevel();
if(CoopLevel == D3D_OK)
{
_device->EndScene();
CoopLevel = _device->Present( NULL, NULL, NULL, NULL );
}
if(CoopLevel == D3DERR_DEVICELOST || CoopLevel == D3DERR_DEVICENOTRESET)
{
if(!_assetsReleased)
{
callbacks.ReleaseAssets();
_assetsReleased = true;
}
else
{
HRESULT CoopLevel = _device->TestCooperativeLevel();
if(CoopLevel == D3DERR_DEVICENOTRESET || CoopLevel == D3D_OK)
{
D3DPRESENT_PARAMETERS d3dpp;
LoadPresentParameters(d3dpp, window.Handle(), window.Width(), window.Height());
if(_device->Reset(&d3dpp) == D3D_OK)
{
InitializeStateMachine();
_assetsReleased = false;
callbacks.ResetAssets();
}
}
}
}
}
void D3D9GraphicsDevice::ReSize(ApplicationWindow &window, GraphicsDeviceCallbacks &callbacks)
{
callbacks.ReleaseAssets();
_assetsReleased = true;
D3DPRESENT_PARAMETERS d3dpp;
LoadPresentParameters(d3dpp, window.Handle(), window.Width(), window.Height());
if(_device->Reset(&d3dpp) == D3D_OK)
{
InitializeStateMachine();
_assetsReleased = false;
callbacks.ResetAssets();
}
}
void D3D9GraphicsDevice::ClearTexture(UINT index)
{
_device->SetTexture(index, NULL);
}
void D3D9GraphicsDevice::ToggleWireframe()
{
DWORD value = 0;
_device->GetRenderState(D3DRS_FILLMODE, &value);
if(value == D3DFILL_SOLID)
{
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
else
{
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}
}
void D3D9GraphicsDevice::Render(const Mesh &m)
{
_device->SetFVF(D3DMeshFVF);
_device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, m.VertexCount(), m.FaceCount(), m.Indices(), D3DFMT_INDEX32, m.Vertices(), sizeof(MeshVertex));
}
LPDIRECT3DDEVICE9 D3D9GraphicsDevice::GetDevice()
{
return _device;
}
void D3D9GraphicsDevice::CaptureDesktop(ApplicationWindow &window, Bitmap &bmp)
{
RECT DesktopRect;
GetClientRect(GetDesktopWindow(), &DesktopRect);
if(_desktopSurface == NULL)
{
HRESULT hr = _device->CreateOffscreenPlainSurface(DesktopRect.right, DesktopRect.bottom, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &_desktopSurface, NULL);
PersistentAssert(!FAILED(hr) && _desktopSurface != NULL, "CreateOffscreenPlainSurface failed");
}
HDC DesktopSurfaceDC;
_desktopSurface->GetDC(&DesktopSurfaceDC);
BitBlt(DesktopSurfaceDC, 0, 0, DesktopRect.right, DesktopRect.bottom, GetDC(GetDesktopWindow()), 0, 0, SRCCOPY);
_desktopSurface->ReleaseDC(DesktopSurfaceDC);
bmp.LoadFromSurface(_desktopSurface);
}
void D3D9GraphicsDevice::CaptureScreen(ApplicationWindow &window, Bitmap &bmp)
{
const bool CaptureFrontBuffer = true;
if(CaptureFrontBuffer)
{
RECT DesktopRect;
GetWindowRect(GetDesktopWindow(), &DesktopRect);
LPDIRECT3DSURFACE9 Surface;
HRESULT hr = _device->CreateOffscreenPlainSurface(DesktopRect.right - DesktopRect.left, DesktopRect.bottom - DesktopRect.top, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &Surface, NULL);
PersistentAssert(!FAILED(hr), "CreateOffscreenPlainSurface failed");
PersistentAssert(Surface != NULL, "Invalid surface handle from CreateOffscreenPlainSurface");
hr = _device->GetFrontBufferData(0, Surface);
PersistentAssert(!FAILED(hr), "GetFrontBufferData failed");
Bitmap DesktopBmp;
DesktopBmp.LoadFromSurface(Surface);
DesktopBmp.FlipVertical();
Surface->Release();
RECT WindowCoord;
GetClientRect(window.Handle(), &WindowCoord);
MapWindowPoints(window.Handle(), GetDesktopWindow(), (LPPOINT)&WindowCoord, 2);
UINT Width = WindowCoord.right - WindowCoord.left;
UINT Height = WindowCoord.bottom - WindowCoord.top;
bmp.Allocate(Width, Height);
DesktopBmp.BltTo(bmp, 0, 0, WindowCoord.left, WindowCoord.top, Width, Height);
bmp.FlipBlueAndRed();
bmp.FlipVertical();
}
else
{
LPDIRECT3DSURFACE9 RenderTarget = NULL;
D3DAlwaysValidate(_device->GetRenderTarget(0, &RenderTarget), "GetRenderTarget");
D3DSURFACE_DESC RenderTargetDesc;
D3DAlwaysValidate(RenderTarget->GetDesc(&RenderTargetDesc), "GetDesc");
bool WindowSurfaceValid = (_windowSurface != NULL);
if(WindowSurfaceValid)
{
D3DSURFACE_DESC WindowSurfaceDesc;
D3DAlwaysValidate(_windowSurface->GetDesc(&WindowSurfaceDesc), "GetDesc");
if(WindowSurfaceDesc.Width != RenderTargetDesc.Width || WindowSurfaceDesc.Height != RenderTargetDesc.Height)
{
WindowSurfaceValid = false;
}
}
if(!WindowSurfaceValid)
{
if(_windowSurface != NULL)
{
_windowSurface->Release();
}
D3DAlwaysValidate(_device->CreateOffscreenPlainSurface(RenderTargetDesc.Width, RenderTargetDesc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &_windowSurface, NULL), "CreateOffscreenPlainSurface");
}
D3DAlwaysValidate(_device->GetRenderTargetData(RenderTarget, _windowSurface), "GetRenderTargetData");
RenderTarget->Release();
bmp.LoadFromSurface(_windowSurface);
}
}
#endif