home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / MyDemos / MyD3D12Project / BoxApp.cpp next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  15.2 KB  |  463 lines

  1. //***************************************************************************************
  2. // BoxApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //
  4. // Shows how to draw a box in Direct3D 12.
  5. //
  6. // Controls:
  7. //   Hold the left mouse button down and move the mouse to rotate.
  8. //   Hold the right mouse button down and move the mouse to zoom in and out.
  9. //***************************************************************************************
  10.  
  11. #include "../../Common/d3dApp.h"
  12. #include "../../Common/MathHelper.h"
  13. #include "../../Common/UploadBuffer.h"
  14.  
  15. using Microsoft::WRL::ComPtr;
  16. using namespace DirectX;
  17. using namespace DirectX::PackedVector;
  18.  
  19. struct Vertex
  20. {
  21.     XMFLOAT3 Pos;
  22.     XMFLOAT4 Color;
  23. };
  24.  
  25. struct ObjectConstants
  26. {
  27.     XMFLOAT4X4 WorldViewProj = MathHelper::Identity4x4();
  28. };
  29.  
  30. class BoxApp : public D3DApp
  31. {
  32. public:
  33.     BoxApp(HINSTANCE hInstance);
  34.     BoxApp(const BoxApp& rhs) = delete;
  35.     BoxApp& operator=(const BoxApp& rhs) = delete;
  36.     ~BoxApp();
  37.  
  38.     virtual bool Initialize()override;
  39.  
  40. private:
  41.     virtual void OnResize()override;
  42.     virtual void Update(const GameTimer& gt)override;
  43.     virtual void Draw(const GameTimer& gt)override;
  44.  
  45.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  46.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  47.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  48.  
  49.     void BuildDescriptorHeaps();
  50.     void BuildConstantBuffers();
  51.     void BuildRootSignature();
  52.     void BuildShadersAndInputLayout();
  53.     void BuildBoxGeometry();
  54.     void BuildPSO();
  55.  
  56. private:
  57.     
  58.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  59.     ComPtr<ID3D12DescriptorHeap> mCbvHeap = nullptr;
  60.  
  61.     std::unique_ptr<UploadBuffer<ObjectConstants>> mObjectCB = nullptr;
  62.  
  63.     std::unique_ptr<MeshGeometry> mBoxGeo = nullptr;
  64.  
  65.     ComPtr<ID3DBlob> mvsByteCode = nullptr;
  66.     ComPtr<ID3DBlob> mpsByteCode = nullptr;
  67.  
  68.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  69.  
  70.     ComPtr<ID3D12PipelineState> mPSO = nullptr;
  71.  
  72.     XMFLOAT4X4 mWorld = MathHelper::Identity4x4();
  73.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  74.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  75.  
  76.     float mTheta = 1.5f*XM_PI;
  77.     float mPhi = XM_PIDIV4;
  78.     float mRadius = 5.0f;
  79.  
  80.     POINT mLastMousePos;
  81. };
  82.  
  83. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  84.                    PSTR cmdLine, int showCmd)
  85. {
  86.     // Enable run-time memory check for debug builds.
  87. #if defined(DEBUG) | defined(_DEBUG)
  88.     _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
  89. #endif
  90.  
  91.     try
  92.     {
  93.         BoxApp theApp(hInstance);
  94.         if(!theApp.Initialize())
  95.             return 0;
  96.  
  97.         return theApp.Run();
  98.     }
  99.     catch(DxException& e)
  100.     {
  101.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  102.         return 0;
  103.     }
  104. }
  105.  
  106. BoxApp::BoxApp(HINSTANCE hInstance)
  107. : D3DApp(hInstance) 
  108. {
  109. }
  110.  
  111. BoxApp::~BoxApp()
  112. {
  113. }
  114.  
  115. bool BoxApp::Initialize()
  116. {
  117.     if(!D3DApp::Initialize())
  118.         return false;
  119.         
  120.     // Reset the command list to prep for initialization commands.
  121.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  122.  
  123.     BuildDescriptorHeaps();
  124.     BuildConstantBuffers();
  125.     BuildRootSignature();
  126.     BuildShadersAndInputLayout();
  127.     BuildBoxGeometry();
  128.     BuildPSO();
  129.  
  130.     // Execute the initialization commands.
  131.     ThrowIfFailed(mCommandList->Close());
  132.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  133.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  134.  
  135.     // Wait until initialization is complete.
  136.     FlushCommandQueue();
  137.  
  138.     return true;
  139. }
  140.  
  141. void BoxApp::OnResize()
  142. {
  143.     D3DApp::OnResize();
  144.  
  145.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  146.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  147.     XMStoreFloat4x4(&mProj, P);
  148. }
  149.  
  150. void BoxApp::Update(const GameTimer& gt)
  151. {
  152.     // Convert Spherical to Cartesian coordinates.
  153.     float x = mRadius*sinf(mPhi)*cosf(mTheta);
  154.     float z = mRadius*sinf(mPhi)*sinf(mTheta);
  155.     float y = mRadius*cosf(mPhi);
  156.  
  157.     // Build the view matrix.
  158.     XMVECTOR pos = XMVectorSet(x, y, z, 1.0f);
  159.     XMVECTOR target = XMVectorZero();
  160.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  161.  
  162.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  163.     XMStoreFloat4x4(&mView, view);
  164.  
  165.     XMMATRIX world = XMLoadFloat4x4(&mWorld);
  166.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  167.     XMMATRIX worldViewProj = world*view*proj;
  168.  
  169.     // Update the constant buffer with the latest worldViewProj matrix.
  170.     ObjectConstants objConstants;
  171.     XMStoreFloat4x4(&objConstants.WorldViewProj, XMMatrixTranspose(worldViewProj));
  172.     mObjectCB->CopyData(0, objConstants);
  173. }
  174.  
  175. void BoxApp::Draw(const GameTimer& gt)
  176. {
  177.     // Reuse the memory associated with command recording.
  178.     // We can only reset when the associated command lists have finished execution on the GPU.
  179.     ThrowIfFailed(mDirectCmdListAlloc->Reset());
  180.  
  181.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  182.     // Reusing the command list reuses memory.
  183.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), mPSO.Get()));
  184.  
  185.     mCommandList->RSSetViewports(1, &mScreenViewport);
  186.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  187.  
  188.     // Indicate a state transition on the resource usage.
  189.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  190.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  191.  
  192.     // Clear the back buffer and depth buffer.
  193.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  194.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  195.     
  196.     // Specify the buffers we are going to render to.
  197.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  198.  
  199.     ID3D12DescriptorHeap* descriptorHeaps[] = { mCbvHeap.Get() };
  200.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  201.  
  202.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  203.  
  204.     mCommandList->IASetVertexBuffers(0, 1, &mBoxGeo->VertexBufferView());
  205.     mCommandList->IASetIndexBuffer(&mBoxGeo->IndexBufferView());
  206.     mCommandList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  207.     
  208.     mCommandList->SetGraphicsRootDescriptorTable(0, mCbvHeap->GetGPUDescriptorHandleForHeapStart());
  209.  
  210.     mCommandList->DrawIndexedInstanced(
  211.         mBoxGeo->DrawArgs["box"].IndexCount, 
  212.         1, 0, 0, 0);
  213.     
  214.     // Indicate a state transition on the resource usage.
  215.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  216.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  217.  
  218.     // Done recording commands.
  219.     ThrowIfFailed(mCommandList->Close());
  220.  
  221.     // Add the command list to the queue for execution.
  222.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  223.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  224.     
  225.     // swap the back and front buffers
  226.     ThrowIfFailed(mSwapChain->Present(0, 0));
  227.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  228.  
  229.     // Wait until frame commands are complete.  This waiting is inefficient and is
  230.     // done for simplicity.  Later we will show how to organize our rendering code
  231.     // so we do not have to wait per frame.
  232.     FlushCommandQueue();
  233. }
  234.  
  235. void BoxApp::OnMouseDown(WPARAM btnState, int x, int y)
  236. {
  237.     mLastMousePos.x = x;
  238.     mLastMousePos.y = y;
  239.  
  240.     SetCapture(mhMainWnd);
  241. }
  242.  
  243. void BoxApp::OnMouseUp(WPARAM btnState, int x, int y)
  244. {
  245.     ReleaseCapture();
  246. }
  247.  
  248. void BoxApp::OnMouseMove(WPARAM btnState, int x, int y)
  249. {
  250.     if((btnState & MK_LBUTTON) != 0)
  251.     {
  252.         // Make each pixel correspond to a quarter of a degree.
  253.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  254.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  255.  
  256.         // Update angles based on input to orbit camera around box.
  257.         mTheta += dx;
  258.         mPhi += dy;
  259.  
  260.         // Restrict the angle mPhi.
  261.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  262.     }
  263.     else if((btnState & MK_RBUTTON) != 0)
  264.     {
  265.         // Make each pixel correspond to 0.005 unit in the scene.
  266.         float dx = 0.005f*static_cast<float>(x - mLastMousePos.x);
  267.         float dy = 0.005f*static_cast<float>(y - mLastMousePos.y);
  268.  
  269.         // Update the camera radius based on input.
  270.         mRadius += dx - dy;
  271.  
  272.         // Restrict the radius.
  273.         mRadius = MathHelper::Clamp(mRadius, 3.0f, 15.0f);
  274.     }
  275.  
  276.     mLastMousePos.x = x;
  277.     mLastMousePos.y = y;
  278. }
  279.  
  280. void BoxApp::BuildDescriptorHeaps()
  281. {
  282.     D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
  283.     cbvHeapDesc.NumDescriptors = 1;
  284.     cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  285.     cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  286.     cbvHeapDesc.NodeMask = 0;
  287.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc,
  288.         IID_PPV_ARGS(&mCbvHeap)));
  289. }
  290.  
  291. void BoxApp::BuildConstantBuffers()
  292. {
  293.     mObjectCB = std::make_unique<UploadBuffer<ObjectConstants>>(md3dDevice.Get(), 1, true);
  294.  
  295.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  296.  
  297.     D3D12_GPU_VIRTUAL_ADDRESS cbAddress = mObjectCB->Resource()->GetGPUVirtualAddress();
  298.     // Offset to the ith object constant buffer in the buffer.
  299.     int boxCBufIndex = 0;
  300.     cbAddress += boxCBufIndex*objCBByteSize;
  301.  
  302.     D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
  303.     cbvDesc.BufferLocation = cbAddress;
  304.     cbvDesc.SizeInBytes = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  305.  
  306.     md3dDevice->CreateConstantBufferView(
  307.         &cbvDesc,
  308.         mCbvHeap->GetCPUDescriptorHandleForHeapStart());
  309. }
  310.  
  311. void BoxApp::BuildRootSignature()
  312. {
  313.     // Shader programs typically require resources as input (constant buffers,
  314.     // textures, samplers).  The root signature defines the resources the shader
  315.     // programs expect.  If we think of the shader programs as a function, and
  316.     // the input resources as function parameters, then the root signature can be
  317.     // thought of as defining the function signature.  
  318.  
  319.     // Root parameter can be a table, root descriptor or root constants.
  320.     CD3DX12_ROOT_PARAMETER slotRootParameter[1];
  321.  
  322.     // Create a single descriptor table of CBVs.
  323.     CD3DX12_DESCRIPTOR_RANGE cbvTable;
  324.     cbvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
  325.     slotRootParameter[0].InitAsDescriptorTable(1, &cbvTable);
  326.  
  327.     // A root signature is an array of root parameters.
  328.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(1, slotRootParameter, 0, nullptr, 
  329.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  330.  
  331.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  332.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  333.     ComPtr<ID3DBlob> errorBlob = nullptr;
  334.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  335.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  336.  
  337.     if(errorBlob != nullptr)
  338.     {
  339.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  340.     }
  341.     ThrowIfFailed(hr);
  342.  
  343.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  344.         0,
  345.         serializedRootSig->GetBufferPointer(),
  346.         serializedRootSig->GetBufferSize(),
  347.         IID_PPV_ARGS(&mRootSignature)));
  348. }
  349.  
  350. void BoxApp::BuildShadersAndInputLayout()
  351. {
  352.     HRESULT hr = S_OK;
  353.     
  354.     mvsByteCode = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "VS", "vs_5_0");
  355.     mpsByteCode = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "PS", "ps_5_0");
  356.  
  357.     mInputLayout =
  358.     {
  359.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  360.         { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
  361.     };
  362. }
  363.  
  364. void BoxApp::BuildBoxGeometry()
  365. {
  366.     std::array<Vertex, 8> vertices =
  367.     {
  368.         Vertex({ XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(Colors::White) }),
  369.         Vertex({ XMFLOAT3(-1.0f, +1.0f, -1.0f), XMFLOAT4(Colors::Black) }),
  370.         Vertex({ XMFLOAT3(+1.0f, +1.0f, -1.0f), XMFLOAT4(Colors::Red) }),
  371.         Vertex({ XMFLOAT3(+1.0f, -1.0f, -1.0f), XMFLOAT4(Colors::Green) }),
  372.         Vertex({ XMFLOAT3(-1.0f, -1.0f, +1.0f), XMFLOAT4(Colors::Blue) }),
  373.         Vertex({ XMFLOAT3(-1.0f, +1.0f, +1.0f), XMFLOAT4(Colors::Yellow) }),
  374.         Vertex({ XMFLOAT3(+1.0f, +1.0f, +1.0f), XMFLOAT4(Colors::Cyan) }),
  375.         Vertex({ XMFLOAT3(+1.0f, -1.0f, +1.0f), XMFLOAT4(Colors::Magenta) })
  376.     };
  377.  
  378.     std::array<std::uint16_t, 36> indices =
  379.     {
  380.         // front face
  381.         0, 1, 2,
  382.         0, 2, 3,
  383.  
  384.         // back face
  385.         4, 6, 5,
  386.         4, 7, 6,
  387.  
  388.         // left face
  389.         4, 5, 1,
  390.         4, 1, 0,
  391.  
  392.         // right face
  393.         3, 2, 6,
  394.         3, 6, 7,
  395.  
  396.         // top face
  397.         1, 5, 6,
  398.         1, 6, 2,
  399.  
  400.         // bottom face
  401.         4, 0, 3,
  402.         4, 3, 7
  403.     };
  404.  
  405.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  406.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  407.  
  408.     mBoxGeo = std::make_unique<MeshGeometry>();
  409.     mBoxGeo->Name = "boxGeo";
  410.  
  411.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &mBoxGeo->VertexBufferCPU));
  412.     CopyMemory(mBoxGeo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  413.  
  414.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &mBoxGeo->IndexBufferCPU));
  415.     CopyMemory(mBoxGeo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  416.  
  417.     mBoxGeo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  418.         mCommandList.Get(), vertices.data(), vbByteSize, mBoxGeo->VertexBufferUploader);
  419.  
  420.     mBoxGeo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  421.         mCommandList.Get(), indices.data(), ibByteSize, mBoxGeo->IndexBufferUploader);
  422.  
  423.     mBoxGeo->VertexByteStride = sizeof(Vertex);
  424.     mBoxGeo->VertexBufferByteSize = vbByteSize;
  425.     mBoxGeo->IndexFormat = DXGI_FORMAT_R16_UINT;
  426.     mBoxGeo->IndexBufferByteSize = ibByteSize;
  427.  
  428.     SubmeshGeometry submesh;
  429.     submesh.IndexCount = (UINT)indices.size();
  430.     submesh.StartIndexLocation = 0;
  431.     submesh.BaseVertexLocation = 0;
  432.  
  433.     mBoxGeo->DrawArgs["box"] = submesh;
  434. }
  435.  
  436. void BoxApp::BuildPSO()
  437. {
  438.     D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
  439.     ZeroMemory(&psoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  440.     psoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  441.     psoDesc.pRootSignature = mRootSignature.Get();
  442.     psoDesc.VS = 
  443.     { 
  444.         reinterpret_cast<BYTE*>(mvsByteCode->GetBufferPointer()), 
  445.         mvsByteCode->GetBufferSize() 
  446.     };
  447.     psoDesc.PS = 
  448.     { 
  449.         reinterpret_cast<BYTE*>(mpsByteCode->GetBufferPointer()), 
  450.         mpsByteCode->GetBufferSize() 
  451.     };
  452.     psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  453.     psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  454.     psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  455.     psoDesc.SampleMask = UINT_MAX;
  456.     psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  457.     psoDesc.NumRenderTargets = 1;
  458.     psoDesc.RTVFormats[0] = mBackBufferFormat;
  459.     psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  460.     psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  461.     psoDesc.DSVFormat = mDepthStencilFormat;
  462.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));
  463. }