Before I start, I do have the long term goal of creating an engine for DX11, like I did with XNA that I can then use to set up and test my ideas on, this post won't contribute to that engine, in fact, it may be a while before my code become coherent enough to do this, so if you after an engine, please keep with me, we will get there in the end :)
I guess the first thing you need to do is go and download the latest DirectX SDK and get that installed on your system.
At the moment I am using the Visual Studio 12 RC for this, so I guess to avoid confusion, you should to.
Unlike XNA, and forgive me for constantly mentioning XNA, but it’s where I am coming from, you can’t just create a project with it all set up ready to go, well at least not that I know of. So I created an empty Win32 project. So, in your nice new shiny IDE, open up a new project, and create a Win32 Project
In the Application Settings section after that screen, select the Empty Project check box and hit finish
You should now have an empty Win32 C++ project looking something like this
Now, in order for us to start using all the DirectX 11 goodness we need to set up the project so that it knows where DirectX 11 is, so right click on the project name and select Properties and you should get a screen that looks like this.
Select the VC++ Directories and then point the Include Directories and the Library Directories at the relevant folders in the DirectX 11 SDK you have installed, so this is how I set mine up
Select the drop down for the Include Directories and select <Edit…>
In the following popup, select the folder icon, then click the button with the three dots
Now navigate to the include folder in the DirectX SDK you have installed and hit Select Folder
Then hit OK, and now we do the same with the Library Directory
The difference with the lib is we can choose x64 or x86
And you should then have both the folders set like this in the project properties
And hit OK, and we are set up for some basic DirectX stuff, we will have to alter the projects properties again later on, but for now this will be enough to get us going, also I want to show you the sort of compile/linking errors you can get when the project is not set up correctly.
So our project is now ready, the first thing we need to do is create the initial entry point for application, a function called WinMain, and so we are going to add a file to the project called main.cpp
Right click on the Source Files folder in the project and select Add from the popup menu followed by New Item in the next
Now select the C++ File (.cpp) and give it the name main.cpp and click Add
We now have our first source file, first thing we will do is add a #include for the Windows.h header file.
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
return result;
}
{
int result = 0;
return result;
}
Next we need to create a window, and to do this we are going to write our first class. I am going to call this class RandomchaosDX11Utility, over the next few posts we will add to this utility class and use it for a number of things. As I mentioned earlier, these first posts don’t really have a design in mind, at the moment, the classes are a means to an end.
So now we are going to create our first C++ class, right click on the project as we did before, choose add, but then this time select Class from the last pop up menu
Click Add
In the next window we will give the class it’s name, and hit finish
This will build us two files a .cpp and a .h file, the .h file holds the definition of our class, and to start with it will have a constructor and a destructor like this
#pragma once
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
};
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
};
The next block of code is our class definition, as you can see you can specify an access type for a block of class members, in this case the constructor and destructor are declared here as public.
Before we start writing any code in here we need to add the Windows.h file again, this time write it under the #pragma once line.
#pragma once
#include <Windows.h>
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
};
#include <Windows.h>
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
};
#pragma once
#include <Windows.h>
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
// Method to initialize the window
HWND InitWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush = COLOR_BTNFACE);
};
#include <Windows.h>
class RandomchaosDX113DUtility
{
public:
RandomchaosDX113DUtility(void);
~RandomchaosDX113DUtility(void);
// Method to initialize the window
HWND InitWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush = COLOR_BTNFACE);
};
There are a few things going on here, so lest have a look at the parameters and the return type.
The return type is HWND, this will be a handle to our window, we then have a number of parameters, the first is a LPCTSTR, it’s a string type, this parameter is used to populate the windows title, the next four integers are used to place a size the window, we then have the WNDPROC parameter, and this will be a callback method used to handle messages sent to the window, we will use it in this post to know when the window is being closed.
Now we need to create the function body, open up the .cpp file we have for this class
#include "RandomchaosDX113DUtility.h"
RandomchaosDX113DUtility::RandomchaosDX113DUtility(void)
{
}
RandomchaosDX113DUtility::~RandomchaosDX113DUtility(void)
{
}
RandomchaosDX113DUtility::RandomchaosDX113DUtility(void)
{
}
RandomchaosDX113DUtility::~RandomchaosDX113DUtility(void)
{
}
We also have the constructor and the destructor stubs already written for us, at this point we wont be populating them yet, also note that the methods are prefixed with the class name.
Now we will create the stub for our new function.
HWND RandomchaosDX113DUtility::InitWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush)
{
}
{
}
HWND RandomchaosDX113DUtility::InitWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush)
{
// Register class
WNDCLASSEX wnd_Structure;
wnd_Structure.cbSize = sizeof(WNDCLASSEX);
wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
wnd_Structure.lpfnWndProc = WinProc;
wnd_Structure.cbClsExtra = 0;
wnd_Structure.cbWndExtra = 0;
wnd_Structure.hInstance = GetModuleHandle(NULL);
wnd_Structure.hIcon = NULL;
wnd_Structure.hCursor = NULL;
wnd_Structure.hbrBackground = GetSysColorBrush(colorBrush);
wnd_Structure.lpszMenuName = NULL;
wnd_Structure.lpszClassName = L"WindowClassName";
wnd_Structure.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
if( !RegisterClassEx( &wnd_Structure ) )
return HWND(-1);
return CreateWindowEx(WS_EX_CONTROLPARENT, L"WindowClassName", str_Title, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_SIZEBOX | WS_MAXIMIZEBOX, int_XPos, int_YPos, int_Width, int_Height, NULL, NULL, GetModuleHandle(NULL), NULL);
}
{
// Register class
WNDCLASSEX wnd_Structure;
wnd_Structure.cbSize = sizeof(WNDCLASSEX);
wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
wnd_Structure.lpfnWndProc = WinProc;
wnd_Structure.cbClsExtra = 0;
wnd_Structure.cbWndExtra = 0;
wnd_Structure.hInstance = GetModuleHandle(NULL);
wnd_Structure.hIcon = NULL;
wnd_Structure.hCursor = NULL;
wnd_Structure.hbrBackground = GetSysColorBrush(colorBrush);
wnd_Structure.lpszMenuName = NULL;
wnd_Structure.lpszClassName = L"WindowClassName";
wnd_Structure.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
if( !RegisterClassEx( &wnd_Structure ) )
return HWND(-1);
return CreateWindowEx(WS_EX_CONTROLPARENT, L"WindowClassName", str_Title, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_SIZEBOX | WS_MAXIMIZEBOX, int_XPos, int_YPos, int_Width, int_Height, NULL, NULL, GetModuleHandle(NULL), NULL);
}
We are now going to implement the window creation code, we will go back to main.cpp and at the top we are going to include our new header file, we are going to create an instance of our utility class and create our callback method as well as implement the code to create the window
#include <Windows.h>
#include "RandomchaosDX113DUtility.h"
RandomchaosDX113DUtility utils;
LRESULT CALLBACK ourWinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
return result;
}
#include "RandomchaosDX113DUtility.h"
RandomchaosDX113DUtility utils;
LRESULT CALLBACK ourWinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
return result;
}
So, we are going to use a while loop, and while it’s condition is true our game will continue to run. We will control the condition with a global integer called int_AppRunning and define it at the top of our main.cpp file, just under the instantiation of our utility class.
int int_AppRunning = 1;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
}
DestroyWindow(hWnd);
}
return result;
}
{
int result = 0;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
}
DestroyWindow(hWnd);
}
return result;
}
We will define a MSG object to store incoming messages, we can then implement the pump in the game loop.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
MSG msg_Message;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
}
DestroyWindow(hWnd);
}
return result;
}
{
int result = 0;
MSG msg_Message;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
}
DestroyWindow(hWnd);
}
return result;
}
In our WinProc callback method where we have a switch looking at the incoming messages, we have a case for WM_CLOSE, this is the message passed to our application when the window is being closed, so in here all we have to do is set our global to 0
LRESULT CALLBACK ourWinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
Now, this next bit, I have totally taken from the DirectX 11 SDK code Tutorials, so the information from here on in is my interpretation on this code.
We are going to have a fair bit going on here, first thing we need to do is add some more includes to our source for the DirectX elements we are going to be using.
In the header file we have for the utility class we are going to add the following
#include <D3D11.h>
#include <D3DX11.h>
#include <D3DX11.h>
Now that’s set up the first thing I want to do is include two new headers to our utility class.
#include <D3D11.h>
#include <D3DX11.h>
#include <D3DX11.h>
protected:
D3D_DRIVER_TYPE driverType;
IDXGISwapChain* pSwapChain;
ID3D11Device* pd3dDevice;
D3D_FEATURE_LEVELfeatureLevel;
ID3D11RenderTargetView* pRenderTargetView;
ID3D11DepthStencilView* pDepthStencilView;
ID3D11Texture2D* pDepthStencil;
HWND hWnd;
D3D_DRIVER_TYPE driverType;
IDXGISwapChain* pSwapChain;
ID3D11Device* pd3dDevice;
D3D_FEATURE_LEVELfeatureLevel;
ID3D11RenderTargetView* pRenderTargetView;
ID3D11DepthStencilView* pDepthStencilView;
ID3D11Texture2D* pDepthStencil;
HWND hWnd;
// GraphicsDevice
ID3D11DeviceContext* pImmediateContext;
ID3D11DeviceContext* pImmediateContext;
// Creates our graphics device
HRESULT InitDevice();
HRESULT InitDevice();
// Draw call
void Draw();
void Draw();
HWND RandomchaosDX113DUtility::InitWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush)
{
// Register class
WNDCLASSEX wnd_Structure;
wnd_Structure.cbSize = sizeof(WNDCLASSEX);
wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
wnd_Structure.lpfnWndProc = WinProc;
wnd_Structure.cbClsExtra = 0;
wnd_Structure.cbWndExtra = 0;
wnd_Structure.hInstance = GetModuleHandle(NULL);
wnd_Structure.hIcon = NULL;
wnd_Structure.hCursor = NULL;
wnd_Structure.hbrBackground = GetSysColorBrush(colorBrush);
wnd_Structure.lpszMenuName = NULL;
wnd_Structure.lpszClassName = L"WindowClassName";
wnd_Structure.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
if( !RegisterClassEx( &wnd_Structure ) )
return HWND(-1);
hWnd = CreateWindowEx(WS_EX_CONTROLPARENT, L"WindowClassName", str_Title, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_SIZEBOX | WS_MAXIMIZEBOX, int_XPos, int_YPos, int_Width, int_Height, NULL, NULL, GetModuleHandle(NULL), NULL);
return hWnd;
}
{
// Register class
WNDCLASSEX wnd_Structure;
wnd_Structure.cbSize = sizeof(WNDCLASSEX);
wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
wnd_Structure.lpfnWndProc = WinProc;
wnd_Structure.cbClsExtra = 0;
wnd_Structure.cbWndExtra = 0;
wnd_Structure.hInstance = GetModuleHandle(NULL);
wnd_Structure.hIcon = NULL;
wnd_Structure.hCursor = NULL;
wnd_Structure.hbrBackground = GetSysColorBrush(colorBrush);
wnd_Structure.lpszMenuName = NULL;
wnd_Structure.lpszClassName = L"WindowClassName";
wnd_Structure.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
if( !RegisterClassEx( &wnd_Structure ) )
return HWND(-1);
hWnd = CreateWindowEx(WS_EX_CONTROLPARENT, L"WindowClassName", str_Title, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_SIZEBOX | WS_MAXIMIZEBOX, int_XPos, int_YPos, int_Width, int_Height, NULL, NULL, GetModuleHandle(NULL), NULL);
return hWnd;
}
HRESULT RandomchaosDX113DUtility::InitDevice()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &pSwapChain, &pd3dDevice, &featureLevel, &pImmediateContext );
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = NULL;
hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
// Create depth stencil texture
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );
if( FAILED( hr ) )
return hr;
// Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, &descDSV, &pDepthStencilView );
if( FAILED( hr ) )
return hr;
pImmediateContext->OMSetRenderTargets( 1, &pRenderTargetView, pDepthStencilView );
return S_OK;
}
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &pSwapChain, &pd3dDevice, &featureLevel, &pImmediateContext );
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = NULL;
hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
// Create depth stencil texture
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );
if( FAILED( hr ) )
return hr;
// Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, &descDSV, &pDepthStencilView );
if( FAILED( hr ) )
return hr;
pImmediateContext->OMSetRenderTargets( 1, &pRenderTargetView, pDepthStencilView );
return S_OK;
}
The method starts off getting the windows size, sets the device creation flags, it then sets up a few arrays to help detect what capabilities the card can do. It then sets up a swap chain definition to describe the device, it then loops through the types until it finds a driver type the card supports, if it doesn’t then it returns HRESULT which I imagine would be –1. It then sets up the back buffer, a render target and a depth stencil.
We then set up the Draw call, which in this post is just us clearing the “GraphicsDevice”
void RandomchaosDX113DUtility::Draw()
{
//
// Clear the back buffer
//
float ClearColor[4] = { 0.392156862745098f, 0.5843137254901961f, 0.9294117647058824f, 1.0f }; // red, green, blue, alpha
pImmediateContext->ClearRenderTargetView( pRenderTargetView, ClearColor );
//
// Clear the depth buffer to 1.0 (max depth)
//
pImmediateContext->ClearDepthStencilView( pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );
//
// Present our back buffer to our front buffer
//
pSwapChain->Present( 0, 0 );
}
{
//
// Clear the back buffer
//
float ClearColor[4] = { 0.392156862745098f, 0.5843137254901961f, 0.9294117647058824f, 1.0f }; // red, green, blue, alpha
pImmediateContext->ClearRenderTargetView( pRenderTargetView, ClearColor );
//
// Clear the depth buffer to 1.0 (max depth)
//
pImmediateContext->ClearDepthStencilView( pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );
//
// Present our back buffer to our front buffer
//
pSwapChain->Present( 0, 0 );
}
We now need to implement these calls, so we now open up our main.cpp file, after we initialize the window, we will initialize the device, then in the game loop we will make the draw call.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
int result = 0;
MSG msg_Message;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
utils.InitDevice();
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
utils.Draw();
}
DestroyWindow(hWnd);
}
return result;
}
{
int result = 0;
MSG msg_Message;
HWND hWnd = utils.InitWindow(L"RCDXTutorial1",0,0,800,420,ourWinProc);
if(hWnd != HWND(-1))
{
utils.InitDevice();
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
utils.Draw();
}
DestroyWindow(hWnd);
}
return result;
}
So, what did we do here?
- We set up the project to use DirectX
- We created our first C++ application
- We created our first windowed application
- We created a graphics device
- We cleared the graphics device
Thanks for reading and I hope it will be of some use to you.
You can find the source code for this post here
Looking forward to the upcoming posts!
ReplyDeleteThanks for the walkthrough, definitely helpful.
ReplyDeleteVery nice post! I haven't used C++ for years and it's a bit daunting with all the new pointer/ref stuff. Also very nice step by step of adding a lib to your project. It is quite a bit more complex then C# where you can just add a reference. Any chance you will use Shawn's C++ SpriteBatch code?
ReplyDeleteGlad you liked the post :) I intend to get something rendering, then to use Shawns code later.
DeleteHey Charles, nice post and I too will be looking forward to reading up on your forays into c++ and DX11.
ReplyDeletekeep 'em coming.
Hi John, welcome aboard, hope you find the post useful :)
DeleteThanks! I followed along with the tutorial and everything was very clear :) I'll keep an eye out for the upcoming series, what type of highlighter are you using? For me barely any of the syntax is highlighted.
ReplyDeleteGreat! Glad you found it useful :D
DeleteI am using a plugin for Windows Live Writer, looks to me, what browser are you using?