├── DX12Application.png
├── Resources
├── texture.png
├── BlueNoise64x64.png
├── StaticSamplers.hlsl
├── cube.obj
├── MeshShader.hlsl
├── TestShader.hlsl
└── RaytracingShaders.hlsl
├── .gitmodules
├── Application
├── packages.config
├── WinImgui.h
├── Game.h
├── WinImgui.cpp
├── Application.vcxproj.filters
├── WinMain.cpp
├── Application.vcxproj
└── OBJ_Loader.h
├── DX12Base
├── packages.config
├── Dx12Math.h
├── WindowHelper.h
├── Dx12Utilities.h
├── DX12Base.vcxproj.filters
├── WindowInput.h
├── Dx12Utilities.cpp
├── Dx12RayTracing.h
├── DX12Base.vcxproj
├── WindowHelper.cpp
└── Dx12Device.h
├── LICENSE
├── DirectXTex
├── LICENSE
├── WICTextureLoader
│ ├── WICTextureLoader12.h
│ └── WICTextureLoader12.cpp
└── ReadMe.txt
├── DX12Base.sln
├── README.md
└── .gitignore
/DX12Application.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/DX12Application.png
--------------------------------------------------------------------------------
/Resources/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/Resources/texture.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "imgui"]
2 | path = imgui
3 | url = https://github.com/ocornut/imgui
4 |
--------------------------------------------------------------------------------
/Resources/BlueNoise64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/Resources/BlueNoise64x64.png
--------------------------------------------------------------------------------
/Application/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/DX12Base/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Resources/StaticSamplers.hlsl:
--------------------------------------------------------------------------------
1 |
2 | // Dx12 common static samplers
3 | // More can be added in RootSignature::RootSignature in Dx12Device.cpp
4 |
5 |
6 |
7 | SamplerState SamplerPointClamp : register(s0);
8 | SamplerState SamplerLinearClamp : register(s1);
9 |
10 | SamplerState SamplerPointRepeat : register(s2);
11 | SamplerState SamplerLinearRepeat : register(s3);
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Application/WinImgui.h:
--------------------------------------------------------------------------------
1 |
2 | #pragma once
3 |
4 | #define D_ENABLE_IMGUI 1
5 |
6 |
7 | #include
8 |
9 | #if D_ENABLE_IMGUI
10 | #include
11 | #include
12 | #include
13 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
14 | #endif // D_ENABLE_IMGUI
15 |
16 |
17 | void WinImguiInitialise(const HWND hwnd);
18 |
19 | void WinImguiNewFrame();
20 |
21 | void WinImguiRender();
22 |
23 | void WinImguiShutdown();
24 |
25 |
--------------------------------------------------------------------------------
/Resources/cube.obj:
--------------------------------------------------------------------------------
1 |
2 | v -0.500000 -0.500000 0.500000
3 | v 0.500000 -0.500000 0.500000
4 | v -0.500000 0.500000 0.500000
5 | v 0.500000 0.500000 0.500000
6 | v -0.500000 0.500000 -0.500000
7 | v 0.500000 0.500000 -0.500000
8 | v -0.500000 -0.500000 -0.500000
9 | v 0.500000 -0.500000 -0.500000
10 |
11 | vt 0.000000 0.000000
12 | vt 1.000000 0.000000
13 | vt 0.000000 1.000000
14 | vt 1.000000 1.000000
15 |
16 | vn 0.000000 0.000000 1.000000
17 | vn 0.000000 1.000000 0.000000
18 | vn 0.000000 0.000000 -1.000000
19 | vn 0.000000 -1.000000 0.000000
20 | vn 1.000000 0.000000 0.000000
21 | vn -1.000000 0.000000 0.000000
22 |
23 | s 1
24 | f 1/1/1 2/2/1 3/3/1
25 | f 3/3/1 2/2/1 4/4/1
26 | s 2
27 | f 3/1/2 4/2/2 5/3/2
28 | f 5/3/2 4/2/2 6/4/2
29 | s 3
30 | f 5/4/3 6/3/3 7/2/3
31 | f 7/2/3 6/3/3 8/1/3
32 | s 4
33 | f 7/1/4 8/2/4 1/3/4
34 | f 1/3/4 8/2/4 2/4/4
35 | s 5
36 | f 2/1/5 8/2/5 4/3/5
37 | f 4/3/5 8/2/5 6/4/5
38 | s 6
39 | f 7/1/6 1/2/6 5/3/6
40 | f 5/3/6 1/2/6 3/4/6
41 |
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 SebH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/DirectXTex/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Microsoft Corp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | software and associated documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights to use, copy, modify,
8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all copies
13 | or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/DX12Base/Dx12Math.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DirectXMath.h"
4 | using namespace DirectX;
5 |
6 |
7 |
8 | typedef signed char s8;
9 | typedef unsigned char u8;
10 | //typedef unsigned char byte;
11 |
12 | typedef unsigned int uint;
13 | typedef int sint;
14 |
15 | typedef UINT64 uint64;
16 | typedef INT64 sint64;
17 |
18 | typedef short word;
19 | typedef uint dword;
20 |
21 | typedef XMMATRIX float4x4;
22 | typedef XMVECTOR float4;
23 |
24 |
25 |
26 | const float Pi = 3.14159265359f;
27 |
28 |
29 |
30 | template
31 | inline T Clamp(T x, T MinX, T MaxX)
32 | {
33 | return x > MaxX ? MaxX : (x < MinX ? MinX : x);
34 | }
35 |
36 | template
37 | inline T Sqr(T x) { return x * x; }
38 |
39 | inline float Saturate(float x)
40 | {
41 | return x > 1.0f ? 1.0f : (x < 0.0f ? 0.0f : x);
42 | }
43 |
44 | inline float Lerp(float a, float b, float x)
45 | {
46 | return a + Saturate(x) * (b - a);
47 | }
48 |
49 | inline float DegToRad(float deg)
50 | {
51 | return deg / 180.0f * Pi;
52 | }
53 |
54 | inline float RadToDeg(float rad)
55 | {
56 | return rad * 180.0f / Pi;
57 | }
58 |
59 | inline uint RoundUp(uint Value, uint Alignement)
60 | {
61 | uint Var = Value + Alignement - 1;
62 | return Alignement * (Var / Alignement);
63 | }
64 |
65 | inline uint64 RoundUp(uint64 Value, uint64 Alignement)
66 | {
67 | uint64 Var = Value + Alignement - 1;
68 | return Alignement * (Var / Alignement);
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Resources/MeshShader.hlsl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #include "StaticSamplers.hlsl"
5 |
6 |
7 |
8 | struct MeshVertexInput
9 | {
10 | float3 Position : POSITION;
11 | float3 Normal : NORMAL;
12 | float2 UV : TEXCOORD0;
13 | };
14 |
15 | struct MeshVertexOutput
16 | {
17 | float4 SvPosition : SV_POSITION;
18 | float3 Normal : NORMAL;
19 | float2 UV : TEXCOORD0;
20 | };
21 |
22 | cbuffer MeshConstantBuffer : register(b0)
23 | {
24 | float4x4 ViewProjectionMatrix;
25 | float4x4 MeshWorldMatrix;
26 | float VoxelisationVolumeDepth;
27 | float pad0[3];
28 | }
29 |
30 | Texture2D MeshTexture : register(t0);
31 |
32 | MeshVertexOutput MeshVertexShader(MeshVertexInput input)
33 | {
34 | MeshVertexOutput output;
35 |
36 | output.SvPosition = mul(ViewProjectionMatrix, mul(MeshWorldMatrix, float4(input.Position, 1.0)));
37 |
38 | output.Normal = input.Normal;
39 | output.UV = input.UV;
40 |
41 | return output;
42 | }
43 |
44 | float4 MeshPixelShader(MeshVertexOutput input) : SV_TARGET
45 | {
46 | //return float4(input.Normal.xyz, 1.0f);
47 | //return float4(input.UV.xy, 0.0f, 1.0f);
48 | return MeshTexture.Sample(SamplerLinearClamp, float2(input.UV.xy));
49 | }
50 |
51 | RWTexture3D OutVolumeTexture : register(u0);
52 |
53 | void MeshVoxelisationPixelShader(MeshVertexOutput input)
54 | {
55 | const float4 Data = MeshTexture.Sample(SamplerLinearClamp, float2(input.UV.xy));
56 | OutVolumeTexture[uint3(input.SvPosition.xy, input.SvPosition.z * VoxelisationVolumeDepth)] = Data;
57 | }
58 |
59 |
60 |
--------------------------------------------------------------------------------
/DX12Base/WindowHelper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "WindowInput.h"
6 |
7 | #include
8 |
9 |
10 | // Return true if an event has been intercepted and should not be sent down to the game
11 | typedef bool(*WindowTopLayerProcHandler)(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
12 |
13 |
14 | class WindowHelper
15 | {
16 | public:
17 | WindowHelper(
18 | HINSTANCE hInstance,
19 | const RECT& clientRect,
20 | int nCmdShow,
21 | LPCWSTR windowName);
22 | ~WindowHelper();
23 |
24 | void showWindow();
25 |
26 | bool translateSingleMessage(MSG& msg);
27 |
28 | const WindowInputData& getInputData()
29 | {
30 | return mInput;
31 | }
32 | void clearInputEvents()
33 | {
34 | mInput.mInputEvents.clear();
35 | }
36 |
37 | const HWND getHwnd() { return mHWnd; }
38 |
39 | void processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam);
40 | void processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam);
41 | void processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam);
42 |
43 | void setWindowResizedCallback(std::function windowResizedCallback) { mWindowResizedCallback = windowResizedCallback; }
44 |
45 | private:
46 | WindowHelper();
47 |
48 | HINSTANCE mHInstance; /// The application instance
49 | HWND mHWnd; /// The handle for the window, filled by a function
50 | WNDCLASSEX mWc; /// This struct holds information for the window class
51 | RECT mClientRect; /// The client rectangle where we render into
52 | int mNCmdShow; /// Window show cmd
53 |
54 | WindowInputData mInput; /// input event and status (mouse, keyboard, etc.)
55 |
56 | std::function mWindowResizedCallback = [&](LPARAM lParam) {};
57 | };
58 |
59 |
60 |
--------------------------------------------------------------------------------
/DX12Base/Dx12Utilities.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Dx12Device.h"
4 |
5 |
6 |
7 |
8 | class RenderBufferGenericDynamic
9 | {
10 | public:
11 | RenderBufferGenericDynamic(
12 | uint64 TotalSizeInBytes, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE);
13 | virtual ~RenderBufferGenericDynamic();
14 |
15 | void* Map();
16 | void UnmapAndUpload();
17 |
18 | RenderBufferGeneric& getRenderBuffer() { return mRenderBuffer; }
19 |
20 | protected:
21 |
22 | private:
23 | RenderBufferGenericDynamic();
24 | RenderBufferGenericDynamic(RenderBufferGenericDynamic&);
25 |
26 | RenderBufferGeneric* mFrameUploadBuffers[frameBufferCount];
27 | RenderBufferGeneric mRenderBuffer;
28 | };
29 |
30 |
31 |
32 |
33 | ////////////////////////////////////////////////////////////////////////////////////////////////////
34 | ////////////////////////////////////////////////////////////////////////////////////////////////////
35 | ////////////////////////////////////////////////////////////////////////////////////////////////////
36 |
37 |
38 |
39 |
40 | class RenderTextureDynamic
41 | {
42 | public:
43 | RenderTextureDynamic(
44 | unsigned int width, unsigned int height,
45 | unsigned int depth, DXGI_FORMAT format,
46 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE);
47 | virtual ~RenderTextureDynamic();
48 |
49 | // Map and Unmpap have not been tested so far
50 | void* Map();
51 | void UnmapAndUpload();
52 |
53 | void Upload(void* DataPtr, unsigned int RowPitchByte, unsigned int SlicePitchByte);
54 |
55 | UINT64 getWidth() { return mRenderTexture.getD3D12Resource()->GetDesc().Width; }
56 | UINT64 getHeight() { return mRenderTexture.getD3D12Resource()->GetDesc().Height; }
57 | RenderTexture& getRenderTexture() { return mRenderTexture; }
58 |
59 | protected:
60 |
61 | private:
62 | RenderTextureDynamic();
63 | RenderTextureDynamic(RenderTextureDynamic&);
64 |
65 | unsigned int mInitDataCopySizeByte = 0;
66 | unsigned int mRowPitchByte = 0;
67 | unsigned int mSlicePitchByte = 0;
68 |
69 | ID3D12Resource* mFrameUploadTextures[frameBufferCount];
70 | RenderTexture mRenderTexture;
71 | };
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/DX12Base/DX12Base.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
11 |
12 |
13 |
14 |
15 | Source Files
16 |
17 |
18 | Source Files
19 |
20 |
21 | Source Files
22 |
23 |
24 | Source Files
25 |
26 |
27 | Source Files
28 |
29 |
30 |
31 |
32 | Source Files
33 |
34 |
35 | Source Files
36 |
37 |
38 | Source Files
39 |
40 |
41 | Source Files
42 |
43 |
44 | Source Files
45 |
46 |
47 | Source Files
48 |
49 |
50 | Source Files
51 |
52 |
53 | Source Files
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Resources/TestShader.hlsl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #include "StaticSamplers.hlsl"
5 |
6 |
7 |
8 | cbuffer MyBuffer : register(b0)
9 | {
10 | float4 FloatVector;
11 | }
12 |
13 |
14 | struct VertexInput
15 | {
16 | uint VertexID : SV_VertexID;
17 | float3 position : POSITION;
18 | float2 uv : TEXCOORD0;
19 | };
20 |
21 | struct VertexOutput
22 | {
23 | float4 position : SV_POSITION;
24 | float2 uv : TEXCOORD0;
25 | };
26 |
27 | VertexOutput ColorVertexShader(VertexInput input)
28 | {
29 | VertexOutput output; // TODO init to 0
30 |
31 | output.position = float4(input.position.xyz, 1.0);
32 | output.uv = input.uv;
33 |
34 | return output;
35 | }
36 |
37 | //StructuredBuffer buffer : register(t0);
38 | Texture2D texture0 : register(t0);
39 |
40 | Texture2D BindlessTextures[ROOT_BINDLESS_SRV_COUNT] : register(ROOT_BINDLESS_SRV_START_REGISTER);
41 |
42 | float4 ColorPixelShader(VertexOutput input) : SV_TARGET
43 | {
44 | const uint TileCountXY = 8;
45 | const uint TilePixelSize = 32;
46 | if (ROOT_BINDLESS_SRV_COUNT==64 &&
47 | all(input.position.xy >= 0) && all(input.position.xy < TileCountXY * TilePixelSize))
48 | {
49 | uint textureIndex = (uint(input.position.y) / TilePixelSize) * TileCountXY + uint(input.position.x) / TilePixelSize;
50 | return BindlessTextures[NonUniformResourceIndex(textureIndex)].Sample(SamplerLinearRepeat, float2(float2(input.position.xy) / float(TilePixelSize)));
51 | }
52 |
53 | return texture0.Sample(SamplerLinearClamp, float2(input.uv.x, 1.0f - input.uv.y));
54 | }
55 |
56 |
57 | VertexOutput TriangleVertexShader(uint VertexID : SV_VertexID)
58 | {
59 | VertexOutput output; // TODO init to 0
60 |
61 | output.position = float4(VertexID == 2 ? 3.0 : -1.0, VertexID == 1 ? 3.0 : -1.0, 0.1, 1.0);
62 | output.uv = (output.position.xy + 1.0) * 0.25;
63 |
64 | return output;
65 | }
66 |
67 | float4 TrianglePixelShader(VertexOutput input) : SV_TARGET
68 | {
69 | return float4(input.uv, 0, 0);
70 | }
71 |
72 | float4 ToneMapPS(VertexOutput input) : SV_TARGET
73 | {
74 | float4 RGBA = texture0.Sample(SamplerPointClamp, input.uv);
75 | return float4(pow(RGBA.rgb, 1.0f / 2.2f), RGBA.a);
76 | }
77 |
78 |
79 | RWBuffer myBuffer : register(u0);
80 |
81 | [numthreads(1, 1, 1)]
82 | void MainComputeShader(uint3 groupId : SV_GroupID, uint groupIndex : SV_GroupIndex)
83 | {
84 | myBuffer[0] = FloatVector;
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------
/DX12Base.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dx12Base", "DX12Base\dx12Base.vcxproj", "{9412077D-D368-4DBD-AACB-6DBA3618CF12}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "Application\Application.vcxproj", "{2CA77969-0EC4-4607-93CC-C63915A2C01F}"
9 | ProjectSection(ProjectDependencies) = postProject
10 | {9412077D-D368-4DBD-AACB-6DBA3618CF12} = {9412077D-D368-4DBD-AACB-6DBA3618CF12}
11 | EndProjectSection
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|x64 = Debug|x64
16 | Debug|x86 = Debug|x86
17 | Release|x64 = Release|x64
18 | Release|x86 = Release|x86
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.ActiveCfg = Debug|x64
22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Build.0 = Debug|x64
23 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Deploy.0 = Debug|x64
24 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.ActiveCfg = Debug|Win32
25 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.Build.0 = Debug|Win32
26 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.ActiveCfg = Release|x64
27 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.Build.0 = Release|x64
28 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.ActiveCfg = Release|Win32
29 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.Build.0 = Release|Win32
30 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.ActiveCfg = Debug|x64
31 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.Build.0 = Debug|x64
32 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.ActiveCfg = Debug|Win32
33 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.Build.0 = Debug|Win32
34 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.ActiveCfg = Release|x64
35 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.Build.0 = Release|x64
36 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.ActiveCfg = Release|Win32
37 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.Build.0 = Release|Win32
38 | EndGlobalSection
39 | GlobalSection(SolutionProperties) = preSolution
40 | HideSolutionNode = FALSE
41 | EndGlobalSection
42 | EndGlobal
43 |
--------------------------------------------------------------------------------
/DirectXTex/WICTextureLoader/WICTextureLoader12.h:
--------------------------------------------------------------------------------
1 | //--------------------------------------------------------------------------------------
2 | // File: WICTextureLoader12.h
3 | //
4 | // Function for loading a WIC image and creating a Direct3D runtime texture for it
5 | // (auto-generating mipmaps if possible)
6 | //
7 | // Note: Assumes application has already called CoInitializeEx
8 | //
9 | // Note these functions are useful for images created as simple 2D textures. For
10 | // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.
11 | // For a full-featured DDS file reader, writer, and texture processing pipeline see
12 | // the 'Texconv' sample and the 'DirectXTex' library.
13 | //
14 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
15 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
17 | // PARTICULAR PURPOSE.
18 | //
19 | // Copyright (c) Microsoft Corporation. All rights reserved.
20 | //
21 | // http://go.microsoft.com/fwlink/?LinkId=248926
22 | // http://go.microsoft.com/fwlink/?LinkID=615561
23 | //--------------------------------------------------------------------------------------
24 |
25 | // Modified by SebH
26 |
27 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | namespace DirectX
34 | {
35 | enum WIC_LOADER_FLAGS
36 | {
37 | WIC_LOADER_DEFAULT = 0,
38 | WIC_LOADER_FORCE_SRGB = 0x1,
39 | WIC_LOADER_IGNORE_SRGB = 0x2,
40 | WIC_LOADER_MIP_AUTOGEN = 0x4,
41 | WIC_LOADER_MIP_RESERVE = 0x8,
42 | };
43 |
44 | struct TextureData
45 | {
46 | UINT dataSizeInByte = 0;
47 | UINT width = 0;
48 | UINT height = 0;
49 | UINT mipCount = 0;
50 | DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
51 | D3D12_SUBRESOURCE_DATA& subresource;
52 | std::unique_ptr& decodedData;
53 |
54 | TextureData(D3D12_SUBRESOURCE_DATA& _subresource, std::unique_ptr& _decodedData)
55 | : subresource(_subresource)
56 | , decodedData(_decodedData)
57 | {}
58 |
59 | private:
60 | TextureData();
61 | TextureData(TextureData&);
62 | };
63 |
64 | // Standard version
65 | HRESULT __cdecl LoadWICTextureFromFile(
66 | _In_z_ const wchar_t* szFileName,
67 | TextureData& texData,
68 | size_t maxsize = 0,
69 | unsigned int loadFlags = WIC_LOADER_DEFAULT);
70 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dx12Base
2 |
3 | 
4 |
5 | A small DirectX 12 program I use to test shaders and techniques (so windows only). It is meant to be simple and straightforward. Nothing fancy to see here: plenty of _engines_ already exist out there. This is just a thin abstraction over DX12 so it is still important to understand its core before using it. But it makes development of demos and prototypes easier for me at least. The DX11 version of this is available [here](https://github.com/sebh/Dx11Base).
6 |
7 | Features are
8 | * Simple class helpers above DirectX 12.0 states and resources
9 | * Simple resource upload is in place for now. Utilies a given for per frame update of dynamic textures/buffers.
10 | * Simple RT support for mesh and material built in SBT with global and local shaders.
11 | * Simple PSO caching.
12 | * Live update of shaders with saving via `ctrl+s`
13 | * UI achieved with [Dear ImGui](https://github.com/ocornut/imgui)
14 | * Performance measured with GPU timers and reported in UI (tested on intel and nvidia so far)
15 | * Simple window and input management (could be improved)
16 | * Easy to debug with [RenderDoc](https://renderdoc.org/) or [nSight](https://developer.nvidia.com/nsight-graphics) for instance
17 |
18 | When cloning the project the first time:
19 | 1. Update submodules (run `git submodule update`)
20 | 2. Open the solution
21 | 3. In Visual Studio, change the _Application_ project _Working Directory_ from `$(ProjectDir)` to `$(SolutionDir)`
22 | 4. Make sure you select a windows SDK and a platform toolset you have locally on your computer for both projects
23 | 5. Copy dxcompiler.dll and dxil.dll from your windows SDK into $(SolutionDir) (I really need to fix that...)
24 | 6. Select _Application_ as the startup project, hit F5
25 |
26 | Submodules
27 | * [imgui](https://github.com/ocornut/imgui) V1.85 supported (change the submodule head to the commit corresponding to the version)
28 |
29 | Have fun and do not hesitate to send back suggestions.
30 |
31 | Seb
32 |
33 |
34 | PS: example of what could be improved:
35 | - Better uploading code (do not allocate one uploading resource per texture/buffer)
36 | - Delayed resource deletion when not needed anymore
37 | - Better desriptors management (instead of a simple linear allocation without reuse of released elements)
38 | - Texture mip generation
39 | - Cubemap textures
40 | - Sparse textures
41 | - Mesh shaders
42 | - etc.
--------------------------------------------------------------------------------
/DX12Base/WindowInput.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | enum InputKey
6 | {
7 | kLeft,
8 | kRight,
9 | kUp,
10 | kDown,
11 | kSpace,
12 | kNumpad0,
13 | kNumpad1,
14 | kNumpad2,
15 | kNumpad3,
16 | kNumpad4,
17 | kNumpad5,
18 | kNumpad6,
19 | kNumpad7,
20 | kNumpad8,
21 | kNumpad9,
22 | kMultiply,
23 | kAdd,
24 | kSeparator,
25 | kSubtract,
26 | kDecimal,
27 | kDivide,
28 | kF1,
29 | kF2,
30 | kF3,
31 | kF4,
32 | kF5,
33 | kF6,
34 | kF7,
35 | kF8,
36 | kF9,
37 | kF10,
38 | kF11,
39 | kF12,
40 |
41 | kShift, // event and input status
42 | kControl, // event and input status
43 | kLshift, // never an event, only set on the input status
44 | kRshift, // never an event, only set on the input status
45 | kLcontrol, // never an event, only set on the input status
46 | kRcontrol, // never an event, only set on the input status
47 |
48 | k0,
49 | k1,
50 | k2,
51 | k3,
52 | k4,
53 | k5,
54 | k6,
55 | k7,
56 | k8,
57 | k9,
58 | kA,
59 | kB,
60 | kC,
61 | kD,
62 | kE,
63 | kF,
64 | kG,
65 | kH,
66 | kI,
67 | kJ,
68 | kK,
69 | kL,
70 | kM,
71 | kN,
72 | kO,
73 | kP,
74 | kQ,
75 | kR,
76 | kS,
77 | kT,
78 | kU,
79 | kV,
80 | kW,
81 | kX,
82 | kY,
83 | kZ,
84 |
85 | kCount,
86 | kUnknown
87 | };
88 | enum InputMouseButton
89 | {
90 | mbLeft,
91 | mbMiddle,
92 | mbRight,
93 | mbCount
94 | };
95 | enum InputEventType
96 | {
97 | etKeyUp,
98 | etKeyDown,
99 | etKeyChar,
100 | etMouseMoved,
101 | etMouseButtonUp,
102 | etMouseButtonDown,
103 | etMouseButtonDoubleClick,
104 | etCount
105 | };
106 |
107 | struct InputEvent
108 | {
109 | InputEventType type;
110 | union
111 | {
112 | InputKey key;
113 | InputMouseButton mouseButton;
114 | };
115 | int mouseX;
116 | int mouseY;
117 | };
118 |
119 | struct WindowInputStatus
120 | {
121 |
122 | bool keys[kCount];
123 | bool mouseButtons[mbCount];
124 | int mouseX;
125 | int mouseY;
126 |
127 | void init()
128 | {
129 | memset(this, 0, sizeof(WindowInputStatus));
130 | }
131 |
132 | };
133 |
134 | typedef std::vector WindowInputEventList;
135 |
136 | struct WindowInputData
137 | {
138 | WindowInputStatus mInputStatus; /// status after all events in mInputEvents
139 | WindowInputEventList mInputEvents; /// every events that occured since last update
140 |
141 | void init()
142 | {
143 | mInputStatus.init();
144 | mInputEvents.clear();
145 | mInputEvents.reserve(16);
146 | }
147 | };
148 |
149 |
--------------------------------------------------------------------------------
/Application/Game.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Dx12Base/WindowInput.h"
4 | #include "Dx12Base/Dx12Device.h"
5 | #include "Dx12Base/Dx12RayTracing.h"
6 |
7 | struct ViewCamera
8 | {
9 | ViewCamera();
10 |
11 | // Source state
12 | float4 mPos;
13 | float mYaw;
14 | float mPitch;
15 |
16 | // Derived data from source state
17 | float4 mLeft;
18 | float4 mForward;
19 | float4 mUp;
20 |
21 | // Movement status
22 | int mMoveForward;
23 | int mMoveLeft;
24 | int mMouseDx;
25 | int mMouseDy;
26 |
27 | void Update();
28 |
29 | float4x4 GetViewMatrix() const;
30 | };
31 |
32 | class Game
33 | {
34 | public:
35 | Game();
36 | ~Game();
37 |
38 | void initialise();
39 | void reallocateResolutionDependent(uint newWidth, uint newHeight);
40 | void shutdown();
41 |
42 | void update(const WindowInputData& inputData);
43 | void render();
44 |
45 | private:
46 |
47 | /// Load/reload all shaders if compilation is succesful.
48 | /// @ReloadMode: true if we are simply trying to reload shaders.
49 | void loadShaders(bool ReloadMode);
50 | /// release all shaders
51 | void releaseShaders();
52 |
53 | void allocateResolutionIndependentResources();
54 | void releaseResolutionIndependentResources();
55 | void allocateResolutionDependentResources(uint newWidth, uint newHeight);
56 | void releaseResolutionDependentResources();
57 |
58 | ViewCamera View;
59 | bool mInitialisedMouse = false;
60 | int mLastMouseX = 0;
61 | int mLastMouseY = 0;
62 | int mMouseX = 0;
63 | int mMouseY = 0;
64 |
65 | InputLayout* layout;
66 |
67 | RenderBufferGeneric* vertexBuffer;
68 | RenderBufferGeneric* indexBuffer;
69 |
70 | uint SphereIndexCount;
71 | uint SphereVertexCount;
72 | InputLayout* SphereVertexLayout;
73 | StructuredBuffer* SphereVertexBuffer;
74 | TypedBuffer* SphereIndexBuffer;
75 |
76 | VertexShader* MeshVertexShader;
77 | PixelShader* MeshPixelShader;
78 | PixelShader* MeshVoxelisationPixelShader;
79 |
80 | VertexShader* TriangleVertexShader;
81 | PixelShader* TrianglePixelShader;
82 |
83 | #if D_ENABLE_DXR
84 | StaticBottomLevelAccelerationStructureBuffer* SphereBLAS;
85 | StaticTopLevelAccelerationStructureBuffer* SceneTLAS;
86 |
87 | RayTracingPipelineStateSimple* mRayTracingPipelineState;
88 | RayTracingPipelineStateClosestAndAnyHit* mRayTracingPipelineStateClosestAndHit;
89 | #endif
90 |
91 | TypedBuffer* UavBuffer;
92 |
93 | VertexShader* vertexShader;
94 | PixelShader* pixelShader;
95 | PixelShader* ToneMapShaderPS;
96 | ComputeShader* computeShader;
97 |
98 | RenderTexture* texture;
99 | RenderTexture* texture2;
100 | RenderTexture* HdrTexture;
101 | RenderTexture* HdrTexture2;
102 | RenderTexture* DepthTexture;
103 |
104 | RenderTexture* VolumeTexture;
105 |
106 | bool ShowRtResult = true;
107 | bool ShowRtWithAnyHit = true;
108 | };
109 |
110 |
111 |
--------------------------------------------------------------------------------
/Application/WinImgui.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "WinImgui.h"
3 | #include "Dx12Base/Dx12Device.h"
4 |
5 |
6 | static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = NULL;
7 |
8 |
9 | void WinImguiInitialise(const HWND hwnd)
10 | {
11 | #if D_ENABLE_IMGUI
12 |
13 | // Setup Dear ImGui context
14 | IMGUI_CHECKVERSION();
15 | ImGui::CreateContext();
16 | ImGuiIO& io = ImGui::GetIO(); (void)io;
17 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
18 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
19 |
20 | // Setup Dear ImGui style
21 | ImGui::StyleColorsDark();
22 | //ImGui::StyleColorsClassic();
23 |
24 | D3D12_DESCRIPTOR_HEAP_DESC desc = {};
25 | desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
26 | desc.NumDescriptors = 1;
27 | desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
28 | HRESULT hr = g_dx12Device->getDevice()->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap));
29 | ATLASSERT(hr == S_OK);
30 |
31 | // Setup Platform/Renderer bindings
32 | ImGui_ImplWin32_Init(hwnd);
33 | ImGui_ImplDX12_Init(g_dx12Device->getDevice(), frameBufferCount,
34 | DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap,
35 | g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
36 | g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
37 |
38 | #endif
39 | }
40 |
41 |
42 | void WinImguiNewFrame()
43 | {
44 | #if D_ENABLE_IMGUI
45 |
46 | ImGui_ImplDX12_NewFrame();
47 | ImGui_ImplWin32_NewFrame();
48 | ImGui::NewFrame();
49 |
50 | #endif
51 | }
52 |
53 | void WinImguiRender()
54 | {
55 | #if D_ENABLE_IMGUI
56 | SCOPED_GPU_TIMER(IMGUI, 100, 100, 255);
57 |
58 | // Render UI
59 |
60 | ID3D12GraphicsCommandList* commandList = g_dx12Device->getFrameCommandList();
61 | ID3D12Resource* backBuffer = g_dx12Device->getBackBuffer();
62 |
63 | D3D12_RESOURCE_BARRIER bbPresentToRt = {};
64 | bbPresentToRt.Transition.pResource = backBuffer;
65 | bbPresentToRt.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
66 | bbPresentToRt.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
67 | bbPresentToRt.Transition.Subresource = 0;
68 | commandList->ResourceBarrier(1, &bbPresentToRt);
69 |
70 | D3D12_CPU_DESCRIPTOR_HANDLE descriptor = g_dx12Device->getBackBufferDescriptor();
71 | commandList->OMSetRenderTargets(1, &descriptor, FALSE, NULL);
72 | commandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap);
73 | ImGui::Render();
74 | ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList);
75 |
76 | D3D12_RESOURCE_BARRIER bbRtToPresent = {};
77 | bbRtToPresent.Transition.pResource = backBuffer;
78 | bbRtToPresent.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
79 | bbRtToPresent.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
80 | bbRtToPresent.Transition.Subresource = 0;
81 | commandList->ResourceBarrier(1, &bbRtToPresent);
82 |
83 | #endif
84 | }
85 |
86 | void WinImguiShutdown()
87 | {
88 | #if D_ENABLE_IMGUI
89 |
90 | ImGui_ImplDX12_Shutdown();
91 | ImGui_ImplWin32_Shutdown();
92 | ImGui::DestroyContext();
93 | resetComPtr(&g_pd3dSrvDescHeap);
94 |
95 | #endif
96 | }
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Application/Application.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
11 |
12 |
13 | {26774f3f-a03e-4f83-9f4c-7164cccca514}
14 |
15 |
16 | {86000fa9-6b6a-46f9-ac8d-1c1708aba136}
17 |
18 |
19 |
20 |
21 | Source Files
22 |
23 |
24 | Source Files
25 |
26 |
27 | imgui
28 |
29 |
30 | imgui
31 |
32 |
33 | imgui
34 |
35 |
36 | imgui
37 |
38 |
39 | Source Files
40 |
41 |
42 | imgui
43 |
44 |
45 | imgui
46 |
47 |
48 | imgui
49 |
50 |
51 |
52 |
53 | Source Files
54 |
55 |
56 | imgui
57 |
58 |
59 | imgui
60 |
61 |
62 | imgui
63 |
64 |
65 | imgui
66 |
67 |
68 | imgui
69 |
70 |
71 | imgui
72 |
73 |
74 | Source Files
75 |
76 |
77 | Source Files
78 |
79 |
80 | imgui
81 |
82 |
83 | imgui
84 |
85 |
86 |
87 |
88 | HLSL
89 |
90 |
91 | HLSL
92 |
93 |
94 | HLSL
95 |
96 |
97 | HLSL
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/Resources/RaytracingShaders.hlsl:
--------------------------------------------------------------------------------
1 |
2 | cbuffer MeshConstantBuffer : register(b0, space1)
3 | {
4 | float4x4 ViewProjectionMatrix;
5 | float4x4 ViewProjectionMatrixInv;
6 |
7 | uint OutputWidth;
8 | uint OutputHeight;
9 | uint HitShaderClosestHitContribution;
10 | uint HitShaderAnyHitContribution;
11 | }
12 |
13 |
14 |
15 | //
16 | // Ray tracing global root signature parameters in space1
17 | //
18 |
19 | RaytracingAccelerationStructure Scene : register(t0, space1);
20 | RWTexture2D LuminanceRenderTarget : register(u0, space1);
21 |
22 | struct RayPayload
23 | {
24 | float4 Color;
25 | };
26 |
27 |
28 |
29 | [shader("raygeneration")]
30 | void MyRaygenShader()
31 | {
32 | RayDesc Ray;
33 | Ray.TMin = 0.0001f;
34 | Ray.TMax = 1000.0f;
35 | Ray.Origin = float3(0.0f, 0.0f, 0.0f);
36 | Ray.Direction = float3(0.0f, 1.0f, 0.0f);
37 |
38 | // Compute clip space
39 | uint2 LaunchIndex = DispatchRaysIndex().xy;
40 | float2 DispatchDimension = float2(DispatchRaysDimensions().xy);
41 | float2 ClipXY = (((LaunchIndex.xy + 0.5f) / DispatchDimension.xy) * 2.0f - 1.0f);
42 | ClipXY.y *= -1.0f;
43 |
44 | // Compute start and end points from view matrix
45 | float4 StartPos = mul(ViewProjectionMatrixInv, float4(ClipXY, 0.0f, 1.0));
46 | StartPos /= StartPos.wwww;
47 | float4 EndPos = mul(ViewProjectionMatrixInv, float4(ClipXY, 1.0f, 1.0));
48 | EndPos /= EndPos.wwww;
49 | Ray.Origin = StartPos.xyz;
50 | Ray.Direction = normalize(EndPos.xyz - StartPos.xyz);
51 |
52 | // Trace
53 | RayPayload Payload = { float4(0.5f, 0.5f, 0.5f, 0.0f) };
54 | uint InstanceInclusionMask = 0xFF;
55 | // RayFlags: see https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#ray-flags
56 | #if CLOSESTANDANYHIT==1
57 | // By default use the closest hit shader
58 | uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES;
59 | uint RayContributionToHitGroupIndex = HitShaderClosestHitContribution;
60 | if (LaunchIndex.y < DispatchDimension.y / 2)
61 | {
62 | // If in the top part of the screen, use the any hit shader
63 | RayFlags = RAY_FLAG_FORCE_NON_OPAQUE; // force the execution of any hit shaders
64 | RayContributionToHitGroupIndex = HitShaderAnyHitContribution;
65 | }
66 | uint MultiplierForGeometryContributionToHitGroupIndex = 0;
67 | uint MissShaderIndex = 0;
68 | #else
69 | uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES;
70 | uint RayContributionToHitGroupIndex = 0;
71 | uint MultiplierForGeometryContributionToHitGroupIndex = 0;
72 | uint MissShaderIndex = 0;
73 | #endif
74 |
75 | TraceRay(Scene, RayFlags, InstanceInclusionMask, RayContributionToHitGroupIndex, MultiplierForGeometryContributionToHitGroupIndex, MissShaderIndex, Ray, Payload);
76 |
77 | // Write the raytraced color to the output texture.
78 | LuminanceRenderTarget[DispatchRaysIndex().xy] = Payload.Color;
79 | }
80 |
81 |
82 |
83 | //
84 | // Ray tracing local root signature parameters in space0
85 | //
86 |
87 | struct VertexStruct
88 | {
89 | float3 Position;
90 | float3 Normal;
91 | float2 UV;
92 | };
93 | StructuredBuffer VertexBuffer : register(t0, space0);
94 | Buffer IndexBuffer : register(t1, space0);
95 |
96 | #include "StaticSamplers.hlsl"
97 | Texture2D MeshTexture : register(t2, space0);
98 |
99 |
100 | [shader("closesthit")]
101 | void MyClosestHitShader(inout RayPayload Payload, in BuiltInTriangleIntersectionAttributes Attr)
102 | {
103 | float3 barycentrics = float3(1 - Attr.barycentrics.x - Attr.barycentrics.y, Attr.barycentrics.x, Attr.barycentrics.y);
104 |
105 | uint vertId = 3 * PrimitiveIndex();
106 | float2 uv0 = VertexBuffer[IndexBuffer[vertId] + 0].UV;
107 | float2 uv1 = VertexBuffer[IndexBuffer[vertId] + 1].UV;
108 | float2 uv2 = VertexBuffer[IndexBuffer[vertId] + 2].UV;
109 | float2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z;
110 |
111 | Payload.Color = float4(MeshTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb, 1.0);
112 | //Payload.Color = float4(barycentrics, 1);
113 | //Payload.Color = float4(WorldRayOrigin() + RayTCurrent() * WorldRayDirection(), 1.0f);
114 | }
115 |
116 | [shader("anyhit")]
117 | void MyAnyHitShader(inout RayPayload Payload, in BuiltInTriangleIntersectionAttributes Attr)
118 | {
119 | float3 barycentrics = float3(1 - Attr.barycentrics.x - Attr.barycentrics.y, Attr.barycentrics.x, Attr.barycentrics.y);
120 |
121 | uint vertId = 3 * PrimitiveIndex();
122 | float2 uv0 = VertexBuffer[IndexBuffer[vertId] + 0].UV;
123 | float2 uv1 = VertexBuffer[IndexBuffer[vertId] + 1].UV;
124 | float2 uv2 = VertexBuffer[IndexBuffer[vertId] + 2].UV;
125 | float2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z;
126 |
127 | Payload.Color = float4(barycentrics * 2 * MeshTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb, 1);
128 | AcceptHitAndEndSearch();
129 | }
130 |
131 | [shader("miss")]
132 | void MyMissShader(inout RayPayload Payload)
133 | {
134 | Payload.Color = float4(0.1, 0, 0, 1);
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/DX12Base/Dx12Utilities.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Dx12Utilities.h"
3 |
4 | #include "d3dx12.h"
5 |
6 |
7 |
8 |
9 | RenderBufferGenericDynamic::RenderBufferGenericDynamic(uint64 TotalSizeInBytes, D3D12_RESOURCE_FLAGS flags)
10 | : mRenderBuffer(TotalSizeInBytes, nullptr, flags, RenderBufferType_Default)
11 | {
12 | for (int i = 0; i < frameBufferCount; ++i)
13 | {
14 | mFrameUploadBuffers[i] = new RenderBufferGeneric(TotalSizeInBytes, nullptr, D3D12_RESOURCE_FLAG_NONE, RenderBufferType_Upload);
15 | }
16 | }
17 |
18 | RenderBufferGenericDynamic::~RenderBufferGenericDynamic()
19 | {
20 | for (int i = 0; i < frameBufferCount; ++i)
21 | {
22 | delete mFrameUploadBuffers[i];
23 | }
24 | }
25 |
26 |
27 | void* RenderBufferGenericDynamic::Map()
28 | {
29 | int frameIndex = g_dx12Device->getFrameIndex();
30 |
31 | void* ptr;
32 | mFrameUploadBuffers[frameIndex]->getD3D12Resource()->Map(0, nullptr, &ptr);
33 | ATLASSERT(mRenderBuffer.GetSizeInBytes() <= UINT_MAX);
34 | return ptr;
35 | }
36 |
37 | void RenderBufferGenericDynamic::UnmapAndUpload()
38 | {
39 | int frameIndex = g_dx12Device->getFrameIndex();
40 | mFrameUploadBuffers[frameIndex]->getD3D12Resource()->Unmap(0, nullptr);
41 |
42 | mRenderBuffer.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST);
43 | g_dx12Device->getFrameCommandList()->CopyResource(mRenderBuffer.getD3D12Resource(), mFrameUploadBuffers[frameIndex]->getD3D12Resource());
44 | }
45 |
46 |
47 |
48 |
49 | ////////////////////////////////////////////////////////////////////////////////////////////////////
50 | ////////////////////////////////////////////////////////////////////////////////////////////////////
51 | ////////////////////////////////////////////////////////////////////////////////////////////////////
52 |
53 |
54 |
55 |
56 | RenderTextureDynamic::RenderTextureDynamic(
57 | unsigned int width, unsigned int height,
58 | unsigned int depth, DXGI_FORMAT format,
59 | D3D12_RESOURCE_FLAGS flags)
60 | : mRenderTexture(width, height, depth, format, flags)
61 | {
62 | // TODO: dimension should be fetched from mRenderTexture
63 | D3D12_RESOURCE_DIMENSION dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
64 | if (depth > 1)
65 | dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
66 |
67 | D3D12_RESOURCE_DESC resourceDesc = getRenderTextureResourceDesc(D3D12_RESOURCE_DIMENSION_TEXTURE2D, width, height, depth, format, flags);
68 |
69 | uint64 textureUploadBufferSize = 0;
70 | g_dx12Device->getDevice()->GetCopyableFootprints(&resourceDesc, 0, 1, 0, nullptr, nullptr, nullptr, &textureUploadBufferSize);
71 |
72 | D3D12_RESOURCE_DESC uploadBufferDesc; // TODO upload buffer desc
73 | uploadBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
74 | uploadBufferDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
75 | uploadBufferDesc.Width = textureUploadBufferSize;
76 | uploadBufferDesc.Height = uploadBufferDesc.DepthOrArraySize = uploadBufferDesc.MipLevels = 1;
77 | uploadBufferDesc.Format = DXGI_FORMAT_UNKNOWN;
78 | uploadBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
79 | uploadBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
80 | uploadBufferDesc.SampleDesc.Count = 1;
81 | uploadBufferDesc.SampleDesc.Quality = 0;
82 | D3D12_HEAP_PROPERTIES uploadHeapProperties = getUploadMemoryHeapProperties();
83 |
84 | for (int i = 0; i < frameBufferCount; ++i)
85 | {
86 | g_dx12Device->getDevice()->CreateCommittedResource(&uploadHeapProperties,
87 | D3D12_HEAP_FLAG_NONE,
88 | &uploadBufferDesc,
89 | D3D12_RESOURCE_STATE_GENERIC_READ,
90 | nullptr,
91 | IID_PPV_ARGS(&mFrameUploadTextures[i]));
92 | setDxDebugName(mFrameUploadTextures[i], L"RenderTextureDynamicUploadHeap");
93 | }
94 |
95 | }
96 |
97 | RenderTextureDynamic::~RenderTextureDynamic()
98 | {
99 | for (int i = 0; i < frameBufferCount; ++i)
100 | {
101 | resetComPtr(&mFrameUploadTextures[i]);
102 | }
103 | }
104 |
105 | void* RenderTextureDynamic::Map()
106 | {
107 | int frameIndex = g_dx12Device->getFrameIndex();
108 |
109 | void* ptr;
110 | mFrameUploadTextures[frameIndex]->Map(0, nullptr, &ptr);
111 | return ptr;
112 | }
113 |
114 | void RenderTextureDynamic::UnmapAndUpload()
115 | {
116 | int frameIndex = g_dx12Device->getFrameIndex();
117 | mFrameUploadTextures[frameIndex]->Unmap(0, nullptr);
118 |
119 | mRenderTexture.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST);
120 |
121 | auto commandList = g_dx12Device->getFrameCommandList();
122 | commandList->CopyResource(mRenderTexture.getD3D12Resource(), mFrameUploadTextures[frameIndex]);
123 | }
124 |
125 | void RenderTextureDynamic::Upload(void* DataPtr, unsigned int RowPitchByte, unsigned int SlicePitchByte)
126 | {
127 | int frameIndex = g_dx12Device->getFrameIndex();
128 | auto commandList = g_dx12Device->getFrameCommandList();
129 |
130 | D3D12_SUBRESOURCE_DATA SubResourceData;
131 | SubResourceData.pData = DataPtr;
132 | SubResourceData.RowPitch = RowPitchByte;
133 | SubResourceData.SlicePitch = SlicePitchByte;
134 |
135 | mRenderTexture.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST);
136 |
137 | // using helper
138 | UpdateSubresources<1>(
139 | commandList,
140 | mRenderTexture.getD3D12Resource(),
141 | mFrameUploadTextures[frameIndex],
142 | 0,
143 | 0,
144 | 1,
145 | &SubResourceData);
146 | // UpdateSubresources changes the resources state
147 | }
148 |
149 |
150 |
151 |
152 | ////////////////////////////////////////////////////////////////////////////////////////////////////
153 | ////////////////////////////////////////////////////////////////////////////////////////////////////
154 | ////////////////////////////////////////////////////////////////////////////////////////////////////
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *x64/*.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
290 | *.cap
291 |
292 | imgui.ini
293 |
--------------------------------------------------------------------------------
/DX12Base/Dx12RayTracing.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Dx12Device.h"
4 |
5 |
6 |
7 | #if D_ENABLE_DXR
8 |
9 |
10 |
11 | class AccelerationStructureBuffer : public RenderBufferGeneric
12 | {
13 | public:
14 | AccelerationStructureBuffer(uint64 TotalSizeInBytes);
15 | virtual ~AccelerationStructureBuffer();
16 |
17 | private:
18 | AccelerationStructureBuffer();
19 | AccelerationStructureBuffer(AccelerationStructureBuffer&);
20 | };
21 |
22 |
23 |
24 | class StaticBottomLevelAccelerationStructureBuffer
25 | {
26 | public:
27 | StaticBottomLevelAccelerationStructureBuffer(D3D12_RAYTRACING_GEOMETRY_DESC* Meshes, uint MeshCount);
28 | virtual ~StaticBottomLevelAccelerationStructureBuffer();
29 |
30 | AccelerationStructureBuffer& GetBuffer() { return *mBlasResult; }
31 | D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress() { return mBlasResult->getGPUVirtualAddress(); }
32 |
33 | private:
34 | StaticBottomLevelAccelerationStructureBuffer();
35 | StaticBottomLevelAccelerationStructureBuffer(StaticBottomLevelAccelerationStructureBuffer&);
36 |
37 | RenderBufferGeneric* mBlasScratch;
38 | AccelerationStructureBuffer* mBlasResult;
39 | };
40 |
41 | class StaticTopLevelAccelerationStructureBuffer
42 | {
43 | public:
44 | StaticTopLevelAccelerationStructureBuffer(D3D12_RAYTRACING_INSTANCE_DESC* Instances, uint InstanceCount);
45 | virtual ~StaticTopLevelAccelerationStructureBuffer();
46 |
47 | AccelerationStructureBuffer& GetBuffer() { return *mTlasResult; }
48 | D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress() { return mTlasResult->getGPUVirtualAddress(); }
49 |
50 | private:
51 | StaticTopLevelAccelerationStructureBuffer();
52 | StaticTopLevelAccelerationStructureBuffer(StaticTopLevelAccelerationStructureBuffer&);
53 |
54 | RenderBufferGeneric* mTlasScratch;
55 | AccelerationStructureBuffer* mTlasResult;
56 | RenderBufferGeneric* mTlasInstanceBuffer;
57 | uint mInstanceCount;
58 | };
59 |
60 |
61 |
62 | class RayGenerationShader : public ShaderBase
63 | {
64 | public:
65 | RayGenerationShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros);
66 | virtual ~RayGenerationShader();
67 | };
68 |
69 | class ClosestHitShader : public ShaderBase
70 | {
71 | public:
72 | ClosestHitShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros);
73 | virtual ~ClosestHitShader();
74 | };
75 |
76 | class AnyHitShader : public ShaderBase
77 | {
78 | public:
79 | AnyHitShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros);
80 | virtual ~AnyHitShader();
81 | };
82 |
83 | class MissShader : public ShaderBase
84 | {
85 | public:
86 | MissShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros);
87 | virtual ~MissShader();
88 | };
89 |
90 | struct RayTracingPipelineStateShaderDesc
91 | {
92 | const TCHAR* mShaderFilepath;
93 | const TCHAR* mShaderEntryName;
94 | Macros mMacros;
95 | };
96 |
97 |
98 |
99 | class RayTracingPipelineStateSimple
100 | {
101 | public:
102 | RayTracingPipelineStateSimple();
103 | virtual ~RayTracingPipelineStateSimple();
104 |
105 | // Create a simple RayGen, CLosestHit and Miss shader trio.
106 | void CreateRTState(RayTracingPipelineStateShaderDesc& RayGenShaderDesc, RayTracingPipelineStateShaderDesc& ClosestHitShaderDesc, RayTracingPipelineStateShaderDesc& MissShaderDesc);
107 |
108 | ID3D12StateObject* mRayTracingPipelineStateObject; // Ray tracing pipeline
109 | ID3D12StateObjectProperties* mRayTracingPipelineStateObjectProp; // Ray tracing pipeline properties intereface
110 |
111 | // SimpleRTState
112 | RayGenerationShader* mRayGenShader;
113 | ClosestHitShader* mClosestHitShader;
114 | MissShader* mMissShader;
115 | void* mRayGenShaderIdentifier;
116 | void* mHitGroupShaderIdentifier;
117 | void* mMissShaderIdentifier;
118 | };
119 |
120 | class RayTracingPipelineStateClosestAndAnyHit
121 | {
122 | public:
123 | RayTracingPipelineStateClosestAndAnyHit();
124 | virtual ~RayTracingPipelineStateClosestAndAnyHit();
125 |
126 | // Create a simple RayGen, CLosestHit and Miss shader trio.
127 | void CreateRTState(
128 | RayTracingPipelineStateShaderDesc& RayGenShaderDesc, RayTracingPipelineStateShaderDesc& MissShaderDesc,
129 | RayTracingPipelineStateShaderDesc& ClosestHitShaderDesc, RayTracingPipelineStateShaderDesc& AnyHitShaderDesc);
130 |
131 | ID3D12StateObject* mRayTracingPipelineStateObject; // Ray tracing pipeline
132 | ID3D12StateObjectProperties* mRayTracingPipelineStateObjectProp; // Ray tracing pipeline properties intereface
133 |
134 | // SimpleRTState
135 | RayGenerationShader* mRayGenShader;
136 | MissShader* mMissShader;
137 | ClosestHitShader* mClosestHitShader;
138 | AnyHitShader* mAnyHitShader;
139 | void* mRayGenShaderIdentifier;
140 | void* mMissShaderIdentifier;
141 | void* mClosestHitGroupShaderIdentifier;
142 | void* mAnyHitGroupShaderIdentifier;
143 | };
144 |
145 |
146 |
147 | class DispatchRaysCallSBTHeapCPU
148 | {
149 | public:
150 | DispatchRaysCallSBTHeapCPU(uint SizeBytes);
151 | virtual ~DispatchRaysCallSBTHeapCPU();
152 |
153 | void BeginRecording(ID3D12GraphicsCommandList4& CommandList);
154 | void EndRecording();
155 |
156 | struct SBTMemory
157 | {
158 | void* mPtr;
159 | D3D12_GPU_VIRTUAL_ADDRESS mGPUAddress;
160 | };
161 | SBTMemory AllocateSBTMemory(const uint ByteCount);
162 |
163 | struct AllocatedSBTMemory
164 | {
165 | const RootSignature* mRtLocalRootSignature;
166 |
167 | uint mHitGroupCount;
168 | uint mHitGroupByteCount;
169 |
170 | uint mSBTByteCount;
171 | SBTMemory mSBTMemory;
172 |
173 | uint mSBTRGSStartOffsetInBytes;
174 | uint mSBTRGSSizeInBytes;
175 | uint mSBTMissStartOffsetInBytes;
176 | uint mSBTMissSizeInBytes;
177 | uint mSBTMissStrideInBytes ;
178 | uint mSBTHitGStartOffsetInBytes;
179 | uint mSBTHitGSizeInBytes;
180 | uint mSBTHitGStrideInBytes;
181 |
182 | D3D12_DISPATCH_RAYS_DESC mDispatchRayDesc;
183 |
184 | // Set local root signature parameter for hit group.
185 | void setHitGroupLocalRootSignatureParameter(uint HitGroupIndex, RootParameterByteOffset Param, void* PTR);
186 | // It is assumed that RayGen and Miss shaders only use global root parameters for now. This could be changed, they already have the local root signature assigned.
187 | };
188 |
189 | // When SBT memory is allocated, the client is in charge of setting up the memory according to the RayTracingState pipeline it has been create from.
190 | // We do check boundary when writing local root parameters in setHitGroupLocalRootSignatureParameter and that is it.
191 | AllocatedSBTMemory AllocateSimpleSBT(const RootSignature& RtLocalRootSignature, uint HitGroupCount, const RayTracingPipelineStateSimple& RTPS);
192 | AllocatedSBTMemory AllocateClosestAndAnyHitSBT(const RootSignature& RtLocalRootSignature, uint MeshInstanceCount, const RayTracingPipelineStateClosestAndAnyHit& RTPS);
193 |
194 | private:
195 | DispatchRaysCallSBTHeapCPU();
196 | DispatchRaysCallSBTHeapCPU(DispatchRaysCallSBTHeapCPU&);
197 |
198 | RenderBufferGeneric* mUploadHeapSBT;
199 | RenderBufferGeneric* mGPUSBT;
200 |
201 | byte* mCpuMemoryStart;
202 | uint mAllocatedBytes;
203 | };
204 |
205 |
206 |
207 | #endif // D_ENABLE_DXR
208 |
209 |
210 |
--------------------------------------------------------------------------------
/Application/WinMain.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Dx12Base/WindowHelper.h"
3 | #include "Dx12Base/Dx12Device.h"
4 |
5 | #include "Game.h"
6 |
7 | #include "WinImgui.h"
8 |
9 |
10 | bool ImguiTopLayerProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
11 | {
12 | ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam);
13 | return ImGui::GetIO().WantCaptureKeyboard || ImGui::GetIO().WantCaptureMouse;
14 | }
15 |
16 | static uint PreviousResolutionWidth = 0;
17 | static uint PreviousResolutionHeight = 0;
18 |
19 | // the entry point for any Windows program
20 | int WINAPI WinMain(
21 | HINSTANCE hInstance,
22 | HINSTANCE hPrevInstance,
23 | LPSTR lpCmdLine,
24 | int nCmdShow)
25 | {
26 | static bool sVSyncEnable = true;
27 | static bool sStablePowerEnable = false;
28 | static bool sPreviousStablePowerEnable = !sStablePowerEnable;
29 | static float sTimerGraphWidth = 18.0f;
30 |
31 | // Get a window size that matches the desired client size
32 | const unsigned int desiredPosX = 20;
33 | const unsigned int desiredPosY = 20;
34 | const unsigned int desiredClientWidth = 1280;
35 | const unsigned int desiredClientHeight = 720;
36 | RECT clientRect;
37 | clientRect.left = desiredPosX;
38 | clientRect.right = desiredPosX + desiredClientWidth;
39 | clientRect.bottom = desiredPosY + desiredClientHeight;
40 | clientRect.top = desiredPosY;
41 |
42 | // Create the window
43 | WindowHelper win(hInstance, clientRect, nCmdShow, L"D3D12 Application");
44 | win.showWindow();
45 |
46 | // Create the d3d device
47 | PreviousResolutionWidth = desiredClientWidth;
48 | PreviousResolutionHeight = desiredClientHeight;
49 | Dx12Device::initialise(win.getHwnd(), desiredClientWidth, desiredClientHeight);
50 | CachedPSOManager::initialise();
51 |
52 | WinImguiInitialise(win.getHwnd());
53 |
54 | // Create the game
55 | Game game;
56 |
57 | // Register the resize callback
58 | auto windowResizedCallback = [&](LPARAM lParam)
59 | {
60 | // No threading mechanism so safe to do update call from here.
61 | uint newWidth = LOWORD(lParam);
62 | uint newHeight = HIWORD(lParam);
63 |
64 | // When moving the window around, we can still get a size callback. So we check for an actual change of resolution.
65 | if (newWidth != PreviousResolutionWidth || newHeight != PreviousResolutionHeight)
66 | {
67 | // ImGui_ImplDX12_InvalidateDeviceObjects(); // This is in fact wrong: sone imgui resource can still be in flight in a commandlist. Also this is only needed if we recreate the device.
68 | const bool bRecreate = true;
69 | g_dx12Device->updateSwapChain(bRecreate, newWidth, newHeight);
70 | // ImGui_ImplDX12_CreateDeviceObjects();
71 |
72 | game.reallocateResolutionDependent(newWidth, newHeight);
73 |
74 | PreviousResolutionWidth = newWidth;
75 | PreviousResolutionHeight = newHeight;
76 | }
77 | };
78 | win.setWindowResizedCallback(windowResizedCallback);
79 |
80 | MSG msg = { 0 };
81 | while (true)
82 | {
83 | bool msgValid = win.translateSingleMessage(msg);
84 |
85 | if (msgValid)
86 | {
87 | const bool bMessageInterceptedByTopLayer = ImguiTopLayerProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam);
88 | if (!bMessageInterceptedByTopLayer)
89 | {
90 | if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
91 | break;// process escape key
92 |
93 | if (msg.message == WM_QUIT)
94 | break; // time to quit
95 |
96 | // A message has been processed and not consumed by imgui. Send the message to the WindowProc function.
97 | DispatchMessage(&msg);
98 | }
99 | }
100 | else
101 | {
102 | // Game update
103 | game.update(win.getInputData());
104 |
105 | // Game render
106 | g_dx12Device->beginFrame();
107 |
108 | {
109 | SCOPED_GPU_TIMER(RenderFrame, 200, 200, 200);
110 |
111 | static bool initDone = false;
112 | if (!initDone)
113 | {
114 | game.initialise();
115 | initDone = true;
116 | }
117 |
118 | WinImguiNewFrame();
119 | game.render();
120 |
121 | ImGui::SetNextWindowSize(ImVec2(400.0f, 400.0f), ImGuiCond_FirstUseEver);
122 | ImGui::Begin("GPU performance");
123 | Dx12Device::GPUTimersReport TimerReport = g_dx12Device->GetGPUTimerReport();
124 | if (TimerReport.mLastValidGPUTimerSlotCount > 0)
125 | {
126 | UINT64 StartTime = TimerReport.mLastValidTimeStamps[TimerReport.mLastValidGPUTimers[0].mQueryIndexStart];
127 | double TickPerSeconds = double(TimerReport.mLastValidTimeStampTickPerSeconds);
128 |
129 | static float sTimerGraphWidthMs = 33.0f;
130 | ImGui::Checkbox("VSync", &sVSyncEnable);
131 | #ifdef _DEBUG
132 | ImGui::Checkbox("StablePower", &sStablePowerEnable);
133 | #endif
134 | ImGui::SliderFloat("TimerGraphWidth (ms)", &sTimerGraphWidthMs, 1.0, 60.0);
135 |
136 | ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
137 | ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f));
138 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
139 | ImGui::BeginChild("Timer graph", ImVec2(0, 150), true, ImGuiWindowFlags_HorizontalScrollbar);
140 | const float WindowPixelWidth = ImGui::GetWindowWidth();
141 | const float PixelPerMs = WindowPixelWidth / sTimerGraphWidthMs;
142 | #if 1
143 | for (int targetLevel = 0; targetLevel < 8; ++targetLevel)
144 | {
145 | bool printDone = false;
146 | for (UINT i=0; i>8) & 0xFF, int(Timer.mRGBA>>16) & 0xFF, int(Timer.mRGBA>>24) & 0xFF);
159 | ImGui::PushStyleColor(ImGuiCol_Button, color);
160 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
161 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
162 | {
163 | // Set cursor to the correct position and size according to when things started this day
164 | ImGui::SetCursorPosX(TimerStartMs * PixelPerMs);
165 | ImGui::PushItemWidth(TimerEndMs * PixelPerMs);
166 |
167 | char debugStr[128];
168 | sprintf_s(debugStr, 128, "%ls %.3f ms\n", Timer.mEventName, DurationMs);
169 | ImGui::Button(debugStr, ImVec2(DurationMs * PixelPerMs, 0.0f));
170 | if (ImGui::IsItemHovered())
171 | {
172 | ImGui::SetTooltip(debugStr);
173 | }
174 | ImGui::SameLine();
175 | ImGui::PopItemWidth();
176 | }
177 | ImGui::PopStyleColor(3);
178 | printDone = true;
179 | }
180 | }
181 | if (printDone)
182 | ImGui::NewLine(); // start a new line if anything has been printed
183 | }
184 | #endif
185 | ImGui::EndChild();
186 | ImGui::PopStyleVar(3);
187 |
188 | {
189 | char debugStr[256];
190 | sprintf_s(debugStr, 256, "Cached Raster PSO count %zu", g_CachedPSOManager->GetCachedRasterPSOCount());
191 | ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), debugStr);
192 | sprintf_s(debugStr, 256, "Cached compute PSO count %zu", g_CachedPSOManager->GetCachedComputePSOCount());
193 | ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), debugStr);
194 | }
195 |
196 | for (UINT i = 0; i < TimerReport.mLastValidGPUTimerSlotCount; ++i)
197 | {
198 | Dx12Device::GPUTimer& Timer = TimerReport.mLastValidGPUTimers[i];
199 | float TimerStart = float(double(TimerReport.mLastValidTimeStamps[Timer.mQueryIndexStart] - StartTime) / TickPerSeconds);
200 | float TimerEnd = float(double(TimerReport.mLastValidTimeStamps[Timer.mQueryIndexEnd] - StartTime) / TickPerSeconds);
201 | float TimerStartMs = TimerStart * 1000.0f;
202 | float TimerEndMs = TimerEnd * 1000.0f;
203 | float DurationMs = TimerEndMs - TimerStartMs;
204 |
205 | char* levelOffset = "---------------"; // 16 chars
206 | unsigned int levelShift = 16 - 2 * Timer.mLevel - 1;
207 | char* levelOffsetPtr = levelOffset + (levelShift < 0 ? 0 : levelShift); // cheap way to add shifting to a printf
208 |
209 | char debugStr[128];
210 | sprintf_s(debugStr, 128, "%s%ls %.3f ms\n", levelOffsetPtr, Timer.mEventName, DurationMs);
211 | ImU32 color = ImColor(int(Timer.mRGBA) & 0xFF, int(Timer.mRGBA >> 8) & 0xFF, int(Timer.mRGBA >> 16) & 0xFF, int(Timer.mRGBA >> 24) & 0xFF);
212 | ImGui::TextColored(ImVec4(float(int(Timer.mRGBA) & 0xFF) / 255.0f, float(int(Timer.mRGBA >> 8) & 0xFF) / 255.0f, float(int(Timer.mRGBA >> 16) & 0xFF) / 255.0f, 255.0f), debugStr);
213 | }
214 | }
215 | ImGui::End();
216 |
217 | WinImguiRender();
218 | }
219 |
220 | // Swap the back buffer
221 | g_dx12Device->endFrameAndSwap(sVSyncEnable);
222 |
223 | #if 0 // SetStablePowerState is only available when developer mode is enabled. So it is deisabled by default.
224 | if (sPreviousStablePowerEnable != sStablePowerEnable)
225 | {
226 |
227 | sPreviousStablePowerEnable = sStablePowerEnable;
228 | HRESULT hr = g_dx12Device->getDevice()->SetStablePowerState(sStablePowerEnable);
229 | ATLASSERT(hr == S_OK);
230 | }
231 | #endif
232 |
233 | // Events have all been processed in this path by the game
234 | win.clearInputEvents();
235 | }
236 | }
237 |
238 | g_dx12Device->closeBufferedFramesBeforeShutdown(); // close all frames
239 |
240 | WinImguiShutdown();
241 | game.shutdown(); // game release its resources
242 | CachedPSOManager::shutdown(); // release the cached PSOs
243 | Dx12Device::shutdown(); // now we can safely delete the dx12 device we hold
244 |
245 | // End of application
246 | return 0;
247 | }
248 |
249 |
250 |
--------------------------------------------------------------------------------
/DX12Base/DX12Base.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}
23 | Win32Proj
24 | DX12Base
25 | 10.0.18362.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | Unicode
40 |
41 |
42 | StaticLibrary
43 | true
44 | v141
45 | Unicode
46 |
47 |
48 | StaticLibrary
49 | false
50 | v141
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\
78 | C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um;$(ExecutablePath)
79 |
80 |
81 | false
82 |
83 |
84 | true
85 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\
86 | C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um;$(ExecutablePath)
87 |
88 |
89 |
90 |
91 |
92 | Level3
93 | Disabled
94 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
95 | true
96 |
97 |
98 | Windows
99 | true
100 |
101 |
102 |
103 |
104 |
105 |
106 | Level3
107 | Disabled
108 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
109 | true
110 |
111 |
112 |
113 |
114 | Windows
115 | true
116 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
117 |
118 |
119 | C:\Program Files %28x86%29\Windows Kits\10\bin\10.0.18362.0\x64;%(AdditionalLibraryDirectories)
120 | dxcompiler.lib;d3d12.lib;dxgi.lib;d3dcompiler.lib;
121 |
122 |
123 |
124 |
125 | Level3
126 |
127 |
128 | MaxSpeed
129 | true
130 | true
131 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
132 | true
133 |
134 |
135 | Windows
136 | true
137 | true
138 | true
139 |
140 |
141 |
142 |
143 | Level3
144 |
145 |
146 | Full
147 | true
148 | true
149 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
150 | true
151 | $(IntDir)
152 | $(IntDir)
153 | $(IntDir)
154 | $(IntDir)
155 |
156 |
157 | Windows
158 | true
159 | true
160 | DebugFastLink
161 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
162 |
163 |
164 | C:\Program Files %28x86%29\Windows Kits\10\bin\10.0.18362.0\x64;%(AdditionalLibraryDirectories)
165 | dxcompiler.lib;d3d12.lib;dxgi.lib;d3dcompiler.lib;
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
195 |
196 |
197 |
198 |
--------------------------------------------------------------------------------
/DX12Base/WindowHelper.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "WindowHelper.h"
3 |
4 | static UINT LastSizeMessage = 0;
5 | static WPARAM LastSizewParam = 0;
6 | static LPARAM LastSizelParam = 0;
7 |
8 | LRESULT CALLBACK WindowProcess(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
9 | {
10 | WindowHelper *window = (WindowHelper*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
11 |
12 | switch (message)
13 | {
14 | case WM_DESTROY:
15 | PostQuitMessage(0);
16 | return 0;
17 | break;
18 | }
19 |
20 | switch (message)
21 | {
22 | case WM_MOUSEMOVE:
23 | case WM_LBUTTONDOWN:
24 | case WM_RBUTTONDOWN:
25 | case WM_MBUTTONDOWN:
26 | case WM_LBUTTONUP:
27 | case WM_RBUTTONUP:
28 | case WM_MBUTTONUP:
29 | case WM_LBUTTONDBLCLK:
30 | case WM_RBUTTONDBLCLK:
31 | case WM_MBUTTONDBLCLK:
32 | case WM_NCMOUSELEAVE:
33 | case WM_MOUSEWHEEL:
34 | case WM_MOUSEHWHEEL:
35 | window->processMouseMessage(message, wParam, lParam);
36 | break;
37 |
38 | case WM_KEYDOWN:
39 | case WM_KEYUP:
40 | case WM_CHAR:
41 | case WM_SYSCHAR:
42 | window->processKeyMessage(message, wParam, lParam);
43 | break;
44 |
45 | case WM_EXITSIZEMOVE:
46 | window->processWindowSizeMessage(LastSizeMessage, LastSizewParam, LastSizelParam);
47 | SetForegroundWindow(hWnd);
48 | return true;
49 | break;
50 |
51 | case WM_SIZE:
52 | if (wParam != SIZE_MINIMIZED)
53 | {
54 | // This is a spammy event, let's resize only when stopping the resizing using the WM_EXITSIZEMOVE event.
55 | // This has the benefit to not ask for too many resolutino depenent descriptors to be created and go out of the current limit (simple linear array)
56 | LastSizeMessage = message;
57 | LastSizewParam = wParam;
58 | LastSizelParam = lParam;
59 | // Disabled because this locks down the program
60 | // window->processWindowSizeMessage(message, wParam, lParam);
61 | // return true;
62 | }
63 | break;
64 |
65 | //case WM_SIZING: // When receiving that message, the backbuffer we get is null for some reason. Would be good to still see image on screen.
66 | //Also it seems that this is not even enough to handle a window going full screen. Using Atl+Enter make things crash of lock up.
67 | }
68 |
69 | // Handle any messages the switch statement didn't
70 | return DefWindowProc(hWnd, message, wParam, lParam);
71 | }
72 |
73 |
74 | WindowHelper::WindowHelper(HINSTANCE hInstance, const RECT& clientRect, int nCmdShow, LPCWSTR windowName)
75 | : mHInstance(hInstance)
76 | , mNCmdShow(nCmdShow)
77 | , mClientRect(clientRect)
78 | {
79 | mInput.init();
80 |
81 | // And create the rectangle that will allow it
82 | RECT rect = { 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top }; // set the size, but not the position otherwise does not seem to work
83 | DWORD style = (WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); // WS_OVERLAPPED without edge resize, WS_OVERLAPPEDWINDOW with
84 | BOOL menu = false;
85 | AdjustWindowRect(&rect, style, menu);
86 | //Get the required window dimensions
87 | int WindowWidth = rect.right - rect.left; //Required width
88 | //WindowWidth += (2 * GetSystemMetrics(SM_CXFIXEDFRAME)); //Add frame widths
89 | int WindowHeight = rect.bottom - rect.top; //Required height
90 | //WindowHeight += GetSystemMetrics(SM_CYCAPTION); //Titlebar height
91 | //WindowHeight += GetSystemMetrics(SM_CYMENU); //Uncomment for menu bar height
92 | //WindowHeight += (2 * GetSystemMetrics(SM_CYFIXEDFRAME)); //Frame heights
93 |
94 | // clear out the window class for use
95 | ZeroMemory(&mWc, sizeof(WNDCLASSEX));
96 | // fill in the struct with the needed information
97 | mWc.cbSize = sizeof(WNDCLASSEX);
98 | mWc.style = CS_HREDRAW | CS_VREDRAW;
99 | mWc.lpfnWndProc = WindowProcess;
100 | mWc.hInstance = mHInstance;
101 | mWc.hCursor = LoadCursor(NULL, IDC_ARROW);
102 | mWc.hbrBackground = (HBRUSH)COLOR_WINDOW;
103 | mWc.lpszClassName = L"WindowClass1";
104 |
105 | // register the window class
106 | RegisterClassEx(&mWc);
107 |
108 | // create the window and use the result as the handle
109 | mHWnd = CreateWindowEx(NULL,
110 | L"WindowClass1", // name of the window class
111 | windowName, // title of the window
112 | style, // not resizable
113 | clientRect.top, // x-position of the window
114 | clientRect.left, // y-position of the window
115 | WindowWidth, // width of the window
116 | WindowHeight, // height of the window
117 | NULL, // we have no parent window, NULL
118 | NULL, // we aren't using menus, NULL
119 | hInstance, // application handle
120 | NULL); // used with multiple windows, NULL
121 |
122 | SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)(this));
123 | SetWindowPos(mHWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); // Make sure the pointer is cached https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowlongptra
124 | }
125 |
126 | WindowHelper::~WindowHelper()
127 | {
128 | }
129 |
130 |
131 | void WindowHelper::showWindow()
132 | {
133 | ShowWindow(mHWnd, mNCmdShow);
134 | }
135 |
136 | bool WindowHelper::translateSingleMessage(MSG& msg)
137 | {
138 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
139 | {
140 | // translate keystroke messages into the right format
141 | TranslateMessage(&msg);
142 |
143 | // Message translated
144 | return true;
145 | }
146 |
147 | // No message translated
148 | return false;
149 | }
150 |
151 | void WindowHelper::processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam)
152 | {
153 | // TODO WM_NCMOUSELEAVE
154 |
155 | mInput.mInputStatus.mouseX = LOWORD(lParam);
156 | mInput.mInputStatus.mouseY = HIWORD(lParam);
157 |
158 | InputEvent event;
159 | event.mouseX = mInput.mInputStatus.mouseX;
160 | event.mouseY = mInput.mInputStatus.mouseY;
161 | switch (message)
162 | {
163 | case WM_MOUSEMOVE:
164 | event.type = etMouseMoved;
165 | break;
166 | case WM_LBUTTONDOWN:
167 | event.type = etMouseButtonDown;
168 | event.mouseButton = mbLeft;
169 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true;
170 | break;
171 | case WM_MBUTTONDOWN:
172 | event.type = etMouseButtonDown;
173 | event.mouseButton = mbMiddle;
174 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true;
175 | break;
176 | case WM_RBUTTONDOWN:
177 | event.type = etMouseButtonDown;
178 | event.mouseButton = mbRight;
179 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true;
180 | break;
181 | case WM_LBUTTONUP:
182 | event.type = etMouseButtonUp;
183 | event.mouseButton = mbLeft;
184 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false;
185 | break;
186 | case WM_MBUTTONUP:
187 | event.type = etMouseButtonUp;
188 | event.mouseButton = mbMiddle;
189 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false;
190 | break;
191 | case WM_RBUTTONUP:
192 | event.type = etMouseButtonUp;
193 | event.mouseButton = mbRight;
194 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false;
195 | break;
196 | case WM_LBUTTONDBLCLK:
197 | event.type = etMouseButtonDoubleClick;
198 | event.mouseButton = mbLeft;
199 | break;
200 | case WM_MBUTTONDBLCLK:
201 | event.type = etMouseButtonDoubleClick;
202 | event.mouseButton = mbMiddle;
203 | break;
204 | case WM_RBUTTONDBLCLK:
205 | event.type = etMouseButtonDoubleClick;
206 | event.mouseButton = mbRight;
207 | break;
208 |
209 | // TODO
210 | //case WM_MOUSEWHEEL:
211 | //case WM_MOUSEHWHEEL:
212 | }
213 | mInput.mInputEvents.push_back(event);
214 | }
215 |
216 | static InputKey translateKey(WPARAM wParam)
217 | {
218 | switch (wParam)
219 | {
220 | case VK_RIGHT: return kRight;
221 | case VK_LEFT: return kLeft;
222 | case VK_DOWN: return kDown;
223 | case VK_UP: return kUp;
224 | case VK_SPACE: return kSpace;
225 | case VK_NUMPAD0: return kNumpad0;
226 | case VK_NUMPAD1: return kNumpad1;
227 | case VK_NUMPAD2: return kNumpad2;
228 | case VK_NUMPAD3: return kNumpad3;
229 | case VK_NUMPAD4: return kNumpad4;
230 | case VK_NUMPAD5: return kNumpad5;
231 | case VK_NUMPAD6: return kNumpad6;
232 | case VK_NUMPAD7: return kNumpad7;
233 | case VK_NUMPAD8: return kNumpad8;
234 | case VK_NUMPAD9: return kNumpad9;
235 | case VK_MULTIPLY: return kMultiply;
236 | case VK_ADD: return kAdd;
237 | case VK_SEPARATOR: return kSeparator;
238 | case VK_SUBTRACT: return kSubtract;
239 | case VK_DECIMAL: return kDecimal;
240 | case VK_DIVIDE: return kDivide;
241 | case VK_F1: return kF1;
242 | case VK_F2: return kF2;
243 | case VK_F3: return kF3;
244 | case VK_F4: return kF4;
245 | case VK_F5: return kF5;
246 | case VK_F6: return kF6;
247 | case VK_F7: return kF7;
248 | case VK_F8: return kF8;
249 | case VK_F9: return kF9;
250 | case VK_F10: return kF10;
251 | case VK_F11: return kF11;
252 | case VK_F12: return kF12;
253 | case VK_SHIFT: return kShift;
254 | case VK_CONTROL: return kControl;
255 |
256 | case '0': return k0;
257 | case '1': return k1;
258 | case '2': return k2;
259 | case '3': return k3;
260 | case '4': return k4;
261 | case '5': return k5;
262 | case '6': return k6;
263 | case '7': return k7;
264 | case '8': return k8;
265 | case '9': return k9;
266 | case 'A': return kA;
267 | case 'B': return kB;
268 | case 'C': return kC;
269 | case 'D': return kD;
270 | case 'E': return kE;
271 | case 'F': return kF;
272 | case 'G': return kG;
273 | case 'H': return kH;
274 | case 'I': return kI;
275 | case 'J': return kJ;
276 | case 'K': return kK;
277 | case 'L': return kL;
278 | case 'M': return kM;
279 | case 'N': return kN;
280 | case 'O': return kO;
281 | case 'P': return kP;
282 | case 'Q': return kQ;
283 | case 'R': return kR;
284 | case 'S': return kS;
285 | case 'T': return kT;
286 | case 'U': return kU;
287 | case 'V': return kV;
288 | case 'W': return kW;
289 | case 'X': return kX;
290 | case 'Y': return kY;
291 | case 'Z': return kZ;
292 |
293 | // TODO VK_GAMEPAD
294 |
295 | default:
296 | return kUnknown;
297 | }
298 | }
299 |
300 | void WindowHelper::processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam)
301 | {
302 | InputEvent event;
303 | event.mouseX = mInput.mInputStatus.mouseX;
304 | event.mouseY = mInput.mInputStatus.mouseY;
305 |
306 | event.key = translateKey(wParam);
307 | if (event.key == kUnknown)
308 | return; // unkown key so do not register the event.
309 |
310 | switch (message)
311 | {
312 | case WM_KEYDOWN:
313 | event.type = etKeyDown;
314 | mInput.mInputStatus.keys[event.key] = true;
315 | break;
316 | case WM_KEYUP:
317 | event.type = etKeyUp;
318 | mInput.mInputStatus.keys[event.key] = false;
319 | break;
320 |
321 | case WM_SYSCHAR:
322 | case WM_CHAR:
323 | event.type = etKeyChar;
324 | break;
325 | }
326 |
327 | if (event.key == kControl)
328 | {
329 | mInput.mInputStatus.keys[kLcontrol] = GetKeyState(VK_LCONTROL)!=0;
330 | mInput.mInputStatus.keys[kRcontrol] = GetKeyState(VK_RCONTROL)!=0;
331 | }
332 | else if (event.key == kShift)
333 | {
334 | mInput.mInputStatus.keys[kLshift] = GetKeyState(VK_LSHIFT)!=0;
335 | mInput.mInputStatus.keys[kRshift] = GetKeyState(VK_RSHIFT)!=0;
336 | }
337 |
338 | mInput.mInputEvents.push_back(event);
339 | }
340 |
341 | void WindowHelper::processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam)
342 | {
343 | mWindowResizedCallback(lParam);
344 | }
345 |
346 |
347 |
--------------------------------------------------------------------------------
/Application/Application.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}
23 | Win32Proj
24 | Application
25 | 10.0.18362.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v141
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v141
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\
78 |
79 |
80 | false
81 |
82 |
83 | true
84 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\
85 |
86 |
87 |
88 |
89 |
90 | Level3
91 | Disabled
92 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Windows
97 | true
98 |
99 |
100 |
101 |
102 |
103 |
104 | Level3
105 | Disabled
106 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS
107 | true
108 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories)
109 |
110 |
111 | Windows
112 | true
113 | dx12Base.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
114 | $(TargetDir)
115 |
116 |
117 |
118 |
119 | Level3
120 |
121 |
122 | MaxSpeed
123 | true
124 | true
125 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
126 | true
127 |
128 |
129 | Windows
130 | true
131 | true
132 | true
133 |
134 |
135 |
136 |
137 | Level3
138 |
139 |
140 | Full
141 | true
142 | true
143 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS
144 | true
145 | $(IntDir)
146 | $(IntDir)
147 | $(IntDir)
148 | $(IntDir)
149 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories)
150 |
151 |
152 | Windows
153 | true
154 | true
155 | DebugFastLink
156 | dx12Base.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
157 | $(TargetDir)
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 | true
188 | true
189 |
190 |
191 | true
192 | true
193 |
194 |
195 | true
196 | true
197 |
198 |
199 | true
200 | true
201 | true
202 | true
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
215 |
216 |
217 |
218 |
--------------------------------------------------------------------------------
/DirectXTex/ReadMe.txt:
--------------------------------------------------------------------------------
1 | DIRECTX TEXTURE LIBRARY (DirectXTex)
2 | ------------------------------------
3 |
4 | Copyright (c) Microsoft Corporation. All rights reserved.
5 |
6 | July 26, 2017
7 |
8 | This package contains DirectXTex, a shared source library for reading and writing DDS
9 | files, and performing various texture content processing operations including
10 | resizing, format conversion, mip-map generation, block compression for Direct3D runtime
11 | texture resources, and height-map to normal-map conversion. This library makes
12 | use of the Windows Image Component (WIC) APIs. It also includes simple .TGA and .HDR
13 | readers and writers since these image file formats are commonly used for texture content
14 | processing pipelines, but are not currently supported by a built-in WIC codec.
15 |
16 | The source is written for Visual Studio 2013 or 2015. It is recommended that you
17 | make use of VS 2013 Update 5 or VS 2015 Update 3 and Windows 7 Service Pack 1 or later.
18 |
19 | DirectXTex\
20 | This contains the DirectXTex library. This includes a full-featured DDS reader and writer
21 | including legacy format conversions, a TGA reader and writer, a HDR reader and writer,
22 | a WIC-based bitmap reader and writer (BMP, JPEG, PNG, TIFF, and HD Photo), and various
23 | texture processing functions. This is intended primarily for tool usage.
24 |
25 | Note that the majority of the header files here are intended for internal implementation
26 | of the library only (BC.h, BCDirectCompute.h, DDS.h, DirectXTexP.h, filters.h, and scoped.h).
27 | Only DirectXTex.h is meant as a 'public' header for the library.
28 |
29 | Texconv\
30 | This DirectXTex sample is an implementation of the "texconv" command-line texture utility
31 | from the DirectX SDK utilizing DirectXTex rather than D3DX.
32 |
33 | It supports the same arguments as the Texture Conversion Tool Extended (texconvex.exe) DirectX
34 | SDK utility. The primary differences are the -10 and -11 arguments are not applicable and the
35 | filter names (POINT, LINEAR, CUBIC, FANT or BOX, TRIANGLE, *_DITHER, *_DITHER_DIFFUSION).
36 | This also includes support for the JPEG XR (HD Photo) bitmap format.
37 | (see )
38 |
39 | See for details.
40 |
41 | Texassemble\
42 | This DirectXTex sample is a command-line utility for creating cubemaps, volume maps, or
43 | texture arrays from a set of individual input image files.
44 |
45 | See for details.
46 |
47 | Texdiag\
48 | This DirectXTex sample is a command-line utility for analyzing image contents, primarily for
49 | debugging purposes.
50 |
51 | See
52 |
53 | DDSView\
54 | This DirectXTex sample is a simple Direct3D 11-based viewer for DDS files. For array textures
55 | or volume maps, the "<" and ">" keyboard keys will show different images contained in the DDS.
56 | The "1" through "0" keys can also be used to jump to a specific image index.
57 |
58 | DDSTextureLoader\
59 | This contains a streamlined version of the DirectX SDK sample DDSWithoutD3DX11 texture
60 | loading code for a simple light-weight runtime DDS loader. This version only supports
61 | Direct3D 11 or Direct3D 12 and performs no runtime pixel data conversions (i.e. 24bpp
62 | legacy DDS files always fail). This is ideal for runtime usage, and supports the full
63 | complement of Direct3D texture resources (1D, 2D, volume maps, cubemaps, mipmap levels,
64 | texture arrays, BC formats, etc.).
65 |
66 | ScreenGrab\
67 | This contains screen grab modules for Direct3D 11 and Direct3D 12 primarily intended
68 | for creating screenshots. The images are written as a DDS or as an image file format
69 | using WIC.
70 |
71 | WICTextureLoader\
72 | This contains a Direct3D 11 and Direct3D 12 2D texture loader that uses WIC to load a
73 | bitmap (BMP, JPEG, PNG, HD Photo, or other WIC supported file container), resize if needed
74 | based on the current feature level (or by explicit parameter), format convert to a
75 | DXGI_FORMAT if required, and then create a 2D texture. Note this does not support 1D textures,
76 | volume textures, cubemaps, or texture arrays. DDSTextureLoader is recommended for fully
77 | "precooked" textures for maximum performance and image quality, but this loader can be useful
78 | for creating simple 2D texture from standard image files at runtime.
79 |
80 | NOTE: DDSTextureLoader, ScreenGrab, and WICTextureLoader are 'stand-alone' versions of the same
81 | modules provided in the DirectX Tool Kit.
82 |
83 | All content and source code for this package are subject to the terms of the MIT License.
84 | .
85 |
86 | Documentation is available at .
87 |
88 | For the latest version of DirectXTex, bug reports, etc. please visit the project site.
89 |
90 | http://go.microsoft.com/fwlink/?LinkId=248926
91 |
92 | This project has adopted the Microsoft Open Source Code of Conduct. For more information see the
93 | Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
94 |
95 | https://opensource.microsoft.com/codeofconduct/
96 |
97 |
98 | ------------------------------------
99 | RELEASE NOTES
100 |
101 | * The alpha mode specification for DDS files was updated between the March 2013 and April 2013 releases. Any
102 | DDS files created using the DDS_FLAGS_FORCE_DX10_EXT_MISC2 flag or the texconv -dx10 switch using the
103 | March 2013 release should be refreshed.
104 |
105 | * Due to the underlying Windows BMP WIC codec, alpha channels are not supported for 16bpp or 32bpp BMP pixel format
106 | files. The Windows 8.x and Windows 10 version of the Windows BMP WIC codec does support 32bpp pixel formats with
107 | alpha when using the BITMAPV5HEADER file header. Note the updated WIC is available on Windows 7 SP1 with KB 2670838
108 | installed.
109 |
110 | * While DXGI 1.0 and DXGI 1.1 include 5:6:5 (DXGI_FORMAT_B5G6R5_UNORM) and 5:5:5:1 (DXGI_FORMAT_B5G5R5A1_UNORM)
111 | pixel format enumerations, the DirectX 10.x and 11.0 Runtimes do not support these formats for use with Direct3D.
112 | The DirectX 11.1 runtime, DXGI 1.2, and the WDDM 1.2 driver model fully support 16bpp formats (5:6:5, 5:5:5:1, and
113 | 4:4:4:4).
114 |
115 | * WICTextureLoader cannot load .TGA or .HDR files unless the system has a 3rd party WIC codec installed. You
116 | must use the DirectXTex library for TGA/HDR file format support without relying on an add-on WIC codec.
117 |
118 | * Loading of 96bpp floating-point TIFF files results in a corrupted image prior to Windows 8. This fix is available
119 | on Windows 7 SP1 with KB 2670838 installed.
120 |
121 |
122 | ------------------------------------
123 | RELEASE HISTORY
124 |
125 | July 26, 2017
126 | Support for reading non-standard DDS files written by nVidia Texture Tools (NVTT)
127 | Fix for ComputeMSE when using CMSE_IMAGE2_X2_BIAS
128 | Fix for WIC writer then codec target format requires a palette
129 | Code cleanup
130 |
131 | April 24, 2017
132 | VS 2017 project updates
133 | Regenerated shaders using Windows 10 Creators Update SDK (15063)
134 | Updated D3DX12 internal copy to latest version
135 |
136 | April 7, 2017
137 | VS 2017 updated for Windows Creators Update SDK (15063)
138 | texassemble: -tonemap switch
139 | texconv: -wicmulti switch
140 |
141 | January 31, 2017
142 | DirectX 12 versions of IsSupported, CreateTexture (PrepareUpload), and CaptureTexture
143 | Update to DirectX 11 version of IsSupported
144 | WIC format 40bppCMYKAlpha should be converted to RGBA8 rather than RGBA16
145 | DDS support for L8A8 with bitcount 8 rather than 16
146 | DXGI_FORMAT_R32G8X24_TYPELESS and DXGI_FORMAT_R24G8_TYPELESS should be IsDepthStencil formats
147 | Updates to DDSTextureLoader, ScreenGrab, and WICTextureLoader
148 | Minor code cleanup
149 |
150 | December 5, 2016
151 | Fixed over-validation in DDS header parsing
152 | VS 2017 RC projects added
153 | Minor code cleanup
154 |
155 | October 5, 2016
156 | *breaking change*
157 | Renamed Evaluate to EvaluateImage, Transform to TransformImage
158 | texdiag: new command-line tool for texture debugging
159 | texconv: -bcmax, -bcquick, -tonemap, and -x2bias switches
160 | texconv: overwrite writing and -y switch
161 | texconv/texassemble: optional OpenEXR support
162 | texassemble: command syntax with support for generating strip and cross images from cubemap
163 | Updates to DDSTextureLoader, WICTextureLoader, and ScreenGrab
164 | Minor code cleanup
165 |
166 | September 14, 2016
167 | HDR (RGBE Radiance) file format reader and writer
168 | Evaluate and Transform functions for computing user-defined functions on images
169 | Fix BC6H GPU shaders on WARP device
170 | Fix for alignment issues on ARM devices in software compression codec
171 | Added TEX_THRESHOLD_DEFAULT (0.5f) constant default alpha threshold value for Convert & Compress
172 | Minor CaptureTexture optimization
173 | texconv/texassemble: Support for .hdr file format
174 | texconv: added -gpu switch to specify adapter to use for GPU-based compression codecs
175 | texconv: added -badtails switch to enable loading of legacy DXTn DDS files with incomplete mipchain tails
176 | texconv: added -c switch for old-school colorkey/chromakey transparency to alpha conversion
177 | texconv: added -alpha switch for reverse premultiply along with TEX_PMALPHA_REVERSE flag
178 | texconv: added wildcard support for input filename and optional -r switch for recursive search
179 |
180 | August 4, 2016
181 | CompileShader script updated to build external pdbs
182 | Regenerated shaders using Windows 10 Anniversary Update SDK (14393)
183 |
184 | August 2, 2016
185 | Updated for VS 2015 Update 3 and Windows 10 SDK (14393)
186 |
187 | August 1, 2016
188 | Workaround for bug in XMStoreFloat3SE (impacts conversions to DXGI_FORMAT_R9G9B9E5_SHAREDEXP)
189 | DDSTextureLoader12, WICTextureLoader12, and ScreenGrab12 for Direct3D 12 support
190 | Minor code cleanup
191 |
192 | June 27, 2016
193 | texconv command-line tool -wicq and -wiclossless switches
194 | Code cleanup
195 |
196 | April 26, 2016
197 | Optional callback from WIC reader functions to query additional metadata
198 | Retired obsolete adapter code
199 | Minor code cleanup
200 |
201 | February 23, 2016
202 | Fix to clean up partial or zero-length image files on failed write
203 | Retired VS 2012 projects
204 |
205 | November 30, 2015
206 | texconv command-line tool -fl switch now supports 12.0 and 12.1 feature levels
207 | Updated for VS 2015 Update 1 and Windows 10 SDK (10586)
208 |
209 | October 30, 2015
210 | DDS support for legacy bumpmap formats (V8U8, Q8W8V8U8, V16U16)
211 | Fix for buffer overread in BC CPU compressor
212 | Minor code cleanup
213 |
214 | August 18, 2015
215 | Added GetWICFactory and SetWICFactory
216 | Updates for new DXGI 1.3 types
217 | Xbox One platform updates
218 |
219 | July 29, 2015
220 | Fixed rounding problem with 32-bit RGBA/BGRA format conversions
221 | texconv: use CPU parallel compression for BC1-BC5 (-singleproc disables)
222 | Updated for VS 2015 and Windows 10 SDK RTM
223 | Retired VS 2010 and Windows 8.0 Store projects
224 |
225 | June 18, 2015
226 | New BC_FLAGS_USE_3SUBSETS option for BC7 compressors; now defaults to skipping 3 subset blocks
227 | Fixed bug with MakeTypeless and A8_UNORM
228 | Fixed file length validation problem in LoadDDSFromFile
229 |
230 | March 27, 2015
231 | Added projects for Windows apps Technical Preview
232 | Fixed bug with WIC-based mipmap generation for non-WIC supported formats
233 | Fixed bug with WIC multiframe loader when resizing required
234 | texconv: Added -nmap/-nmapamp for generating normal maps from height maps
235 | texconv/texassemble: Updated to load multiframe WIC files (tiff, gif)
236 | Minor code cleanup
237 |
238 | November 24, 2014
239 | Updates for Visual Studio 2015 Technical Preview
240 | Minor code cleanup
241 |
242 | September 22, 2014
243 | Format conversion improvements and bug fixes (depth/stencil, alpha-only, float16, RGB -> 1 channel)
244 | Fixed issue when BC decompressing non-standard compressed rowPitch images
245 | Explicit calling-convention annotation for all 'public' functions
246 | Code cleanup
247 | Xbox One platform updates
248 |
249 | July 15, 2014
250 | texconv command-line tool fixes
251 | Fixed problem with 'wide' images with CPU Compress
252 | Updates to Xbox One platform support
253 |
254 | April 3, 2014
255 | Windows phone 8.1 platform support
256 |
257 | February 24, 2014
258 | Direct3D 11 video and Xbox One extended format support
259 | New APIs: IsPlanar, IsPalettized, IsDepthStencil, ConvertToSinglePlane
260 | Added 'alphaWeight' parameter to GPU Compress [breaking change]
261 | texconv '-aw' switch to control the alpha weighting for the BC7 GPU compressor
262 | Fixed bug with ordered dithering in non-WIC conversion codepaths
263 | Fixed SaveToDDS* functions when using arbitrary row pitch values
264 |
265 | January 24, 2014
266 | Added sRGB flags for Compress (TEX_COMPRESS_SRGB*)
267 | Added 'compress' flag parameter to GPU versions of Compress [breaking change]
268 | Minor fix for potential rounding problem in GPU Compress
269 | Code cleanup (removed DXGI_1_2_FORMATS control define; ScopedObject typedef removed)
270 | Dropped VS 2010 support without the Windows 8.1 SDK (removed USE_XNAMATH control define)
271 |
272 | December 24, 2013
273 | texconv updated with -fl and -pow2 command-line switches
274 | Fixed bug in Resize when doing custom filtering which occurred when exactly doubling the image size
275 | Added move operators to ScratchImage and Blob classes
276 | Xbox One platform support
277 |
278 | October 21, 2013
279 | Updated for Visual Studio 2013 and Windows 8.1 SDK RTM
280 | PremultiplyAlpha updated with new 'flags' parameter and to use sRGB correct blending
281 | Fixed colorspace conversion issue with DirectCompute compressor when compressing for BC7 SRGB
282 |
283 | August 13, 2013
284 | DirectCompute 4.0 BC6H/BC7 compressor integration
285 | texconv utility uses DirectCompute compression by default for BC6H/BC7, -nogpu disables use of DirectCompute
286 |
287 | August 1, 2013
288 | Support for BC compression/decompression of non-power-of-2 mipmapped textures
289 | Fixes for BC6H / BC7 codecs to better match published standard
290 | Fix for BC4 / BC5 codecs when compressing RGB images
291 | Minor fix for the BC1-3 codec
292 | New optional flags for ComputeMSE to compare UNORM vs. SNORM images
293 | New WIC loading flag added to control use of WIC metadata to return sRGB vs. non-sRGB formats
294 | Code cleanup and /analyze fixes
295 | Project file cleanup
296 | Texconv utility uses parallel BC compression by default for BC6H/BC7, -singleproc disables multithreaded behavior
297 |
298 | July 1, 2013
299 | VS 2013 Preview projects added
300 | SaveToWIC functions updated with new optional setCustomProps parameter
301 |
302 | June 15, 2013
303 | Custom filtering implementation for Resize & GenerateMipMaps(3D) - Point, Box, Linear, Cubic, and Triangle
304 | TEX_FILTER_TRIANGLE finite low-pass triangle filter
305 | TEX_FILTER_WRAP, TEX_FILTER_MIRROR texture semantics for custom filtering
306 | TEX_FILTER_BOX alias for TEX_FILTER_FANT WIC
307 | Ordered and error diffusion dithering for non-WIC conversion
308 | sRGB gamma correct custom filtering and conversion
309 | DDS_FLAGS_EXPAND_LUMINANCE - Reader conversion option for L8, L16, and A8L8 legacy DDS files
310 | Added use of WIC metadata for sRGB pixel formats
311 | Added BitsPerColor utility function
312 | Fixed Convert threshold parameter usage
313 | Non-power-of-2 volume map support, fixed bug with non-square volume maps
314 | Texconv utility update with -xlum, -wrap, and -mirror options; reworked -if options for improved dithering
315 | Texassemble utility for creating cubemaps, volume maps, and texture arrays
316 | DDSTextureLoader and WICTextureLoader sync'd with DirectXTK versions
317 |
318 | April 16, 2013
319 | Updated alpha-mode metadata details in .DDS files
320 | Added new control flags for Convert
321 | Added new optional flags for ComputeMSE
322 | Fixed conversion handling for sRGB formats
323 | Fixed internal routines for handling R10G10B10_XR_BIAS_A2_UNORM, R9G9B9E5_SHAREDEXP, and FORMAT_R1_UNORM
324 | Fixed WIC I/O for GUID_WICPixelFormat32bppRGBE pixel format files (HD Photo)
325 | Fixed non-square image handling in GenerateMipMaps3D
326 | Fixed some error handling in the DDS load code
327 |
328 | March 22, 2013
329 | Supports reading and writing alpha-mode (straight, premultiplied, etc.) metadata in .DDS files
330 | Added build option to use WICCreateImagingFactory_Proxy instead of CoCreateInstance to obtain WIC factory
331 |
332 | January 29, 2013
333 | Added PremultiplyAlpha to DirectXTex; -pmalpha switch for texconv command-line tool
334 | Fixed problem with forceSRGB implementation for Ex versions of CreateTexture, CreateShaderResourceView, DDSTextureLoader and WICTextureLoader
335 |
336 | December 11, 2012
337 | Ex versions of CreateTexture, CreateShaderResourceView, DDSTextureLoader and WICTextureLoader
338 | Fixed BC2 and BC3 decompression issue for unusual color encoding case
339 | Converted annotation to SAL2 for improved VS 2012 /analyze experience
340 | Updated DirectXTex, DDSView, and Texconv with VS 2010 + Windows 8.0 SDK project using official 'property sheets'
341 |
342 | November 15, 2012
343 | Added support for WIC2 when available on Windows 8 and Windows 7 with KB 2670838
344 | Added optional targetGUID parameter to SaveWIC* APIs to influence final container pixel format choice
345 | Fixed bug in SaveDDS* which was generating invalid DDS files for 1D dimension textures
346 | Improved robustness of CaptureTexture when resolving MSAA source textures
347 | Sync'd DDSTextureLoader, ScreenGrab, and WICTextureLoader standalone versions with latest DirectXTK release
348 |
349 | September 28, 2012
350 | Added ScreenGrab module for creating runtime screenshots
351 | Renamed project files for better naming consistency
352 | New Typeless utilities for DirectXTex
353 | Some minor code cleanup for DirectXTex's WIC writer function
354 | Bug fixes and new -tu/-tf options for texconv
355 |
356 | June 22, 2012
357 | Moved to using XNA Math 2.05 instead of XNA Math 2.04 for USE_XNAMATH builds
358 | Fixed BGR vs. RGB color channel swizzle problem with 24bpp legacy .DDS files in DirectXTex
359 | Update to DirectXTex WIC and WICTextureLoader for additional 96bpp float format handling on Windows 8
360 |
361 | May 31, 2012
362 | Minor fix for DDSTextureLoader's retry fallback that can happen with 10level9 feature levels
363 | Switched to use "_DEBUG" instead of "DEBUG" and cleaned up debug warnings
364 | added Windows Store style application project files for DirectXTex
365 |
366 | April 20, 2012
367 | DirectTex's WIC-based writer opts-in for the Windows 8 BMP encoder option for writing 32 bpp RGBA files with the BITMAPV5HEADER
368 |
369 | March 30, 2012
370 | WICTextureLoader updated with Windows 8 WIC pixel formats
371 | DirectXTex updated with limited non-power-of-2 texture support and TEX_FILTER_SEPARATE_ALPHA option
372 | Texconv updated with '-sepalpha' command-line option
373 | Added USE_XNAMATH control define to build DirectXTex using either XNAMath or DirectXMath
374 | Added VS 2012 project files (which use DirectXMath instead of XNAMath and define DXGI_1_2_FORMATS)
375 |
376 | March 15, 2012
377 | Fix for resource leak in CreateShaderResourceView() Direct3D 11 helper function in DirectXTex
378 |
379 | March 5, 2012
380 | Fix for too much temp memory allocated by WICTextureLoader; cleaned up legacy 'min/max' macro usage in DirectXTex
381 |
382 | February 21, 2012
383 | WICTextureLoader updated to handle systems and device drivers without BGRA or 16bpp format support
384 |
385 | February 20, 2012
386 | Some code cleanup for DirectXTex and DDSTextureLoader
387 | Fixed bug in 10:10:10:2 format fixup in the LoadDDSFromMemory function
388 | Fixed bugs in "non-zero alpha" special-case handling in LoadTGAFromFile
389 | Fixed bug in _SwizzleScanline when copying alpha channel for BGRA<->RGBA swizzling
390 |
391 | February 11, 2012
392 | Update of DDSTextureLoader to also build in Windows Store style apps; added WICTextureLoader
393 | Added CMYK WIC pixel formats to the DirectXTex conversion table
394 |
395 | January 30, 2012
396 | Minor code-cleanup for DirectXTex to enable use of PCH through 'directxtexp.h' header
397 |
398 | January 24, 2011
399 | Some code-cleanup for DirectXTex
400 | Added DXGI 1.2 implementation for DDSTextureLoader and DirectXTex guarded with DXGI_1_2_FORMATS compiliation define
401 |
402 | December 16, 2011
403 | Fixed x64 compilation warnings in DDSTextureLoader
404 |
405 | November 30, 2011
406 | Fixed some of the constants used in IsSupportedTexture(),
407 | added ability to strip off top levels of mips in DDSTextureLoader,
408 | changed DirectXTex to use CoCreateInstance rather than LoadLibrary to obtain the WIC factory,
409 | a few minor /analyze related annotations for DirectXTex
410 |
411 | October 27, 2011
412 | Original release
--------------------------------------------------------------------------------
/DirectXTex/WICTextureLoader/WICTextureLoader12.cpp:
--------------------------------------------------------------------------------
1 | //--------------------------------------------------------------------------------------
2 | // File: WICTextureLoader12.cpp
3 | //
4 | // Function for loading a WIC image and creating a Direct3D 12 runtime texture for it
5 | // (auto-generating mipmaps if possible)
6 | //
7 | // Note: Assumes application has already called CoInitializeEx
8 | //
9 | // Note these functions are useful for images created as simple 2D textures. For
10 | // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.
11 | // For a full-featured DDS file reader, writer, and texture processing pipeline see
12 | // the 'Texconv' sample and the 'DirectXTex' library.
13 | //
14 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
15 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
17 | // PARTICULAR PURPOSE.
18 | //
19 | // Copyright (c) Microsoft Corporation. All rights reserved.
20 | //
21 | // http://go.microsoft.com/fwlink/?LinkId=248926
22 | // http://go.microsoft.com/fwlink/?LinkID=615561
23 | //--------------------------------------------------------------------------------------
24 |
25 | // Modified by SebH
26 |
27 | // We could load multi-frame images (TIFF/GIF) into a texture array.
28 | // For now, we just load the first frame (note: DirectXTex supports multi-frame images)
29 |
30 | #include "WICTextureLoader12.h"
31 |
32 | #include
33 | #include
34 |
35 | #include
36 |
37 | #include
38 |
39 | #include
40 |
41 | using namespace DirectX;
42 | using Microsoft::WRL::ComPtr;
43 |
44 | namespace
45 | {
46 | //-------------------------------------------------------------------------------------
47 | // WIC Pixel Format Translation Data
48 | //-------------------------------------------------------------------------------------
49 | struct WICTranslate
50 | {
51 | GUID wic;
52 | DXGI_FORMAT format;
53 | };
54 |
55 | const WICTranslate g_WICFormats[] =
56 | {
57 | { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT },
58 |
59 | { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT },
60 | { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM },
61 |
62 | { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM },
63 | { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM },
64 | { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM },
65 |
66 | { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
67 | { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM },
68 |
69 | { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM },
70 | { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM },
71 |
72 | { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT },
73 | { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT },
74 | { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM },
75 | { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM },
76 |
77 | { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM },
78 |
79 | { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT },
80 | };
81 |
82 | //-------------------------------------------------------------------------------------
83 | // WIC Pixel Format nearest conversion table
84 | //-------------------------------------------------------------------------------------
85 |
86 | struct WICConvert
87 | {
88 | GUID source;
89 | GUID target;
90 | };
91 |
92 | const WICConvert g_WICConvert[] =
93 | {
94 | // Note target GUID in this conversion table must be one of those directly supported formats (above).
95 |
96 | { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
97 |
98 | { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
99 | { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
100 | { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
101 | { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
102 |
103 | { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
104 | { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
105 |
106 | { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
107 | { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT
108 |
109 | { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM
110 |
111 | { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM
112 |
113 | { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
114 | { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
115 | { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
116 | { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
117 |
118 | { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
119 | { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
120 | { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
121 | { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
122 | { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
123 |
124 | { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
125 | { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
126 | { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
127 | { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
128 | { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
129 | { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
130 | { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
131 |
132 | { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
133 | { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
134 | { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
135 | { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
136 | { GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
137 |
138 | { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
139 | { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
140 | { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
141 | { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
142 |
143 | { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
144 | { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
145 | { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
146 |
147 | { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat96bppRGBFloat }, // DXGI_FORMAT_R32G32B32_FLOAT
148 |
149 | // We don't support n-channel formats
150 | };
151 |
152 | IWICImagingFactory2* _GetWIC()
153 | {
154 | static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;
155 |
156 | IWICImagingFactory2* factory = nullptr;
157 | (void)InitOnceExecuteOnce(&s_initOnce,
158 | [](PINIT_ONCE, PVOID, PVOID *factory) -> BOOL
159 | {
160 | return SUCCEEDED( CoCreateInstance(
161 | CLSID_WICImagingFactory2,
162 | nullptr,
163 | CLSCTX_INPROC_SERVER,
164 | __uuidof(IWICImagingFactory2),
165 | factory) ) ? TRUE : FALSE;
166 | }, nullptr, reinterpret_cast(&factory));
167 |
168 | return factory;
169 | }
170 |
171 | //---------------------------------------------------------------------------------
172 | template
173 | inline void SetDebugObjectName(_In_ ID3D12DeviceChild* resource, _In_z_ const wchar_t(&name)[TNameLength])
174 | {
175 | #if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
176 | resource->SetName(name);
177 | #else
178 | UNREFERENCED_PARAMETER(resource);
179 | UNREFERENCED_PARAMETER(name);
180 | #endif
181 | }
182 |
183 | inline uint32_t CountMips(uint32_t width, uint32_t height)
184 | {
185 | if (width == 0 || height == 0)
186 | return 0;
187 |
188 | uint32_t count = 1;
189 | while (width > 1 || height > 1)
190 | {
191 | width >>= 1;
192 | height >>= 1;
193 | count++;
194 | }
195 | return count;
196 | }
197 |
198 | //--------------------------------------------------------------------------------------
199 | DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format)
200 | {
201 | switch (format)
202 | {
203 | case DXGI_FORMAT_R8G8B8A8_UNORM:
204 | return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
205 |
206 | case DXGI_FORMAT_BC1_UNORM:
207 | return DXGI_FORMAT_BC1_UNORM_SRGB;
208 |
209 | case DXGI_FORMAT_BC2_UNORM:
210 | return DXGI_FORMAT_BC2_UNORM_SRGB;
211 |
212 | case DXGI_FORMAT_BC3_UNORM:
213 | return DXGI_FORMAT_BC3_UNORM_SRGB;
214 |
215 | case DXGI_FORMAT_B8G8R8A8_UNORM:
216 | return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
217 |
218 | case DXGI_FORMAT_B8G8R8X8_UNORM:
219 | return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
220 |
221 | case DXGI_FORMAT_BC7_UNORM:
222 | return DXGI_FORMAT_BC7_UNORM_SRGB;
223 |
224 | default:
225 | return format;
226 | }
227 | }
228 |
229 | //---------------------------------------------------------------------------------
230 | DXGI_FORMAT _WICToDXGI(const GUID& guid)
231 | {
232 | for (size_t i = 0; i < _countof(g_WICFormats); ++i)
233 | {
234 | if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0)
235 | return g_WICFormats[i].format;
236 | }
237 |
238 | return DXGI_FORMAT_UNKNOWN;
239 | }
240 |
241 | //---------------------------------------------------------------------------------
242 | size_t _WICBitsPerPixel(REFGUID targetGuid)
243 | {
244 | auto pWIC = _GetWIC();
245 | if (!pWIC)
246 | return 0;
247 |
248 | ComPtr cinfo;
249 | if (FAILED(pWIC->CreateComponentInfo(targetGuid, cinfo.GetAddressOf())))
250 | return 0;
251 |
252 | WICComponentType type;
253 | if (FAILED(cinfo->GetComponentType(&type)))
254 | return 0;
255 |
256 | if (type != WICPixelFormat)
257 | return 0;
258 |
259 | ComPtr pfinfo;
260 | if (FAILED(cinfo.As(&pfinfo)))
261 | return 0;
262 |
263 | UINT bpp;
264 | if (FAILED(pfinfo->GetBitsPerPixel(&bpp)))
265 | return 0;
266 |
267 | return bpp;
268 | }
269 |
270 | //---------------------------------------------------------------------------------
271 | HRESULT CreateTextureFromWIC(
272 | _In_ IWICBitmapFrameDecode *frame,
273 | size_t maxsize,
274 | unsigned int loadFlags,
275 | TextureData& texData)
276 | {
277 | UINT width, height;
278 | HRESULT hr = frame->GetSize(&width, &height);
279 | if (FAILED(hr))
280 | return hr;
281 |
282 | assert(width > 0 && height > 0);
283 |
284 | if (!maxsize)
285 | {
286 | maxsize = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
287 | }
288 |
289 | assert(maxsize > 0);
290 |
291 | UINT twidth, theight;
292 | if (width > maxsize || height > maxsize)
293 | {
294 | float ar = static_cast(height) / static_cast(width);
295 | if (width > height)
296 | {
297 | twidth = static_cast(maxsize);
298 | theight = std::max(1, static_cast(static_cast(maxsize) * ar));
299 | }
300 | else
301 | {
302 | theight = static_cast(maxsize);
303 | twidth = std::max(1, static_cast(static_cast(maxsize) / ar));
304 | }
305 | assert(twidth <= maxsize && theight <= maxsize);
306 | }
307 | else
308 | {
309 | twidth = width;
310 | theight = height;
311 | }
312 |
313 | // Determine format
314 | WICPixelFormatGUID pixelFormat;
315 | hr = frame->GetPixelFormat(&pixelFormat);
316 | if (FAILED(hr))
317 | return hr;
318 |
319 | WICPixelFormatGUID convertGUID;
320 | memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID));
321 |
322 | size_t bpp = 0;
323 |
324 | DXGI_FORMAT format = _WICToDXGI(pixelFormat);
325 | if (format == DXGI_FORMAT_UNKNOWN)
326 | {
327 | for (size_t i = 0; i < _countof(g_WICConvert); ++i)
328 | {
329 | if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)
330 | {
331 | memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID));
332 |
333 | format = _WICToDXGI(g_WICConvert[i].target);
334 | assert(format != DXGI_FORMAT_UNKNOWN);
335 | bpp = _WICBitsPerPixel(convertGUID);
336 | break;
337 | }
338 | }
339 |
340 | if (format == DXGI_FORMAT_UNKNOWN)
341 | return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
342 | }
343 | else
344 | {
345 | bpp = _WICBitsPerPixel(pixelFormat);
346 | }
347 |
348 | if (!bpp)
349 | return E_FAIL;
350 |
351 | // Handle sRGB formats
352 | if (loadFlags & WIC_LOADER_FORCE_SRGB)
353 | {
354 | format = MakeSRGB(format);
355 | }
356 | else if (!(loadFlags & WIC_LOADER_IGNORE_SRGB))
357 | {
358 | ComPtr metareader;
359 | if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf())))
360 | {
361 | GUID containerFormat;
362 | if (SUCCEEDED(metareader->GetContainerFormat(&containerFormat)))
363 | {
364 | // Check for sRGB colorspace metadata
365 | bool sRGB = false;
366 |
367 | PROPVARIANT value;
368 | PropVariantInit(&value);
369 |
370 | if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0)
371 | {
372 | // Check for sRGB chunk
373 | if (SUCCEEDED(metareader->GetMetadataByName(L"/sRGB/RenderingIntent", &value)) && value.vt == VT_UI1)
374 | {
375 | sRGB = true;
376 | }
377 | }
378 | else if (SUCCEEDED(metareader->GetMetadataByName(L"System.Image.ColorSpace", &value)) && value.vt == VT_UI2 && value.uiVal == 1)
379 | {
380 | sRGB = true;
381 | }
382 |
383 | (void)PropVariantClear(&value);
384 |
385 | if (sRGB)
386 | format = MakeSRGB(format);
387 | }
388 | }
389 | }
390 |
391 | // Allocate memory for decoded image
392 | size_t rowPitch = (twidth * bpp + 7) / 8;
393 | texData.dataSizeInByte = UINT(rowPitch * theight);
394 |
395 | texData.decodedData.reset(new (std::nothrow) uint8_t[texData.dataSizeInByte]);
396 | if (!texData.decodedData)
397 | return E_OUTOFMEMORY;
398 |
399 | // Load image data
400 | if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0
401 | && twidth == width
402 | && theight == height)
403 | {
404 | // No format conversion or resize needed
405 | hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get());
406 | if (FAILED(hr))
407 | return hr;
408 | }
409 | else if (twidth != width || theight != height)
410 | {
411 | // Resize
412 | auto pWIC = _GetWIC();
413 | if (!pWIC)
414 | return E_NOINTERFACE;
415 |
416 | ComPtr scaler;
417 | hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf());
418 | if (FAILED(hr))
419 | return hr;
420 |
421 | hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant);
422 | if (FAILED(hr))
423 | return hr;
424 |
425 | WICPixelFormatGUID pfScaler;
426 | hr = scaler->GetPixelFormat(&pfScaler);
427 | if (FAILED(hr))
428 | return hr;
429 |
430 | if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0)
431 | {
432 | // No format conversion needed
433 | hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get());
434 | if (FAILED(hr))
435 | return hr;
436 | }
437 | else
438 | {
439 | ComPtr FC;
440 | hr = pWIC->CreateFormatConverter(FC.GetAddressOf());
441 | if (FAILED(hr))
442 | return hr;
443 |
444 | BOOL canConvert = FALSE;
445 | hr = FC->CanConvert(pfScaler, convertGUID, &canConvert);
446 | if (FAILED(hr) || !canConvert)
447 | {
448 | return E_UNEXPECTED;
449 | }
450 |
451 | hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut);
452 | if (FAILED(hr))
453 | return hr;
454 |
455 | hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get());
456 | if (FAILED(hr))
457 | return hr;
458 | }
459 | }
460 | else
461 | {
462 | // Format conversion but no resize
463 | auto pWIC = _GetWIC();
464 | if (!pWIC)
465 | return E_NOINTERFACE;
466 |
467 | ComPtr FC;
468 | hr = pWIC->CreateFormatConverter(FC.GetAddressOf());
469 | if (FAILED(hr))
470 | return hr;
471 |
472 | BOOL canConvert = FALSE;
473 | hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert);
474 | if (FAILED(hr) || !canConvert)
475 | {
476 | return E_UNEXPECTED;
477 | }
478 |
479 | hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut);
480 | if (FAILED(hr))
481 | return hr;
482 |
483 | hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get());
484 | if (FAILED(hr))
485 | return hr;
486 | }
487 |
488 | // Count the number of mips
489 | texData.mipCount = (loadFlags & (WIC_LOADER_MIP_AUTOGEN|WIC_LOADER_MIP_RESERVE)) ? CountMips(twidth, theight) : 1;
490 | texData.width = twidth;
491 | texData.height = theight;
492 | texData.format = format;
493 |
494 | // Create texture
495 | /* D3D12_RESOURCE_DESC desc = {};
496 | desc.Width = twidth;
497 | desc.Height = theight;
498 | desc.MipLevels = (uint16_t)mipCount;
499 | desc.DepthOrArraySize = 1;
500 | desc.Format = format;
501 | desc.SampleDesc.Count = 1;
502 | desc.SampleDesc.Quality = 0;
503 | desc.Flags = resFlags;
504 | desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
505 |
506 | CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
507 |
508 | ID3D12Resource* tex = nullptr;
509 | hr = d3dDevice->CreateCommittedResource(
510 | &defaultHeapProperties,
511 | D3D12_HEAP_FLAG_NONE,
512 | &desc,
513 | D3D12_RESOURCE_STATE_COPY_DEST,
514 | nullptr,
515 | IID_PPV_ARGS(&tex));
516 |
517 | if (FAILED(hr))
518 | {
519 | return hr;
520 | }
521 |
522 | _Analysis_assume_(tex != 0);
523 | */
524 |
525 | texData.subresource.pData = texData.decodedData.get();
526 | texData.subresource.RowPitch = rowPitch;
527 | texData.subresource.SlicePitch = texData.dataSizeInByte;
528 |
529 | // The texture us mirrored on Y so mirror it now to hqve Y up.
530 | BYTE* textureDataSource = new BYTE[texData.dataSizeInByte];
531 | {
532 | BYTE* finalData = texData.decodedData.get();
533 | memcpy(textureDataSource, finalData, texData.dataSizeInByte);
534 | // Now copy rows but in reverse order
535 | for (INT r = height - 1; r >= 0; --r)
536 | {
537 | INT dstR = height - 1 - r;
538 | memcpy(finalData + dstR * rowPitch, textureDataSource + r * rowPitch, rowPitch);
539 | }
540 | }
541 | delete [] textureDataSource;
542 |
543 | // *texture = tex;
544 | return hr;
545 | }
546 | } // anonymous namespace
547 |
548 |
549 |
550 |
551 | //--------------------------------------------------------------------------------------
552 | _Use_decl_annotations_
553 | HRESULT DirectX::LoadWICTextureFromFile(
554 | _In_z_ const wchar_t* fileName,
555 | TextureData& texData,
556 | size_t maxsize,
557 | unsigned int loadFlags)
558 | {
559 | if (!fileName )
560 | return E_INVALIDARG;
561 |
562 | auto pWIC = _GetWIC();
563 | if ( !pWIC )
564 | return E_NOINTERFACE;
565 |
566 | // Initialize WIC
567 | ComPtr decoder;
568 | HRESULT hr = pWIC->CreateDecoderFromFilename( fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() );
569 | if ( FAILED(hr) )
570 | return hr;
571 |
572 | ComPtr frame;
573 | hr = decoder->GetFrame( 0, frame.GetAddressOf() );
574 | if ( FAILED(hr) )
575 | return hr;
576 |
577 | hr = CreateTextureFromWIC( frame.Get(), maxsize,
578 | loadFlags, texData);
579 |
580 | //#if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
581 | // if ( SUCCEEDED(hr) )
582 | // {
583 | // const wchar_t* pstrName = wcsrchr(fileName, '\\' );
584 | // if (!pstrName)
585 | // {
586 | // pstrName = fileName;
587 | // }
588 | // else
589 | // {
590 | // pstrName++;
591 | // }
592 | //
593 | // if (texture != 0 && *texture != 0)
594 | // {
595 | // (*texture)->SetName(pstrName);
596 | // }
597 | // }
598 | //#endif
599 |
600 | return hr;
601 | }
602 |
603 |
604 |
605 |
606 |
--------------------------------------------------------------------------------
/Application/OBJ_Loader.h:
--------------------------------------------------------------------------------
1 | // OBJ_Loader.h - A Single Header OBJ Model Loader
2 |
3 | #pragma once
4 |
5 | #include
6 |
7 | // Vector - STD Vector/Array Library
8 | #include
9 |
10 | // String - STD String Library
11 | #include
12 |
13 | // fStream - STD File I/O Library
14 | #include
15 |
16 | // Print progress to console while loading (large models)
17 | #define OBJL_CONSOLE_OUTPUT
18 |
19 | // Namespace: OBJL
20 | //
21 | // Description: The namespace that holds eveyrthing that
22 | // is needed and used for the OBJ Model Loader
23 | namespace objl
24 | {
25 | // Structure: Vector2
26 | //
27 | // Description: A 2D Vector that Holds Positional Data
28 | struct Vector2
29 | {
30 | // Default Constructor
31 | Vector2()
32 | {
33 | X = 0.0f;
34 | Y = 0.0f;
35 | }
36 | // Variable Set Constructor
37 | Vector2(float X_, float Y_)
38 | {
39 | X = X_;
40 | Y = Y_;
41 | }
42 | // Bool Equals Operator Overload
43 | bool operator==(const Vector2& other) const
44 | {
45 | return (this->X == other.X && this->Y == other.Y);
46 | }
47 | // Bool Not Equals Operator Overload
48 | bool operator!=(const Vector2& other) const
49 | {
50 | return !(this->X == other.X && this->Y == other.Y);
51 | }
52 | // Addition Operator Overload
53 | Vector2 operator+(const Vector2& right) const
54 | {
55 | return Vector2(this->X + right.X, this->Y + right.Y);
56 | }
57 | // Subtraction Operator Overload
58 | Vector2 operator-(const Vector2& right) const
59 | {
60 | return Vector2(this->X - right.X, this->Y - right.Y);
61 | }
62 | // Float Multiplication Operator Overload
63 | Vector2 operator*(const float& other) const
64 | {
65 | return Vector2(this->X *other, this->Y * other);
66 | }
67 |
68 | // Positional Variables
69 | float X;
70 | float Y;
71 | };
72 |
73 | // Structure: Vector3
74 | //
75 | // Description: A 3D Vector that Holds Positional Data
76 | struct Vector3
77 | {
78 | // Default Constructor
79 | Vector3()
80 | {
81 | X = 0.0f;
82 | Y = 0.0f;
83 | Z = 0.0f;
84 | }
85 | // Variable Set Constructor
86 | Vector3(float X_, float Y_, float Z_)
87 | {
88 | X = X_;
89 | Y = Y_;
90 | Z = Z_;
91 | }
92 | // Bool Equals Operator Overload
93 | bool operator==(const Vector3& other) const
94 | {
95 | return (this->X == other.X && this->Y == other.Y && this->Z == other.Z);
96 | }
97 | // Bool Not Equals Operator Overload
98 | bool operator!=(const Vector3& other) const
99 | {
100 | return !(this->X == other.X && this->Y == other.Y && this->Z == other.Z);
101 | }
102 | // Addition Operator Overload
103 | Vector3 operator+(const Vector3& right) const
104 | {
105 | return Vector3(this->X + right.X, this->Y + right.Y, this->Z + right.Z);
106 | }
107 | // Subtraction Operator Overload
108 | Vector3 operator-(const Vector3& right) const
109 | {
110 | return Vector3(this->X - right.X, this->Y - right.Y, this->Z - right.Z);
111 | }
112 | // Float Multiplication Operator Overload
113 | Vector3 operator*(const float& other) const
114 | {
115 | return Vector3(this->X *other, this->Y * other, this->Z - other);
116 | }
117 |
118 | // Positional Variables
119 | float X;
120 | float Y;
121 | float Z;
122 | };
123 |
124 | // Structure: Vertex
125 | //
126 | // Description: Model Vertex object that holds
127 | // a Position, Normal, and Texture Coordinate
128 | struct Vertex
129 | {
130 | // Position Vector
131 | Vector3 Position;
132 |
133 | // Normal Vector
134 | Vector3 Normal;
135 |
136 | // Texture Coordinate Vector
137 | Vector2 TextureCoordinate;
138 | };
139 |
140 | struct Material
141 | {
142 | Material()
143 | {
144 | name;
145 | Ns = 0.0f;
146 | Ni = 0.0f;
147 | d = 0.0f;
148 | illum = 0;
149 | }
150 |
151 | // Material Name
152 | std::string name;
153 | // Ambient Color
154 | Vector3 Ka;
155 | // Diffuse Color
156 | Vector3 Kd;
157 | // Specular Color
158 | Vector3 Ks;
159 | // Specular Exponent
160 | float Ns;
161 | // Optical Density
162 | float Ni;
163 | // Dissolve
164 | float d;
165 | // Illumination
166 | int illum;
167 | // Ambient Texture Map
168 | std::string map_Ka;
169 | // Diffuse Texture Map
170 | std::string map_Kd;
171 | // Specular Texture Map
172 | std::string map_Ks;
173 | // Specular Hightlight Map
174 | std::string map_Ns;
175 | // Alpha Texture Map
176 | std::string map_d;
177 | // Bump Map
178 | std::string map_bump;
179 | };
180 |
181 | // Structure: Mesh
182 | //
183 | // Description: A Simple Mesh Object that holds
184 | // a name, a vertex list, and an index list
185 | struct Mesh
186 | {
187 | // Default Constructor
188 | Mesh()
189 | {
190 |
191 | }
192 | // Variable Set Constructor
193 | Mesh(std::vector& _Vertices, std::vector& _Indices)
194 | {
195 | Vertices = _Vertices;
196 | Indices = _Indices;
197 | }
198 | // Mesh Name
199 | std::string MeshName;
200 | // Vertex List
201 | std::vector Vertices;
202 | // Index List
203 | std::vector Indices;
204 |
205 | // Material
206 | Material MeshMaterial;
207 | };
208 |
209 | // Namespace: Math
210 | //
211 | // Description: The namespace that holds all of the math
212 | // functions need for OBJL
213 | namespace math
214 | {
215 | // Vector3 Cross Product
216 | Vector3 CrossV3(const Vector3 a, const Vector3 b)
217 | {
218 | return Vector3(a.Y * b.Z - a.Z * b.Y,
219 | a.Z * b.X - a.X * b.Z,
220 | a.X * b.Y - a.Y * b.X);
221 | }
222 |
223 | // Vector3 Magnitude Calculation
224 | float MagnitudeV3(const Vector3 in)
225 | {
226 | return (sqrtf(powf(in.X, 2) + powf(in.Y, 2) + powf(in.Z, 2)));
227 | }
228 |
229 | // Vector3 DotProduct
230 | float DotV3(const Vector3 a, const Vector3 b)
231 | {
232 | return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z);
233 | }
234 |
235 | // Angle between 2 Vector3 Objects
236 | float AngleBetweenV3(const Vector3 a, const Vector3 b)
237 | {
238 | float angle = DotV3(a, b);
239 | angle /= (MagnitudeV3(a) * MagnitudeV3(b));
240 | return angle = acosf(angle);
241 | }
242 | }
243 |
244 | // Namespace: Algorithm
245 | //
246 | // Description: The namespace that holds all of the
247 | // Algorithms needed for OBJL
248 | namespace algorithm
249 | {
250 | // Vector3 Multiplication Opertor Overload
251 | Vector3 operator*(const float& left, const Vector3& right)
252 | {
253 | return Vector3(right.X * left, right.Y * left, right.Z * left);
254 | }
255 |
256 | // Check to see if a Vector3 Point is within a 3 Vector3 Triangle
257 | bool inTriangle(Vector3 point, Vector3 tri1, Vector3 tri2, Vector3 tri3)
258 | {
259 | // Starting vars
260 | Vector3 u = tri2 - tri1;
261 | Vector3 v = tri3 - tri1;
262 | Vector3 w = point - tri1;
263 | Vector3 n = math::CrossV3(u, v);
264 |
265 | float y = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n));
266 | float b = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n));
267 | float a = 1 - y - b;
268 |
269 | // Projected point
270 | Vector3 p = (a * tri1) + (b * tri2) + (y * tri3);
271 |
272 | if (a >= 0 && a <= 1
273 | && b >= 0 && b <= 1
274 | && y >= 0 && y <= 1)
275 | {
276 | return true;
277 | }
278 | else
279 | return false;
280 | }
281 |
282 | // Split a String into a string array at a given token
283 | inline void split(const std::string &in,
284 | std::vector &out,
285 | std::string token)
286 | {
287 | out.clear();
288 |
289 | std::string temp;
290 |
291 | for (int i = 0; i < int(in.size()); i++)
292 | {
293 | std::string test = in.substr(i, token.size());
294 |
295 | if (test == token)
296 | {
297 | if (!temp.empty())
298 | {
299 | out.push_back(temp);
300 | temp.clear();
301 | i += (int)token.size() - 1;
302 | }
303 | else
304 | {
305 | out.push_back("");
306 | }
307 | }
308 | else if (i + token.size() >= in.size())
309 | {
310 | temp += in.substr(i, token.size());
311 | out.push_back(temp);
312 | break;
313 | }
314 | else
315 | {
316 | temp += in[i];
317 | }
318 | }
319 | }
320 |
321 | // Get tail of string after first token and possibly following spaces
322 | inline std::string tail(const std::string &in)
323 | {
324 | size_t token_start = in.find_first_not_of(" \t");
325 | size_t space_start = in.find_first_of(" \t", token_start);
326 | size_t tail_start = in.find_first_not_of(" \t", space_start);
327 | size_t tail_end = in.find_last_not_of(" \t");
328 | if (tail_start != std::string::npos && tail_end != std::string::npos)
329 | {
330 | return in.substr(tail_start, tail_end - tail_start + 1);
331 | }
332 | else if (tail_start != std::string::npos)
333 | {
334 | return in.substr(tail_start);
335 | }
336 | return "";
337 | }
338 |
339 | // Get first token of string
340 | inline std::string firstToken(const std::string &in)
341 | {
342 | if (!in.empty())
343 | {
344 | size_t token_start = in.find_first_not_of(" \t");
345 | size_t token_end = in.find_first_of(" \t", token_start);
346 | if (token_start != std::string::npos && token_end != std::string::npos)
347 | {
348 | return in.substr(token_start, token_end - token_start);
349 | }
350 | else if (token_start != std::string::npos)
351 | {
352 | return in.substr(token_start);
353 | }
354 | }
355 | return "";
356 | }
357 |
358 | // Get element at given index position
359 | template
360 | inline const T & getElement(const std::vector &elements, std::string &index)
361 | {
362 | int idx = std::stoi(index);
363 | if (idx < 0)
364 | idx = int(elements.size()) + idx;
365 | else
366 | idx--;
367 | return elements[idx];
368 | }
369 | }
370 |
371 | // Class: Loader
372 | //
373 | // Description: The OBJ Model Loader
374 | class Loader
375 | {
376 | public:
377 | // Default Constructor
378 | Loader()
379 | {
380 |
381 | }
382 | ~Loader()
383 | {
384 | LoadedMeshes.clear();
385 | }
386 |
387 | // Load a file into the loader
388 | //
389 | // If file is loaded return true
390 | //
391 | // If the file is unable to be found
392 | // or unable to be loaded return false
393 | bool LoadFile(std::string Path)
394 | {
395 | // If the file is not an .obj file return false
396 | if (Path.substr(Path.size() - 4, 4) != ".obj")
397 | return false;
398 |
399 |
400 | std::ifstream file(Path);
401 |
402 | if (!file.is_open())
403 | return false;
404 |
405 | LoadedMeshes.clear();
406 | LoadedVertices.clear();
407 | LoadedIndices.clear();
408 |
409 | std::vector Positions;
410 | std::vector TCoords;
411 | std::vector Normals;
412 |
413 | std::vector Vertices;
414 | std::vector Indices;
415 |
416 | std::vector MeshMatNames;
417 |
418 | bool listening = false;
419 | std::string meshname;
420 |
421 | Mesh tempMesh;
422 |
423 | #ifdef OBJL_CONSOLE_OUTPUT
424 | const unsigned int outputEveryNth = 1000;
425 | unsigned int outputIndicator = outputEveryNth;
426 | #endif
427 |
428 | std::string curline;
429 | while (std::getline(file, curline))
430 | {
431 | #ifdef OBJL_CONSOLE_OUTPUT
432 | if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1)
433 | {
434 | if (!meshname.empty())
435 | {
436 | std::cout
437 | << "\r- " << meshname
438 | << "\t| vertices > " << Positions.size()
439 | << "\t| texcoords > " << TCoords.size()
440 | << "\t| normals > " << Normals.size()
441 | << "\t| triangles > " << (Vertices.size() / 3)
442 | << (!MeshMatNames.empty() ? "\t| material: " + MeshMatNames.back() : "");
443 | }
444 | }
445 | #endif
446 |
447 | // Generate a Mesh Object or Prepare for an object to be created
448 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g" || curline[0] == 'g')
449 | {
450 | if (!listening)
451 | {
452 | listening = true;
453 |
454 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g")
455 | {
456 | meshname = algorithm::tail(curline);
457 | }
458 | else
459 | {
460 | meshname = "unnamed";
461 | }
462 | }
463 | else
464 | {
465 | // Generate the mesh to put into the array
466 |
467 | if (!Indices.empty() && !Vertices.empty())
468 | {
469 | // Create Mesh
470 | tempMesh = Mesh(Vertices, Indices);
471 | tempMesh.MeshName = meshname;
472 |
473 | // Insert Mesh
474 | LoadedMeshes.push_back(tempMesh);
475 |
476 | // Cleanup
477 | Vertices.clear();
478 | Indices.clear();
479 | meshname.clear();
480 |
481 | meshname = algorithm::tail(curline);
482 | }
483 | else
484 | {
485 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g")
486 | {
487 | meshname = algorithm::tail(curline);
488 | }
489 | else
490 | {
491 | meshname = "unnamed";
492 | }
493 | }
494 | }
495 | #ifdef OBJL_CONSOLE_OUTPUT
496 | std::cout << std::endl;
497 | outputIndicator = 0;
498 | #endif
499 | }
500 | // Generate a Vertex Position
501 | if (algorithm::firstToken(curline) == "v")
502 | {
503 | std::vector spos;
504 | Vector3 vpos;
505 | algorithm::split(algorithm::tail(curline), spos, " ");
506 |
507 | vpos.X = std::stof(spos[0]);
508 | vpos.Y = std::stof(spos[1]);
509 | vpos.Z = std::stof(spos[2]);
510 |
511 | Positions.push_back(vpos);
512 | }
513 | // Generate a Vertex Texture Coordinate
514 | if (algorithm::firstToken(curline) == "vt")
515 | {
516 | std::vector stex;
517 | Vector2 vtex;
518 | algorithm::split(algorithm::tail(curline), stex, " ");
519 |
520 | vtex.X = std::stof(stex[0]);
521 | vtex.Y = std::stof(stex[1]);
522 |
523 | TCoords.push_back(vtex);
524 | }
525 | // Generate a Vertex Normal;
526 | if (algorithm::firstToken(curline) == "vn")
527 | {
528 | std::vector snor;
529 | Vector3 vnor;
530 | algorithm::split(algorithm::tail(curline), snor, " ");
531 |
532 | vnor.X = std::stof(snor[0]);
533 | vnor.Y = std::stof(snor[1]);
534 | vnor.Z = std::stof(snor[2]);
535 |
536 | Normals.push_back(vnor);
537 | }
538 | // Generate a Face (vertices & indices)
539 | if (algorithm::firstToken(curline) == "f")
540 | {
541 | // Generate the vertices
542 | std::vector vVerts;
543 | GenVerticesFromRawOBJ(vVerts, Positions, TCoords, Normals, curline);
544 |
545 | // Add Vertices
546 | for (int i = 0; i < int(vVerts.size()); i++)
547 | {
548 | Vertices.push_back(vVerts[i]);
549 |
550 | LoadedVertices.push_back(vVerts[i]);
551 | }
552 |
553 | std::vector iIndices;
554 |
555 | VertexTriangluation(iIndices, vVerts);
556 |
557 | // Add Indices
558 | for (int i = 0; i < int(iIndices.size()); i++)
559 | {
560 | unsigned int indnum = (unsigned int)((Vertices.size()) - vVerts.size()) + iIndices[i];
561 | Indices.push_back(indnum);
562 |
563 | indnum = (unsigned int)((LoadedVertices.size()) - vVerts.size()) + iIndices[i];
564 | LoadedIndices.push_back(indnum);
565 |
566 | }
567 | }
568 | // Get Mesh Material Name
569 | if (algorithm::firstToken(curline) == "usemtl")
570 | {
571 | MeshMatNames.push_back(algorithm::tail(curline));
572 |
573 | // Create new Mesh, if Material changes within a group
574 | if (!Indices.empty() && !Vertices.empty())
575 | {
576 | // Create Mesh
577 | tempMesh = Mesh(Vertices, Indices);
578 | tempMesh.MeshName = meshname;
579 | int i = 2;
580 | while(1) {
581 | tempMesh.MeshName = meshname + "_" + std::to_string(i);
582 |
583 | for (auto &m : LoadedMeshes)
584 | if (m.MeshName == tempMesh.MeshName)
585 | continue;
586 | break;
587 | }
588 |
589 | // Insert Mesh
590 | LoadedMeshes.push_back(tempMesh);
591 |
592 | // Cleanup
593 | Vertices.clear();
594 | Indices.clear();
595 | }
596 |
597 | #ifdef OBJL_CONSOLE_OUTPUT
598 | outputIndicator = 0;
599 | #endif
600 | }
601 | // Load Materials
602 | if (algorithm::firstToken(curline) == "mtllib")
603 | {
604 | // Generate LoadedMaterial
605 |
606 | // Generate a path to the material file
607 | std::vector temp;
608 | algorithm::split(Path, temp, "/");
609 |
610 | std::string pathtomat = "";
611 |
612 | if (temp.size() != 1)
613 | {
614 | for (int i = 0; i < temp.size() - 1; i++)
615 | {
616 | pathtomat += temp[i] + "/";
617 | }
618 | }
619 |
620 |
621 | pathtomat += algorithm::tail(curline);
622 |
623 | #ifdef OBJL_CONSOLE_OUTPUT
624 | std::cout << std::endl << "- find materials in: " << pathtomat << std::endl;
625 | #endif
626 |
627 | // Load Materials
628 | LoadMaterials(pathtomat);
629 | }
630 | }
631 |
632 | #ifdef OBJL_CONSOLE_OUTPUT
633 | std::cout << std::endl;
634 | #endif
635 |
636 | // Deal with last mesh
637 |
638 | if (!Indices.empty() && !Vertices.empty())
639 | {
640 | // Create Mesh
641 | tempMesh = Mesh(Vertices, Indices);
642 | tempMesh.MeshName = meshname;
643 |
644 | // Insert Mesh
645 | LoadedMeshes.push_back(tempMesh);
646 | }
647 |
648 | file.close();
649 |
650 | // Set Materials for each Mesh
651 | for (int i = 0; i < MeshMatNames.size(); i++)
652 | {
653 | std::string matname = MeshMatNames[i];
654 |
655 | // Find corresponding material name in loaded materials
656 | // when found copy material variables into mesh material
657 | for (int j = 0; j < LoadedMaterials.size(); j++)
658 | {
659 | if (LoadedMaterials[j].name == matname)
660 | {
661 | LoadedMeshes[i].MeshMaterial = LoadedMaterials[j];
662 | break;
663 | }
664 | }
665 | }
666 |
667 | if (LoadedMeshes.empty() && LoadedVertices.empty() && LoadedIndices.empty())
668 | {
669 | return false;
670 | }
671 | else
672 | {
673 | return true;
674 | }
675 | }
676 |
677 | // Loaded Mesh Objects
678 | std::vector LoadedMeshes;
679 | // Loaded Vertex Objects
680 | std::vector LoadedVertices;
681 | // Loaded Index Positions
682 | std::vector LoadedIndices;
683 | // Loaded Material Objects
684 | std::vector LoadedMaterials;
685 |
686 | private:
687 | // Generate vertices from a list of positions,
688 | // tcoords, normals and a face line
689 | void GenVerticesFromRawOBJ(std::vector& oVerts,
690 | const std::vector& iPositions,
691 | const std::vector& iTCoords,
692 | const std::vector& iNormals,
693 | std::string icurline)
694 | {
695 | std::vector sface, svert;
696 | Vertex vVert;
697 | algorithm::split(algorithm::tail(icurline), sface, " ");
698 |
699 | bool noNormal = false;
700 |
701 | // For every given vertex do this
702 | for (int i = 0; i < int(sface.size()); i++)
703 | {
704 | // See What type the vertex is.
705 | int vtype;
706 |
707 | algorithm::split(sface[i], svert, "/");
708 |
709 | // Check for just position - v1
710 | if (svert.size() == 1)
711 | {
712 | // Only position
713 | vtype = 1;
714 | }
715 |
716 | // Check for position & texture - v1/vt1
717 | if (svert.size() == 2)
718 | {
719 | // Position & Texture
720 | vtype = 2;
721 | }
722 |
723 | // Check for Position, Texture and Normal - v1/vt1/vn1
724 | // or if Position and Normal - v1//vn1
725 | if (svert.size() == 3)
726 | {
727 | if (svert[1] != "")
728 | {
729 | // Position, Texture, and Normal
730 | vtype = 4;
731 | }
732 | else
733 | {
734 | // Position & Normal
735 | vtype = 3;
736 | }
737 | }
738 |
739 | // Calculate and store the vertex
740 | switch (vtype)
741 | {
742 | case 1: // P
743 | {
744 | vVert.Position = algorithm::getElement(iPositions, svert[0]);
745 | vVert.TextureCoordinate = Vector2(0, 0);
746 | noNormal = true;
747 | oVerts.push_back(vVert);
748 | break;
749 | }
750 | case 2: // P/T
751 | {
752 | vVert.Position = algorithm::getElement(iPositions, svert[0]);
753 | vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]);
754 | noNormal = true;
755 | oVerts.push_back(vVert);
756 | break;
757 | }
758 | case 3: // P//N
759 | {
760 | vVert.Position = algorithm::getElement(iPositions, svert[0]);
761 | vVert.TextureCoordinate = Vector2(0, 0);
762 | vVert.Normal = algorithm::getElement(iNormals, svert[2]);
763 | oVerts.push_back(vVert);
764 | break;
765 | }
766 | case 4: // P/T/N
767 | {
768 | vVert.Position = algorithm::getElement(iPositions, svert[0]);
769 | vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]);
770 | vVert.Normal = algorithm::getElement(iNormals, svert[2]);
771 | oVerts.push_back(vVert);
772 | break;
773 | }
774 | default:
775 | {
776 | break;
777 | }
778 | }
779 | }
780 |
781 | // take care of missing normals
782 | // these may not be truly acurate but it is the
783 | // best they get for not compiling a mesh with normals
784 | if (noNormal)
785 | {
786 | Vector3 A = oVerts[0].Position - oVerts[1].Position;
787 | Vector3 B = oVerts[2].Position - oVerts[1].Position;
788 |
789 | Vector3 normal = math::CrossV3(A, B);
790 |
791 | for (int i = 0; i < int(oVerts.size()); i++)
792 | {
793 | oVerts[i].Normal = normal;
794 | }
795 | }
796 | }
797 |
798 | // Triangulate a list of vertices into a face by printing
799 | // inducies corresponding with triangles within it
800 | void VertexTriangluation(std::vector& oIndices,
801 | const std::vector& iVerts)
802 | {
803 | // If there are 2 or less verts,
804 | // no triangle can be created,
805 | // so exit
806 | if (iVerts.size() < 3)
807 | {
808 | return;
809 | }
810 | // If it is a triangle no need to calculate it
811 | if (iVerts.size() == 3)
812 | {
813 | oIndices.push_back(0);
814 | oIndices.push_back(1);
815 | oIndices.push_back(2);
816 | return;
817 | }
818 |
819 | // Create a list of vertices
820 | std::vector tVerts = iVerts;
821 |
822 | while (true)
823 | {
824 | // For every vertex
825 | for (int i = 0; i < int(tVerts.size()); i++)
826 | {
827 | // pPrev = the previous vertex in the list
828 | Vertex pPrev;
829 | if (i == 0)
830 | {
831 | pPrev = tVerts[tVerts.size() - 1];
832 | }
833 | else
834 | {
835 | pPrev = tVerts[i - 1];
836 | }
837 |
838 | // pCur = the current vertex;
839 | Vertex pCur = tVerts[i];
840 |
841 | // pNext = the next vertex in the list
842 | Vertex pNext;
843 | if (i == tVerts.size() - 1)
844 | {
845 | pNext = tVerts[0];
846 | }
847 | else
848 | {
849 | pNext = tVerts[i + 1];
850 | }
851 |
852 | // Check to see if there are only 3 verts left
853 | // if so this is the last triangle
854 | if (tVerts.size() == 3)
855 | {
856 | // Create a triangle from pCur, pPrev, pNext
857 | for (int j = 0; j < int(tVerts.size()); j++)
858 | {
859 | if (iVerts[j].Position == pCur.Position)
860 | oIndices.push_back(j);
861 | if (iVerts[j].Position == pPrev.Position)
862 | oIndices.push_back(j);
863 | if (iVerts[j].Position == pNext.Position)
864 | oIndices.push_back(j);
865 | }
866 |
867 | tVerts.clear();
868 | break;
869 | }
870 | if (tVerts.size() == 4)
871 | {
872 | // Create a triangle from pCur, pPrev, pNext
873 | for (int j = 0; j < int(iVerts.size()); j++)
874 | {
875 | if (iVerts[j].Position == pCur.Position)
876 | oIndices.push_back(j);
877 | if (iVerts[j].Position == pPrev.Position)
878 | oIndices.push_back(j);
879 | if (iVerts[j].Position == pNext.Position)
880 | oIndices.push_back(j);
881 | }
882 |
883 | Vector3 tempVec;
884 | for (int j = 0; j < int(tVerts.size()); j++)
885 | {
886 | if (tVerts[j].Position != pCur.Position
887 | && tVerts[j].Position != pPrev.Position
888 | && tVerts[j].Position != pNext.Position)
889 | {
890 | tempVec = tVerts[j].Position;
891 | break;
892 | }
893 | }
894 |
895 | // Create a triangle from pCur, pPrev, pNext
896 | for (int j = 0; j < int(iVerts.size()); j++)
897 | {
898 | if (iVerts[j].Position == pPrev.Position)
899 | oIndices.push_back(j);
900 | if (iVerts[j].Position == pNext.Position)
901 | oIndices.push_back(j);
902 | if (iVerts[j].Position == tempVec)
903 | oIndices.push_back(j);
904 | }
905 |
906 | tVerts.clear();
907 | break;
908 | }
909 |
910 | // If Vertex is not an interior vertex
911 | float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (180.0f / 3.14159265359f);
912 | if (angle <= 0 && angle >= 180)
913 | continue;
914 |
915 | // If any vertices are within this triangle
916 | bool inTri = false;
917 | for (int j = 0; j < int(iVerts.size()); j++)
918 | {
919 | if (algorithm::inTriangle(iVerts[j].Position, pPrev.Position, pCur.Position, pNext.Position)
920 | && iVerts[j].Position != pPrev.Position
921 | && iVerts[j].Position != pCur.Position
922 | && iVerts[j].Position != pNext.Position)
923 | {
924 | inTri = true;
925 | break;
926 | }
927 | }
928 | if (inTri)
929 | continue;
930 |
931 | // Create a triangle from pCur, pPrev, pNext
932 | for (int j = 0; j < int(iVerts.size()); j++)
933 | {
934 | if (iVerts[j].Position == pCur.Position)
935 | oIndices.push_back(j);
936 | if (iVerts[j].Position == pPrev.Position)
937 | oIndices.push_back(j);
938 | if (iVerts[j].Position == pNext.Position)
939 | oIndices.push_back(j);
940 | }
941 |
942 | // Delete pCur from the list
943 | for (int j = 0; j < int(tVerts.size()); j++)
944 | {
945 | if (tVerts[j].Position == pCur.Position)
946 | {
947 | tVerts.erase(tVerts.begin() + j);
948 | break;
949 | }
950 | }
951 |
952 | // reset i to the start
953 | // -1 since loop will add 1 to it
954 | i = -1;
955 | }
956 |
957 | // if no triangles were created
958 | if (oIndices.size() == 0)
959 | break;
960 |
961 | // if no more vertices
962 | if (tVerts.size() == 0)
963 | break;
964 | }
965 | }
966 |
967 | // Load Materials from .mtl file
968 | bool LoadMaterials(std::string path)
969 | {
970 | // If the file is not a material file return false
971 | if (path.substr(path.size() - 4, path.size()) != ".mtl")
972 | return false;
973 |
974 | std::ifstream file(path);
975 |
976 | // If the file is not found return false
977 | if (!file.is_open())
978 | return false;
979 |
980 | Material tempMaterial;
981 |
982 | bool listening = false;
983 |
984 | // Go through each line looking for material variables
985 | std::string curline;
986 | while (std::getline(file, curline))
987 | {
988 | // new material and material name
989 | if (algorithm::firstToken(curline) == "newmtl")
990 | {
991 | if (!listening)
992 | {
993 | listening = true;
994 |
995 | if (curline.size() > 7)
996 | {
997 | tempMaterial.name = algorithm::tail(curline);
998 | }
999 | else
1000 | {
1001 | tempMaterial.name = "none";
1002 | }
1003 | }
1004 | else
1005 | {
1006 | // Generate the material
1007 |
1008 | // Push Back loaded Material
1009 | LoadedMaterials.push_back(tempMaterial);
1010 |
1011 | // Clear Loaded Material
1012 | tempMaterial = Material();
1013 |
1014 | if (curline.size() > 7)
1015 | {
1016 | tempMaterial.name = algorithm::tail(curline);
1017 | }
1018 | else
1019 | {
1020 | tempMaterial.name = "none";
1021 | }
1022 | }
1023 | }
1024 | // Ambient Color
1025 | if (algorithm::firstToken(curline) == "Ka")
1026 | {
1027 | std::vector temp;
1028 | algorithm::split(algorithm::tail(curline), temp, " ");
1029 |
1030 | if (temp.size() != 3)
1031 | continue;
1032 |
1033 | tempMaterial.Ka.X = std::stof(temp[0]);
1034 | tempMaterial.Ka.Y = std::stof(temp[1]);
1035 | tempMaterial.Ka.Z = std::stof(temp[2]);
1036 | }
1037 | // Diffuse Color
1038 | if (algorithm::firstToken(curline) == "Kd")
1039 | {
1040 | std::vector temp;
1041 | algorithm::split(algorithm::tail(curline), temp, " ");
1042 |
1043 | if (temp.size() != 3)
1044 | continue;
1045 |
1046 | tempMaterial.Kd.X = std::stof(temp[0]);
1047 | tempMaterial.Kd.Y = std::stof(temp[1]);
1048 | tempMaterial.Kd.Z = std::stof(temp[2]);
1049 | }
1050 | // Specular Color
1051 | if (algorithm::firstToken(curline) == "Ks")
1052 | {
1053 | std::vector temp;
1054 | algorithm::split(algorithm::tail(curline), temp, " ");
1055 |
1056 | if (temp.size() != 3)
1057 | continue;
1058 |
1059 | tempMaterial.Ks.X = std::stof(temp[0]);
1060 | tempMaterial.Ks.Y = std::stof(temp[1]);
1061 | tempMaterial.Ks.Z = std::stof(temp[2]);
1062 | }
1063 | // Specular Exponent
1064 | if (algorithm::firstToken(curline) == "Ns")
1065 | {
1066 | tempMaterial.Ns = std::stof(algorithm::tail(curline));
1067 | }
1068 | // Optical Density
1069 | if (algorithm::firstToken(curline) == "Ni")
1070 | {
1071 | tempMaterial.Ni = std::stof(algorithm::tail(curline));
1072 | }
1073 | // Dissolve
1074 | if (algorithm::firstToken(curline) == "d")
1075 | {
1076 | tempMaterial.d = std::stof(algorithm::tail(curline));
1077 | }
1078 | // Illumination
1079 | if (algorithm::firstToken(curline) == "illum")
1080 | {
1081 | tempMaterial.illum = std::stoi(algorithm::tail(curline));
1082 | }
1083 | // Ambient Texture Map
1084 | if (algorithm::firstToken(curline) == "map_Ka")
1085 | {
1086 | tempMaterial.map_Ka = algorithm::tail(curline);
1087 | }
1088 | // Diffuse Texture Map
1089 | if (algorithm::firstToken(curline) == "map_Kd")
1090 | {
1091 | tempMaterial.map_Kd = algorithm::tail(curline);
1092 | }
1093 | // Specular Texture Map
1094 | if (algorithm::firstToken(curline) == "map_Ks")
1095 | {
1096 | tempMaterial.map_Ks = algorithm::tail(curline);
1097 | }
1098 | // Specular Hightlight Map
1099 | if (algorithm::firstToken(curline) == "map_Ns")
1100 | {
1101 | tempMaterial.map_Ns = algorithm::tail(curline);
1102 | }
1103 | // Alpha Texture Map
1104 | if (algorithm::firstToken(curline) == "map_d")
1105 | {
1106 | tempMaterial.map_d = algorithm::tail(curline);
1107 | }
1108 | // Bump Map
1109 | if (algorithm::firstToken(curline) == "map_Bump" || algorithm::firstToken(curline) == "map_bump")
1110 | {
1111 | tempMaterial.map_bump = algorithm::tail(curline);
1112 | }
1113 | }
1114 |
1115 | // Deal with last material
1116 |
1117 | // Push Back loaded Material
1118 | LoadedMaterials.push_back(tempMaterial);
1119 |
1120 | // Test to see if anything was loaded
1121 | // If not return false
1122 | if (LoadedMaterials.empty())
1123 | return false;
1124 | // If so return true
1125 | else
1126 | return true;
1127 | }
1128 | };
1129 | }
1130 |
--------------------------------------------------------------------------------
/DX12Base/Dx12Device.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define DX_DEBUG_EVENT 1
4 | #define DX_DEBUG_RESOURCE_NAME 1
5 |
6 | // Windows and Dx12 includes
7 | #include