#include "StdAfx.h"
#include "device.h"
#pragma comment(lib, "winmm.lib")
namespace Sunlight
{
namespace DirectX
{
namespace Graphics
{
Device::Device(Direct3D *d3d) :
Width(640),
Height(480),
BitsPerPixel(16),
Windowed(false),
Direct3DObject(d3d),
FrameRateFilterTime(100),
m_bCreated(false)
{
}
Device::~Device()
{
Destroy();
}
void Device::Create()
{
Create(false);
}
void Device::Create(bool bReset)
{
if (m_bCreated && !bReset)
return;
if (m_pParentWindow == NULL)
throw new ArgumentNullException(S"ParentWindow");
HRESULT h;
D3DPRESENT_PARAMETERS d3dpp;
FillD3DPP(&d3dpp);
if (bReset)
{
if (!Windowed)
SetupWindow();
h = m_pDevice->Reset(&d3dpp);
if (FAILED(h))
throw new Sunlight::DirectX::DirectXException(S"IDirect3D8::Reset", h);
if (Windowed)
SetupWindow();
SetupDevice();
}
else
{
IDirect3DDevice8 __nogc *pDevice = m_pDevice;
HWND hWndMain = (HWND)m_pParentWindow->Handle.ToPointer();
SetupWindow();
h = ((LPDIRECT3D8)Direct3DObject->GetDirect3D())->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWndMain,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pDevice);
if (FAILED(h))
{
h = ((LPDIRECT3D8)Direct3DObject->GetDirect3D())->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWndMain,
D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &pDevice);
}
if (FAILED(h))
{
h = ((LPDIRECT3D8)Direct3DObject->GetDirect3D())->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWndMain,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice);
}
if (FAILED(h))
throw new Sunlight::DirectX::DirectXException(S"IDirect3D8::CreateDevice", h);
m_pDevice = pDevice;
SetupDevice();
__hook(&System::Windows::Forms::Form::Closed, m_pParentWindow, &Device::OnFormClosed, this);
m_bCreated = true;
__raise Created(this, new EventArgs());
}
D3DDISPLAYMODE mode;
m_pDevice->GetDisplayMode(&mode);
if (mode.RefreshRate != 0)
m_nFrameRate = m_nRefreshRate = mode.RefreshRate;
else
m_nFrameRate = m_nRefreshRate = 60;
m_dwFilteredFrameStartTime = m_dwFrameStartTime = timeGetTime();
m_nFilterFrames = 0;
__raise Initialized(this, new EventArgs());
}
void Device::SetupWindow()
{
m_pParentWindow->AutoScale = false;
if (!Windowed)
{
SetWindowLong((HWND)m_pParentWindow->Handle.ToPointer(), GWL_STYLE, WS_POPUP);
m_pParentWindow->Location = Drawing::Point(0, 0);
m_pParentWindow->Size = Drawing::Size(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
}
else
{
DWORD dwStyle = WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX;
m_pParentWindow->Hide();
int cxScreen = GetSystemMetrics(SM_CXSCREEN);
int cyScreen = GetSystemMetrics(SM_CYSCREEN);
RECT r;
r.left = (cxScreen - Width) / 2;
r.top = (cyScreen - Height) / 2;
r.right = r.left + Width;
r.bottom = r.top + Height;
AdjustWindowRect(&r, dwStyle, FALSE);
m_pParentWindow->Size = Drawing::Size(r.right - r.left, r.bottom - r.top);
m_pParentWindow->Location = Drawing::Point(r.left, r.top);
}
m_pParentWindow->Show();
}
void Device::SetupDevice()
{
m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
m_pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
}
void Device::FillD3DPP(D3DPRESENT_PARAMETERS *pd3dpp)
{
ZeroMemory(pd3dpp, sizeof(D3DPRESENT_PARAMETERS));
if (!Windowed)
{
pd3dpp->Windowed = FALSE;
pd3dpp->BackBufferCount = 2;
pd3dpp->BackBufferFormat = D3DFMT_R5G6B5;
pd3dpp->BackBufferWidth = Width;
pd3dpp->BackBufferHeight = Height;
pd3dpp->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pd3dpp->FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
}
else
{
pd3dpp->Windowed = TRUE;
pd3dpp->BackBufferFormat = Direct3DObject->DefaultDisplayMode.Format;
}
pd3dpp->SwapEffect = D3DSWAPEFFECT_DISCARD;
pd3dpp->hDeviceWindow = (HWND)m_pParentWindow->Handle.ToPointer();
pd3dpp->EnableAutoDepthStencil = TRUE;
pd3dpp->AutoDepthStencilFormat = D3DFMT_D16;
m_nFormat = pd3dpp->BackBufferFormat;
}
void Device::Reset()
{
__raise Lost(this, new EventArgs());
Create(true);
}
void Device::OnFormClosed(Object *sender, EventArgs* e)
{
Destroy();
}
void Device::Destroy()
{
if (m_pDevice != NULL)
{
__raise Lost(this, new EventArgs());
__raise Releasing(this, new EventArgs());
m_pDevice->Release();
m_pDevice = NULL;
ParentWindow->Hide();
}
m_bCreated = false;
}
void Device::BeginScene()
{
Create();
m_pDevice->BeginScene();
}
void Device::EndScene()
{
m_pDevice->BeginScene();
}
void Device::Flip()
{
DWORD dwFrameEndTime = timeGetTime();
m_nFrameRate = 1000.0 / (double)(dwFrameEndTime - m_dwFrameStartTime);
m_dwFrameStartTime = dwFrameEndTime;
if (m_nFrameRate < 1)
m_nFrameRate = 1;
m_nFilterFrames++;
if ((dwFrameEndTime - m_dwFilteredFrameStartTime) > (DWORD)FrameRateFilterTime)
{
m_nFilteredFrameRate = (1000 * m_nFilterFrames) / (dwFrameEndTime - m_dwFilteredFrameStartTime);
m_nFilterFrames = 0;
m_dwFilteredFrameStartTime = dwFrameEndTime;
}
m_pDevice->Present(NULL, NULL, NULL, NULL);
}
System::Windows::Forms::Form *Device::get_ParentWindow()
{
return m_pParentWindow;
}
void Device::set_ParentWindow(System::Windows::Forms::Form *pParent)
{
if (m_pDevice != NULL)
{
Destroy();
m_pParentWindow = pParent;
Create(false);
}
else
m_pParentWindow = pParent;
}
IDirect3DDevice8 *Device::get_Direct3DDevice()
{
return m_pDevice;
}
bool Device::get_Paused()
{
HRESULT h = m_pDevice->TestCooperativeLevel();
switch (h)
{
case D3D_OK:
return false;
case D3DERR_DEVICELOST:
return true;
case D3DERR_DEVICENOTRESET:
Reset();
return true;
}
throw new DirectXException(S"IDirect3DDevice8::TestCooperativeLevel", h);
}
DWORD Device::get_Format()
{
return m_nFormat;
}
double Device::get_FrameRate()
{
return m_nFrameRate;
}
double Device::get_FilteredFrameRate()
{
return m_nFilteredFrameRate;
}
int Device::get_RefreshRate()
{
return m_nRefreshRate;
}
bool Device::get_IsCreated()
{
return m_bCreated;
}
}
}
}