OSDN Git Service

最初のコミット
[shooting3/shootinggame.git] / ShootingGame / DirectXBase.cpp
1 //// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
2 //// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
3 //// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
4 //// PARTICULAR PURPOSE.
5 ////
6 //// Copyright (c) Microsoft Corporation. All rights reserved
7
8 #include "pch.h"
9 #include "DirectXBase.h" 
10
11 using namespace Windows::UI::Core;
12 using namespace Windows::Foundation;
13 using namespace Microsoft::WRL;
14 using namespace D2D1;
15
16 // Constructor.
17 DirectXBase::DirectXBase() :
18     m_dpi(-1.0f)
19 {
20 }
21
22 // Initialize the Direct3D resources required to run.
23 void DirectXBase::Initialize(CoreWindow^ window, float dpi)
24 {
25     m_window = window;
26
27     CreateDeviceIndependentResources();
28     CreateDeviceResources();
29     SetDpi(dpi);
30 }
31
32 // These are the resources required independent of hardware.
33 void DirectXBase::CreateDeviceIndependentResources()
34 {
35     D2D1_FACTORY_OPTIONS options;
36     ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
37
38 #if defined(_DEBUG)
39      // If the project is in a debug build, enable Direct2D debugging via SDK Layers
40     options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
41 #endif
42
43     DX::ThrowIfFailed(
44         D2D1CreateFactory(
45             D2D1_FACTORY_TYPE_SINGLE_THREADED,
46             __uuidof(ID2D1Factory1),
47             &options,
48             &m_d2dFactory
49             )
50         );
51
52     DX::ThrowIfFailed(
53         DWriteCreateFactory(
54             DWRITE_FACTORY_TYPE_SHARED,
55             __uuidof(IDWriteFactory),
56             &m_dwriteFactory
57             )
58         );
59
60     DX::ThrowIfFailed(
61         CoCreateInstance(
62             CLSID_WICImagingFactory,
63             nullptr,
64             CLSCTX_INPROC_SERVER,
65             IID_PPV_ARGS(&m_wicFactory)
66             )
67         );
68 }
69
70 // These are the resources that depend on the device.
71 void DirectXBase::CreateDeviceResources()
72 {
73     // This flag adds support for surfaces with a different color channel ordering than the API default.
74     // It is recommended usage, and is required for compatibility with Direct2D.
75     UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
76     ComPtr<IDXGIDevice> dxgiDevice;
77
78 #if defined(_DEBUG)
79     // If the project is in a debug build, enable debugging via SDK Layers with this flag.
80     creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
81 #endif
82
83     // This array defines the set of DirectX hardware feature levels this app will support.
84     // Note the ordering should be preserved.
85     // Don't forget to declare your application's minimum required feature level in its
86     // description.  All applications are assumed to support 9.1 unless otherwise stated.
87     D3D_FEATURE_LEVEL featureLevels[] = 
88     {
89         D3D_FEATURE_LEVEL_11_1,
90         D3D_FEATURE_LEVEL_11_0,
91         D3D_FEATURE_LEVEL_10_1,
92         D3D_FEATURE_LEVEL_10_0,
93         D3D_FEATURE_LEVEL_9_3,
94         D3D_FEATURE_LEVEL_9_2,
95         D3D_FEATURE_LEVEL_9_1
96     };
97
98     // Create the DX11 API device object, and get a corresponding context.
99     ComPtr<ID3D11Device> device;
100     ComPtr<ID3D11DeviceContext> context;
101     DX::ThrowIfFailed(
102         D3D11CreateDevice(
103             nullptr,                    // specify null to use the default adapter
104             D3D_DRIVER_TYPE_HARDWARE,
105             0,                          // leave as 0 unless software device
106             creationFlags,              // optionally set debug and Direct2D compatibility flags
107             featureLevels,              // list of feature levels this app can support
108             ARRAYSIZE(featureLevels),   // number of entries in above list
109             D3D11_SDK_VERSION,          // always set this to D3D11_SDK_VERSION for Metro style apps
110             &device,                    // returns the Direct3D device created
111             &m_featureLevel,            // returns feature level of device created
112             &context                    // returns the device immediate context
113             )
114         );
115
116     // Get the DirectX11.1 device by QI off the DirectX11 one.
117     DX::ThrowIfFailed(
118         device.As(&m_d3dDevice)
119         );
120
121     // And get the corresponding device context in the same way.
122     DX::ThrowIfFailed(
123         context.As(&m_d3dContext)
124         );
125
126     // Obtain the underlying DXGI device of the Direct3D11.1 device.
127     DX::ThrowIfFailed(
128         m_d3dDevice.As(&dxgiDevice)
129         );
130
131     // Obtain the Direct2D device for 2-D rendering.
132     DX::ThrowIfFailed(
133         m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
134         );
135
136     // And get its corresponding device context object.
137     DX::ThrowIfFailed(
138         m_d2dDevice->CreateDeviceContext(
139             D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
140             &m_d2dContext
141             )
142         );
143
144     // Release the swap chain (if it exists) as it will be incompatible with
145     // the new device.
146     m_swapChain = nullptr;
147 }
148
149 // Helps track the DPI in the helper class.
150 // This is called in the dpiChanged event handler in the view class.
151 void DirectXBase::SetDpi(float dpi)
152 {
153     if (dpi != m_dpi)
154     {
155         // Save the DPI of this display in our class.
156         m_dpi = dpi;
157         
158         // Update Direct2D's stored DPI.
159         m_d2dContext->SetDpi(m_dpi, m_dpi);
160
161         // Often a DPI change implies a window size change. In some cases Windows will issues
162         // both a size changed event and a DPI changed event. In this case, the resulting bounds 
163         // will not change, and the window resize code will only be executed once.
164         UpdateForWindowSizeChange();
165     }
166 }
167
168 // This routine is called in the event handler for the view SizeChanged event.
169 void DirectXBase::UpdateForWindowSizeChange()
170 {
171     if (m_window->Bounds.Width  != m_windowBounds.Width ||
172         m_window->Bounds.Height != m_windowBounds.Height)
173     {
174         m_d2dContext->SetTarget(nullptr);
175         m_d2dTargetBitmap = nullptr;
176         m_renderTargetView = nullptr;
177         m_depthStencilView = nullptr;
178         CreateWindowSizeDependentResources();
179     }
180 }
181
182 // Allocate all memory resources that change on a window SizeChanged event.
183 void DirectXBase::CreateWindowSizeDependentResources()
184 {
185     // Store the window bounds so the next time we get a SizeChanged event we can
186     // avoid rebuilding everything if the size is identical.
187     m_windowBounds = m_window->Bounds;
188
189     // If the swap chain already exists, resize it.
190     if(m_swapChain != nullptr)
191     {
192         DX::ThrowIfFailed(
193             m_swapChain->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0)
194             );
195     }
196     // Otherwise, create a new one.
197     else
198     {
199         // Allocate a descriptor.
200         DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
201         swapChainDesc.Width = 0;                                     // use automatic sizing
202         swapChainDesc.Height = 0;
203         swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;           // this is the most common swapchain format
204         swapChainDesc.Stereo = false; 
205         swapChainDesc.SampleDesc.Count = 1;                          // don't use multi-sampling
206         swapChainDesc.SampleDesc.Quality = 0;
207         swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
208         swapChainDesc.BufferCount = 2;                               // use double buffering to enable flip
209         swapChainDesc.Scaling = DXGI_SCALING_NONE;
210         swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all Metro style apps must use this SwapEffect
211         swapChainDesc.Flags = 0;
212
213         // Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device
214
215         // First, retrieve the underlying DXGI Device from the D3D Device.
216         ComPtr<IDXGIDevice1>  dxgiDevice;
217         DX::ThrowIfFailed(
218             m_d3dDevice.As(&dxgiDevice)
219             );
220
221         // Identify the physical adapter (GPU or card) this device is running on.
222         ComPtr<IDXGIAdapter> dxgiAdapter;
223         DX::ThrowIfFailed(
224             dxgiDevice->GetAdapter(&dxgiAdapter)
225             );
226
227         // And obtain the factory object that created it.
228         ComPtr<IDXGIFactory2> dxgiFactory;
229         DX::ThrowIfFailed(
230             dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
231             );
232
233         // Obtain the final swap chain for this window from the DXGI factory.
234         DX::ThrowIfFailed(
235             dxgiFactory->CreateSwapChainForCoreWindow(
236                 m_d3dDevice.Get(),
237                 reinterpret_cast<IUnknown*>(m_window),
238                 &swapChainDesc,
239                 nullptr,    // allow on all displays
240                 &m_swapChain
241                 )
242             );
243
244         // Ensure that DXGI does not queue more than one frame at a time. This both reduces 
245         // latency and ensures that the application will only render after each VSync, minimizing 
246         // power consumption.
247         DX::ThrowIfFailed(
248             dxgiDevice->SetMaximumFrameLatency(1)
249             );
250
251     }
252
253     // Obtain the backbuffer for this window which will be the final 3D rendertarget.
254     ComPtr<ID3D11Texture2D> backBuffer;
255     DX::ThrowIfFailed(
256         m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
257         );
258
259     // Create a view interface on the rendertarget to use on bind.
260     DX::ThrowIfFailed(
261         m_d3dDevice->CreateRenderTargetView(
262             backBuffer.Get(),
263             nullptr,
264             &m_renderTargetView
265             )
266         );
267
268     // Cache the rendertarget dimensions in our helper class for convenient use.
269     D3D11_TEXTURE2D_DESC backBufferDesc = {0};
270     backBuffer->GetDesc(&backBufferDesc);
271     m_renderTargetSize.Width  = static_cast<float>(backBufferDesc.Width);
272     m_renderTargetSize.Height = static_cast<float>(backBufferDesc.Height);
273
274     // Create a descriptor for the depth/stencil buffer.
275     CD3D11_TEXTURE2D_DESC depthStencilDesc(
276         DXGI_FORMAT_D24_UNORM_S8_UINT, 
277         backBufferDesc.Width,
278         backBufferDesc.Height,
279         1,
280         1,
281         D3D11_BIND_DEPTH_STENCIL
282         );
283
284     // Allocate a 2-D surface as the depth/stencil buffer.
285     ComPtr<ID3D11Texture2D> depthStencil;
286     DX::ThrowIfFailed(
287         m_d3dDevice->CreateTexture2D(
288             &depthStencilDesc,
289             nullptr,
290             &depthStencil
291             )
292         );
293
294     // Create a DepthStencil view on this surface to use on bind.
295     DX::ThrowIfFailed(
296         m_d3dDevice->CreateDepthStencilView(
297             depthStencil.Get(),
298             &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D),
299             &m_depthStencilView
300             )
301         );
302
303     // Create a viewport descriptor of the full window size.
304     CD3D11_VIEWPORT viewport(
305         0.0f,
306         0.0f,
307         static_cast<float>(backBufferDesc.Width),
308         static_cast<float>(backBufferDesc.Height)
309         );
310
311     // Set the current viewport using the descriptor.
312     m_d3dContext->RSSetViewports(1, &viewport);
313
314     // Now we set up the Direct2D render target bitmap linked to the swapchain. 
315     // Whenever we render to this bitmap, it will be directly rendered to the 
316     // swapchain associated with the window.
317     D2D1_BITMAP_PROPERTIES1 bitmapProperties = 
318         BitmapProperties1(
319             D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
320             PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
321             m_dpi,
322             m_dpi
323             );
324
325     // Direct2D needs the dxgi version of the backbuffer surface pointer.
326     ComPtr<IDXGISurface> dxgiBackBuffer;
327     DX::ThrowIfFailed(
328         m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
329         );
330
331     // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
332     DX::ThrowIfFailed(
333         m_d2dContext->CreateBitmapFromDxgiSurface(
334             dxgiBackBuffer.Get(),
335             &bitmapProperties,
336             &m_d2dTargetBitmap
337             )
338         );
339
340     // So now we can set the Direct2D render target.
341     m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
342
343     // Set D2D text anti-alias mode to Grayscale to ensure proper rendering of text on intermediate surfaces.
344     m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
345 }
346
347 // Method to deliver the final image to the display.
348 void DirectXBase::Present()
349 {
350     // The application may optionally specify "dirty" or "scroll" rects to improve efficiency
351     // in certain scenarios.  In this sample, however, we do not utilize those features.
352     DXGI_PRESENT_PARAMETERS parameters = {0};
353     parameters.DirtyRectsCount = 0;
354     parameters.pDirtyRects = nullptr;
355     parameters.pScrollRect = nullptr;
356     parameters.pScrollOffset = nullptr;
357     
358     // The first argument instructs DXGI to block until VSync, putting the application
359     // to sleep until the next VSync. This ensures we don't waste any cycles rendering
360     // frames that will never be displayed to the screen.
361     HRESULT hr = m_swapChain->Present1(1, 0, &parameters);
362
363     // If the device was removed either by a disconnect or a driver upgrade, we 
364     // must completely reinitialize the renderer.
365     if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
366     {
367         Initialize(m_window, m_dpi);
368     }
369     else
370     {
371         DX::ThrowIfFailed(hr);
372     }
373 }