Introduction
In this lesson, we will be learning a way to impliment a simple first person camera, which will enable us to look up, down, left, and right with the mouse, and move forward and back, and strafe left and right. It's not too difficult, so i'll just get right to the code and explain whats going on as we go.
We will be using a seamless grass texture I made to texture the ground with grass, here it is:
//Include and link appropriate libraries and headers//
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment (lib, "D3D10_1.lib")
#pragma comment (lib, "DXGI.lib")
#pragma comment (lib, "D2D1.lib")
#pragma comment (lib, "dwrite.lib")
#pragma comment (lib, "dinput8.lib")
#pragma comment (lib, "dxguid.lib")
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>
#include <D3D10_1.h>
#include <DXGI.h>
#include <D2D1.h>
#include <sstream>
#include <dwrite.h>
#include <dinput.h>
//Global Declarations - Interfaces//
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;
ID3D11Buffer* squareIndexBuffer;
ID3D11DepthStencilView* depthStencilView;
ID3D11Texture2D* depthStencilBuffer;
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D11PixelShader* D2D_PS;
ID3D10Blob* D2D_PS_Buffer;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
ID3D11Buffer* cbPerObjectBuffer;
ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;
ID3D11ShaderResourceView* CubesTexture;
ID3D11SamplerState* CubesTexSamplerState;
ID3D11Buffer* cbPerFrameBuffer;
ID3D10Device1 *d3d101Device;
IDXGIKeyedMutex *keyedMutex11;
IDXGIKeyedMutex *keyedMutex10;
ID2D1RenderTarget *D2DRenderTarget;
ID2D1SolidColorBrush *Brush;
ID3D11Texture2D *BackBuffer11;
ID3D11Texture2D *sharedTex11;
ID3D11Buffer *d2dVertBuffer;
ID3D11Buffer *d2dIndexBuffer;
ID3D11ShaderResourceView *d2dTexture;
IDWriteFactory *DWriteFactory;
IDWriteTextFormat *TextFormat;
IDirectInputDevice8* DIKeyboard;
IDirectInputDevice8* DIMouse;
std::wstring printText;
//Global Declarations - Others//
LPCTSTR WndClassName = L"firstwindow";
HWND hwnd = NULL;
HRESULT hr;
int Width = 800;
int Height = 600;
DIMOUSESTATE mouseLastState;
LPDIRECTINPUT8 DirectInput;
float rotx = 0;
float rotz = 0;
float scaleX = 1.0f;
float scaleY = 1.0f;
XMMATRIX Rotationx;
XMMATRIX Rotationz;
XMMATRIX WVP;
XMMATRIX cube1World;
XMMATRIX cube2World;
XMMATRIX camView;
XMMATRIX camProjection;
XMMATRIX d2dWorld;
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;
///////////////**************new**************////////////////////
XMVECTOR DefaultForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
XMVECTOR DefaultRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
XMVECTOR camForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
XMVECTOR camRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
XMMATRIX camRotationMatrix;
XMMATRIX groundWorld;
float moveLeftRight = 0.0f;
float moveBackForward = 0.0f;
float camYaw = 0.0f;
float camPitch = 0.0f;
///////////////**************new**************////////////////////
XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;
double countsPerSecond = 0.0;
__int64 CounterStart = 0;
int frameCount = 0;
int fps = 0;
__int64 frameTimeOld = 0;
double frameTime;
//Function Prototypes//
bool InitializeDirect3d11App(HINSTANCE hInstance);
void CleanUp();
bool InitScene();
void DrawScene();
bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter);
void InitD2DScreenTexture();
void UpdateScene(double time);
///////////////**************new**************////////////////////
void UpdateCamera();
///////////////**************new**************////////////////////
void RenderText(std::wstring text, int inInt);
void StartTimer();
double GetTime();
double GetFrameTime();
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd,
int width, int height,
bool windowed);
int messageloop();
bool InitDirectInput(HINSTANCE hInstance);
void DetectInput(double time);
LRESULT CALLBACK WndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
//Create effects constant buffer's structure//
struct cbPerObject
{
XMMATRIX WVP;
XMMATRIX World;
};
cbPerObject cbPerObj;
struct Light
{
Light()
{
ZeroMemory(this, sizeof(Light));
}
XMFLOAT3 dir;
float pad;
XMFLOAT4 ambient;
XMFLOAT4 diffuse;
};
Light light;
struct cbPerFrame
{
Light light;
};
cbPerFrame constbuffPerFrame;
struct Vertex //Overloaded Vertex Structure
{
Vertex(){}
Vertex(float x, float y, float z,
float u, float v,
float nx, float ny, float nz)
: pos(x,y,z), texCoord(u, v), normal(nx, ny, nz){}
XMFLOAT3 pos;
XMFLOAT2 texCoord;
XMFLOAT3 normal;
};
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
UINT numElements = ARRAYSIZE(layout);
int WINAPI WinMain(HINSTANCE hInstance, //Main windows function
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true))
{
MessageBox(0, L"Window Initialization - Failed",
L"Error", MB_OK);
return 0;
}
if(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D
{
MessageBox(0, L"Direct3D Initialization - Failed",
L"Error", MB_OK);
return 0;
}
if(!InitScene()) //Initialize our scene
{
MessageBox(0, L"Scene Initialization - Failed",
L"Error", MB_OK);
return 0;
}
if(!InitDirectInput(hInstance))
{
MessageBox(0, L"Direct Input Initialization - Failed",
L"Error", MB_OK);
return 0;
}
messageloop();
CleanUp();
return 0;
}
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd,
int width, int height,
bool windowed)
{
typedef struct _WNDCLASS {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = WndClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Error registering class",
L"Error", MB_OK | MB_ICONERROR);
return 1;
}
hwnd = CreateWindowEx(
NULL,
WndClassName,
L"Lesson 4 - Begin Drawing",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd)
{
MessageBox(NULL, L"Error creating window",
L"Error", MB_OK | MB_ICONERROR);
return 1;
}
ShowWindow(hwnd, ShowWnd);
UpdateWindow(hwnd);
return true;
}
bool InitializeDirect3d11App(HINSTANCE hInstance)
{
//Describe our SwapChain Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = Width;
bufferDesc.Height = Height;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//Describe our SwapChain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd;
///////////////**************new**************////////////////////
swapChainDesc.Windowed = false;
///////////////**************new**************////////////////////
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
// Create DXGI factory to enumerate adapters///////////////////////////////////////////////////////////////////////////
IDXGIFactory1 *DXGIFactory;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&DXGIFactory);
// Use the first adapter
IDXGIAdapter1 *Adapter;
hr = DXGIFactory->EnumAdapters1(0, &Adapter);
DXGIFactory->Release();
//Create our Direct3D 11 Device and SwapChain//////////////////////////////////////////////////////////////////////////
hr = D3D11CreateDeviceAndSwapChain(Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);
//Initialize Direct2D, Direct3D 10.1, DirectWrite
InitD2D_D3D101_DWrite(Adapter);
//Release the Adapter interface
Adapter->Release();
//Create our BackBuffer and Render Target
hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer11 );
hr = d3d11Device->CreateRenderTargetView( BackBuffer11, NULL, &renderTargetView );
//Describe our Depth/Stencil Buffer
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = Width;
depthStencilDesc.Height = Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
//Create the Depth/Stencil View
d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);
return true;
}
bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter)
{
//Create our Direc3D 10.1 Device///////////////////////////////////////////////////////////////////////////////////////
hr = D3D10CreateDevice1(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL,D3D10_CREATE_DEVICE_BGRA_SUPPORT,
D3D10_FEATURE_LEVEL_9_3, D3D10_1_SDK_VERSION, &d3d101Device );
//Create Shared Texture that Direct3D 10.1 will render on//////////////////////////////////////////////////////////////
D3D11_TEXTURE2D_DESC sharedTexDesc;
ZeroMemory(&sharedTexDesc, sizeof(sharedTexDesc));
sharedTexDesc.Width = Width;
sharedTexDesc.Height = Height;
sharedTexDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sharedTexDesc.MipLevels = 1;
sharedTexDesc.ArraySize = 1;
sharedTexDesc.SampleDesc.Count = 1;
sharedTexDesc.Usage = D3D11_USAGE_DEFAULT;
sharedTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
sharedTexDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
hr = d3d11Device->CreateTexture2D(&sharedTexDesc, NULL, &sharedTex11);
// Get the keyed mutex for the shared texture (for D3D11)///////////////////////////////////////////////////////////////
hr = sharedTex11->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&keyedMutex11);
// Get the shared handle needed to open the shared texture in D3D10.1///////////////////////////////////////////////////
IDXGIResource *sharedResource10;
HANDLE sharedHandle10;
hr = sharedTex11->QueryInterface(__uuidof(IDXGIResource), (void**)&sharedResource10);
hr = sharedResource10->GetSharedHandle(&sharedHandle10);
sharedResource10->Release();
// Open the surface for the shared texture in D3D10.1///////////////////////////////////////////////////////////////////
IDXGISurface1 *sharedSurface10;
hr = d3d101Device->OpenSharedResource(sharedHandle10, __uuidof(IDXGISurface1), (void**)(&sharedSurface10));
hr = sharedSurface10->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&keyedMutex10);
// Create D2D factory///////////////////////////////////////////////////////////////////////////////////////////////////
ID2D1Factory *D2DFactory;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), (void**)&D2DFactory);
D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties;
ZeroMemory(&renderTargetProperties, sizeof(renderTargetProperties));
renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE;
renderTargetProperties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
hr = D2DFactory->CreateDxgiSurfaceRenderTarget(sharedSurface10, &renderTargetProperties, &D2DRenderTarget);
sharedSurface10->Release();
D2DFactory->Release();
// Create a solid color brush to draw something with
hr = D2DRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), &Brush);
//DirectWrite///////////////////////////////////////////////////////////////////////////////////////////////////////////
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&DWriteFactory));
hr = DWriteFactory->CreateTextFormat(
L"Script",
NULL,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
24.0f,
L"en-us",
&TextFormat
);
hr = TextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
hr = TextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
d3d101Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);
return true;
}
bool InitDirectInput(HINSTANCE hInstance)
{
hr = DirectInput8Create(hInstance,
DIRECTINPUT_VERSION,
IID_IDirectInput8,
(void**)&DirectInput,
NULL);
hr = DirectInput->CreateDevice(GUID_SysKeyboard,
&DIKeyboard,
NULL);
hr = DirectInput->CreateDevice(GUID_SysMouse,
&DIMouse,
NULL);
hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
hr = DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
hr = DIMouse->SetDataFormat(&c_dfDIMouse);
hr = DIMouse->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND);
return true;
}
///////////////**************new**************////////////////////
void UpdateCamera()
{
camRotationMatrix = XMMatrixRotationRollPitchYaw(camPitch, camYaw, 0);
camTarget = XMVector3TransformCoord(DefaultForward, camRotationMatrix );
camTarget = XMVector3Normalize(camTarget);
XMMATRIX RotateYTempMatrix;
RotateYTempMatrix = XMMatrixRotationY(camYaw);
camRight = XMVector3TransformCoord(DefaultRight, RotateYTempMatrix);
camUp = XMVector3TransformCoord(camUp, RotateYTempMatrix);
camForward = XMVector3TransformCoord(DefaultForward, RotateYTempMatrix);
camPosition += moveLeftRight*camRight;
camPosition += moveBackForward*camForward;
moveLeftRight = 0.0f;
moveBackForward = 0.0f;
camTarget = camPosition + camTarget;
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
}
void DetectInput(double time)
{
DIMOUSESTATE mouseCurrState;
BYTE keyboardState[256];
DIKeyboard->Acquire();
DIMouse->Acquire();
DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouseCurrState);
DIKeyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState);
if(keyboardState[DIK_ESCAPE] & 0x80)
PostMessage(hwnd, WM_DESTROY, 0, 0);
float speed = 15.0f * time;
if(keyboardState[DIK_A] & 0x80)
{
moveLeftRight -= speed;
}
if(keyboardState[DIK_D] & 0x80)
{
moveLeftRight += speed;
}
if(keyboardState[DIK_W] & 0x80)
{
moveBackForward += speed;
}
if(keyboardState[DIK_S] & 0x80)
{
moveBackForward -= speed;
}
if((mouseCurrState.lX != mouseLastState.lX) || (mouseCurrState.lY != mouseLastState.lY))
{
camYaw += mouseLastState.lX * 0.001f;
camPitch += mouseCurrState.lY * 0.001f;
mouseLastState = mouseCurrState;
}
UpdateCamera();
return;
}
///////////////**************new**************////////////////////
void CleanUp()
{
///////////////**************new**************////////////////////
SwapChain->SetFullscreenState(false, NULL);
PostMessage(hwnd, WM_DESTROY, 0, 0);
///////////////**************new**************////////////////////
//Release the COM Objects we created
SwapChain->Release();
d3d11Device->Release();
d3d11DevCon->Release();
renderTargetView->Release();
squareVertBuffer->Release();
squareIndexBuffer->Release();
VS->Release();
PS->Release();
VS_Buffer->Release();
PS_Buffer->Release();
vertLayout->Release();
depthStencilView->Release();
depthStencilBuffer->Release();
cbPerObjectBuffer->Release();
Transparency->Release();
CCWcullMode->Release();
CWcullMode->Release();
d3d101Device->Release();
keyedMutex11->Release();
keyedMutex10->Release();
D2DRenderTarget->Release();
Brush->Release();
BackBuffer11->Release();
sharedTex11->Release();
DWriteFactory->Release();
TextFormat->Release();
d2dTexture->Release();
cbPerFrameBuffer->Release();
DIKeyboard->Unacquire();
DIMouse->Unacquire();
DirectInput->Release();
}
void InitD2DScreenTexture()
{
//Create the vertex buffer
Vertex v[] =
{
// Front Face
Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f),
Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,-1.0f, 1.0f, -1.0f),
Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f),
Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f),
};
DWORD indices[] = {
// Front Face
0, 1, 2,
0, 2, 3,
};
D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &d2dIndexBuffer);
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 4;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &d2dVertBuffer);
//Create A shader resource view from the texture D2D will render to,
//So we can use it to texture a square which overlays our scene
d3d11Device->CreateShaderResourceView(sharedTex11, NULL, &d2dTexture);
}
bool InitScene()
{
InitD2DScreenTexture();
//Compile Shaders from shader file
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "D2D_PS", "ps_4_0", 0, 0, 0, &D2D_PS_Buffer, 0, 0);
//Create the Shader Objects
hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
hr = d3d11Device->CreatePixelShader(D2D_PS_Buffer->GetBufferPointer(), D2D_PS_Buffer->GetBufferSize(), NULL, &D2D_PS);
//Set Vertex and Pixel Shaders
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);
///////////////**************new**************////////////////////
light.dir = XMFLOAT3(0.0f, 1.0f, 0.0f);
light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
//Create the vertex buffer
Vertex v[] =
{
// Bottom Face
Vertex(-1.0f, -1.0f, -1.0f, 100.0f, 100.0f, 0.0f, 1.0f, 0.0f),
Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 100.0f, 0.0f, 1.0f, 0.0f),
Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f),
Vertex(-1.0f, -1.0f, 1.0f, 100.0f, 0.0f, 0.0f, 1.0f, 0.0f),
};
DWORD indices[] = {
0, 1, 2,
0, 2, 3,
};
D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 4;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &squareVertBuffer);
///////////////**************new**************////////////////////
//Create the Input Layout
hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(),
VS_Buffer->GetBufferSize(), &vertLayout );
//Set the Input Layout
d3d11DevCon->IASetInputLayout( vertLayout );
//Set Primitive Topology
d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
//Create the Viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Width;
viewport.Height = Height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
//Set the Viewport
d3d11DevCon->RSSetViewports(1, &viewport);
//Create the buffer to send to the cbuffer in effect file
D3D11_BUFFER_DESC cbbd;
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerObject);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);
//Create the buffer to send to the cbuffer per frame in effect file
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerFrame);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerFrameBuffer);
//Camera information
camPosition = XMVectorSet( 0.0f, 5.0f, -8.0f, 0.0f );
camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
camUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
//Set the View matrix
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
//Set the Projection matrix
camProjection = XMMatrixPerspectiveFovLH( 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f);
D3D11_BLEND_DESC blendDesc;
ZeroMemory( &blendDesc, sizeof(blendDesc) );
D3D11_RENDER_TARGET_BLEND_DESC rtbd;
ZeroMemory( &rtbd, sizeof(rtbd) );
rtbd.BlendEnable = true;
rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR;
rtbd.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
rtbd.BlendOp = D3D11_BLEND_OP_ADD;
rtbd.SrcBlendAlpha = D3D11_BLEND_ONE;
rtbd.DestBlendAlpha = D3D11_BLEND_ZERO;
rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD;
rtbd.RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL;
blendDesc.AlphaToCoverageEnable = false;
blendDesc.RenderTarget[0] = rtbd;
hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"grass.jpg",
NULL, NULL, &CubesTexture, NULL );
// Describe the Sample State
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
//Create the Sample State
hr = d3d11Device->CreateSamplerState( &sampDesc, &CubesTexSamplerState );
d3d11Device->CreateBlendState(&blendDesc, &Transparency);
D3D11_RASTERIZER_DESC cmdesc;
ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC));
cmdesc.FillMode = D3D11_FILL_SOLID;
cmdesc.CullMode = D3D11_CULL_BACK;
cmdesc.FrontCounterClockwise = true;
hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode);
cmdesc.FrontCounterClockwise = false;
hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode);
return true;
}
void StartTimer()
{
LARGE_INTEGER frequencyCount;
QueryPerformanceFrequency(&frequencyCount);
countsPerSecond = double(frequencyCount.QuadPart);
QueryPerformanceCounter(&frequencyCount);
CounterStart = frequencyCount.QuadPart;
}
double GetTime()
{
LARGE_INTEGER currentTime;
QueryPerformanceCounter(¤tTime);
return double(currentTime.QuadPart-CounterStart)/countsPerSecond;
}
double GetFrameTime()
{
LARGE_INTEGER currentTime;
__int64 tickCount;
QueryPerformanceCounter(¤tTime);
tickCount = currentTime.QuadPart-frameTimeOld;
frameTimeOld = currentTime.QuadPart;
if(tickCount < 0.0f)
tickCount = 0.0f;
return float(tickCount)/countsPerSecond;
}
void UpdateScene(double time)
{
//Reset cube1World
groundWorld = XMMatrixIdentity();
//Define cube1's world space matrix
///////////////**************new**************////////////////////
Scale = XMMatrixScaling( 500.0f, 10.0f, 500.0f );
Translation = XMMatrixTranslation( 0.0f, 10.0f, 0.0f );
//Set cube1's world space using the transformations
groundWorld = Scale * Translation;
///////////////**************new**************////////////////////
}
void RenderText(std::wstring text, int inInt)
{
d3d11DevCon->PSSetShader(D2D_PS, 0, 0);
//Release the D3D 11 Device
keyedMutex11->ReleaseSync(0);
//Use D3D10.1 device
keyedMutex10->AcquireSync(0, 5);
//Draw D2D content
D2DRenderTarget->BeginDraw();
//Clear D2D Background
D2DRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f));
//Create our string
std::wostringstream printString;
printString << text << inInt;
printText = printString.str();
//Set the Font Color
D2D1_COLOR_F FontColor = D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f);
//Set the brush color D2D will use to draw with
Brush->SetColor(FontColor);
//Create the D2D Render Area
D2D1_RECT_F layoutRect = D2D1::RectF(0, 0, Width, Height);
//Draw the Text
D2DRenderTarget->DrawText(
printText.c_str(),
wcslen(printText.c_str()),
TextFormat,
layoutRect,
Brush
);
D2DRenderTarget->EndDraw();
//Release the D3D10.1 Device
keyedMutex10->ReleaseSync(1);
//Use the D3D11 Device
keyedMutex11->AcquireSync(1, 5);
//Use the shader resource representing the direct2d render target
//to texture a square which is rendered in screen space so it
//overlays on top of our entire scene. We use alpha blending so
//that the entire background of the D2D render target is "invisible",
//And only the stuff we draw with D2D will be visible (the text)
//Set the blend state for D2D render target texture objects
d3d11DevCon->OMSetBlendState(Transparency, NULL, 0xffffffff);
//Set the d2d Index buffer
d3d11DevCon->IASetIndexBuffer( d2dIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
//Set the d2d vertex buffer
UINT stride = sizeof( Vertex );
UINT offset = 0;
d3d11DevCon->IASetVertexBuffers( 0, 1, &d2dVertBuffer, &stride, &offset );
WVP = XMMatrixIdentity();
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
d3d11DevCon->PSSetShaderResources( 0, 1, &d2dTexture );
d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
d3d11DevCon->RSSetState(CWcullMode);
//Draw the second cube
d3d11DevCon->DrawIndexed( 6, 0, 0 );
}
void DrawScene()
{
//Clear our render target and depth/stencil view
float bgColor[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);
d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);
constbuffPerFrame.light = light;
d3d11DevCon->UpdateSubresource( cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0 );
d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer);
//Set our Render Target
d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView );
//Set the default blend state (no blending) for opaque objects
d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff);
//Set Vertex and Pixel Shaders
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);
//Set the cubes index buffer
d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
//Set the cubes vertex buffer
UINT stride = sizeof( Vertex );
UINT offset = 0;
d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset );
//Set the WVP matrix and send it to the constant buffer in effect file
WVP = groundWorld * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
cbPerObj.World = XMMatrixTranspose(groundWorld);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );
d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
d3d11DevCon->RSSetState(CCWcullMode);
d3d11DevCon->DrawIndexed( 6, 0, 0 );
RenderText(L"FPS: ", fps);
//Present the backbuffer to the screen
SwapChain->Present(0, 0);
}
int messageloop(){
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(true)
{
BOOL PeekMessageL(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg
);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else{
// run game code
frameCount++;
if(GetTime() > 1.0f)
{
fps = frameCount;
frameCount = 0;
StartTimer();
}
frameTime = GetFrameTime();
DetectInput(frameTime);
UpdateScene(frameTime);
DrawScene();
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch( msg )
{
case WM_KEYDOWN:
if( wParam == VK_ESCAPE ){
DestroyWindow(hwnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,
msg,
wParam,
lParam);
}
struct Light
{
float3 dir;
float4 ambient;
float4 diffuse;
};
cbuffer cbPerFrame
{
Light light;
};
cbuffer cbPerObject
{
float4x4 WVP;
float4x4 World;
};
Texture2D ObjTexture;
SamplerState ObjSamplerState;
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
float3 normal : NORMAL;
};
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.normal = mul(normal, World);
output.TexCoord = inTexCoord;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
input.normal = normalize(input.normal);
float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
float3 finalColor;
finalColor = diffuse * light.ambient;
finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse);
return float4(finalColor, diffuse.a);
}
float4 D2D_PS(VS_OUTPUT input) : SV_TARGET
{
float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
return diffuse;
}
Global Declarations
Here we have a bunch of new declarations. You can see four new vectors, two new matrices, and a couple floats. The first two vectors are describing the forward and right direction in the world. We will use these when calculating the rotation of our camera. The second two vectors are the forward and right directions of our camera. We will use the to move our camera around, so when we press the forward key, all we have to do is move along the camForward vector to make it look like our camera is walking straigt ahead.
The camRotationMatrix doesn't actually need to be created, since we could have just used the same rotation matrix we have been using for our cubes, but I just made it anyway. We will use it to rotate our camera! The second one is another matrix describing the world space of our "ground". Again, we could have used one of the cube world matrices, but i thought this would be more clear.
The first two floats, moveLeftRight and moveBackForward, will be used to move along the camForward and camRight vectors when we want to move the camera forward or strafe right. The second two floats are used to calculate the rotation around the x and y axis for our camera when looking around.
XMVECTOR DefaultForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
XMVECTOR DefaultRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
XMVECTOR camForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
XMVECTOR camRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
XMMATRIX camRotationMatrix;
XMMATRIX groundWorld;
float moveLeftRight = 0.0f;
float moveBackForward = 0.0f;
float camYaw = 0.0f;
float camPitch = 0.0f;
New Function
This is a prototype of our new function, which will be used to update our camera.
void UpdateCamera();
Going Fullscreen
Here is our swapchain description. To go fullscreen, we have to set the Windowed member to false. We can go in and out of fullscreen by pressing "Alt+Enter".
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd;
///////////////**************new**************////////////////////
swapChainDesc.Windowed = false;
///////////////**************new**************////////////////////
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
The UpdateCamera() Function
Here is our UpdateCamera() function, which will be called every frame at the end of our DetectInput() function.
void UpdateCamera()
{
camRotationMatrix = XMMatrixRotationRollPitchYaw(camPitch, camYaw, 0);
camTarget = XMVector3TransformCoord(DefaultForward, camRotationMatrix );
camTarget = XMVector3Normalize(camTarget);
XMMATRIX RotateYTempMatrix;
RotateYTempMatrix = XMMatrixRotationY(camPitch);
camRight = XMVector3TransformCoord(DefaultRight, RotateYTempMatrix);
camUp = XMVector3TransformCoord(camUp, RotateYTempMatrix);
camForward = XMVector3TransformCoord(DefaultForward, RotateYTempMatrix);
camPosition += moveLeftRight*camRight;
camPosition += moveBackForward*camForward;
moveLeftRight = 0.0f;
moveBackForward = 0.0f;
camTarget = camPosition + camTarget;
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
}
Rotating the Camera
The first three lines in our UpdateCamera() function will update the cameras target. The first line uses a new function from the xna math library, called XMMatrixRotationRollPitchYaw. This function has three parameters, the first is the pitch in radians to rotate, the second is the Yaw in radians to rotate, and the third is the Roll in radians to rotate. It returns a rotation matrix. This function is very usefull for cameras especially. you are able to rotate around all axis' at the same time, Yaw, Pitch, Roll. Yaw is the rotation left/right (y-axis), pitch is the rotation up/down (x-axis) and Roll is the rotation like your doing a cartwheel (z-axis). Our camera will be looking up/down and left/right, So we will be setting the yaw and pitch parameters of this function. Since we are not using the roll parameter, we set that to zero.
The next line sets our cameras Target vector by rotating the DefaultForward vector with the rotationMatrix we just created, and setting it to our Target matrix. After that, we normalize our vector, because the last operation may have made one or more of the Target vectors values greater than 1.0f, or less than -1.0f, in which case it would be not of unit length.
camRotationMatrix = XMMatrixRotationRollPitchYaw(camPitch, camYaw, 0);
camTarget = XMVector3TransformCoord(DefaultForward, camRotationMatrix );
camTarget = XMVector3Normalize(camTarget);
Now we need to find the new Right and Forward directions of our camera. We will do this using a rotation matrix which will be rotated on the Y-axis. Since our camera is a first person camera, and we only need to move in the X and Z directions, We need to keep our camera's forward and right vectors pointing only in the x and z axis. We will use those vectors to move our camera back, forward, left and right. First we create a new matrix, then we rotate that matrix using the yaw variable we have set when the mouse moves.
XMMATRIX RotateYTempMatrix;
RotateYTempMatrix = XMMatrixRotationY(camYaw);
Update the camForward, camUp, and camRight Vectors
Next we transform the camera's right, up, and forward vectors using the RotateYTempMatrix matrix we just defined, and rotate the default right, up, and default forward vectors then set the result in the right, up, and forward vectors.
camRight = XMVector3TransformCoord(DefaultRight, RotateYTempMatrix);
camUp = XMVector3TransformCoord(camUp, RotateYTempMatrix);
camForward = XMVector3TransformCoord(DefaultForward, RotateYTempMatrix);
Moving the Camera
Next we update the position of our camera using the two values, moveLeftRight, and moveBackForward, and the two vectors, Right, and Forward. To move the camera left and right, we multiply the moveLeftRight variable withthe Right vector, and add that to the Position. Then to move back and forward, we multiply moveBackForward with the Forward vector and add that to the Position too. The moveLeftRight and moveBackForward values will be calculated when direct input detects a certain key was pressed (in the case of this lesson A,S,D, or W).
After that we reset the moveLeftRight and moveBackForward variables.
camPosition += moveLeftRight*camRight;
camPosition += moveBackForward*camForward;
moveLeftRight = 0.0f;
moveBackForward = 0.0f;
Set the camView Matrix
Now we add the Position of our camera to the target vector, then update our View matrix by using the XMMatrixLookAtLH() D3D function. This function updates our View matrix we use to calculate our WVP matrix by using the cameras position, Target, and Up vectors.
camTarget = camPosition + camTarget;
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
The DetectInput() Function
We have updated our DetectInput() function to update our camera when moving the mouse or pressing the W, S, A, or D keys. Notice the line before we start checking for input. We have a new variable called "speed". This is the speed our camera will move when we reposition it every frame. We take the time variable passed in when this function is called, and multiply it with our speed, so that our camera will move the exact same distance in one second whatever the frames per second are. Next we check if the W, S, A, and D keys were pressed, and update the moveLeftRight and moveBackForward accordingly. After that we check for the mouse input, where we will update the camYaw and camPitch depending on how much the mouse has moved in the x or y axis since the last frame. After all that, we update our camera by calling the UpdateCamera() function.
void DetectInput(double time)
{
DIMOUSESTATE mouseCurrState;
BYTE keyboardState[256];
DIKeyboard->Acquire();
DIMouse->Acquire();
DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouseCurrState);
DIKeyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState);
if(keyboardState[DIK_ESCAPE] & 0x80)
PostMessage(hwnd, WM_DESTROY, 0, 0);
float speed = 15.0f * time;
if(keyboardState[DIK_A] & 0x80)
{
moveLeftRight -= speed;
}
if(keyboardState[DIK_D] & 0x80)
{
moveLeftRight += speed;
}
if(keyboardState[DIK_W] & 0x80)
{
moveBackForward += speed;
}
if(keyboardState[DIK_S] & 0x80)
{
moveBackForward -= speed;
}
if((mouseCurrState.lX != mouseLastState.lX) || (mouseCurrState.lY != mouseLastState.lY))
{
camYaw += mouseLastState.lX * 0.001f;
camPitch += mouseCurrState.lY * 0.001f;
mouseLastState = mouseCurrState;
}
UpdateCamera();
return;
}
Clean Up - Exiting Fullscreen
Since Direct3D can't exit properly from fullscreen directly, we need to do something extra before we actually exit. We need to take our application out of fullscreen and into windowed mode before we actually start cleaning up. We can do that in the CleanUp() function by calling the SetFullScreenState() method of our swapchain.
void CleanUp()
{
///////////////**************new**************////////////////////
SwapChain->SetFullscreenState(false, NULL);
PostMessage(hwnd, WM_DESTROY, 0, 0);
///////////////**************new**************////////////////////
//Release the COM Objects we created
SwapChain->Release();
d3d11Device->Release();
d3d11DevCon->Release();
renderTargetView->Release();
squareVertBuffer->Release();
squareIndexBuffer->Release();
VS->Release();
PS->Release();
VS_Buffer->Release();
PS_Buffer->Release();
vertLayout->Release();
depthStencilView->Release();
depthStencilBuffer->Release();
cbPerObjectBuffer->Release();
Transparency->Release();
CCWcullMode->Release();
CWcullMode->Release();
d3d101Device->Release();
keyedMutex11->Release();
keyedMutex10->Release();
D2DRenderTarget->Release();
Brush->Release();
BackBuffer11->Release();
sharedTex11->Release();
DWriteFactory->Release();
TextFormat->Release();
d2dTexture->Release();
cbPerFrameBuffer->Release();
DIKeyboard->Unacquire();
DIMouse->Unacquire();
DirectInput->Release();
}
Change the Light Direction
Of course we don't have to do this, but to get the full color of our grass texture, we need to make sure the light is hitting it directly from above.
light.dir = XMFLOAT3(0.0f, 1.0f, 0.0f);
light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
Describing the Ground's Vertex and Index Buffers
Our ground wil be a simple square. Notice our texture coordinates though. This is to get a repeating texture (I created a seamless grass texture for this), instead of one very very very stretched out texture covering the whole ground.
//Create the vertex buffer
Vertex v[] =
{
// Bottom Face
Vertex(-1.0f, -1.0f, -1.0f, 100.0f, 100.0f, 0.0f, 1.0f, 0.0f),
Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 100.0f, 0.0f, 1.0f, 0.0f),
Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f),
Vertex(-1.0f, -1.0f, 1.0f, 100.0f, 0.0f, 0.0f, 1.0f, 0.0f),
};
DWORD indices[] = {
0, 1, 2,
0, 2, 3,
};
D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 4;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &squareVertBuffer);
Updated Texture
We are not using that brain texture now, we are going to use a nice seamless grass texture!
hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"grass.jpg",
NULL, NULL, &CubesTexture, NULL );
Updating Our Scene
We are not using the cubes in this lesson, so we won't be updating their world spaces. Instead, we will scale our ground to be 1000 units wide and long, and move it down 10 units on the y axis.
void UpdateScene(double time)
{
//Reset cube1World
groundWorld = XMMatrixIdentity();
//Define cube1's world space matrix
///////////////**************new**************////////////////////
Scale = XMMatrixScaling( 500.0f, 10.0f, 500.0f );
Translation = XMMatrixTranslation( 0.0f, 10.0f, 0.0f );
//Set cube1's world space using the transformations
groundWorld = Scale * Translation;
///////////////**************new**************////////////////////
}
Change the Background Color
I thought a pitch black background was somewhat boring, so i changed it to a dark shade of grey.
float bgColor[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
Thats it for our simple camera! Hope you got some use out of this one!
Exercise:
1. Make a Free-Look Camera, where you are not restricted to moving around on the X and Z plane.