原文:Directx11学习笔记【八】 龙书D3DApp的实现
directx11龙书中的初始化程序D3DApp跟我们上次写的初始化程序大体一致,只是包含了计时器的内容,而且使用了深度模板缓冲。
D3DUtil类,定义了一些工具和宏,目前只定义了两个宏,以后还会添加
#ifndef D3DUTIL_H
#define D3DUTIL_H #include <d3dx11.h>
#include <xnamath.h>
#include <dxerr.h>
#include <cassert> //-------------------------------
//方便检测d3d errors
//-------------------------------
#if defined(DEBUG) | defined(_DEBUG)
#ifndef HR
#define HR(x) \
{ \
HRESULT hr = (x); \
if (FAILED(hr)) \
{ \
DXTrace(__FILE__, (DWORD)__LINE__, hr, L#x, true); \
} \
}
#endif #else
#ifndef HR
#define HR(x) (x)
#endif
#endif //------------------------------
//方便删除COM objects
//------------------------------
#define ReleaseCOM(x) { if(x){ x->Release(); x = 0; } } #endif//D3DUTIL_H
基类D3DApp的实现
.h文件
#ifndef D3DAPP_H
#define D3DAPP_H #include <windows.h>
#include <string>
#include "D3DUtil.h"
#include "GameTimer.h" class D3DApp
{
public:
D3DApp(HINSTANCE hInstance);
virtual ~D3DApp(); HINSTANCE AppInst() const;
HWND MainWnd() const;
float AspectRatio() const; int Run(); virtual bool Init();
virtual void OnResize();
virtual void UpdateScene(float dt) = ;
virtual void DrawScene();
virtual LRESULT MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); //鼠标事件
virtual void OnMouseDown(WPARAM btnState, int x, int y){}
virtual void OnMouseUp(WPARAM btnState, int x, int y){}
virtual void OnMouseMove(WPARAM btnState, int x, int y){} protected:
bool InitMainWindow();
bool InitDirect3D();
//计算FPS
void CalculateFrameStats(); protected:
HINSTANCE m_hAppInst; //实例句柄
HWND m_hMainWnd; //主窗口句柄
bool m_isAppPaused;
bool m_isMinimized;
bool m_isMaximized;
bool m_isResizing;
UINT m_4xMsaaQuality; //4重采样质量 GameTimer m_timer; //计时器
D3D_DRIVER_TYPE m_d3dDriverType; //驱动类型
ID3D11Device *m_pD3dDevice; //设备
ID3D11DeviceContext *m_pImmediateContext; //设备上下文
IDXGISwapChain *m_pSwapChain; //交换链
ID3D11Texture2D *m_pDepthStencilBuffer; //深度模板缓冲
ID3D11RenderTargetView *m_pRenderTargetView; //渲染目标视图
ID3D11DepthStencilView *m_pDepthStencilView; //深度模板缓冲视图
D3D11_VIEWPORT m_screenViewPort; //视口 std::wstring m_mainWndCaption; //窗口标题
int m_clientWidth;
int m_clientHeight;
bool m_isEnable4xMsaa; //是否支持4重采样
};
#endif //D3DAPP_H
.cpp
#include <windowsx.h>//包含大量可用的宏和各种方便的工具
#include <sstream>
#include "D3DApp.h" namespace
{
D3DApp *g_d3dApp = NULL;
} LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return g_d3dApp->MsgProc(hWnd,msg,wParam,lParam);
} D3DApp::D3DApp(HINSTANCE hInstance) :
m_hAppInst(hInstance),
m_mainWndCaption(L"D3D11 Application"),
m_d3dDriverType(D3D_DRIVER_TYPE_HARDWARE),
m_clientHeight(),
m_clientWidth(),
m_isEnable4xMsaa(false),
m_hMainWnd(NULL),
m_isAppPaused(false),
m_isMaximized(false),
m_isMinimized(false),
m_isResizing(false),
m_4xMsaaQuality(), m_pD3dDevice(NULL),
m_pImmediateContext(NULL),
m_pSwapChain(NULL),
m_pRenderTargetView(NULL),
m_pDepthStencilBuffer(NULL)
{
ZeroMemory(&m_screenViewPort, sizeof(D3D11_VIEWPORT));
g_d3dApp = this;
} D3DApp::~D3DApp()
{
ReleaseCOM(m_pRenderTargetView);
ReleaseCOM(m_pDepthStencilBuffer);
ReleaseCOM(m_pSwapChain);
ReleaseCOM(m_pDepthStencilView); if (m_pImmediateContext)
m_pImmediateContext->ClearState(); ReleaseCOM(m_pImmediateContext);
ReleaseCOM(m_pD3dDevice);
} HINSTANCE D3DApp::AppInst() const
{
return m_hAppInst;
} HWND D3DApp::MainWnd() const
{
return m_hMainWnd;
} float D3DApp::AspectRatio() const
{
return static_cast<float>(m_clientWidth / m_clientHeight);
} int D3DApp::Run()
{
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
m_timer.Reset(); while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, , , PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
m_timer.Tick();
if (!m_isAppPaused)
{
CalculateFrameStats();
UpdateScene(m_timer.DeltaTime());
DrawScene();
}
else
{
Sleep();
}
}
}
return static_cast<int>(msg.wParam);
} bool D3DApp::Init()
{
if (!InitMainWindow())
return false;
if (!InitDirect3D())
return false;
return true;
} void D3DApp::OnResize()
{
assert(m_pImmediateContext);
assert(m_pD3dDevice);
assert(m_pSwapChain); //release old views
ReleaseCOM(m_pRenderTargetView);
ReleaseCOM(m_pDepthStencilView);
ReleaseCOM(m_pDepthStencilBuffer); HR(m_pSwapChain->ResizeBuffers(, m_clientWidth, m_clientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, ));
ID3D11Texture2D *backBuffer;
HR(m_pSwapChain->GetBuffer(, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
HR(m_pD3dDevice->CreateRenderTargetView(backBuffer, , &m_pRenderTargetView));
ReleaseCOM(backBuffer); //create depth/stencil buffer and view
D3D11_TEXTURE2D_DESC depthStencilDecs;
depthStencilDecs.Width = m_clientWidth;
depthStencilDecs.Height = m_clientHeight;
depthStencilDecs.MipLevels = ;
depthStencilDecs.ArraySize = ;
depthStencilDecs.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; //是否使用4重采样
if (m_isEnable4xMsaa)
{
depthStencilDecs.SampleDesc.Count = ;
depthStencilDecs.SampleDesc.Quality = m_4xMsaaQuality - ;
}
else
{
depthStencilDecs.SampleDesc.Count = ;
depthStencilDecs.SampleDesc.Quality = ;
} depthStencilDecs.Usage = D3D11_USAGE_DEFAULT;
depthStencilDecs.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDecs.CPUAccessFlags = ;
depthStencilDecs.MiscFlags = ; HR(m_pD3dDevice->CreateTexture2D(&depthStencilDecs, , &m_pDepthStencilBuffer));
HR(m_pD3dDevice->CreateDepthStencilView(m_pDepthStencilBuffer, , &m_pDepthStencilView)); //绑定新的render target view 和 depth/stencil view到管线
m_pImmediateContext->OMSetRenderTargets(, &m_pRenderTargetView, m_pDepthStencilView); //设置viewport
m_screenViewPort.TopLeftX = ;
m_screenViewPort.TopLeftY = ;
m_screenViewPort.Width = m_clientWidth;
m_screenViewPort.Height = m_clientHeight;
m_screenViewPort.MaxDepth = 1.0f;
m_screenViewPort.MinDepth = 0.0f; m_pImmediateContext->RSSetViewports(, &m_screenViewPort);
} LRESULT D3DApp::MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
//当一个窗口被激活或失去激活状态
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
{
m_isAppPaused = true;
m_timer.Stop();
}
else
{
m_isAppPaused = false;
m_timer.Start();
}
return ; //当用户重绘窗口时
case WM_SIZE:
m_clientWidth = LOWORD(lParam);
m_clientHeight = HIWORD(lParam);
if (m_pD3dDevice)
{
if (wParam == SIZE_MINIMIZED)//窗口最小化
{
m_isAppPaused = true;
m_isMinimized = true;
m_isMaximized = true;
}
else if (wParam == SIZE_MAXIMIZED)//窗口最大化
{
m_isAppPaused = false;
m_isMinimized = false;
m_isMaximized = true;
OnResize();
}
else if (wParam == SIZE_RESTORED)//窗口大小改变既不是最大化也不是最小化
{
if (m_isMinimized)
{
m_isAppPaused = false;
m_isMinimized = false;
OnResize();
}
else if (m_isMaximized)
{
m_isAppPaused = false;
m_isMaximized = false;
OnResize();
}
//当用户正在改变窗口大小时不调用OnResize(),当改变完成后再
//调用
else if (m_isResizing)
{ }
else
{
OnResize();
}
}
}
return ; //用户开始拖拽改变窗口大小
case WM_ENTERSIZEMOVE:
m_isAppPaused = true;
m_isResizing = true;
m_timer.Stop();
return ; //用户改变窗口大小完毕
case WM_EXITSIZEMOVE:
m_isAppPaused = false;
m_isResizing = false;
m_timer.Start();
OnResize();
return ;
//窗口销毁
case WM_DESTROY:
PostQuitMessage();
return ; //The WM_MENUCHAR message is sent when a menu is active and the user presses
// a key that does not correspond to any mnemonic or accelerator key.
case WM_MENUCHAR:
return MAKELRESULT(, MNC_CLOSE); //防止窗口变得太小
case WM_GETMINMAXINFO:
((MINMAXINFO*)lParam)->ptMinTrackSize.x = ;
((MINMAXINFO*)lParam)->ptMinTrackSize.y = ;
return ; case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
OnMouseDown(wParam, GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
return ;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
OnMouseUp(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return ;
case WM_MOUSEMOVE:
OnMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return ;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
} bool D3DApp::InitMainWindow()
{
WNDCLASS wc;
wc.cbClsExtra = ;
wc.cbWndExtra = ;
wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(NULL_BRUSH));
wc.hCursor = LoadCursor(, IDC_ARROW);
wc.hIcon = LoadIcon(, IDI_APPLICATION);
wc.hInstance = m_hAppInst;
wc.lpfnWndProc = MainWndProc;
wc.lpszClassName = L"D3DWndClassName";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClass(&wc))
{
MessageBox(, L"RegisterClass Failed", , );
return false;
} RECT rect{ , , m_clientWidth, m_clientHeight };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, false);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top; m_hMainWnd = CreateWindow(L"D3DWndClassName", m_mainWndCaption.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
width, height, NULL, NULL, m_hAppInst, );
if (!m_hMainWnd)
{
MessageBox(, L"CreateWindow Failed", , );
return ;
} ShowWindow(m_hMainWnd,SW_SHOW);
UpdateWindow(m_hMainWnd); return true;
} bool D3DApp::InitDirect3D()
{
UINT createDeviceFlags = ;
#if defined(DEBUG) || defined(_DEBUG)
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif D3D_FEATURE_LEVEL featureLevel;
HRESULT hr = D3D11CreateDevice(
,//默认的adapter
m_d3dDriverType,
,
createDeviceFlags,
, ,
D3D11_SDK_VERSION,
&m_pD3dDevice,
&featureLevel,
&m_pImmediateContext
);
if (FAILED(hr))
{
MessageBox(, L"D3D11CreateDevice Failed", , );
return hr;
} if (featureLevel != D3D_FEATURE_LEVEL_11_0)
{
MessageBox(, L"Direct3D Feature Level 11 unsupported!", , );
return false;
} //check 4x msaa quality support
HR(m_pD3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, , &m_4xMsaaQuality));
assert(m_4xMsaaQuality > ); //填充交换链描述
DXGI_SWAP_CHAIN_DESC sd;
sd.BufferDesc.Width = m_clientWidth;
sd.BufferDesc.Height = m_clientHeight;
sd.BufferDesc.RefreshRate.Numerator = ;
sd.BufferDesc.RefreshRate.Denominator = ;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//是否用4重采样
if (m_isEnable4xMsaa)
{
sd.SampleDesc.Count = ;
sd.SampleDesc.Quality = m_4xMsaaQuality - ;
}
else
{
sd.SampleDesc.Count = ;
sd.SampleDesc.Quality = ;
} sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = ;
sd.OutputWindow = m_hMainWnd;
sd.Windowed = true;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = ; //要创建交换链必须得到IDXGIFactory
IDXGIDevice *pDxgiDevice = ;
HR(m_pD3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDxgiDevice))); IDXGIAdapter *pDxgiAdapter = ;
HR(pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&pDxgiAdapter))); IDXGIFactory *pDxgiFactory = ;
HR(pDxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&pDxgiFactory))); HR(pDxgiFactory->CreateSwapChain(m_pD3dDevice, &sd, &m_pSwapChain)); ReleaseCOM(pDxgiDevice);
ReleaseCOM(pDxgiAdapter);
ReleaseCOM(pDxgiFactory); OnResize(); return true;
} void D3DApp::CalculateFrameStats()
{
//计算fps,每一帧调用
static int frameCnt = ;
static float timeElapsed = 0.0f; frameCnt++; if ((m_timer.TotalTime() - timeElapsed) >= 1.0f)
{
float fps = static_cast<float>(frameCnt);
float mspf = .f / fps; std::wostringstream outs;
outs.precision();//浮点数显示6位
outs << m_mainWndCaption << L" " << L"FPS:" << fps << L" "
<< L"Frame Time:" << mspf << L" (ms) ";
SetWindowText(m_hMainWnd, outs.str().c_str()); frameCnt = ;
timeElapsed += 1.0f;
}
} void D3DApp::DrawScene()
{ }
初始化程序
InitDirect3DApp.h
#ifndef INITDIRECT3DAPP_H
#define INITDIRECT3DAPP_H #include "D3DApp.h" class InitDirect3DApp : public D3DApp
{
public:
InitDirect3DApp(HINSTANCE hInstance);
~InitDirect3DApp(); bool Init();
void OnResize();
void UpdateScene(float dt);
void DrawScene();
}; #endif//INITDIRECT3DAPP_H
InitDirect3DApp.cpp
#include "InitDirect3DApp.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif InitDirect3DApp theApp(hInstance); if (!theApp.Init())
return ;
return theApp.Run();
} InitDirect3DApp::InitDirect3DApp(HINSTANCE hInstance) : D3DApp(hInstance)
{
} InitDirect3DApp::~InitDirect3DApp()
{
} bool InitDirect3DApp::Init()
{
if (!D3DApp::Init())
return false;
return true;
} void InitDirect3DApp::OnResize()
{
D3DApp::OnResize();
} void InitDirect3DApp::UpdateScene(float dt)
{ } void InitDirect3DApp::DrawScene()
{
assert(m_pImmediateContext);
assert(m_pSwapChain); float ClearColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, ClearColor);
m_pImmediateContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, );
HR(m_pSwapChain->Present(, ));
}