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 / Common / d3dUtil.h < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  9.2 KB  |  288 lines

  1. //***************************************************************************************
  2. // d3dUtil.h by Frank Luna (C) 2015 All Rights Reserved.
  3. //
  4. // General helper code.
  5. //***************************************************************************************
  6.  
  7. #pragma once
  8.  
  9. #include <windows.h>
  10. #include <wrl.h>
  11. #include <dxgi1_4.h>
  12. #include <d3d12.h>
  13. #include <D3Dcompiler.h>
  14. #include <DirectXMath.h>
  15. #include <DirectXPackedVector.h>
  16. #include <DirectXColors.h>
  17. #include <DirectXCollision.h>
  18. #include <string>
  19. #include <memory>
  20. #include <algorithm>
  21. #include <vector>
  22. #include <array>
  23. #include <unordered_map>
  24. #include <cstdint>
  25. #include <fstream>
  26. #include <sstream>
  27. #include <cassert>
  28. #include "d3dx12.h"
  29. #include "DDSTextureLoader.h"
  30. #include "MathHelper.h"
  31.  
  32. extern const int gNumFrameResources;
  33.  
  34. inline void d3dSetDebugName(IDXGIObject* obj, const char* name)
  35. {
  36.     if(obj)
  37.     {
  38.         obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
  39.     }
  40. }
  41. inline void d3dSetDebugName(ID3D12Device* obj, const char* name)
  42. {
  43.     if(obj)
  44.     {
  45.         obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
  46.     }
  47. }
  48. inline void d3dSetDebugName(ID3D12DeviceChild* obj, const char* name)
  49. {
  50.     if(obj)
  51.     {
  52.         obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
  53.     }
  54. }
  55.  
  56. inline std::wstring AnsiToWString(const std::string& str)
  57. {
  58.     WCHAR buffer[512];
  59.     MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);
  60.     return std::wstring(buffer);
  61. }
  62.  
  63. /*
  64. #if defined(_DEBUG)
  65.     #ifndef Assert
  66.     #define Assert(x, description)                                  \
  67.     {                                                               \
  68.         static bool ignoreAssert = false;                           \
  69.         if(!ignoreAssert && !(x))                                   \
  70.         {                                                           \
  71.             Debug::AssertResult result = Debug::ShowAssertDialog(   \
  72.             (L#x), description, AnsiToWString(__FILE__), __LINE__); \
  73.         if(result == Debug::AssertIgnore)                           \
  74.         {                                                           \
  75.             ignoreAssert = true;                                    \
  76.         }                                                           \
  77.                     else if(result == Debug::AssertBreak)           \
  78.         {                                                           \
  79.             __debugbreak();                                         \
  80.         }                                                           \
  81.         }                                                           \
  82.     }
  83.     #endif
  84. #else
  85.     #ifndef Assert
  86.     #define Assert(x, description) 
  87.     #endif
  88. #endif         
  89.     */
  90.  
  91. class d3dUtil
  92. {
  93. public:
  94.  
  95.     static bool IsKeyDown(int vkeyCode);
  96.  
  97.     static std::string ToString(HRESULT hr);
  98.  
  99.     static UINT CalcConstantBufferByteSize(UINT byteSize)
  100.     {
  101.         // Constant buffers must be a multiple of the minimum hardware
  102.         // allocation size (usually 256 bytes).  So round up to nearest
  103.         // multiple of 256.  We do this by adding 255 and then masking off
  104.         // the lower 2 bytes which store all bits < 256.
  105.         // Example: Suppose byteSize = 300.
  106.         // (300 + 255) & ~255
  107.         // 555 & ~255
  108.         // 0x022B & ~0x00ff
  109.         // 0x022B & 0xff00
  110.         // 0x0200
  111.         // 512
  112.         return (byteSize + 255) & ~255;
  113.     }
  114.  
  115.     static Microsoft::WRL::ComPtr<ID3DBlob> LoadBinary(const std::wstring& filename);
  116.  
  117.     static Microsoft::WRL::ComPtr<ID3D12Resource> CreateDefaultBuffer(
  118.         ID3D12Device* device,
  119.         ID3D12GraphicsCommandList* cmdList,
  120.         const void* initData,
  121.         UINT64 byteSize,
  122.         Microsoft::WRL::ComPtr<ID3D12Resource>& uploadBuffer);
  123.  
  124.     static Microsoft::WRL::ComPtr<ID3DBlob> CompileShader(
  125.         const std::wstring& filename,
  126.         const D3D_SHADER_MACRO* defines,
  127.         const std::string& entrypoint,
  128.         const std::string& target);
  129. };
  130.  
  131. class DxException
  132. {
  133. public:
  134.     DxException() = default;
  135.     DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, int lineNumber);
  136.  
  137.     std::wstring ToString()const;
  138.  
  139.     HRESULT ErrorCode = S_OK;
  140.     std::wstring FunctionName;
  141.     std::wstring Filename;
  142.     int LineNumber = -1;
  143. };
  144.  
  145. // Defines a subrange of geometry in a MeshGeometry.  This is for when multiple
  146. // geometries are stored in one vertex and index buffer.  It provides the offsets
  147. // and data needed to draw a subset of geometry stores in the vertex and index 
  148. // buffers so that we can implement the technique described by Figure 6.3.
  149. struct SubmeshGeometry
  150. {
  151.     UINT IndexCount = 0;
  152.     UINT StartIndexLocation = 0;
  153.     INT BaseVertexLocation = 0;
  154.  
  155.     // Bounding box of the geometry defined by this submesh. 
  156.     // This is used in later chapters of the book.
  157.     DirectX::BoundingBox Bounds;
  158. };
  159.  
  160. struct MeshGeometry
  161. {
  162.     // Give it a name so we can look it up by name.
  163.     std::string Name;
  164.  
  165.     // System memory copies.  Use Blobs because the vertex/index format can be generic.
  166.     // It is up to the client to cast appropriately.  
  167.     Microsoft::WRL::ComPtr<ID3DBlob> VertexBufferCPU = nullptr;
  168.     Microsoft::WRL::ComPtr<ID3DBlob> IndexBufferCPU  = nullptr;
  169.  
  170.     Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferGPU = nullptr;
  171.     Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferGPU = nullptr;
  172.  
  173.     Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferUploader = nullptr;
  174.     Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferUploader = nullptr;
  175.  
  176.     // Data about the buffers.
  177.     UINT VertexByteStride = 0;
  178.     UINT VertexBufferByteSize = 0;
  179.     DXGI_FORMAT IndexFormat = DXGI_FORMAT_R16_UINT;
  180.     UINT IndexBufferByteSize = 0;
  181.  
  182.     // A MeshGeometry may store multiple geometries in one vertex/index buffer.
  183.     // Use this container to define the Submesh geometries so we can draw
  184.     // the Submeshes individually.
  185.     std::unordered_map<std::string, SubmeshGeometry> DrawArgs;
  186.  
  187.     D3D12_VERTEX_BUFFER_VIEW VertexBufferView()const
  188.     {
  189.         D3D12_VERTEX_BUFFER_VIEW vbv;
  190.         vbv.BufferLocation = VertexBufferGPU->GetGPUVirtualAddress();
  191.         vbv.StrideInBytes = VertexByteStride;
  192.         vbv.SizeInBytes = VertexBufferByteSize;
  193.  
  194.         return vbv;
  195.     }
  196.  
  197.     D3D12_INDEX_BUFFER_VIEW IndexBufferView()const
  198.     {
  199.         D3D12_INDEX_BUFFER_VIEW ibv;
  200.         ibv.BufferLocation = IndexBufferGPU->GetGPUVirtualAddress();
  201.         ibv.Format = IndexFormat;
  202.         ibv.SizeInBytes = IndexBufferByteSize;
  203.  
  204.         return ibv;
  205.     }
  206.  
  207.     // We can free this memory after we finish upload to the GPU.
  208.     void DisposeUploaders()
  209.     {
  210.         VertexBufferUploader = nullptr;
  211.         IndexBufferUploader = nullptr;
  212.     }
  213. };
  214.  
  215. struct Light
  216. {
  217.     DirectX::XMFLOAT3 Strength = { 0.5f, 0.5f, 0.5f };
  218.     float FalloffStart = 1.0f;                          // point/spot light only
  219.     DirectX::XMFLOAT3 Direction = { 0.0f, -1.0f, 0.0f };// directional/spot light only
  220.     float FalloffEnd = 10.0f;                           // point/spot light only
  221.     DirectX::XMFLOAT3 Position = { 0.0f, 0.0f, 0.0f };  // point/spot light only
  222.     float SpotPower = 64.0f;                            // spot light only
  223. };
  224.  
  225. #define MaxLights 16
  226.  
  227. struct MaterialConstants
  228. {
  229.     DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };
  230.     DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };
  231.     float Roughness = 0.25f;
  232.  
  233.     // Used in texture mapping.
  234.     DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
  235. };
  236.  
  237. // Simple struct to represent a material for our demos.  A production 3D engine
  238. // would likely create a class hierarchy of Materials.
  239. struct Material
  240. {
  241.     // Unique material name for lookup.
  242.     std::string Name;
  243.  
  244.     // Index into constant buffer corresponding to this material.
  245.     int MatCBIndex = -1;
  246.  
  247.     // Index into SRV heap for diffuse texture.
  248.     int DiffuseSrvHeapIndex = -1;
  249.  
  250.     // Index into SRV heap for normal texture.
  251.     int NormalSrvHeapIndex = -1;
  252.  
  253.     // Dirty flag indicating the material has changed and we need to update the constant buffer.
  254.     // Because we have a material constant buffer for each FrameResource, we have to apply the
  255.     // update to each FrameResource.  Thus, when we modify a material we should set 
  256.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  257.     int NumFramesDirty = gNumFrameResources;
  258.  
  259.     // Material constant buffer data used for shading.
  260.     DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };
  261.     DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };
  262.     float Roughness = .25f;
  263.     DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
  264. };
  265.  
  266. struct Texture
  267. {
  268.     // Unique material name for lookup.
  269.     std::string Name;
  270.  
  271.     std::wstring Filename;
  272.  
  273.     Microsoft::WRL::ComPtr<ID3D12Resource> Resource = nullptr;
  274.     Microsoft::WRL::ComPtr<ID3D12Resource> UploadHeap = nullptr;
  275. };
  276.  
  277. #ifndef ThrowIfFailed
  278. #define ThrowIfFailed(x)                                              \
  279. {                                                                     \
  280.     HRESULT hr__ = (x);                                               \
  281.     std::wstring wfn = AnsiToWString(__FILE__);                       \
  282.     if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \
  283. }
  284. #endif
  285.  
  286. #ifndef ReleaseCom
  287. #define ReleaseCom(x) { if(x){ x->Release(); x = 0; } }
  288. #endif