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 / Chapter 7 Drawing in Direct3D Part II / Shapes / ShapesApp.cpp < prev   
Encoding:
C/C++ Source or Header  |  2016-03-02  |  30.2 KB  |  806 lines

  1. //***************************************************************************************
  2. // ShapesApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //
  4. // Hold down '1' key to view scene in wireframe mode.
  5. //***************************************************************************************
  6.  
  7. #include "../../Common/d3dApp.h"
  8. #include "../../Common/MathHelper.h"
  9. #include "../../Common/UploadBuffer.h"
  10. #include "../../Common/GeometryGenerator.h"
  11. #include "FrameResource.h"
  12.  
  13. using Microsoft::WRL::ComPtr;
  14. using namespace DirectX;
  15. using namespace DirectX::PackedVector;
  16.  
  17. const int gNumFrameResources = 3;
  18.  
  19. // Lightweight structure stores parameters to draw a shape.  This will
  20. // vary from app-to-app.
  21. struct RenderItem
  22. {
  23.     RenderItem() = default;
  24.  
  25.     // World matrix of the shape that describes the object's local space
  26.     // relative to the world space, which defines the position, orientation,
  27.     // and scale of the object in the world.
  28.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  29.  
  30.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  31.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  32.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  33.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  34.     int NumFramesDirty = gNumFrameResources;
  35.  
  36.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  37.     UINT ObjCBIndex = -1;
  38.  
  39.     MeshGeometry* Geo = nullptr;
  40.  
  41.     // Primitive topology.
  42.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  43.  
  44.     // DrawIndexedInstanced parameters.
  45.     UINT IndexCount = 0;
  46.     UINT StartIndexLocation = 0;
  47.     int BaseVertexLocation = 0;
  48. };
  49.  
  50. class ShapesApp : public D3DApp
  51. {
  52. public:
  53.     ShapesApp(HINSTANCE hInstance);
  54.     ShapesApp(const ShapesApp& rhs) = delete;
  55.     ShapesApp& operator=(const ShapesApp& rhs) = delete;
  56.     ~ShapesApp();
  57.  
  58.     virtual bool Initialize()override;
  59.  
  60. private:
  61.     virtual void OnResize()override;
  62.     virtual void Update(const GameTimer& gt)override;
  63.     virtual void Draw(const GameTimer& gt)override;
  64.  
  65.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  66.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  67.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  68.  
  69.     void OnKeyboardInput(const GameTimer& gt);
  70.     void UpdateCamera(const GameTimer& gt);
  71.     void UpdateObjectCBs(const GameTimer& gt);
  72.     void UpdateMainPassCB(const GameTimer& gt);
  73.  
  74.     void BuildDescriptorHeaps();
  75.     void BuildConstantBufferViews();
  76.     void BuildRootSignature();
  77.     void BuildShadersAndInputLayout();
  78.     void BuildShapeGeometry();
  79.     void BuildPSOs();
  80.     void BuildFrameResources();
  81.     void BuildRenderItems();
  82.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  83.  
  84. private:
  85.  
  86.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  87.     FrameResource* mCurrFrameResource = nullptr;
  88.     int mCurrFrameResourceIndex = 0;
  89.  
  90.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  91.     ComPtr<ID3D12DescriptorHeap> mCbvHeap = nullptr;
  92.  
  93.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  94.  
  95.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  96.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  97.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  98.  
  99.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  100.  
  101.     // List of all the render items.
  102.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  103.  
  104.     // Render items divided by PSO.
  105.     std::vector<RenderItem*> mOpaqueRitems;
  106.  
  107.     PassConstants mMainPassCB;
  108.  
  109.     UINT mPassCbvOffset = 0;
  110.  
  111.     bool mIsWireframe = false;
  112.  
  113.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  114.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  115.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  116.  
  117.     float mTheta = 1.5f*XM_PI;
  118.     float mPhi = 0.2f*XM_PI;
  119.     float mRadius = 15.0f;
  120.  
  121.     POINT mLastMousePos;
  122. };
  123.  
  124. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  125.     PSTR cmdLine, int showCmd)
  126. {
  127.     // Enable run-time memory check for debug builds.
  128. #if defined(DEBUG) | defined(_DEBUG)
  129.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  130. #endif
  131.  
  132.     try
  133.     {
  134.         ShapesApp theApp(hInstance);
  135.         if(!theApp.Initialize())
  136.             return 0;
  137.  
  138.         return theApp.Run();
  139.     }
  140.     catch(DxException& e)
  141.     {
  142.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  143.         return 0;
  144.     }
  145. }
  146.  
  147. ShapesApp::ShapesApp(HINSTANCE hInstance)
  148.     : D3DApp(hInstance)
  149. {
  150. }
  151.  
  152. ShapesApp::~ShapesApp()
  153. {
  154.     if(md3dDevice != nullptr)
  155.         FlushCommandQueue();
  156. }
  157.  
  158. bool ShapesApp::Initialize()
  159. {
  160.     if(!D3DApp::Initialize())
  161.         return false;
  162.  
  163.     // Reset the command list to prep for initialization commands.
  164.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  165.  
  166.     BuildRootSignature();
  167.     BuildShadersAndInputLayout();
  168.     BuildShapeGeometry();
  169.     BuildRenderItems();
  170.     BuildFrameResources();
  171.     BuildDescriptorHeaps();
  172.     BuildConstantBufferViews();
  173.     BuildPSOs();
  174.  
  175.     // Execute the initialization commands.
  176.     ThrowIfFailed(mCommandList->Close());
  177.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  178.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  179.  
  180.     // Wait until initialization is complete.
  181.     FlushCommandQueue();
  182.  
  183.     return true;
  184. }
  185.  
  186. void ShapesApp::OnResize()
  187. {
  188.     D3DApp::OnResize();
  189.  
  190.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  191.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  192.     XMStoreFloat4x4(&mProj, P);
  193. }
  194.  
  195. void ShapesApp::Update(const GameTimer& gt)
  196. {
  197.     OnKeyboardInput(gt);
  198.     UpdateCamera(gt);
  199.  
  200.     // Cycle through the circular frame resource array.
  201.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  202.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  203.  
  204.     // Has the GPU finished processing the commands of the current frame resource?
  205.     // If not, wait until the GPU has completed commands up to this fence point.
  206.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  207.     {
  208.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  209.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  210.         WaitForSingleObject(eventHandle, INFINITE);
  211.         CloseHandle(eventHandle);
  212.     }
  213.  
  214.     UpdateObjectCBs(gt);
  215.     UpdateMainPassCB(gt);
  216. }
  217.  
  218. void ShapesApp::Draw(const GameTimer& gt)
  219. {
  220.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  221.  
  222.     // Reuse the memory associated with command recording.
  223.     // We can only reset when the associated command lists have finished execution on the GPU.
  224.     ThrowIfFailed(cmdListAlloc->Reset());
  225.  
  226.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  227.     // Reusing the command list reuses memory.
  228.     if(mIsWireframe)
  229.     {
  230.         ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque_wireframe"].Get()));
  231.     }
  232.     else
  233.     {
  234.         ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  235.     }
  236.  
  237.     mCommandList->RSSetViewports(1, &mScreenViewport);
  238.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  239.  
  240.     // Indicate a state transition on the resource usage.
  241.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  242.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  243.  
  244.     // Clear the back buffer and depth buffer.
  245.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  246.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  247.  
  248.     // Specify the buffers we are going to render to.
  249.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  250.  
  251.     ID3D12DescriptorHeap* descriptorHeaps[] = { mCbvHeap.Get() };
  252.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  253.  
  254.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  255.  
  256.     int passCbvIndex = mPassCbvOffset + mCurrFrameResourceIndex;
  257.     auto passCbvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(mCbvHeap->GetGPUDescriptorHandleForHeapStart());
  258.     passCbvHandle.Offset(passCbvIndex, mCbvSrvUavDescriptorSize);
  259.     mCommandList->SetGraphicsRootDescriptorTable(1, passCbvHandle);
  260.  
  261.     DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
  262.  
  263.     // Indicate a state transition on the resource usage.
  264.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  265.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  266.  
  267.     // Done recording commands.
  268.     ThrowIfFailed(mCommandList->Close());
  269.  
  270.     // Add the command list to the queue for execution.
  271.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  272.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  273.  
  274.     // Swap the back and front buffers
  275.     ThrowIfFailed(mSwapChain->Present(0, 0));
  276.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  277.  
  278.     // Advance the fence value to mark commands up to this fence point.
  279.     mCurrFrameResource->Fence = ++mCurrentFence;
  280.     
  281.     // Add an instruction to the command queue to set a new fence point. 
  282.     // Because we are on the GPU timeline, the new fence point won't be 
  283.     // set until the GPU finishes processing all the commands prior to this Signal().
  284.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  285. }
  286.  
  287. void ShapesApp::OnMouseDown(WPARAM btnState, int x, int y)
  288. {
  289.     mLastMousePos.x = x;
  290.     mLastMousePos.y = y;
  291.  
  292.     SetCapture(mhMainWnd);
  293. }
  294.  
  295. void ShapesApp::OnMouseUp(WPARAM btnState, int x, int y)
  296. {
  297.     ReleaseCapture();
  298. }
  299.  
  300. void ShapesApp::OnMouseMove(WPARAM btnState, int x, int y)
  301. {
  302.     if((btnState & MK_LBUTTON) != 0)
  303.     {
  304.         // Make each pixel correspond to a quarter of a degree.
  305.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  306.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  307.  
  308.         // Update angles based on input to orbit camera around box.
  309.         mTheta += dx;
  310.         mPhi += dy;
  311.  
  312.         // Restrict the angle mPhi.
  313.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  314.     }
  315.     else if((btnState & MK_RBUTTON) != 0)
  316.     {
  317.         // Make each pixel correspond to 0.2 unit in the scene.
  318.         float dx = 0.05f*static_cast<float>(x - mLastMousePos.x);
  319.         float dy = 0.05f*static_cast<float>(y - mLastMousePos.y);
  320.  
  321.         // Update the camera radius based on input.
  322.         mRadius += dx - dy;
  323.  
  324.         // Restrict the radius.
  325.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  326.     }
  327.  
  328.     mLastMousePos.x = x;
  329.     mLastMousePos.y = y;
  330. }
  331.  
  332. void ShapesApp::OnKeyboardInput(const GameTimer& gt)
  333. {
  334.     if(GetAsyncKeyState('1') & 0x8000)
  335.         mIsWireframe = true;
  336.     else
  337.         mIsWireframe = false;
  338. }
  339.  
  340. void ShapesApp::UpdateCamera(const GameTimer& gt)
  341. {
  342.     // Convert Spherical to Cartesian coordinates.
  343.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  344.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  345.     mEyePos.y = mRadius*cosf(mPhi);
  346.  
  347.     // Build the view matrix.
  348.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  349.     XMVECTOR target = XMVectorZero();
  350.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  351.  
  352.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  353.     XMStoreFloat4x4(&mView, view);
  354. }
  355.  
  356. void ShapesApp::UpdateObjectCBs(const GameTimer& gt)
  357. {
  358.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  359.     for(auto& e : mAllRitems)
  360.     {
  361.         // Only update the cbuffer data if the constants have changed.  
  362.         // This needs to be tracked per frame resource.
  363.         if(e->NumFramesDirty > 0)
  364.         {
  365.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  366.  
  367.             ObjectConstants objConstants;
  368.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  369.  
  370.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  371.  
  372.             // Next FrameResource need to be updated too.
  373.             e->NumFramesDirty--;
  374.         }
  375.     }
  376. }
  377.  
  378. void ShapesApp::UpdateMainPassCB(const GameTimer& gt)
  379. {
  380.     XMMATRIX view = XMLoadFloat4x4(&mView);
  381.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  382.  
  383.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  384.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  385.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  386.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  387.  
  388.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  389.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  390.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  391.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  392.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  393.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  394.     mMainPassCB.EyePosW = mEyePos;
  395.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  396.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  397.     mMainPassCB.NearZ = 1.0f;
  398.     mMainPassCB.FarZ = 1000.0f;
  399.     mMainPassCB.TotalTime = gt.TotalTime();
  400.     mMainPassCB.DeltaTime = gt.DeltaTime();
  401.  
  402.     auto currPassCB = mCurrFrameResource->PassCB.get();
  403.     currPassCB->CopyData(0, mMainPassCB);
  404. }
  405.  
  406. void ShapesApp::BuildDescriptorHeaps()
  407. {
  408.     UINT objCount = (UINT)mOpaqueRitems.size();
  409.  
  410.     // Need a CBV descriptor for each object for each frame resource,
  411.     // +1 for the perPass CBV for each frame resource.
  412.     UINT numDescriptors = (objCount+1) * gNumFrameResources;
  413.  
  414.     // Save an offset to the start of the pass CBVs.  These are the last 3 descriptors.
  415.     mPassCbvOffset = objCount * gNumFrameResources;
  416.  
  417.     D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
  418.     cbvHeapDesc.NumDescriptors = numDescriptors;
  419.     cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  420.     cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  421.     cbvHeapDesc.NodeMask = 0;
  422.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc,
  423.         IID_PPV_ARGS(&mCbvHeap)));
  424. }
  425.  
  426. void ShapesApp::BuildConstantBufferViews()
  427. {
  428.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  429.  
  430.     UINT objCount = (UINT)mOpaqueRitems.size();
  431.  
  432.     // Need a CBV descriptor for each object for each frame resource.
  433.     for(int frameIndex = 0; frameIndex < gNumFrameResources; ++frameIndex)
  434.     {
  435.         auto objectCB = mFrameResources[frameIndex]->ObjectCB->Resource();
  436.         for(UINT i = 0; i < objCount; ++i)
  437.         {
  438.             D3D12_GPU_VIRTUAL_ADDRESS cbAddress = objectCB->GetGPUVirtualAddress();
  439.  
  440.             // Offset to the ith object constant buffer in the buffer.
  441.             cbAddress += i*objCBByteSize;
  442.  
  443.             // Offset to the object cbv in the descriptor heap.
  444.             int heapIndex = frameIndex*objCount + i;
  445.             auto handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(mCbvHeap->GetCPUDescriptorHandleForHeapStart());
  446.             handle.Offset(heapIndex, mCbvSrvUavDescriptorSize);
  447.  
  448.             D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
  449.             cbvDesc.BufferLocation = cbAddress;
  450.             cbvDesc.SizeInBytes = objCBByteSize;
  451.  
  452.             md3dDevice->CreateConstantBufferView(&cbvDesc, handle);
  453.         }
  454.     }
  455.  
  456.     UINT passCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(PassConstants));
  457.  
  458.     // Last three descriptors are the pass CBVs for each frame resource.
  459.     for(int frameIndex = 0; frameIndex < gNumFrameResources; ++frameIndex)
  460.     {
  461.         auto passCB = mFrameResources[frameIndex]->PassCB->Resource();
  462.         D3D12_GPU_VIRTUAL_ADDRESS cbAddress = passCB->GetGPUVirtualAddress();
  463.  
  464.         // Offset to the pass cbv in the descriptor heap.
  465.         int heapIndex = mPassCbvOffset + frameIndex;
  466.         auto handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(mCbvHeap->GetCPUDescriptorHandleForHeapStart());
  467.         handle.Offset(heapIndex, mCbvSrvUavDescriptorSize);
  468.  
  469.         D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
  470.         cbvDesc.BufferLocation = cbAddress;
  471.         cbvDesc.SizeInBytes = passCBByteSize;
  472.         
  473.         md3dDevice->CreateConstantBufferView(&cbvDesc, handle);
  474.     }
  475. }
  476.  
  477. void ShapesApp::BuildRootSignature()
  478. {
  479.     CD3DX12_DESCRIPTOR_RANGE cbvTable0;
  480.     cbvTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
  481.  
  482.     CD3DX12_DESCRIPTOR_RANGE cbvTable1;
  483.     cbvTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 1);
  484.  
  485.     // Root parameter can be a table, root descriptor or root constants.
  486.     CD3DX12_ROOT_PARAMETER slotRootParameter[2];
  487.  
  488.     // Create root CBVs.
  489.     slotRootParameter[0].InitAsDescriptorTable(1, &cbvTable0);
  490.     slotRootParameter[1].InitAsDescriptorTable(1, &cbvTable1);
  491.  
  492.     // A root signature is an array of root parameters.
  493.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(2, slotRootParameter, 0, nullptr, 
  494.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  495.  
  496.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  497.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  498.     ComPtr<ID3DBlob> errorBlob = nullptr;
  499.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  500.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  501.  
  502.     if(errorBlob != nullptr)
  503.     {
  504.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  505.     }
  506.     ThrowIfFailed(hr);
  507.  
  508.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  509.         0,
  510.         serializedRootSig->GetBufferPointer(),
  511.         serializedRootSig->GetBufferSize(),
  512.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  513. }
  514.  
  515. void ShapesApp::BuildShadersAndInputLayout()
  516. {
  517.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "VS", "vs_5_1");
  518.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "PS", "ps_5_1");
  519.     
  520.     mInputLayout =
  521.     {
  522.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  523.         { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  524.     };
  525. }
  526.  
  527. void ShapesApp::BuildShapeGeometry()
  528. {
  529.     GeometryGenerator geoGen;
  530.     GeometryGenerator::MeshData box = geoGen.CreateBox(1.5f, 0.5f, 1.5f, 3);
  531.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(20.0f, 30.0f, 60, 40);
  532.     GeometryGenerator::MeshData sphere = geoGen.CreateSphere(0.5f, 20, 20);
  533.     GeometryGenerator::MeshData cylinder = geoGen.CreateCylinder(0.5f, 0.3f, 3.0f, 20, 20);
  534.  
  535.     //
  536.     // We are concatenating all the geometry into one big vertex/index buffer.  So
  537.     // define the regions in the buffer each submesh covers.
  538.     //
  539.  
  540.     // Cache the vertex offsets to each object in the concatenated vertex buffer.
  541.     UINT boxVertexOffset = 0;
  542.     UINT gridVertexOffset = (UINT)box.Vertices.size();
  543.     UINT sphereVertexOffset = gridVertexOffset + (UINT)grid.Vertices.size();
  544.     UINT cylinderVertexOffset = sphereVertexOffset + (UINT)sphere.Vertices.size();
  545.  
  546.     // Cache the starting index for each object in the concatenated index buffer.
  547.     UINT boxIndexOffset = 0;
  548.     UINT gridIndexOffset = (UINT)box.Indices32.size();
  549.     UINT sphereIndexOffset = gridIndexOffset + (UINT)grid.Indices32.size();
  550.     UINT cylinderIndexOffset = sphereIndexOffset + (UINT)sphere.Indices32.size();
  551.  
  552.     // Define the SubmeshGeometry that cover different 
  553.     // regions of the vertex/index buffers.
  554.  
  555.     SubmeshGeometry boxSubmesh;
  556.     boxSubmesh.IndexCount = (UINT)box.Indices32.size();
  557.     boxSubmesh.StartIndexLocation = boxIndexOffset;
  558.     boxSubmesh.BaseVertexLocation = boxVertexOffset;
  559.  
  560.     SubmeshGeometry gridSubmesh;
  561.     gridSubmesh.IndexCount = (UINT)grid.Indices32.size();
  562.     gridSubmesh.StartIndexLocation = gridIndexOffset;
  563.     gridSubmesh.BaseVertexLocation = gridVertexOffset;
  564.  
  565.     SubmeshGeometry sphereSubmesh;
  566.     sphereSubmesh.IndexCount = (UINT)sphere.Indices32.size();
  567.     sphereSubmesh.StartIndexLocation = sphereIndexOffset;
  568.     sphereSubmesh.BaseVertexLocation = sphereVertexOffset;
  569.  
  570.     SubmeshGeometry cylinderSubmesh;
  571.     cylinderSubmesh.IndexCount = (UINT)cylinder.Indices32.size();
  572.     cylinderSubmesh.StartIndexLocation = cylinderIndexOffset;
  573.     cylinderSubmesh.BaseVertexLocation = cylinderVertexOffset;
  574.  
  575.     //
  576.     // Extract the vertex elements we are interested in and pack the
  577.     // vertices of all the meshes into one vertex buffer.
  578.     //
  579.  
  580.     auto totalVertexCount =
  581.         box.Vertices.size() +
  582.         grid.Vertices.size() +
  583.         sphere.Vertices.size() +
  584.         cylinder.Vertices.size();
  585.  
  586.     std::vector<Vertex> vertices(totalVertexCount);
  587.  
  588.     UINT k = 0;
  589.     for(size_t i = 0; i < box.Vertices.size(); ++i, ++k)
  590.     {
  591.         vertices[k].Pos = box.Vertices[i].Position;
  592.         vertices[k].Color = XMFLOAT4(DirectX::Colors::DarkGreen);
  593.     }
  594.  
  595.     for(size_t i = 0; i < grid.Vertices.size(); ++i, ++k)
  596.     {
  597.         vertices[k].Pos = grid.Vertices[i].Position;
  598.         vertices[k].Color = XMFLOAT4(DirectX::Colors::ForestGreen);
  599.     }
  600.  
  601.     for(size_t i = 0; i < sphere.Vertices.size(); ++i, ++k)
  602.     {
  603.         vertices[k].Pos = sphere.Vertices[i].Position;
  604.         vertices[k].Color = XMFLOAT4(DirectX::Colors::Crimson);
  605.     }
  606.  
  607.     for(size_t i = 0; i < cylinder.Vertices.size(); ++i, ++k)
  608.     {
  609.         vertices[k].Pos = cylinder.Vertices[i].Position;
  610.         vertices[k].Color = XMFLOAT4(DirectX::Colors::SteelBlue);
  611.     }
  612.  
  613.     std::vector<std::uint16_t> indices;
  614.     indices.insert(indices.end(), std::begin(box.GetIndices16()), std::end(box.GetIndices16()));
  615.     indices.insert(indices.end(), std::begin(grid.GetIndices16()), std::end(grid.GetIndices16()));
  616.     indices.insert(indices.end(), std::begin(sphere.GetIndices16()), std::end(sphere.GetIndices16()));
  617.     indices.insert(indices.end(), std::begin(cylinder.GetIndices16()), std::end(cylinder.GetIndices16()));
  618.  
  619.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  620.     const UINT ibByteSize = (UINT)indices.size()  * sizeof(std::uint16_t);
  621.  
  622.     auto geo = std::make_unique<MeshGeometry>();
  623.     geo->Name = "shapeGeo";
  624.  
  625.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  626.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  627.  
  628.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  629.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  630.  
  631.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  632.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  633.  
  634.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  635.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  636.  
  637.     geo->VertexByteStride = sizeof(Vertex);
  638.     geo->VertexBufferByteSize = vbByteSize;
  639.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  640.     geo->IndexBufferByteSize = ibByteSize;
  641.  
  642.     geo->DrawArgs["box"] = boxSubmesh;
  643.     geo->DrawArgs["grid"] = gridSubmesh;
  644.     geo->DrawArgs["sphere"] = sphereSubmesh;
  645.     geo->DrawArgs["cylinder"] = cylinderSubmesh;
  646.  
  647.     mGeometries[geo->Name] = std::move(geo);
  648. }
  649.  
  650. void ShapesApp::BuildPSOs()
  651. {
  652.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  653.  
  654.     //
  655.     // PSO for opaque objects.
  656.     //
  657.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  658.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  659.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  660.     opaquePsoDesc.VS = 
  661.     { 
  662.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  663.         mShaders["standardVS"]->GetBufferSize()
  664.     };
  665.     opaquePsoDesc.PS = 
  666.     { 
  667.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  668.         mShaders["opaquePS"]->GetBufferSize()
  669.     };
  670.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  671.     opaquePsoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  672.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  673.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  674.     opaquePsoDesc.SampleMask = UINT_MAX;
  675.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  676.     opaquePsoDesc.NumRenderTargets = 1;
  677.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  678.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  679.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  680.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  681.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  682.  
  683.  
  684.     //
  685.     // PSO for opaque wireframe objects.
  686.     //
  687.  
  688.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaqueWireframePsoDesc = opaquePsoDesc;
  689.     opaqueWireframePsoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  690.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaqueWireframePsoDesc, IID_PPV_ARGS(&mPSOs["opaque_wireframe"])));
  691. }
  692.  
  693. void ShapesApp::BuildFrameResources()
  694. {
  695.     for(int i = 0; i < gNumFrameResources; ++i)
  696.     {
  697.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  698.             1, (UINT)mAllRitems.size()));
  699.     }
  700. }
  701.  
  702. void ShapesApp::BuildRenderItems()
  703. {
  704.     auto boxRitem = std::make_unique<RenderItem>();
  705.     XMStoreFloat4x4(&boxRitem->World, XMMatrixScaling(2.0f, 2.0f, 2.0f)*XMMatrixTranslation(0.0f, 0.5f, 0.0f));
  706.     boxRitem->ObjCBIndex = 0;
  707.     boxRitem->Geo = mGeometries["shapeGeo"].get();
  708.     boxRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  709.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  710.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  711.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  712.     mAllRitems.push_back(std::move(boxRitem));
  713.  
  714.     auto gridRitem = std::make_unique<RenderItem>();
  715.     gridRitem->World = MathHelper::Identity4x4();
  716.     gridRitem->ObjCBIndex = 1;
  717.     gridRitem->Geo = mGeometries["shapeGeo"].get();
  718.     gridRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  719.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  720.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  721.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  722.     mAllRitems.push_back(std::move(gridRitem));
  723.  
  724.     UINT objCBIndex = 2;
  725.     for(int i = 0; i < 5; ++i)
  726.     {
  727.         auto leftCylRitem = std::make_unique<RenderItem>();
  728.         auto rightCylRitem = std::make_unique<RenderItem>();
  729.         auto leftSphereRitem = std::make_unique<RenderItem>();
  730.         auto rightSphereRitem = std::make_unique<RenderItem>();
  731.  
  732.         XMMATRIX leftCylWorld = XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f);
  733.         XMMATRIX rightCylWorld = XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f);
  734.  
  735.         XMMATRIX leftSphereWorld = XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f);
  736.         XMMATRIX rightSphereWorld = XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f);
  737.  
  738.         XMStoreFloat4x4(&leftCylRitem->World, rightCylWorld);
  739.         leftCylRitem->ObjCBIndex = objCBIndex++;
  740.         leftCylRitem->Geo = mGeometries["shapeGeo"].get();
  741.         leftCylRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  742.         leftCylRitem->IndexCount = leftCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  743.         leftCylRitem->StartIndexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  744.         leftCylRitem->BaseVertexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  745.  
  746.         XMStoreFloat4x4(&rightCylRitem->World, leftCylWorld);
  747.         rightCylRitem->ObjCBIndex = objCBIndex++;
  748.         rightCylRitem->Geo = mGeometries["shapeGeo"].get();
  749.         rightCylRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  750.         rightCylRitem->IndexCount = rightCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  751.         rightCylRitem->StartIndexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  752.         rightCylRitem->BaseVertexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  753.  
  754.         XMStoreFloat4x4(&leftSphereRitem->World, leftSphereWorld);
  755.         leftSphereRitem->ObjCBIndex = objCBIndex++;
  756.         leftSphereRitem->Geo = mGeometries["shapeGeo"].get();
  757.         leftSphereRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  758.         leftSphereRitem->IndexCount = leftSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  759.         leftSphereRitem->StartIndexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  760.         leftSphereRitem->BaseVertexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  761.  
  762.         XMStoreFloat4x4(&rightSphereRitem->World, rightSphereWorld);
  763.         rightSphereRitem->ObjCBIndex = objCBIndex++;
  764.         rightSphereRitem->Geo = mGeometries["shapeGeo"].get();
  765.         rightSphereRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  766.         rightSphereRitem->IndexCount = rightSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  767.         rightSphereRitem->StartIndexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  768.         rightSphereRitem->BaseVertexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  769.  
  770.         mAllRitems.push_back(std::move(leftCylRitem));
  771.         mAllRitems.push_back(std::move(rightCylRitem));
  772.         mAllRitems.push_back(std::move(leftSphereRitem));
  773.         mAllRitems.push_back(std::move(rightSphereRitem));
  774.     }
  775.  
  776.     // All the render items are opaque.
  777.     for(auto& e : mAllRitems)
  778.         mOpaqueRitems.push_back(e.get());
  779. }
  780.  
  781. void ShapesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  782. {
  783.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  784.  
  785.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  786.  
  787.     // For each render item...
  788.     for(size_t i = 0; i < ritems.size(); ++i)
  789.     {
  790.         auto ri = ritems[i];
  791.  
  792.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  793.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  794.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  795.  
  796.         // Offset to the CBV in the descriptor heap for this object and for this frame resource.
  797.         UINT cbvIndex = mCurrFrameResourceIndex*(UINT)mOpaqueRitems.size() + ri->ObjCBIndex;
  798.         auto cbvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(mCbvHeap->GetGPUDescriptorHandleForHeapStart());
  799.         cbvHandle.Offset(cbvIndex, mCbvSrvUavDescriptorSize);
  800.  
  801.         cmdList->SetGraphicsRootDescriptorTable(0, cbvHandle);
  802.  
  803.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  804.     }
  805. }
  806.