#include "D3DApp.h"
#include <assert.h>
#include <iostream>
namespace {
D3DApp* _gWinProcOwner = nullptr;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (_gWinProcOwner) { return _gWinProcOwner->MsgProc(hwnd, msg, wParam, lParam); }
else { return DefWindowProc(hwnd, msg, wParam, lParam); }
}
D3DApp::D3DApp(HINSTANCE hInstance, std::string appName, UINT32 width, UINT32 height)
: mhAppInstance{ hInstance }, mWindowCaption{ appName }, mClientWidth{ width }, mClientHeight{ height }
{
_gWinProcOwner = this;
}
D3DApp::~D3DApp()
{
mDepthStencilView->Release();
mRenderTargetView->Release();
mDepthStencilBuffer->Release();
mSwapChain->Release();
mImmediateContext->Release();
mDevice->Release();
}
HINSTANCE D3DApp::AppInst() const
{
return mhAppInstance;
}
HWND D3DApp::MainWnd() const
{
return mhWindow;
}
float D3DApp::AspectRatio() const
{
//TODO
return 0.0f;
}
int D3DApp::Run()
{
//TODO
return 0;
}
bool D3DApp::Init()
{
if (!mhWindow)
{
//Init Window
if (!InitMainWindow()) {
return false;
}
//Init Direct3D
if (!InitDirect3D()) {
return false;
}
return true;
}
return false;
}
void D3DApp::OnResize()
{
//TODO
}
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
MessageBox(0, "This is the D3DApp version of MsgProc()", 0, 0);
}break;
case WM_CLOSE:
{
PostQuitMessage(0);
}break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return LRESULT();
}
bool D3DApp::InitMainWindow()
{
//Define and Register Window Class
WNDCLASS clientWindow{};
clientWindow.style = CS_OWNDC;
clientWindow.lpfnWndProc = WindowProc;
clientWindow.hInstance = mhAppInstance;
clientWindow.hCursor = LoadCursor(mhAppInstance, IDC_ARROW);
clientWindow.lpszClassName = "clientWindow";
if (FAILED(RegisterClass(&clientWindow)))
{
MessageBox(NULL, "Couldn't register window class", NULL, NULL);
return false;
}
//Create Window
RECT r{ 0,0,(LONG)mClientWidth,(LONG)mClientHeight };
LONG newWidth = r.right - r.left;
LONG newHeight = r.bottom - r.top;
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
mhWindow = CreateWindow("clientWindow", mWindowCaption.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
GetSystemMetrics(SM_CXFULLSCREEN) / 2 - newWidth / 2, GetSystemMetrics(SM_CYFULLSCREEN) / 2 - newHeight / 2,
newWidth, newHeight, NULL, NULL, mhAppInstance, 0);
if (!mhWindow)
{
MessageBox(NULL, "Window creation failed", NULL, NULL);
return false;
}
return true;
}
bool D3DApp::InitDirect3D()
{
//Device and ImmediateContext creation
UINT createDeviceFlags{};
#if defined(DEBUG) || defined(_DEBUG)
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_FEATURE_LEVEL featureLevel{};
HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, 0, 0,
D3D11_SDK_VERSION, &mDevice, &featureLevel, &mImmediateContext);
if (FAILED(hr))
{
MessageBox(0, "D3D11CreateDevice failed", 0, 0);
return false;
}
if (featureLevel != D3D_FEATURE_LEVEL_11_0)
{
MessageBox(0, "Direct3D Feature Level 11 not supported", 0, 0);
return false;
}
//MSAA Quality Check
mDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality);
assert(m4xMsaaQuality > 0);
//4xMSAA Description
DXGI_SAMPLE_DESC sampleDesc{};
sampleDesc.Count = mEnable4xMsaa ? 4 : 1;
sampleDesc.Quality = mEnable4xMsaa ? (m4xMsaaQuality - 1) : 0;
//SwapChain creation
{
//buffer Description
DXGI_MODE_DESC bufferDesc{};
bufferDesc.Width = mClientWidth;
bufferDesc.Height = mClientHeight;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//SwapChain Description
DXGI_SWAP_CHAIN_DESC swapChainDesc{};
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc = sampleDesc;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = mhWindow;
swapChainDesc.Windowed = mWindowed;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = 0;
//Get Factory used to create ID3D11Device
IDXGIDevice* device{};
mDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&device));
IDXGIAdapter* adapter{};
device->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&adapter));
IDXGIFactory* factory{};
adapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&factory));
//Create swapChain
factory->CreateSwapChain(mDevice, &swapChainDesc, &mSwapChain);
//Release COM interfaces
device->Release();
adapter->Release();
factory->Release();
}
//Render Target View creation
ID3D11Texture2D* backBuffer{};
mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer));
mDevice->CreateRenderTargetView(backBuffer, NULL, &mRenderTargetView);
backBuffer->Release();
//Depth/Stencil Buffer creation
D3D11_TEXTURE2D_DESC depthBufferDesc;
depthBufferDesc.Width = mClientWidth;
depthBufferDesc.Height = mClientHeight;
depthBufferDesc.MipLevels = 1;
depthBufferDesc.ArraySize = 1;
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.SampleDesc = sampleDesc;
depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthBufferDesc.CPUAccessFlags = 0;
depthBufferDesc.MiscFlags = 0;
mDevice->CreateTexture2D(&depthBufferDesc, 0, &mDepthStencilBuffer);
mDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView);
//Bind RenderTargerView and DepthStencilView to the OutputMerger Stage
mImmediateContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);
//Set Vieport
D3D11_VIEWPORT vieport{};
vieport.TopLeftX = 0.f;
vieport.TopLeftY = 0.f;
vieport.Width = static_cast<float>(mClientWidth);
vieport.Height = static_cast<float>(mClientHeight);
vieport.MinDepth = 0;
vieport.MaxDepth = 1;
mImmediateContext->RSSetViewports(1, &vieport);
return true;
}
void D3DApp::CalculateFrameStats()
{
//TODO
}