[subheading]Setting Up the Project[/subheading]
The DXSDK installation defines the DXSDK_DIR environment variable which can be used to include all the directX files into our project.
for all configurations
In the Project Properties -> C/C++ -> Additional Include Directories add $(DXSDK_DIR)\Include (apart from all the include files) (for all configurations)
In the Project Properties -> Linker -> Additional Library Directories add ..\..\bin\;"$(DXSDK_DIR)\Lib\x86"
Debug Mode
In the Project Properties -> Linker -> Input-> Additional Dependencies add d3dx9d.lib DxErr.lib d3d9.lib winmm.lib dinput8.lib dxguid.lib
Release Mode
In the Project Properties -> Linker -> Input-> Additional Dependencies add d3dx9.lib DxErr.lib d3d9.lib dinput8.lib dxguid.lib winmm.lib
[subheading]IDXBase Interface : DxBase.hxx[/subheading]
Since we dont need to expose all the functions to the rest of the world, we will just include a small subset in the interface. We will come to the purpose of each function in just a bit.
[spoiler]
namespace Graphics
{
class IDXBase
: public Base::cNonCopyable
{
public:
virtual ~IDXBase(){}
virtual void VOnInitialization(const HWND hWnd, const D3DCOLOR & bkColor, const bool bFullScreen, const int iWidth, const int iHeight) = 0;
virtual HRESULT VOnResetDevice() = 0;
virtual HRESULT VBeginRender() = 0;
virtual void VEndRender(const HRESULT hr) = 0;
virtual HRESULT VIsAvailable() const = 0;
virtual void VOnDestroy() = 0;
virtual LPDIRECT3DDEVICE9 VGetDevice() const = 0;
virtual void VToggleFullScreen() = 0;
GRAPHIC_API static IDXBase * GetInstance();
};
}
[/spoiler]
[subheading]cDxBase Class : DxBase.h[/subheading]
The cDxBase class handles the creation of the directX device
[spoiler]
namespace Graphics
{
class cDXBase
: public IDXBase
{
public:
static cDXBase * Create();
private:
cDXBase() ;
~cDXBase() ;
void VOnInitialization(const HWND hWnd, const D3DCOLOR& bkColor, const bool bFullScreen, const int iWidth, const int iHeight);
HRESULT VOnResetDevice() ;
HRESULT VBeginRender();
void VEndRender(const HRESULT hr);
LPDIRECT3DDEVICE9 VGetDevice() const;
HRESULT VIsAvailable() const;
void VOnDestroy();
void VToggleFullScreen();
void DirectxInit() ;
void CreateDirectxDevice() ;
void SetParameters();
void Cleanup() ;
private:
LPDIRECT3D9 m_pD3D ;
LPDIRECT3DDEVICE9 m_pd3dDevice ;
D3DCAPS9 m_Caps ;
D3DCOLOR m_BkColor ;
HWND m_Hwnd ;
D3DPRESENT_PARAMETERS m_d3dpp ;
int m_iWidth;
int m_iHeight ;
D3DDISPLAYMODE m_displayMode;
bool m_bFullScreen;
};
static cDXBase * s_pDXBase= NULL;
}
[/spoiler]
[subheading]Implementation : DxBase.cpp[/subheading]
Constructor
[spoiler]
cDXBase::cDXBase()
: m_pD3D(NULL)
, m_pd3dDevice(NULL)
, m_Hwnd(NULL)
, m_BkColor(BLACK)
, m_bFullScreen(false)
, m_iWidth(0)
, m_iHeight(0)
{
}
[/spoiler]
Destructor - Make sure the directX object and device are released
[spoiler]
cDXBase::~cDXBase()
{
Cleanup();
}
[/spoiler]
method Create - Creates an object of this class and returns it
[spoiler]
cDXBase* cDXBase::Create()
{
return(DEBUG_NEW cDXBase());
}
[/spoiler]
method VOnInitialization - This is the first function that needs to be called since it is responsible for creating the directX object and device
[spoiler]
void cDXBase::VOnInitialization( const HWND hWnd, const D3DCOLOR& bkColor, const bool bFullScreen, const int iWidth, const int iHeight)
{
m_Hwnd = hWnd;
m_BkColor = bkColor;
m_bFullScreen = bFullScreen;
m_iHeight = iHeight;
m_iWidth = iWidth;
// Initialize DirectX
DirectxInit() ;
// Fill out presentation parameters
SetParameters() ;
CreateDirectxDevice() ;
}
[/spoiler]
method VOnResetDevice - Resets the device
[spoiler]
HRESULT cDXBase::VOnResetDevice()
{
if (m_pd3dDevice)
{
HRESULT hr ;
hr = m_pd3dDevice->Reset(&m_d3dpp) ;
return hr ;
}
return 0;
}
[/spoiler]
method VBeginRender- This function clears the surface with the specified color and prepares it for rendering. This function must always be called before we render any geometry.
[spoiler]
HRESULT cDXBase::VBeginRender()
{
HRESULT hr;
// clear the frame with the specified color
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, m_BkColor, 1.0f, 0) ;
hr = m_pd3dDevice->BeginScene() ;
return hr;
}
[/spoiler]
method VEndRender- This function displays what we just rendered to the screen .This function must always be called after we are done rendering
[spoiler]
void cDXBase::VEndRender( const HRESULT hr )
{
if(SUCCEEDED(hr))
{
m_pd3dDevice->EndScene() ;
}
// Present/Display the contents
m_pd3dDevice->Present(NULL, NULL, NULL, NULL) ;
}
[/spoiler]
method VGetDevice
[spoiler]
LPDIRECT3DDEVICE9 cDXBase::VGetDevice() const
{
return m_pd3dDevice;
}
[/spoiler]method VIsAvailable - This function checks whether the device is available for rendering or not. We need to call this function before we begin rendering
[spoiler]
HRESULT cDXBase::VIsAvailable() const
{
return(m_pd3dDevice->TestCooperativeLevel()) ;
}
[/spoiler]method VOnDestroy- Releases the DirectX object and deletes the singleton object
[spoiler]
void cDXBase::VOnDestroy()
{
Cleanup();
delete this;
s_pDXBase = NULL;
}
[/spoiler]method VToggleFullScreen - Toggles between full screen and windowed mode
[spoiler]
void cDXBase::VToggleFullScreen()
{
m_bFullScreen = !m_bFullScreen;
SetParameters();
}
[/spoiler]method DirectxInit- This function creates the Direct3D object. After creating the object, we get the system's current display mode by calling GetAdapterDisplayMode which will be used when we create a fullscreen device. Then we check what the video card is capable of by calling GetDeviceCaps.
[spoiler]
void cDXBase::DirectxInit()
{
//create the Direct3d Object
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION) ;
if(m_pD3D == NULL)
{
\\ error
PostQuitMessage(0);
}
// get the display mode
m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &m_displayMode );
// get the device caps
m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &m_Caps) ;
}
[/spoiler]method CreateDirectxDevice - This function check if the hardware supports transformation and lighting and whether it supports a pure device. In the end, we create the directX device based on the parameters that we have filled and the hardware capabilities.
[spoiler]
void cDXBase::CreateDirectxDevice()
{
int vp = 0 ; // the typeof vertex processing
if(m_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
{
// hardware vertex processing is supported.
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING ;
// Check for pure device
if ( m_Caps.DevCaps & D3DDEVCAPS_PUREDEVICE )
{
vp |= D3DCREATE_PUREDEVICE;
}
}
else
{
// use software vertex processing.
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING ;
}
// Create the D3DDevice
if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, m_Hwnd, vp, &m_d3dpp, &m_pd3dDevice)))
{
\\ error
PostQuitMessage(0) ;
}
}
[/spoiler]method SetParameters - This function fills out the D3DPRESENT_PARAMETERS structures depending on whether it is a full screen or windowed application. We also check which depth stencil format is supported by calling CheckDeviceFormat
[spoiler]
void cDXBase::SetParameters()
{
ZeroMemory(&m_d3dpp, sizeof(m_d3dpp)) ;
m_d3dpp.BackBufferCount = 1 ;
m_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE ;
m_d3dpp.MultiSampleQuality = 0 ;
m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD ;
m_d3dpp.hDeviceWindow = m_Hwnd ;
m_d3dpp.Flags = 0 ;
m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;
m_d3dpp.EnableAutoDepthStencil = true ;
m_d3dpp.Windowed = !m_bFullScreen;
if(m_bFullScreen)
{
m_d3dpp.BackBufferWidth = m_iWidth;
m_d3dpp.BackBufferHeight = m_iHeight;
m_d3dpp.FullScreen_RefreshRateInHz = m_displayMode.RefreshRate;
m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; //pixel format
}
else
{
m_d3dpp.BackBufferWidth = 0;
m_d3dpp.BackBufferHeight = 0;
m_d3dpp.FullScreen_RefreshRateInHz = 0 ;
m_d3dpp.BackBufferFormat = m_displayMode.Format;
}
if (SUCCEEDED(m_pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_d3dpp.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8)))
{
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
}
else if (SUCCEEDED(m_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_d3dpp.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8)))
{
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
}
else if (SUCCEEDED(m_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_d3dpp.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16)))
{
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
}
else
{
// error
}
}
[/spoiler]
method Cleanup - This function releases the directx device and object. SafeRelease is a special macro which releases the object if it not released
[spoiler]
void cDXBase::Cleanup()
{
// release the Direct3d device
SAFE_RELEASE(m_pd3dDevice) ;
// release the Direct3d object
SAFE_RELEASE(m_pD3D) ;
}
[/spoiler]
[subheading]Running the code[/subheading]
The code needs to be added in the following functions
MainWindow.cpp
[spoiler]
void cMainWindow::OnWindowCreated()
//Bring the window into the foreground and activates the window
SetForegroundWindow(m_Hwnd);
//Set the keyboard focus
SetFocus(m_Hwnd);
// initialize DirectX
IDXBase::GetInstance()->VOnInitialization(m_Hwnd, TAN, m_bFullScreen, m_iFullScreenWidth, m_iFullScreenHeight);
}
void cMainWindow::OnWindowDestroyed()
{
// return to the default mode
ChangeDisplaySettings(NULL, 0);
// release the graphic object
IDXBase::GetInstance()->VOnDestroy();
ReleaseCapture() ;
PostQuitMessage(0) ;
}
void cMainWindow::VToggleFullScreen()
{
.. // previous code here
if (m_bFullScreen)
{
.. // previous code here
}
else
{
.. // previous code here
}
IDXBase::GetInstance()->VToggleFullScreen();
IDXBase::GetInstance()->VOnResetDevice();
if (!IsWindowVisible(m_Hwnd))
{
ShowWindow(m_Hwnd, SW_SHOW);
}
}
[/spoiler]
WinMain
[spoiler]
int WINAPI WinMain(const HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
.. // previous code
else
{
//No message to process?
// Then do your game stuff here
HRESULT hr = IDXBase::GetInstance()->VIsAvailable() ;
if(hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET)
{
if(hr == D3DERR_DEVICELOST)
{
Sleep(50);
}
else
{
if(hr == D3DERR_DEVICENOTRESET)
{
hr = IDXBase::GetInstance()->VOnResetDevice() ;
}
}
}
if(SUCCEEDED(hr))
{
hr = IDXBase::GetInstance()->VBeginRender();
}
if (SUCCEEDED(hr))
{
// render your stuff here
IDXBase::GetInstance()->VEndRender(hr);
}
}
..// destroy code
}
[/spoiler]