/
Game.cpp
369 lines (303 loc) · 12.1 KB
/
Game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
//
// Game.cpp -
//
#include "pch.h"
#include "Game.h"
using namespace DirectX;
using namespace DirectX::SimpleMath;
using Microsoft::WRL::ComPtr;
// Constructor.
Game::Game() :
m_window(0),
m_featureLevel( D3D_FEATURE_LEVEL_9_1 )
{
// •`‰æƒ}ƒl[ƒWƒƒ[ì¬
i_render_manager = std::make_shared<render_manager>();
}
// Initialize the Direct3D resources required to run.
void Game::Initialize(HWND window)
{
m_window = window;
CreateDevice();
CreateResources();
// TODO: Change the timer settings if you want something other than the default variable timestep mode.
// e.g. for 60 FPS fixed timestep update logic, call:
/*
m_timer.SetFixedTimeStep(true);
m_timer.SetTargetElapsedSeconds(1.0 / 60);
*/
}
// Executes basic game loop.
void Game::Tick()
{
m_timer.Tick([&]()
{
Update(m_timer);
});
Render();
}
// Updates the world
void Game::Update(DX::StepTimer const& timer)
{
float elapsedTime = float(timer.GetElapsedSeconds());
// TODO: Add your game logic here
elapsedTime;
i_render_manager->update();
}
// Draws the scene
void Game::Render()
{
// Don't try to render anything before the first Update.
if (m_timer.GetFrameCount() == 0)
return;
Clear();
// TODO: Add your rendering code here
i_render_manager->render();
Present();
}
// Helper method to clear the backbuffers
void Game::Clear()
{
// Clear the views
m_d3dContext->ClearRenderTargetView(m_renderTargetView.Get(), Colors::CornflowerBlue);
m_d3dContext->ClearDepthStencilView(m_depthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
m_d3dContext->OMSetRenderTargets(1, m_renderTargetView.GetAddressOf(), m_depthStencilView.Get());
}
// Presents the backbuffer contents to the screen
void Game::Present()
{
// The first argument instructs DXGI to block until VSync, putting the application
// to sleep until the next VSync. This ensures we don't waste any cycles rendering
// frames that will never be displayed to the screen.
HRESULT hr = m_swapChain->Present(1, 0);
// If the device was reset we must completely reinitialize the renderer.
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
OnDeviceLost();
}
else
{
DX::ThrowIfFailed(hr);
}
}
// Message handlers
void Game::OnActivated()
{
// TODO: Game is becoming active window
}
void Game::OnDeactivated()
{
// TODO: Game is becoming background window
}
void Game::OnSuspending()
{
// TODO: Game is being power-suspended (or minimized)
}
void Game::OnResuming()
{
m_timer.ResetElapsedTime();
// TODO: Game is being power-resumed (or returning from minimize)
}
void Game::OnWindowSizeChanged()
{
CreateResources();
// TODO: Game window is being resized
}
// Properties
void Game::GetDefaultSize(size_t& width, size_t& height) const
{
// TODO: Change to desired default window size (note minimum size is 320x200)
width = 800;
height = 600;
}
// These are the resources that depend on the device.
void Game::CreateDevice()
{
// This flag adds support for surfaces with a different color channel ordering than the API default.
UINT creationFlags = 0;
#ifdef _DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
static const D3D_FEATURE_LEVEL featureLevels [] =
{
// TODO: Modify for supported Direct3D feature levels (see code below related to 11.1 fallback handling)
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
};
// Create the DX11 API device object, and get a corresponding context.
HRESULT hr = D3D11CreateDevice(
nullptr, // specify null to use the default adapter
D3D_DRIVER_TYPE_HARDWARE,
nullptr, // leave as nullptr unless software device
creationFlags, // optionally set debug and Direct2D compatibility flags
featureLevels, // list of feature levels this app can support
_countof(featureLevels), // number of entries in above list
D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION
m_d3dDevice.ReleaseAndGetAddressOf(), // returns the Direct3D device created
&m_featureLevel, // returns feature level of device created
m_d3dContext.ReleaseAndGetAddressOf() // returns the device immediate context
);
if ( hr == E_INVALIDARG )
{
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
hr = D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
creationFlags, &featureLevels[1], _countof(featureLevels) - 1,
D3D11_SDK_VERSION, m_d3dDevice.ReleaseAndGetAddressOf(),
&m_featureLevel, m_d3dContext.ReleaseAndGetAddressOf() );
}
DX::ThrowIfFailed(hr);
#ifndef NDEBUG
ComPtr<ID3D11Debug> d3dDebug;
hr = m_d3dDevice.As(&d3dDebug);
if (SUCCEEDED(hr))
{
ComPtr<ID3D11InfoQueue> d3dInfoQueue;
hr = d3dDebug.As(&d3dInfoQueue);
if (SUCCEEDED(hr))
{
#ifdef _DEBUG
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
#endif
D3D11_MESSAGE_ID hide [] =
{
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
// TODO: Add more message IDs here as needed
};
D3D11_INFO_QUEUE_FILTER filter;
memset(&filter, 0, sizeof(filter));
filter.DenyList.NumIDs = _countof(hide);
filter.DenyList.pIDList = hide;
d3dInfoQueue->AddStorageFilterEntries(&filter);
}
}
#endif
// TODO: Initialize device dependent objects here (independent of window size)
i_render_manager->update_d3d(m_d3dDevice, m_d3dContext);
i_render_manager->create_device();
}
// Allocate all memory resources that change on a window SizeChanged event.
void Game::CreateResources()
{
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews [] = { nullptr };
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
m_renderTargetView.Reset();
m_depthStencilView.Reset();
m_d3dContext->Flush();
RECT rc;
GetWindowRect( m_window, &rc );
UINT backBufferWidth = std::max<UINT>( rc.right - rc.left, 1 );
UINT backBufferHeight = std::max<UINT>( rc.bottom - rc.top, 1);
DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
DXGI_FORMAT depthBufferFormat = (m_featureLevel >= D3D_FEATURE_LEVEL_10_0) ? DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D16_UNORM;
// If the swap chain already exists, resize it, otherwise create one.
if (m_swapChain)
{
HRESULT hr = m_swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, backBufferFormat, 0);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
// If the device was removed for any reason, a new device and swap chain will need to be created.
OnDeviceLost();
// Everything is set up now. Do not continue execution of this method. OnDeviceLost will reenter this method
// and correctly set up the new device.
return;
}
else
{
DX::ThrowIfFailed(hr);
}
}
else
{
// First, retrieve the underlying DXGI Device from the D3D Device
ComPtr<IDXGIDevice1> dxgiDevice;
DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
// Identify the physical adapter (GPU or card) this device is running on.
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));
// And obtain the factory object that created it.
ComPtr<IDXGIFactory1> dxgiFactory;
DX::ThrowIfFailed(dxgiAdapter->GetParent(__uuidof(IDXGIFactory1), &dxgiFactory));
ComPtr<IDXGIFactory2> dxgiFactory2;
HRESULT hr = dxgiFactory.As(&dxgiFactory2);
if (SUCCEEDED(hr))
{
// DirectX 11.1 or later
m_d3dDevice.As( &m_d3dDevice1 );
m_d3dContext.As( &m_d3dContext1 );
// Create a descriptor for the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = backBufferWidth;
swapChainDesc.Height = backBufferHeight;
swapChainDesc.Format = backBufferFormat;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = { 0 };
fsSwapChainDesc.Windowed = TRUE;
// Create a SwapChain from a CoreWindow.
DX::ThrowIfFailed( dxgiFactory2->CreateSwapChainForHwnd(
m_d3dDevice.Get(), m_window, &swapChainDesc,
&fsSwapChainDesc,
nullptr, m_swapChain1.ReleaseAndGetAddressOf() ) );
m_swapChain1.As( &m_swapChain );
}
else
{
DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Width = backBufferWidth;
swapChainDesc.BufferDesc.Height = backBufferHeight;
swapChainDesc.BufferDesc.Format = backBufferFormat;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = m_window;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = TRUE;
DX::ThrowIfFailed( dxgiFactory->CreateSwapChain( m_d3dDevice.Get(), &swapChainDesc, m_swapChain.ReleaseAndGetAddressOf() ) );
}
// This template does not support 'full-screen' mode and prevents the ALT+ENTER shortcut from working
dxgiFactory->MakeWindowAssociation(m_window, DXGI_MWA_NO_ALT_ENTER);
}
// Obtain the backbuffer for this window which will be the final 3D rendertarget.
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer));
// Create a view interface on the rendertarget to use on bind.
DX::ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, m_renderTargetView.ReleaseAndGetAddressOf()));
// Allocate a 2-D surface as the depth/stencil buffer and
// create a DepthStencil view on this surface to use on bind.
CD3D11_TEXTURE2D_DESC depthStencilDesc(depthBufferFormat, backBufferWidth, backBufferHeight, 1, 1, D3D11_BIND_DEPTH_STENCIL);
ComPtr<ID3D11Texture2D> depthStencil;
DX::ThrowIfFailed(m_d3dDevice->CreateTexture2D(&depthStencilDesc, nullptr, depthStencil.GetAddressOf()));
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
DX::ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(depthStencil.Get(), &depthStencilViewDesc, m_depthStencilView.ReleaseAndGetAddressOf()));
// Create a viewport descriptor of the full window size.
CD3D11_VIEWPORT viewPort(0.0f, 0.0f, static_cast<float>(backBufferWidth), static_cast<float>(backBufferHeight));
// Set the current viewport using the descriptor.
m_d3dContext->RSSetViewports(1, &viewPort);
// TODO: Initialize windows-size dependent objects here
i_render_manager->create_resource();
}
void Game::OnDeviceLost()
{
// TODO: Add Direct3D resource cleanup here
m_depthStencil.Reset();
m_depthStencilView.Reset();
m_renderTargetView.Reset();
m_swapChain1.Reset();
m_swapChain.Reset();
m_d3dContext1.Reset();
m_d3dContext.Reset();
m_d3dDevice1.Reset();
m_d3dDevice.Reset();
i_render_manager->on_device_lost();
CreateDevice();
CreateResources();
}