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 22 Quaternions / QuatDemo / QuatApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  43.7 KB  |  1,170 lines

  1. //***************************************************************************************
  2. // QuatApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "../../Common/Camera.h"
  10. #include "FrameResource.h"
  11. #include "AnimationHelper.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.     RenderItem(const RenderItem& rhs) = delete;
  25.  
  26.     // World matrix of the shape that describes the object's local space
  27.     // relative to the world space, which defines the position, orientation,
  28.     // and scale of the object in the world.
  29.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  30.  
  31.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  32.  
  33.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  34.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  35.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  36.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  37.     int NumFramesDirty = gNumFrameResources;
  38.  
  39.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  40.     UINT ObjCBIndex = -1;
  41.  
  42.     Material* Mat = nullptr;
  43.     MeshGeometry* Geo = nullptr;
  44.  
  45.     // Primitive topology.
  46.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  47.  
  48.     // DrawIndexedInstanced parameters.
  49.     UINT IndexCount = 0;
  50.     UINT StartIndexLocation = 0;
  51.     int BaseVertexLocation = 0;
  52. };
  53.  
  54. class QuatApp : public D3DApp
  55. {
  56. public:
  57.     QuatApp(HINSTANCE hInstance);
  58.     QuatApp(const QuatApp& rhs) = delete;
  59.     QuatApp& operator=(const QuatApp& rhs) = delete;
  60.     ~QuatApp();
  61.  
  62.     virtual bool Initialize()override;
  63.  
  64. private:
  65.     virtual void OnResize()override;
  66.     virtual void Update(const GameTimer& gt)override;
  67.     virtual void Draw(const GameTimer& gt)override;
  68.  
  69.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  70.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  71.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  72.  
  73.     void OnKeyboardInput(const GameTimer& gt);
  74.     void AnimateMaterials(const GameTimer& gt);
  75.     void UpdateObjectCBs(const GameTimer& gt);
  76.     void UpdateMaterialBuffer(const GameTimer& gt);
  77.     void UpdateMainPassCB(const GameTimer& gt);
  78.  
  79.     void DefineSkullAnimation();
  80.     void LoadTextures();
  81.     void BuildRootSignature();
  82.     void BuildDescriptorHeaps();
  83.     void BuildShadersAndInputLayout();
  84.     void BuildShapeGeometry();
  85.     void BuildSkullGeometry();
  86.     void BuildPSOs();
  87.     void BuildFrameResources();
  88.     void BuildMaterials();
  89.     void BuildRenderItems();
  90.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  91.  
  92.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  93.  
  94. private:
  95.  
  96.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  97.     FrameResource* mCurrFrameResource = nullptr;
  98.     int mCurrFrameResourceIndex = 0;
  99.  
  100.     UINT mCbvSrvDescriptorSize = 0;
  101.  
  102.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  103.  
  104.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  105.  
  106.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  107.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  108.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  109.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  110.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  111.  
  112.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  113.  
  114.     // List of all the render items.
  115.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  116.  
  117.     // Render items divided by PSO.
  118.     std::vector<RenderItem*> mOpaqueRitems;
  119.  
  120.     RenderItem* mSkullRitem = nullptr;
  121.     XMFLOAT4X4 mSkullWorld = MathHelper::Identity4x4();
  122.  
  123.     PassConstants mMainPassCB;
  124.  
  125.     Camera mCamera;
  126.  
  127.     float mAnimTimePos = 0.0f;
  128.     BoneAnimation mSkullAnimation;
  129.  
  130.     POINT mLastMousePos;
  131. };
  132.  
  133. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  134.     PSTR cmdLine, int showCmd)
  135. {
  136.     // Enable run-time memory check for debug builds.
  137. #if defined(DEBUG) | defined(_DEBUG)
  138.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  139. #endif
  140.  
  141.     try
  142.     {
  143.         QuatApp theApp(hInstance);
  144.         if(!theApp.Initialize())
  145.             return 0;
  146.  
  147.         return theApp.Run();
  148.     }
  149.     catch(DxException& e)
  150.     {
  151.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  152.         return 0;
  153.     }
  154. }
  155.  
  156. QuatApp::QuatApp(HINSTANCE hInstance)
  157.     : D3DApp(hInstance)
  158. {
  159.     DefineSkullAnimation();
  160. }
  161.  
  162. QuatApp::~QuatApp()
  163. {
  164.     if(md3dDevice != nullptr)
  165.         FlushCommandQueue();
  166. }
  167.  
  168. bool QuatApp::Initialize()
  169. {
  170.     if(!D3DApp::Initialize())
  171.         return false;
  172.  
  173.     // Reset the command list to prep for initialization commands.
  174.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  175.  
  176.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  177.     // so we have to query this information.
  178.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  179.  
  180.     mCamera.SetPosition(0.0f, 2.0f, -15.0f);
  181.  
  182.     LoadTextures();
  183.     BuildRootSignature();
  184.     BuildDescriptorHeaps();
  185.     BuildShadersAndInputLayout();
  186.     BuildShapeGeometry();
  187.     BuildSkullGeometry();
  188.     BuildMaterials();
  189.     BuildRenderItems();
  190.     BuildFrameResources();
  191.     BuildPSOs();
  192.  
  193.     // Execute the initialization commands.
  194.     ThrowIfFailed(mCommandList->Close());
  195.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  196.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  197.  
  198.     // Wait until initialization is complete.
  199.     FlushCommandQueue();
  200.  
  201.     return true;
  202. }
  203.  
  204. void QuatApp::OnResize()
  205. {
  206.     D3DApp::OnResize();
  207.  
  208.     mCamera.SetLens(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  209. }
  210.  
  211. void QuatApp::Update(const GameTimer& gt)
  212. {
  213.     OnKeyboardInput(gt);
  214.  
  215.     mAnimTimePos += gt.DeltaTime();
  216.     if(mAnimTimePos >= mSkullAnimation.GetEndTime())
  217.     {
  218.         // Loop animation back to beginning.
  219.         mAnimTimePos = 0.0f;
  220.     }
  221.  
  222.     mSkullAnimation.Interpolate(mAnimTimePos, mSkullWorld);
  223.     mSkullRitem->World = mSkullWorld;
  224.     mSkullRitem->NumFramesDirty = gNumFrameResources;
  225.  
  226.     // Cycle through the circular frame resource array.
  227.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  228.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  229.  
  230.     // Has the GPU finished processing the commands of the current frame resource?
  231.     // If not, wait until the GPU has completed commands up to this fence point.
  232.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  233.     {
  234.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  235.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  236.         WaitForSingleObject(eventHandle, INFINITE);
  237.         CloseHandle(eventHandle);
  238.     }
  239.  
  240.     AnimateMaterials(gt);
  241.     UpdateObjectCBs(gt);
  242.     UpdateMaterialBuffer(gt);
  243.     UpdateMainPassCB(gt);
  244. }
  245.  
  246. void QuatApp::Draw(const GameTimer& gt)
  247. {
  248.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  249.  
  250.     // Reuse the memory associated with command recording.
  251.     // We can only reset when the associated command lists have finished execution on the GPU.
  252.     ThrowIfFailed(cmdListAlloc->Reset());
  253.  
  254.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  255.     // Reusing the command list reuses memory.
  256.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  257.  
  258.     mCommandList->RSSetViewports(1, &mScreenViewport);
  259.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  260.  
  261.     // Indicate a state transition on the resource usage.
  262.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  263.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  264.  
  265.     // Clear the back buffer and depth buffer.
  266.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  267.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  268.  
  269.     // Specify the buffers we are going to render to.
  270.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  271.  
  272.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  273.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  274.  
  275.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  276.  
  277.     auto passCB = mCurrFrameResource->PassCB->Resource();
  278.     mCommandList->SetGraphicsRootConstantBufferView(1, passCB->GetGPUVirtualAddress());
  279.  
  280.     // Bind all the materials used in this scene.  For structured buffers, we can bypass the heap and 
  281.     // set as a root descriptor.
  282.     auto matBuffer = mCurrFrameResource->MaterialBuffer->Resource();
  283.     mCommandList->SetGraphicsRootShaderResourceView(2, matBuffer->GetGPUVirtualAddress());
  284.  
  285.     // Bind all the textures used in this scene.  Observe
  286.     // that we only have to specify the first descriptor in the table.  
  287.     // The root signature knows how many descriptors are expected in the table.
  288.     mCommandList->SetGraphicsRootDescriptorTable(3, mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  289.  
  290.     DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
  291.  
  292.     // Indicate a state transition on the resource usage.
  293.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  294.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  295.  
  296.     // Done recording commands.
  297.     ThrowIfFailed(mCommandList->Close());
  298.  
  299.     // Add the command list to the queue for execution.
  300.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  301.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  302.  
  303.     // Swap the back and front buffers
  304.     ThrowIfFailed(mSwapChain->Present(0, 0));
  305.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  306.  
  307.     // Advance the fence value to mark commands up to this fence point.
  308.     mCurrFrameResource->Fence = ++mCurrentFence;
  309.  
  310.     // Add an instruction to the command queue to set a new fence point. 
  311.     // Because we are on the GPU timeline, the new fence point won't be 
  312.     // set until the GPU finishes processing all the commands prior to this Signal().
  313.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  314. }
  315.  
  316. void QuatApp::OnMouseDown(WPARAM btnState, int x, int y)
  317. {
  318.     mLastMousePos.x = x;
  319.     mLastMousePos.y = y;
  320.  
  321.     SetCapture(mhMainWnd);
  322. }
  323.  
  324. void QuatApp::OnMouseUp(WPARAM btnState, int x, int y)
  325. {
  326.     ReleaseCapture();
  327. }
  328.  
  329. void QuatApp::OnMouseMove(WPARAM btnState, int x, int y)
  330. {
  331.     if((btnState & MK_LBUTTON) != 0)
  332.     {
  333.         // Make each pixel correspond to a quarter of a degree.
  334.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  335.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  336.  
  337.         mCamera.Pitch(dy);
  338.         mCamera.RotateY(dx);
  339.     }
  340.  
  341.     mLastMousePos.x = x;
  342.     mLastMousePos.y = y;
  343. }
  344.  
  345. void QuatApp::OnKeyboardInput(const GameTimer& gt)
  346. {
  347.     const float dt = gt.DeltaTime();
  348.  
  349.     if(GetAsyncKeyState('W') & 0x8000)
  350.         mCamera.Walk(10.0f*dt);
  351.  
  352.     if(GetAsyncKeyState('S') & 0x8000)
  353.         mCamera.Walk(-10.0f*dt);
  354.  
  355.     if(GetAsyncKeyState('A') & 0x8000)
  356.         mCamera.Strafe(-10.0f*dt);
  357.  
  358.     if(GetAsyncKeyState('D') & 0x8000)
  359.         mCamera.Strafe(10.0f*dt);
  360.  
  361.     mCamera.UpdateViewMatrix();
  362. }
  363.  
  364. void QuatApp::AnimateMaterials(const GameTimer& gt)
  365. {
  366.     
  367. }
  368.  
  369. void QuatApp::UpdateObjectCBs(const GameTimer& gt)
  370. {
  371.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  372.     for(auto& e : mAllRitems)
  373.     {
  374.         // Only update the cbuffer data if the constants have changed.  
  375.         // This needs to be tracked per frame resource.
  376.         if(e->NumFramesDirty > 0)
  377.         {
  378.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  379.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  380.  
  381.             ObjectConstants objConstants;
  382.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  383.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  384.             objConstants.MaterialIndex = e->Mat->MatCBIndex;
  385.  
  386.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  387.  
  388.             // Next FrameResource need to be updated too.
  389.             e->NumFramesDirty--;
  390.         }
  391.     }
  392. }
  393.  
  394. void QuatApp::UpdateMaterialBuffer(const GameTimer& gt)
  395. {
  396.     auto currMaterialBuffer = mCurrFrameResource->MaterialBuffer.get();
  397.     for(auto& e : mMaterials)
  398.     {
  399.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  400.         // data changes, it needs to be updated for each FrameResource.
  401.         Material* mat = e.second.get();
  402.         if(mat->NumFramesDirty > 0)
  403.         {
  404.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  405.  
  406.             MaterialData matData;
  407.             matData.DiffuseAlbedo = mat->DiffuseAlbedo;
  408.             matData.FresnelR0 = mat->FresnelR0;
  409.             matData.Roughness = mat->Roughness;
  410.             XMStoreFloat4x4(&matData.MatTransform, XMMatrixTranspose(matTransform));
  411.             matData.DiffuseMapIndex = mat->DiffuseSrvHeapIndex;
  412.  
  413.             currMaterialBuffer->CopyData(mat->MatCBIndex, matData);
  414.  
  415.             // Next FrameResource need to be updated too.
  416.             mat->NumFramesDirty--;
  417.         }
  418.     }
  419. }
  420.  
  421. void QuatApp::UpdateMainPassCB(const GameTimer& gt)
  422. {
  423.     XMMATRIX view = mCamera.GetView();
  424.     XMMATRIX proj = mCamera.GetProj();
  425.  
  426.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  427.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  428.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  429.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  430.  
  431.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  432.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  433.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  434.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  435.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  436.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  437.     mMainPassCB.EyePosW = mCamera.GetPosition3f();
  438.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  439.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  440.     mMainPassCB.NearZ = 1.0f;
  441.     mMainPassCB.FarZ = 1000.0f;
  442.     mMainPassCB.TotalTime = gt.TotalTime();
  443.     mMainPassCB.DeltaTime = gt.DeltaTime();
  444.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  445.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  446.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  447.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  448.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  449.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  450.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  451.  
  452.     auto currPassCB = mCurrFrameResource->PassCB.get();
  453.     currPassCB->CopyData(0, mMainPassCB);
  454. }
  455.  
  456. void QuatApp::DefineSkullAnimation()
  457. {
  458.     //
  459.     // Define the animation keyframes
  460.     //
  461.  
  462.     XMVECTOR q0 = XMQuaternionRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), XMConvertToRadians(30.0f));
  463.     XMVECTOR q1 = XMQuaternionRotationAxis(XMVectorSet(1.0f, 1.0f, 2.0f, 0.0f), XMConvertToRadians(45.0f));
  464.     XMVECTOR q2 = XMQuaternionRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), XMConvertToRadians(-30.0f));
  465.     XMVECTOR q3 = XMQuaternionRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), XMConvertToRadians(70.0f));
  466.  
  467.     mSkullAnimation.Keyframes.resize(5);
  468.     mSkullAnimation.Keyframes[0].TimePos = 0.0f;
  469.     mSkullAnimation.Keyframes[0].Translation = XMFLOAT3(-7.0f, 0.0f, 0.0f);
  470.     mSkullAnimation.Keyframes[0].Scale = XMFLOAT3(0.25f, 0.25f, 0.25f);
  471.     XMStoreFloat4(&mSkullAnimation.Keyframes[0].RotationQuat, q0);
  472.  
  473.     mSkullAnimation.Keyframes[1].TimePos = 2.0f;
  474.     mSkullAnimation.Keyframes[1].Translation = XMFLOAT3(0.0f, 2.0f, 10.0f);
  475.     mSkullAnimation.Keyframes[1].Scale = XMFLOAT3(0.5f, 0.5f, 0.5f);
  476.     XMStoreFloat4(&mSkullAnimation.Keyframes[1].RotationQuat, q1);
  477.  
  478.     mSkullAnimation.Keyframes[2].TimePos = 4.0f;
  479.     mSkullAnimation.Keyframes[2].Translation = XMFLOAT3(7.0f, 0.0f, 0.0f);
  480.     mSkullAnimation.Keyframes[2].Scale = XMFLOAT3(0.25f, 0.25f, 0.25f);
  481.     XMStoreFloat4(&mSkullAnimation.Keyframes[2].RotationQuat, q2);
  482.  
  483.     mSkullAnimation.Keyframes[3].TimePos = 6.0f;
  484.     mSkullAnimation.Keyframes[3].Translation = XMFLOAT3(0.0f, 1.0f, -10.0f);
  485.     mSkullAnimation.Keyframes[3].Scale = XMFLOAT3(0.5f, 0.5f, 0.5f);
  486.     XMStoreFloat4(&mSkullAnimation.Keyframes[3].RotationQuat, q3);
  487.  
  488.     mSkullAnimation.Keyframes[4].TimePos = 8.0f;
  489.     mSkullAnimation.Keyframes[4].Translation = XMFLOAT3(-7.0f, 0.0f, 0.0f);
  490.     mSkullAnimation.Keyframes[4].Scale = XMFLOAT3(0.25f, 0.25f, 0.25f);
  491.     XMStoreFloat4(&mSkullAnimation.Keyframes[4].RotationQuat, q0);
  492. }
  493.  
  494. void QuatApp::LoadTextures()
  495. {
  496.     auto bricksTex = std::make_unique<Texture>();
  497.     bricksTex->Name = "bricksTex";
  498.     bricksTex->Filename = L"../../Textures/bricks2.dds";
  499.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  500.         mCommandList.Get(), bricksTex->Filename.c_str(),
  501.         bricksTex->Resource, bricksTex->UploadHeap));
  502.  
  503.     auto stoneTex = std::make_unique<Texture>();
  504.     stoneTex->Name = "stoneTex";
  505.     stoneTex->Filename = L"../../Textures/stone.dds";
  506.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  507.         mCommandList.Get(), stoneTex->Filename.c_str(),
  508.         stoneTex->Resource, stoneTex->UploadHeap));
  509.  
  510.     auto tileTex = std::make_unique<Texture>();
  511.     tileTex->Name = "tileTex";
  512.     tileTex->Filename = L"../../Textures/tile.dds";
  513.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  514.         mCommandList.Get(), tileTex->Filename.c_str(),
  515.         tileTex->Resource, tileTex->UploadHeap));
  516.  
  517.     auto crateTex = std::make_unique<Texture>();
  518.     crateTex->Name = "crateTex";
  519.     crateTex->Filename = L"../../Textures/WoodCrate01.dds";
  520.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  521.         mCommandList.Get(), crateTex->Filename.c_str(),
  522.         crateTex->Resource, crateTex->UploadHeap));
  523.  
  524.     auto defaultTex = std::make_unique<Texture>();
  525.     defaultTex->Name = "defaultTex";
  526.     defaultTex->Filename = L"../../Textures/white1x1.dds";
  527.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  528.         mCommandList.Get(), defaultTex->Filename.c_str(),
  529.         defaultTex->Resource, defaultTex->UploadHeap));
  530.  
  531.     mTextures[bricksTex->Name] = std::move(bricksTex);
  532.     mTextures[stoneTex->Name] = std::move(stoneTex);
  533.     mTextures[tileTex->Name] = std::move(tileTex);
  534.     mTextures[crateTex->Name] = std::move(crateTex);
  535.     mTextures[defaultTex->Name] = std::move(defaultTex);
  536. }
  537.  
  538. void QuatApp::BuildRootSignature()
  539. {
  540.     CD3DX12_DESCRIPTOR_RANGE texTable;
  541.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 5, 0, 0);
  542.  
  543.     // Root parameter can be a table, root descriptor or root constants.
  544.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  545.  
  546.     // Perfomance TIP: Order from most frequent to least frequent.
  547.     slotRootParameter[0].InitAsConstantBufferView(0);
  548.     slotRootParameter[1].InitAsConstantBufferView(1);
  549.     slotRootParameter[2].InitAsShaderResourceView(0, 1);
  550.     slotRootParameter[3].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  551.  
  552.  
  553.     auto staticSamplers = GetStaticSamplers();
  554.  
  555.     // A root signature is an array of root parameters.
  556.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  557.         (UINT)staticSamplers.size(), staticSamplers.data(),
  558.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  559.  
  560.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  561.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  562.     ComPtr<ID3DBlob> errorBlob = nullptr;
  563.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  564.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  565.  
  566.     if(errorBlob != nullptr)
  567.     {
  568.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  569.     }
  570.     ThrowIfFailed(hr);
  571.  
  572.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  573.         0,
  574.         serializedRootSig->GetBufferPointer(),
  575.         serializedRootSig->GetBufferSize(),
  576.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  577. }
  578.  
  579. void QuatApp::BuildDescriptorHeaps()
  580. {
  581.     //
  582.     // Create the SRV heap.
  583.     //
  584.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  585.     srvHeapDesc.NumDescriptors = 5;
  586.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  587.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  588.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  589.  
  590.     //
  591.     // Fill out the heap with actual descriptors.
  592.     //
  593.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  594.  
  595.     auto bricksTex = mTextures["bricksTex"]->Resource;
  596.     auto stoneTex = mTextures["stoneTex"]->Resource;
  597.     auto tileTex = mTextures["tileTex"]->Resource;
  598.     auto crateTex = mTextures["crateTex"]->Resource;
  599.     auto defaultTex = mTextures["defaultTex"]->Resource;
  600.  
  601.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  602.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  603.     srvDesc.Format = bricksTex->GetDesc().Format;
  604.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  605.     srvDesc.Texture2D.MostDetailedMip = 0;
  606.     srvDesc.Texture2D.MipLevels = bricksTex->GetDesc().MipLevels;
  607.     srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
  608.     md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);
  609.  
  610.     // next descriptor
  611.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  612.  
  613.     srvDesc.Format = stoneTex->GetDesc().Format;
  614.     srvDesc.Texture2D.MipLevels = stoneTex->GetDesc().MipLevels;
  615.     md3dDevice->CreateShaderResourceView(stoneTex.Get(), &srvDesc, hDescriptor);
  616.  
  617.     // next descriptor
  618.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  619.  
  620.     srvDesc.Format = tileTex->GetDesc().Format;
  621.     srvDesc.Texture2D.MipLevels = tileTex->GetDesc().MipLevels;
  622.     md3dDevice->CreateShaderResourceView(tileTex.Get(), &srvDesc, hDescriptor);
  623.  
  624.     // next descriptor
  625.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  626.  
  627.     srvDesc.Format = crateTex->GetDesc().Format;
  628.     srvDesc.Texture2D.MipLevels = crateTex->GetDesc().MipLevels;
  629.     md3dDevice->CreateShaderResourceView(crateTex.Get(), &srvDesc, hDescriptor);
  630.  
  631.     // next descriptor
  632.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  633.  
  634.     srvDesc.Format = defaultTex->GetDesc().Format;
  635.     srvDesc.Texture2D.MipLevels = defaultTex->GetDesc().MipLevels;
  636.     md3dDevice->CreateShaderResourceView(defaultTex.Get(), &srvDesc, hDescriptor);
  637. }
  638.  
  639. void QuatApp::BuildShadersAndInputLayout()
  640. {
  641.     const D3D_SHADER_MACRO alphaTestDefines[] =
  642.     {
  643.         "ALPHA_TEST", "1",
  644.         NULL, NULL
  645.     };
  646.  
  647.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_1");
  648.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_1");
  649.     
  650.     mInputLayout =
  651.     {
  652.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  653.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  654.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  655.     };
  656. }
  657.  
  658. void QuatApp::BuildShapeGeometry()
  659. {
  660.     GeometryGenerator geoGen;
  661.     GeometryGenerator::MeshData box = geoGen.CreateBox(1.0f, 1.0f, 1.0f, 3);
  662.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(20.0f, 30.0f, 60, 40);
  663.     GeometryGenerator::MeshData sphere = geoGen.CreateSphere(0.5f, 20, 20);
  664.     GeometryGenerator::MeshData cylinder = geoGen.CreateCylinder(0.5f, 0.3f, 3.0f, 20, 20);
  665.  
  666.     //
  667.     // We are concatenating all the geometry into one big vertex/index buffer.  So
  668.     // define the regions in the buffer each submesh covers.
  669.     //
  670.  
  671.     // Cache the vertex offsets to each object in the concatenated vertex buffer.
  672.     UINT boxVertexOffset = 0;
  673.     UINT gridVertexOffset = (UINT)box.Vertices.size();
  674.     UINT sphereVertexOffset = gridVertexOffset + (UINT)grid.Vertices.size();
  675.     UINT cylinderVertexOffset = sphereVertexOffset + (UINT)sphere.Vertices.size();
  676.  
  677.     // Cache the starting index for each object in the concatenated index buffer.
  678.     UINT boxIndexOffset = 0;
  679.     UINT gridIndexOffset = (UINT)box.Indices32.size();
  680.     UINT sphereIndexOffset = gridIndexOffset + (UINT)grid.Indices32.size();
  681.     UINT cylinderIndexOffset = sphereIndexOffset + (UINT)sphere.Indices32.size();
  682.  
  683.     SubmeshGeometry boxSubmesh;
  684.     boxSubmesh.IndexCount = (UINT)box.Indices32.size();
  685.     boxSubmesh.StartIndexLocation = boxIndexOffset;
  686.     boxSubmesh.BaseVertexLocation = boxVertexOffset;
  687.  
  688.     SubmeshGeometry gridSubmesh;
  689.     gridSubmesh.IndexCount = (UINT)grid.Indices32.size();
  690.     gridSubmesh.StartIndexLocation = gridIndexOffset;
  691.     gridSubmesh.BaseVertexLocation = gridVertexOffset;
  692.  
  693.     SubmeshGeometry sphereSubmesh;
  694.     sphereSubmesh.IndexCount = (UINT)sphere.Indices32.size();
  695.     sphereSubmesh.StartIndexLocation = sphereIndexOffset;
  696.     sphereSubmesh.BaseVertexLocation = sphereVertexOffset;
  697.  
  698.     SubmeshGeometry cylinderSubmesh;
  699.     cylinderSubmesh.IndexCount = (UINT)cylinder.Indices32.size();
  700.     cylinderSubmesh.StartIndexLocation = cylinderIndexOffset;
  701.     cylinderSubmesh.BaseVertexLocation = cylinderVertexOffset;
  702.  
  703.     //
  704.     // Extract the vertex elements we are interested in and pack the
  705.     // vertices of all the meshes into one vertex buffer.
  706.     //
  707.  
  708.     auto totalVertexCount =
  709.         box.Vertices.size() +
  710.         grid.Vertices.size() +
  711.         sphere.Vertices.size() +
  712.         cylinder.Vertices.size();
  713.  
  714.     std::vector<Vertex> vertices(totalVertexCount);
  715.  
  716.     UINT k = 0;
  717.     for(size_t i = 0; i < box.Vertices.size(); ++i, ++k)
  718.     {
  719.         vertices[k].Pos = box.Vertices[i].Position;
  720.         vertices[k].Normal = box.Vertices[i].Normal;
  721.         vertices[k].TexC = box.Vertices[i].TexC;
  722.     }
  723.  
  724.     for(size_t i = 0; i < grid.Vertices.size(); ++i, ++k)
  725.     {
  726.         vertices[k].Pos = grid.Vertices[i].Position;
  727.         vertices[k].Normal = grid.Vertices[i].Normal;
  728.         vertices[k].TexC = grid.Vertices[i].TexC;
  729.     }
  730.  
  731.     for(size_t i = 0; i < sphere.Vertices.size(); ++i, ++k)
  732.     {
  733.         vertices[k].Pos = sphere.Vertices[i].Position;
  734.         vertices[k].Normal = sphere.Vertices[i].Normal;
  735.         vertices[k].TexC = sphere.Vertices[i].TexC;
  736.     }
  737.  
  738.     for(size_t i = 0; i < cylinder.Vertices.size(); ++i, ++k)
  739.     {
  740.         vertices[k].Pos = cylinder.Vertices[i].Position;
  741.         vertices[k].Normal = cylinder.Vertices[i].Normal;
  742.         vertices[k].TexC = cylinder.Vertices[i].TexC;
  743.     }
  744.  
  745.     std::vector<std::uint16_t> indices;
  746.     indices.insert(indices.end(), std::begin(box.GetIndices16()), std::end(box.GetIndices16()));
  747.     indices.insert(indices.end(), std::begin(grid.GetIndices16()), std::end(grid.GetIndices16()));
  748.     indices.insert(indices.end(), std::begin(sphere.GetIndices16()), std::end(sphere.GetIndices16()));
  749.     indices.insert(indices.end(), std::begin(cylinder.GetIndices16()), std::end(cylinder.GetIndices16()));
  750.  
  751.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  752.     const UINT ibByteSize = (UINT)indices.size()  * sizeof(std::uint16_t);
  753.  
  754.     auto geo = std::make_unique<MeshGeometry>();
  755.     geo->Name = "shapeGeo";
  756.  
  757.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  758.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  759.  
  760.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  761.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  762.  
  763.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  764.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  765.  
  766.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  767.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  768.  
  769.     geo->VertexByteStride = sizeof(Vertex);
  770.     geo->VertexBufferByteSize = vbByteSize;
  771.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  772.     geo->IndexBufferByteSize = ibByteSize;
  773.  
  774.     geo->DrawArgs["box"] = boxSubmesh;
  775.     geo->DrawArgs["grid"] = gridSubmesh;
  776.     geo->DrawArgs["sphere"] = sphereSubmesh;
  777.     geo->DrawArgs["cylinder"] = cylinderSubmesh;
  778.  
  779.     mGeometries[geo->Name] = std::move(geo);
  780. }
  781.  
  782. void QuatApp::BuildSkullGeometry()
  783. {
  784.     std::ifstream fin("Models/skull.txt");
  785.  
  786.     if(!fin)
  787.     {
  788.         MessageBox(0, L"Models/skull.txt not found.", 0, 0);
  789.         return;
  790.     }
  791.  
  792.     UINT vcount = 0;
  793.     UINT tcount = 0;
  794.     std::string ignore;
  795.  
  796.     fin >> ignore >> vcount;
  797.     fin >> ignore >> tcount;
  798.     fin >> ignore >> ignore >> ignore >> ignore;
  799.  
  800.     XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity);
  801.     XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity);
  802.  
  803.     XMVECTOR vMin = XMLoadFloat3(&vMinf3);
  804.     XMVECTOR vMax = XMLoadFloat3(&vMaxf3);
  805.  
  806.     std::vector<Vertex> vertices(vcount);
  807.     for(UINT i = 0; i < vcount; ++i)
  808.     {
  809.         fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
  810.         fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
  811.  
  812.         XMVECTOR P = XMLoadFloat3(&vertices[i].Pos);
  813.  
  814.         // Project point onto unit sphere and generate spherical texture coordinates.
  815.         XMFLOAT3 spherePos;
  816.         XMStoreFloat3(&spherePos, XMVector3Normalize(P));
  817.  
  818.         float theta = atan2f(spherePos.z, spherePos.x);
  819.  
  820.         // Put in [0, 2pi].
  821.         if(theta < 0.0f)
  822.             theta += XM_2PI;
  823.  
  824.         float phi = acosf(spherePos.y);
  825.  
  826.         float u = theta / (2.0f*XM_PI);
  827.         float v = phi / XM_PI;
  828.  
  829.         vertices[i].TexC = { u, v };
  830.  
  831.         vMin = XMVectorMin(vMin, P);
  832.         vMax = XMVectorMax(vMax, P);
  833.     }
  834.  
  835.     BoundingBox bounds;
  836.     XMStoreFloat3(&bounds.Center, 0.5f*(vMin + vMax));
  837.     XMStoreFloat3(&bounds.Extents, 0.5f*(vMax - vMin));
  838.  
  839.     fin >> ignore;
  840.     fin >> ignore;
  841.     fin >> ignore;
  842.  
  843.     std::vector<std::int32_t> indices(3 * tcount);
  844.     for(UINT i = 0; i < tcount; ++i)
  845.     {
  846.         fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
  847.     }
  848.  
  849.     fin.close();
  850.  
  851.     //
  852.     // Pack the indices of all the meshes into one index buffer.
  853.     //
  854.  
  855.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  856.  
  857.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
  858.  
  859.     auto geo = std::make_unique<MeshGeometry>();
  860.     geo->Name = "skullGeo";
  861.  
  862.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  863.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  864.  
  865.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  866.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  867.  
  868.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  869.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  870.  
  871.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  872.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  873.  
  874.     geo->VertexByteStride = sizeof(Vertex);
  875.     geo->VertexBufferByteSize = vbByteSize;
  876.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  877.     geo->IndexBufferByteSize = ibByteSize;
  878.  
  879.     SubmeshGeometry submesh;
  880.     submesh.IndexCount = (UINT)indices.size();
  881.     submesh.StartIndexLocation = 0;
  882.     submesh.BaseVertexLocation = 0;
  883.     submesh.Bounds = bounds;
  884.  
  885.     geo->DrawArgs["skull"] = submesh;
  886.  
  887.     mGeometries[geo->Name] = std::move(geo);
  888. }
  889.  
  890. void QuatApp::BuildPSOs()
  891. {
  892.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  893.  
  894.     //
  895.     // PSO for opaque objects.
  896.     //
  897.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  898.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  899.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  900.     opaquePsoDesc.VS = 
  901.     { 
  902.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  903.         mShaders["standardVS"]->GetBufferSize()
  904.     };
  905.     opaquePsoDesc.PS = 
  906.     { 
  907.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  908.         mShaders["opaquePS"]->GetBufferSize()
  909.     };
  910.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  911.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  912.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  913.     opaquePsoDesc.SampleMask = UINT_MAX;
  914.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  915.     opaquePsoDesc.NumRenderTargets = 1;
  916.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  917.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  918.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  919.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  920.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  921. }
  922.  
  923. void QuatApp::BuildFrameResources()
  924. {
  925.     for(int i = 0; i < gNumFrameResources; ++i)
  926.     {
  927.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  928.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  929.     }
  930. }
  931.  
  932. void QuatApp::BuildMaterials()
  933. {
  934.     auto bricks0 = std::make_unique<Material>();
  935.     bricks0->Name = "bricks0";
  936.     bricks0->MatCBIndex = 0;
  937.     bricks0->DiffuseSrvHeapIndex = 0;
  938.     bricks0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  939.     bricks0->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  940.     bricks0->Roughness = 0.3f;
  941.  
  942.     auto stone0 = std::make_unique<Material>();
  943.     stone0->Name = "stone0";
  944.     stone0->MatCBIndex = 1;
  945.     stone0->DiffuseSrvHeapIndex = 1;
  946.     stone0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  947.     bricks0->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  948.     bricks0->Roughness = 0.3f;
  949.  
  950.     auto tile0 = std::make_unique<Material>();
  951.     tile0->Name = "tile0";
  952.     tile0->MatCBIndex = 2;
  953.     tile0->DiffuseSrvHeapIndex = 2;
  954.     tile0->DiffuseAlbedo = XMFLOAT4(0.9f, 0.9f, 0.9f, 1.0f);
  955.     tile0->FresnelR0 = XMFLOAT3(0.2f, 0.2f, 0.2f);
  956.     tile0->Roughness = 0.1f;
  957.  
  958.     auto crate0 = std::make_unique<Material>();
  959.     crate0->Name = "crate0";
  960.     crate0->MatCBIndex = 3;
  961.     crate0->DiffuseSrvHeapIndex = 3;
  962.     crate0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  963.     crate0->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  964.     crate0->Roughness = 0.7f;
  965.  
  966.     auto skullMat = std::make_unique<Material>();
  967.     skullMat->Name = "skullMat";
  968.     skullMat->MatCBIndex = 4;
  969.     skullMat->DiffuseSrvHeapIndex = 4;
  970.     skullMat->DiffuseAlbedo = XMFLOAT4(0.9f, 0.9f, 0.9f, 1.0f);
  971.     skullMat->FresnelR0 = XMFLOAT3(0.2f, 0.2f, 0.2f);
  972.     skullMat->Roughness = 0.2f;
  973.     
  974.     mMaterials["bricks0"] = std::move(bricks0);
  975.     mMaterials["stone0"] = std::move(stone0);
  976.     mMaterials["tile0"] = std::move(tile0);
  977.     mMaterials["crate0"] = std::move(crate0);
  978.     mMaterials["skullMat"] = std::move(skullMat);
  979. }
  980.  
  981. void QuatApp::BuildRenderItems()
  982. {
  983.     auto skullRitem = std::make_unique<RenderItem>();
  984.     XMStoreFloat4x4(&skullRitem->World,
  985.         XMMatrixScaling(0.5f, 0.5f, 0.5f)*XMMatrixTranslation(0.0f, 1.0f, 0.0f));
  986.     skullRitem->TexTransform = MathHelper::Identity4x4();
  987.     skullRitem->ObjCBIndex = 0;
  988.     skullRitem->Mat = mMaterials["skullMat"].get();
  989.     skullRitem->Geo = mGeometries["skullGeo"].get();
  990.     skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  991.     skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
  992.     skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
  993.     skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;
  994.     mSkullRitem = skullRitem.get();
  995.     mAllRitems.push_back(std::move(skullRitem));
  996.  
  997.     auto boxRitem = std::make_unique<RenderItem>();
  998.     XMStoreFloat4x4(&boxRitem->World, XMMatrixScaling(3.0f, 1.0f, 3.0f)*XMMatrixTranslation(0.0f, 0.5f, 0.0f));
  999.     XMStoreFloat4x4(&boxRitem->TexTransform, XMMatrixScaling(1.0f, 1.0f, 1.0f));
  1000.     boxRitem->ObjCBIndex = 1;
  1001.     boxRitem->Mat = mMaterials["stone0"].get();
  1002.     boxRitem->Geo = mGeometries["shapeGeo"].get();
  1003.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1004.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  1005.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  1006.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  1007.     mAllRitems.push_back(std::move(boxRitem));
  1008.  
  1009.     auto gridRitem = std::make_unique<RenderItem>();
  1010.     gridRitem->World = MathHelper::Identity4x4();
  1011.     XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(8.0f, 8.0f, 1.0f));
  1012.     gridRitem->ObjCBIndex = 2;
  1013.     gridRitem->Mat = mMaterials["tile0"].get();
  1014.     gridRitem->Geo = mGeometries["shapeGeo"].get();
  1015.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1016.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  1017.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1018.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1019.     mAllRitems.push_back(std::move(gridRitem));
  1020.  
  1021.     XMMATRIX brickTexTransform = XMMatrixScaling(1.5f, 2.0f, 1.0f);
  1022.     UINT objCBIndex = 3;
  1023.     for(int i = 0; i < 5; ++i)
  1024.     {
  1025.         auto leftCylRitem = std::make_unique<RenderItem>();
  1026.         auto rightCylRitem = std::make_unique<RenderItem>();
  1027.         auto leftSphereRitem = std::make_unique<RenderItem>();
  1028.         auto rightSphereRitem = std::make_unique<RenderItem>();
  1029.  
  1030.         XMMATRIX leftCylWorld = XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f);
  1031.         XMMATRIX rightCylWorld = XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f);
  1032.  
  1033.         XMMATRIX leftSphereWorld = XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f);
  1034.         XMMATRIX rightSphereWorld = XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f);
  1035.  
  1036.         XMStoreFloat4x4(&leftCylRitem->World, rightCylWorld);
  1037.         XMStoreFloat4x4(&leftCylRitem->TexTransform, brickTexTransform);
  1038.         leftCylRitem->ObjCBIndex = objCBIndex++;
  1039.         leftCylRitem->Mat = mMaterials["bricks0"].get();
  1040.         leftCylRitem->Geo = mGeometries["shapeGeo"].get();
  1041.         leftCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1042.         leftCylRitem->IndexCount = leftCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  1043.         leftCylRitem->StartIndexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  1044.         leftCylRitem->BaseVertexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  1045.  
  1046.         XMStoreFloat4x4(&rightCylRitem->World, leftCylWorld);
  1047.         XMStoreFloat4x4(&rightCylRitem->TexTransform, brickTexTransform);
  1048.         rightCylRitem->ObjCBIndex = objCBIndex++;
  1049.         rightCylRitem->Mat = mMaterials["bricks0"].get();
  1050.         rightCylRitem->Geo = mGeometries["shapeGeo"].get();
  1051.         rightCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1052.         rightCylRitem->IndexCount = rightCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  1053.         rightCylRitem->StartIndexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  1054.         rightCylRitem->BaseVertexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  1055.  
  1056.         XMStoreFloat4x4(&leftSphereRitem->World, leftSphereWorld);
  1057.         leftSphereRitem->TexTransform = MathHelper::Identity4x4();
  1058.         leftSphereRitem->ObjCBIndex = objCBIndex++;
  1059.         leftSphereRitem->Mat = mMaterials["stone0"].get();
  1060.         leftSphereRitem->Geo = mGeometries["shapeGeo"].get();
  1061.         leftSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1062.         leftSphereRitem->IndexCount = leftSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  1063.         leftSphereRitem->StartIndexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  1064.         leftSphereRitem->BaseVertexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  1065.  
  1066.         XMStoreFloat4x4(&rightSphereRitem->World, rightSphereWorld);
  1067.         rightSphereRitem->TexTransform = MathHelper::Identity4x4();
  1068.         rightSphereRitem->ObjCBIndex = objCBIndex++;
  1069.         rightSphereRitem->Mat = mMaterials["stone0"].get();
  1070.         rightSphereRitem->Geo = mGeometries["shapeGeo"].get();
  1071.         rightSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1072.         rightSphereRitem->IndexCount = rightSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  1073.         rightSphereRitem->StartIndexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  1074.         rightSphereRitem->BaseVertexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  1075.  
  1076.         mAllRitems.push_back(std::move(leftCylRitem));
  1077.         mAllRitems.push_back(std::move(rightCylRitem));
  1078.         mAllRitems.push_back(std::move(leftSphereRitem));
  1079.         mAllRitems.push_back(std::move(rightSphereRitem));
  1080.     }
  1081.  
  1082.     // All the render items are opaque.
  1083.     for(auto& e : mAllRitems)
  1084.         mOpaqueRitems.push_back(e.get());
  1085. }
  1086.  
  1087. void QuatApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  1088. {
  1089.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  1090.  
  1091.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  1092.  
  1093.     // For each render item...
  1094.     for(size_t i = 0; i < ritems.size(); ++i)
  1095.     {
  1096.         auto ri = ritems[i];
  1097.  
  1098.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  1099.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  1100.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  1101.  
  1102.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  1103.  
  1104.         // CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  1105.         // tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  1106.  
  1107.         cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
  1108.  
  1109.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  1110.     }
  1111. }
  1112.  
  1113. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> QuatApp::GetStaticSamplers()
  1114. {
  1115.     // Applications usually only need a handful of samplers.  So just define them all up front
  1116.     // and keep them available as part of the root signature.  
  1117.  
  1118.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  1119.         0, // shaderRegister
  1120.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1121.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1122.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1123.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1124.  
  1125.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  1126.         1, // shaderRegister
  1127.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1128.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1129.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1130.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1131.  
  1132.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  1133.         2, // shaderRegister
  1134.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1135.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1136.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1137.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1138.  
  1139.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  1140.         3, // shaderRegister
  1141.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1142.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1143.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1144.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1145.  
  1146.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  1147.         4, // shaderRegister
  1148.         D3D12_FILTER_ANISOTROPIC, // filter
  1149.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1150.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1151.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1152.         0.0f,                             // mipLODBias
  1153.         8);                               // maxAnisotropy
  1154.  
  1155.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1156.         5, // shaderRegister
  1157.         D3D12_FILTER_ANISOTROPIC, // filter
  1158.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1159.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1160.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1161.         0.0f,                              // mipLODBias
  1162.         8);                                // maxAnisotropy
  1163.  
  1164.     return { 
  1165.         pointWrap, pointClamp,
  1166.         linearWrap, linearClamp, 
  1167.         anisotropicWrap, anisotropicClamp };
  1168. }
  1169.  
  1170.