feat: 实现D3D12 RHI抽象层,修复PSO创建问题
- 添加RHI接口定义(IRHIDevice, ICommandList, IResource等) - 实现D3D12Device, D3D12CommandList, D3D12PipelineState等 - 修复RootSignature参数数量(3->4)与HelloEarth一致 - 修复DSV格式设置(Unknown->D24_UNorm_S8_UInt) - 添加Geometry Shader编译 - 创建XCEngineDemo项目验证RHI功能
This commit is contained in:
@@ -1,673 +0,0 @@
|
|||||||
#include "BattleFireDirect.h"
|
|
||||||
ID3D12Device* gD3D12Device = nullptr;
|
|
||||||
ID3D12CommandQueue* gCommandQueue = nullptr;
|
|
||||||
IDXGISwapChain3* gSwapChain = nullptr;
|
|
||||||
ID3D12Resource* gDSRT = nullptr, * gColorRTs[2];
|
|
||||||
int gCurrentRTIndex = 0;
|
|
||||||
ID3D12DescriptorHeap* gSwapChainRTVHeap = nullptr;
|
|
||||||
ID3D12DescriptorHeap* gSwapChainDSVHeap = nullptr;
|
|
||||||
UINT gRTVDescriptorSize = 0;
|
|
||||||
UINT gDSVDescriptorSize = 0;
|
|
||||||
ID3D12CommandAllocator* gCommandAllocator = nullptr;
|
|
||||||
ID3D12GraphicsCommandList* gCommandList = nullptr;
|
|
||||||
ID3D12Fence* gFence = nullptr;
|
|
||||||
HANDLE gFenceEvent = nullptr;
|
|
||||||
UINT64 gFenceValue = 0;
|
|
||||||
|
|
||||||
ID3D12RootSignature* InitRootSignature() {
|
|
||||||
//1110001110101111111111111111111111
|
|
||||||
D3D12_ROOT_PARAMETER rootParameters[4];
|
|
||||||
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
|
||||||
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
||||||
rootParameters[1].Constants.RegisterSpace = 0;
|
|
||||||
rootParameters[1].Constants.ShaderRegister = 0;
|
|
||||||
rootParameters[1].Constants.Num32BitValues = 4;
|
|
||||||
|
|
||||||
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
||||||
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
||||||
rootParameters[0].Descriptor.RegisterSpace = 0;
|
|
||||||
rootParameters[0].Descriptor.ShaderRegister = 1;//cbv
|
|
||||||
|
|
||||||
D3D12_DESCRIPTOR_RANGE descriptorRange[1];
|
|
||||||
descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
||||||
descriptorRange[0].RegisterSpace = 0;
|
|
||||||
descriptorRange[0].BaseShaderRegister = 0;//t0
|
|
||||||
descriptorRange[0].NumDescriptors = 1;
|
|
||||||
descriptorRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
||||||
|
|
||||||
rootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
||||||
rootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
||||||
rootParameters[2].DescriptorTable.pDescriptorRanges = descriptorRange;
|
|
||||||
rootParameters[2].DescriptorTable.NumDescriptorRanges = _countof(descriptorRange);//cbv
|
|
||||||
|
|
||||||
rootParameters[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
|
|
||||||
rootParameters[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
||||||
rootParameters[3].Descriptor.RegisterSpace = 1;
|
|
||||||
rootParameters[3].Descriptor.ShaderRegister = 0;//srv
|
|
||||||
|
|
||||||
D3D12_STATIC_SAMPLER_DESC samplerDesc[1];
|
|
||||||
memset(samplerDesc, 0,sizeof(D3D12_STATIC_SAMPLER_DESC)*_countof(samplerDesc));
|
|
||||||
samplerDesc[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
||||||
samplerDesc[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
|
||||||
samplerDesc[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
|
||||||
samplerDesc[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
|
||||||
samplerDesc[0].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
|
||||||
samplerDesc[0].MaxLOD = D3D12_FLOAT32_MAX;
|
|
||||||
samplerDesc[0].RegisterSpace = 0;
|
|
||||||
samplerDesc[0].ShaderRegister = 0;//s0
|
|
||||||
samplerDesc[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
||||||
|
|
||||||
D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
|
|
||||||
rootSignatureDesc.NumParameters = _countof(rootParameters);
|
|
||||||
rootSignatureDesc.pParameters = rootParameters;
|
|
||||||
rootSignatureDesc.NumStaticSamplers = _countof(samplerDesc);
|
|
||||||
rootSignatureDesc.pStaticSamplers = samplerDesc;
|
|
||||||
rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
|
||||||
|
|
||||||
//64 DWORD -> float 128 WORD -> 16bit
|
|
||||||
ID3DBlob* signature;
|
|
||||||
HRESULT hResult = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr);
|
|
||||||
ID3D12RootSignature* d3d12RootSignature;
|
|
||||||
gD3D12Device->CreateRootSignature(
|
|
||||||
0, signature->GetBufferPointer(), signature->GetBufferSize(),
|
|
||||||
IID_PPV_ARGS(&d3d12RootSignature));
|
|
||||||
|
|
||||||
return d3d12RootSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12RootSignature* InitVolumeRootSignature() {
|
|
||||||
D3D12_ROOT_PARAMETER rootParameters[2];
|
|
||||||
|
|
||||||
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
||||||
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
||||||
rootParameters[0].Descriptor.RegisterSpace = 0;
|
|
||||||
rootParameters[0].Descriptor.ShaderRegister = 1;
|
|
||||||
|
|
||||||
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
|
|
||||||
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
||||||
rootParameters[1].Descriptor.RegisterSpace = 0;
|
|
||||||
rootParameters[1].Descriptor.ShaderRegister = 1;
|
|
||||||
|
|
||||||
D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
|
|
||||||
rootSignatureDesc.NumParameters = _countof(rootParameters);
|
|
||||||
rootSignatureDesc.pParameters = rootParameters;
|
|
||||||
rootSignatureDesc.NumStaticSamplers = 0;
|
|
||||||
rootSignatureDesc.pStaticSamplers = nullptr;
|
|
||||||
rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
|
||||||
|
|
||||||
ID3DBlob* signature;
|
|
||||||
HRESULT hResult = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr);
|
|
||||||
ID3D12RootSignature* d3d12RootSignature;
|
|
||||||
gD3D12Device->CreateRootSignature(
|
|
||||||
0, signature->GetBufferPointer(), signature->GetBufferSize(),
|
|
||||||
IID_PPV_ARGS(&d3d12RootSignature));
|
|
||||||
|
|
||||||
return d3d12RootSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateShaderFromFile(
|
|
||||||
LPCTSTR inShaderFilePath,
|
|
||||||
const char* inMainFunctionName,
|
|
||||||
const char* inTarget,//"vs_5_0","ps_5_0","vs_4_0"
|
|
||||||
D3D12_SHADER_BYTECODE* inShader) {
|
|
||||||
ID3DBlob* shaderBuffer = nullptr;
|
|
||||||
ID3DBlob* errorBuffer = nullptr;
|
|
||||||
HRESULT hResult = D3DCompileFromFile(inShaderFilePath, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
|
||||||
inMainFunctionName, inTarget, D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
|
|
||||||
0, &shaderBuffer, &errorBuffer);
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
char szLog[1024] = {0};
|
|
||||||
if (errorBuffer) {
|
|
||||||
strcpy(szLog, (char*)errorBuffer->GetBufferPointer());
|
|
||||||
} else {
|
|
||||||
strcpy(szLog, "Unknown error");
|
|
||||||
}
|
|
||||||
printf("CreateShaderFromFile error : [%s][%s]:[%s]\n", inMainFunctionName, inTarget, szLog);
|
|
||||||
errorBuffer->Release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
inShader->pShaderBytecode = shaderBuffer->GetBufferPointer();
|
|
||||||
inShader->BytecodeLength = shaderBuffer->GetBufferSize();
|
|
||||||
}
|
|
||||||
ID3D12Resource* CreateConstantBufferObject(int inDataLen) {
|
|
||||||
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
|
|
||||||
d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
|
|
||||||
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
|
|
||||||
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
||||||
d3d12ResourceDesc.Alignment = 0;
|
|
||||||
d3d12ResourceDesc.Width = inDataLen;
|
|
||||||
d3d12ResourceDesc.Height = 1;
|
|
||||||
d3d12ResourceDesc.DepthOrArraySize = 1;
|
|
||||||
d3d12ResourceDesc.MipLevels = 1;
|
|
||||||
d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Count = 1;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Quality = 0;
|
|
||||||
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
||||||
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
||||||
|
|
||||||
ID3D12Resource* bufferObject = nullptr;
|
|
||||||
gD3D12Device->CreateCommittedResource(
|
|
||||||
&d3dHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12ResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&bufferObject)
|
|
||||||
);
|
|
||||||
return bufferObject;
|
|
||||||
}
|
|
||||||
void UpdateConstantBuffer(ID3D12Resource* inCB, void* inData, int inDataLen) {
|
|
||||||
D3D12_RANGE d3d12Range = { 0 };
|
|
||||||
unsigned char* pBuffer = nullptr;
|
|
||||||
inCB->Map(0, &d3d12Range, (void**)&pBuffer);
|
|
||||||
memcpy(pBuffer, inData, inDataLen);
|
|
||||||
inCB->Unmap(0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader,
|
|
||||||
D3D12_SHADER_BYTECODE inGSShader) {
|
|
||||||
D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = {
|
|
||||||
{"POSITION",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
|
|
||||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 4,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
|
|
||||||
{"NORMAL",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 8,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
|
|
||||||
{"TANGENT",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 12,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}
|
|
||||||
};
|
|
||||||
D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {};
|
|
||||||
vertexDataLayoutDesc.NumElements = 4;
|
|
||||||
vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc;
|
|
||||||
|
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
|
||||||
psoDesc.pRootSignature = inID3D12RootSignature;
|
|
||||||
psoDesc.VS = inVertexShader;
|
|
||||||
psoDesc.GS = inGSShader;
|
|
||||||
psoDesc.PS = inPixelShader;
|
|
||||||
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
psoDesc.SampleDesc.Count = 1;
|
|
||||||
psoDesc.SampleDesc.Quality = 0;
|
|
||||||
psoDesc.SampleMask = 0xffffffff;
|
|
||||||
psoDesc.InputLayout = vertexDataLayoutDesc;
|
|
||||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
||||||
|
|
||||||
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
||||||
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
|
|
||||||
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
|
||||||
|
|
||||||
psoDesc.DepthStencilState.DepthEnable = true;
|
|
||||||
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
||||||
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
|
||||||
|
|
||||||
psoDesc.BlendState = { 0 };
|
|
||||||
D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc = {
|
|
||||||
FALSE,FALSE,
|
|
||||||
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
|
|
||||||
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
|
|
||||||
D3D12_LOGIC_OP_NOOP,
|
|
||||||
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
||||||
psoDesc.BlendState.RenderTarget[i] = rtBlendDesc;
|
|
||||||
psoDesc.NumRenderTargets = 1;
|
|
||||||
ID3D12PipelineState* d3d12PSO = nullptr;
|
|
||||||
|
|
||||||
HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return d3d12PSO;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12PipelineState* CreateVolumePSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader) {
|
|
||||||
D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = {
|
|
||||||
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}
|
|
||||||
};
|
|
||||||
D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {};
|
|
||||||
vertexDataLayoutDesc.NumElements = 1;
|
|
||||||
vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc;
|
|
||||||
|
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
|
||||||
psoDesc.pRootSignature = inID3D12RootSignature;
|
|
||||||
psoDesc.VS = inVertexShader;
|
|
||||||
psoDesc.PS = inPixelShader;
|
|
||||||
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
psoDesc.SampleDesc.Count = 1;
|
|
||||||
psoDesc.SampleDesc.Quality = 0;
|
|
||||||
psoDesc.SampleMask = 0xffffffff;
|
|
||||||
psoDesc.InputLayout = vertexDataLayoutDesc;
|
|
||||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
|
||||||
|
|
||||||
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
|
|
||||||
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
||||||
psoDesc.RasterizerState.FrontCounterClockwise = FALSE;
|
|
||||||
psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
|
||||||
psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
|
||||||
psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
|
||||||
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
|
||||||
psoDesc.RasterizerState.MultisampleEnable = FALSE;
|
|
||||||
psoDesc.RasterizerState.AntialiasedLineEnable = FALSE;
|
|
||||||
psoDesc.RasterizerState.ForcedSampleCount = 0;
|
|
||||||
psoDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
||||||
|
|
||||||
psoDesc.DepthStencilState.DepthEnable = TRUE;
|
|
||||||
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
||||||
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
|
|
||||||
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
|
||||||
|
|
||||||
psoDesc.BlendState.AlphaToCoverageEnable = FALSE;
|
|
||||||
psoDesc.BlendState.IndependentBlendEnable = FALSE;
|
|
||||||
for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendEnable = FALSE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].LogicOpEnable = FALSE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].SrcBlend = D3D12_BLEND_ONE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].DestBlend = D3D12_BLEND_ZERO;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].SrcBlendAlpha = D3D12_BLEND_ONE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].DestBlendAlpha = D3D12_BLEND_ZERO;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
}
|
|
||||||
psoDesc.NumRenderTargets = 1;
|
|
||||||
ID3D12PipelineState* d3d12PSO = nullptr;
|
|
||||||
|
|
||||||
HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
printf("CreateVolumePSO failed: 0x%08X\n", hResult);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return d3d12PSO;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12PipelineState* CreateQuadPSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader) {
|
|
||||||
D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = {
|
|
||||||
{"POSITION",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
|
|
||||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,8,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}
|
|
||||||
};
|
|
||||||
D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {};
|
|
||||||
vertexDataLayoutDesc.NumElements = 2;
|
|
||||||
vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc;
|
|
||||||
|
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
|
||||||
psoDesc.pRootSignature = inID3D12RootSignature;
|
|
||||||
psoDesc.VS = inVertexShader;
|
|
||||||
psoDesc.PS = inPixelShader;
|
|
||||||
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
psoDesc.SampleDesc.Count = 1;
|
|
||||||
psoDesc.SampleDesc.Quality = 0;
|
|
||||||
psoDesc.SampleMask = 0xffffffff;
|
|
||||||
psoDesc.InputLayout = vertexDataLayoutDesc;
|
|
||||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
||||||
|
|
||||||
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
||||||
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
||||||
psoDesc.RasterizerState.FrontCounterClockwise = FALSE;
|
|
||||||
psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
|
||||||
psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
|
||||||
psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
|
||||||
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
|
||||||
psoDesc.RasterizerState.MultisampleEnable = FALSE;
|
|
||||||
psoDesc.RasterizerState.AntialiasedLineEnable = FALSE;
|
|
||||||
psoDesc.RasterizerState.ForcedSampleCount = 0;
|
|
||||||
psoDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
||||||
|
|
||||||
psoDesc.DepthStencilState.DepthEnable = TRUE;
|
|
||||||
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
|
|
||||||
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
|
||||||
|
|
||||||
psoDesc.BlendState.AlphaToCoverageEnable = FALSE;
|
|
||||||
psoDesc.BlendState.IndependentBlendEnable = FALSE;
|
|
||||||
for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendEnable = TRUE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].LogicOpEnable = FALSE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].SrcBlendAlpha = D3D12_BLEND_ONE;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
||||||
psoDesc.BlendState.RenderTarget[i].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
}
|
|
||||||
psoDesc.NumRenderTargets = 1;
|
|
||||||
ID3D12PipelineState* d3d12PSO = nullptr;
|
|
||||||
|
|
||||||
HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
printf("CreateQuadPSO failed: 0x%08X\n", hResult);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return d3d12PSO;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitD3D12(HWND inHWND, int inWidth, int inHeight) {
|
|
||||||
HRESULT hResult;
|
|
||||||
UINT dxgiFactoryFlags = 0;
|
|
||||||
#ifdef _DEBUG
|
|
||||||
{
|
|
||||||
ID3D12Debug* debugController = nullptr;
|
|
||||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
|
||||||
debugController->EnableDebugLayer();
|
|
||||||
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
IDXGIFactory4* dxgiFactory;
|
|
||||||
hResult = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
IDXGIAdapter1* adapter;
|
|
||||||
int adapterIndex = 0;
|
|
||||||
bool adapterFound = false;
|
|
||||||
while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) {
|
|
||||||
DXGI_ADAPTER_DESC1 desc;
|
|
||||||
adapter->GetDesc1(&desc);
|
|
||||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr);
|
|
||||||
if (SUCCEEDED(hResult)) {
|
|
||||||
adapterFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
adapterIndex++;
|
|
||||||
}
|
|
||||||
if (false == adapterFound) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&gD3D12Device));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
D3D12_COMMAND_QUEUE_DESC d3d12CommandQueueDesc = {};
|
|
||||||
hResult = gD3D12Device->CreateCommandQueue(&d3d12CommandQueueDesc, IID_PPV_ARGS(&gCommandQueue));
|
|
||||||
if (FAILED(hResult)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
|
|
||||||
swapChainDesc.BufferCount = 2;
|
|
||||||
swapChainDesc.BufferDesc = {};
|
|
||||||
swapChainDesc.BufferDesc.Width = inWidth;
|
|
||||||
swapChainDesc.BufferDesc.Height = inHeight;
|
|
||||||
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
||||||
swapChainDesc.OutputWindow = inHWND;
|
|
||||||
swapChainDesc.SampleDesc.Count = 1;
|
|
||||||
swapChainDesc.Windowed = true;
|
|
||||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
||||||
|
|
||||||
IDXGISwapChain* swapChain = nullptr;
|
|
||||||
dxgiFactory->CreateSwapChain(gCommandQueue, &swapChainDesc, &swapChain);
|
|
||||||
gSwapChain = static_cast<IDXGISwapChain3*>(swapChain);
|
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
|
|
||||||
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
|
|
||||||
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
||||||
d3d12ResourceDesc.Alignment = 0;
|
|
||||||
d3d12ResourceDesc.Width = inWidth;
|
|
||||||
d3d12ResourceDesc.Height = inHeight;
|
|
||||||
d3d12ResourceDesc.DepthOrArraySize = 1;
|
|
||||||
d3d12ResourceDesc.MipLevels = 1;
|
|
||||||
d3d12ResourceDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Count = 1;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Quality = 0;
|
|
||||||
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
||||||
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
||||||
|
|
||||||
D3D12_CLEAR_VALUE dsClearValue = {};
|
|
||||||
dsClearValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
dsClearValue.DepthStencil.Depth = 1.0f;
|
|
||||||
dsClearValue.DepthStencil.Stencil = 0;
|
|
||||||
|
|
||||||
gD3D12Device->CreateCommittedResource(&d3dHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12ResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
|
||||||
&dsClearValue,
|
|
||||||
IID_PPV_ARGS(&gDSRT)
|
|
||||||
);
|
|
||||||
//RTV,DSV,alloc
|
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescRTV = {};
|
|
||||||
d3dDescriptorHeapDescRTV.NumDescriptors = 2;
|
|
||||||
d3dDescriptorHeapDescRTV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
||||||
gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescRTV, IID_PPV_ARGS(&gSwapChainRTVHeap));
|
|
||||||
gRTVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
||||||
|
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescDSV = {};
|
|
||||||
d3dDescriptorHeapDescDSV.NumDescriptors = 1;
|
|
||||||
d3dDescriptorHeapDescDSV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
|
||||||
gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescDSV, IID_PPV_ARGS(&gSwapChainDSVHeap));
|
|
||||||
gDSVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart();
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
gSwapChain->GetBuffer(i, IID_PPV_ARGS(&gColorRTs[i]));
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer;
|
|
||||||
rtvPointer.ptr = rtvHeapStart.ptr + i * gRTVDescriptorSize;
|
|
||||||
gD3D12Device->CreateRenderTargetView(gColorRTs[i], nullptr, rtvPointer);
|
|
||||||
}
|
|
||||||
D3D12_DEPTH_STENCIL_VIEW_DESC d3dDSViewDesc = {};
|
|
||||||
d3dDSViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
||||||
d3dDSViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
|
||||||
|
|
||||||
gD3D12Device->CreateDepthStencilView(gDSRT, &d3dDSViewDesc, gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart());
|
|
||||||
|
|
||||||
gD3D12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&gCommandAllocator));
|
|
||||||
gD3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, gCommandAllocator, nullptr, IID_PPV_ARGS(&gCommandList));
|
|
||||||
|
|
||||||
gD3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&gFence));
|
|
||||||
gFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ID3D12CommandAllocator* GetCommandAllocator() {
|
|
||||||
return gCommandAllocator;
|
|
||||||
}
|
|
||||||
ID3D12GraphicsCommandList* GetCommandList() {
|
|
||||||
return gCommandList;
|
|
||||||
}
|
|
||||||
void WaitForCompletionOfCommandList() {
|
|
||||||
if (gFence->GetCompletedValue() < gFenceValue) {
|
|
||||||
gFence->SetEventOnCompletion(gFenceValue, gFenceEvent);
|
|
||||||
WaitForSingleObject(gFenceEvent, INFINITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void EndCommandList() {
|
|
||||||
gCommandList->Close();//
|
|
||||||
ID3D12CommandList* ppCommandLists[] = { gCommandList };
|
|
||||||
gCommandQueue->ExecuteCommandLists(1, ppCommandLists);
|
|
||||||
//CommandList
|
|
||||||
gFenceValue += 1;
|
|
||||||
gCommandQueue->Signal(gFence, gFenceValue);//
|
|
||||||
}
|
|
||||||
void BeginRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList) {
|
|
||||||
gCurrentRTIndex = gSwapChain->GetCurrentBackBufferIndex();
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
|
||||||
inCommandList->ResourceBarrier(1, &barrier);
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE colorRT, dsv;
|
|
||||||
dsv.ptr = gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart().ptr;
|
|
||||||
colorRT.ptr = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart().ptr + gCurrentRTIndex * gRTVDescriptorSize;
|
|
||||||
inCommandList->OMSetRenderTargets(1, &colorRT, FALSE, &dsv);
|
|
||||||
D3D12_VIEWPORT viewport = { 0.0f,0.0f,1280.0f,720.0f };
|
|
||||||
D3D12_RECT scissorRect = { 0,0,1280,720 };
|
|
||||||
inCommandList->RSSetViewports(1, &viewport);
|
|
||||||
inCommandList->RSSetScissorRects(1, &scissorRect);
|
|
||||||
const float clearColor[] = { 0.0f,0.0f,0.0f,1.0f };
|
|
||||||
inCommandList->ClearRenderTargetView(colorRT, clearColor, 0, nullptr);
|
|
||||||
inCommandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
|
|
||||||
}
|
|
||||||
void EndRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList) {
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
|
|
||||||
inCommandList->ResourceBarrier(1, &barrier);
|
|
||||||
}
|
|
||||||
void SwapD3D12Buffers() {
|
|
||||||
gSwapChain->Present(0, 0);
|
|
||||||
}
|
|
||||||
ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList,
|
|
||||||
void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState) {
|
|
||||||
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
|
|
||||||
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;//gpu
|
|
||||||
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
|
|
||||||
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
||||||
d3d12ResourceDesc.Alignment = 0;
|
|
||||||
d3d12ResourceDesc.Width = inDataLen;
|
|
||||||
d3d12ResourceDesc.Height = 1;
|
|
||||||
d3d12ResourceDesc.DepthOrArraySize = 1;
|
|
||||||
d3d12ResourceDesc.MipLevels = 1;
|
|
||||||
d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Count = 1;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Quality = 0;
|
|
||||||
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
||||||
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
||||||
|
|
||||||
ID3D12Resource* bufferObject = nullptr;
|
|
||||||
gD3D12Device->CreateCommittedResource(
|
|
||||||
&d3dHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12ResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&bufferObject)
|
|
||||||
);
|
|
||||||
d3d12ResourceDesc = bufferObject->GetDesc();
|
|
||||||
UINT64 memorySizeUsed = 0;
|
|
||||||
UINT64 rowSizeInBytes = 0;
|
|
||||||
UINT rowUsed = 0;
|
|
||||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint;
|
|
||||||
gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0,
|
|
||||||
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
|
|
||||||
// 3 x 4 x 4 = 48bytes,32bytes,24bytes + 24bytes
|
|
||||||
ID3D12Resource* tempBufferObject = nullptr;
|
|
||||||
d3dHeapProperties = {};
|
|
||||||
d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
|
|
||||||
gD3D12Device->CreateCommittedResource(
|
|
||||||
&d3dHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12ResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&tempBufferObject)
|
|
||||||
);
|
|
||||||
|
|
||||||
BYTE* pData;
|
|
||||||
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
|
|
||||||
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
|
|
||||||
const BYTE* pSrcData = reinterpret_cast<BYTE*>(inData);
|
|
||||||
for (UINT i = 0; i < rowUsed; i++) {
|
|
||||||
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes);
|
|
||||||
}
|
|
||||||
tempBufferObject->Unmap(0, nullptr);
|
|
||||||
inCommandList->CopyBufferRegion(bufferObject, 0, tempBufferObject, 0, subresourceFootprint.Footprint.Width);
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(bufferObject, D3D12_RESOURCE_STATE_COPY_DEST, inFinalResourceState);
|
|
||||||
inCommandList->ResourceBarrier(1, &barrier);
|
|
||||||
return bufferObject;
|
|
||||||
}
|
|
||||||
D3D12_RESOURCE_BARRIER InitResourceBarrier(
|
|
||||||
ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState,
|
|
||||||
D3D12_RESOURCE_STATES inNextState) {
|
|
||||||
D3D12_RESOURCE_BARRIER d3d12ResourceBarrier;
|
|
||||||
memset(&d3d12ResourceBarrier, 0, sizeof(d3d12ResourceBarrier));
|
|
||||||
d3d12ResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
||||||
d3d12ResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
||||||
d3d12ResourceBarrier.Transition.pResource = inResource;
|
|
||||||
d3d12ResourceBarrier.Transition.StateBefore = inPrevState;
|
|
||||||
d3d12ResourceBarrier.Transition.StateAfter = inNextState;
|
|
||||||
d3d12ResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
||||||
return d3d12ResourceBarrier;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList,
|
|
||||||
const void* inPixelData, int inDataSizeInBytes, int inWidth, int inHeight,
|
|
||||||
DXGI_FORMAT inFormat) {
|
|
||||||
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
|
|
||||||
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
|
|
||||||
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
||||||
d3d12ResourceDesc.Alignment = 0;
|
|
||||||
d3d12ResourceDesc.Width = inWidth;
|
|
||||||
d3d12ResourceDesc.Height = inHeight;
|
|
||||||
d3d12ResourceDesc.DepthOrArraySize = 1;
|
|
||||||
d3d12ResourceDesc.MipLevels = 1;
|
|
||||||
d3d12ResourceDesc.Format = inFormat;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Count = 1;
|
|
||||||
d3d12ResourceDesc.SampleDesc.Quality = 0;
|
|
||||||
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
||||||
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
||||||
|
|
||||||
ID3D12Resource* texture = nullptr;
|
|
||||||
gD3D12Device->CreateCommittedResource(&d3dHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12ResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&texture)
|
|
||||||
);
|
|
||||||
d3d12ResourceDesc = texture->GetDesc();
|
|
||||||
UINT64 memorySizeUsed = 0;
|
|
||||||
UINT64 rowSizeInBytes = 0;
|
|
||||||
UINT rowUsed = 0;
|
|
||||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint;
|
|
||||||
gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0,
|
|
||||||
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
|
|
||||||
// 3 x 4 x 4 = 48bytes,32bytes,24bytes + 24bytes
|
|
||||||
ID3D12Resource* tempBufferObject = nullptr;
|
|
||||||
D3D12_HEAP_PROPERTIES d3dTempHeapProperties = {};
|
|
||||||
d3dTempHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC d3d12TempResourceDesc = {};
|
|
||||||
d3d12TempResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
||||||
d3d12TempResourceDesc.Alignment = 0;
|
|
||||||
d3d12TempResourceDesc.Width = memorySizeUsed;
|
|
||||||
d3d12TempResourceDesc.Height = 1;
|
|
||||||
d3d12TempResourceDesc.DepthOrArraySize = 1;
|
|
||||||
d3d12TempResourceDesc.MipLevels = 1;
|
|
||||||
d3d12TempResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
|
||||||
d3d12TempResourceDesc.SampleDesc.Count = 1;
|
|
||||||
d3d12TempResourceDesc.SampleDesc.Quality = 0;
|
|
||||||
d3d12TempResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
||||||
d3d12TempResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
||||||
|
|
||||||
gD3D12Device->CreateCommittedResource(
|
|
||||||
&d3dTempHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&d3d12TempResourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&tempBufferObject)
|
|
||||||
);
|
|
||||||
BYTE* pData;
|
|
||||||
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
|
|
||||||
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
|
|
||||||
const BYTE* pSrcData = reinterpret_cast<const BYTE*>(inPixelData);
|
|
||||||
for (UINT i = 0; i < rowUsed; i++) {
|
|
||||||
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes);
|
|
||||||
}
|
|
||||||
tempBufferObject->Unmap(0, nullptr);
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION dst = {};
|
|
||||||
dst.pResource = texture;
|
|
||||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
||||||
dst.SubresourceIndex = 0;
|
|
||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION src = {};
|
|
||||||
src.pResource = tempBufferObject;
|
|
||||||
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
||||||
src.PlacedFootprint = subresourceFootprint;
|
|
||||||
inCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(texture,
|
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
|
||||||
inCommandList->ResourceBarrier(1, &barrier);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
ID3D12Device* GetD3DDevice() {
|
|
||||||
return gD3D12Device;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <d3d12.h>
|
|
||||||
#include <dxgi1_4.h>
|
|
||||||
#include <d3dcompiler.h>
|
|
||||||
#include <DirectXMath.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER InitResourceBarrier(
|
|
||||||
ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState,
|
|
||||||
D3D12_RESOURCE_STATES inNextState);
|
|
||||||
ID3D12RootSignature* InitRootSignature();
|
|
||||||
ID3D12RootSignature* InitVolumeRootSignature();
|
|
||||||
void CreateShaderFromFile(
|
|
||||||
LPCTSTR inShaderFilePath,
|
|
||||||
const char* inMainFunctionName,
|
|
||||||
const char* inTarget,//"vs_5_0","ps_5_0","vs_4_0"
|
|
||||||
D3D12_SHADER_BYTECODE* inShader);
|
|
||||||
ID3D12Resource* CreateConstantBufferObject(int inDataLen);
|
|
||||||
void UpdateConstantBuffer(ID3D12Resource* inCB, void* inData, int inDataLen);
|
|
||||||
ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList,
|
|
||||||
void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState);
|
|
||||||
ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader,
|
|
||||||
D3D12_SHADER_BYTECODE inGSShader);
|
|
||||||
ID3D12PipelineState* CreateVolumePSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader);
|
|
||||||
ID3D12PipelineState* CreateQuadPSO(ID3D12RootSignature* inID3D12RootSignature,
|
|
||||||
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader);
|
|
||||||
bool InitD3D12(HWND inHWND, int inWidth, int inHeight);
|
|
||||||
ID3D12GraphicsCommandList* GetCommandList();
|
|
||||||
ID3D12CommandAllocator* GetCommandAllocator();
|
|
||||||
void WaitForCompletionOfCommandList();
|
|
||||||
void EndCommandList();
|
|
||||||
void BeginRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList);
|
|
||||||
void EndRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList);
|
|
||||||
void SwapD3D12Buffers();
|
|
||||||
ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList,
|
|
||||||
const void*inPixelData,int inDataSizeInBytes,int inWidth,int inHeight,
|
|
||||||
DXGI_FORMAT inFormat);
|
|
||||||
ID3D12Device* GetD3DDevice();
|
|
||||||
@@ -1,56 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
project(XCVolumeRenderer VERSION 1.0 LANGUAGES CXX)
|
project(XCEngine)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
|
||||||
|
|
||||||
set(SOURCES
|
add_subdirectory(engine)
|
||||||
main.cpp
|
add_subdirectory(mvs/XCEngineDemo)
|
||||||
BattleFireDirect.cpp
|
add_subdirectory(mvs/HelloEarth)
|
||||||
StaticMeshComponent.cpp
|
add_subdirectory(test)
|
||||||
Utils.cpp
|
|
||||||
stbi/stb_image.cpp
|
|
||||||
NanoVDBLoader.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(HEADERS
|
|
||||||
BattleFireDirect.h
|
|
||||||
StaticMeshComponent.h
|
|
||||||
Utils.h
|
|
||||||
stbi/stb_image.h
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS})
|
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE UNICODE _UNICODE)
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /utf-8 /MT)
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
|
||||||
${CMAKE_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
|
||||||
d3d12.lib
|
|
||||||
dxgi.lib
|
|
||||||
d3dcompiler.lib
|
|
||||||
winmm.lib
|
|
||||||
kernel32.lib
|
|
||||||
user32.lib
|
|
||||||
)
|
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE _DEBUG)
|
|
||||||
else()
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NDEBUG)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
|
||||||
${CMAKE_SOURCE_DIR}/Res
|
|
||||||
$<TARGET_FILE_DIR:${PROJECT_NAME}>/Res
|
|
||||||
)
|
|
||||||
|
|||||||
29
MVS/HelloEarth/CMakeLists.txt
Normal file
29
MVS/HelloEarth/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
project(HelloEarth)
|
||||||
|
|
||||||
|
add_executable(HelloEarth
|
||||||
|
WIN32
|
||||||
|
main.cpp
|
||||||
|
BattleFireDirect.cpp
|
||||||
|
StaticMeshComponent.cpp
|
||||||
|
Utils.cpp
|
||||||
|
stbi/stb_image.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(HelloEarth PRIVATE
|
||||||
|
UNICODE
|
||||||
|
_UNICODE
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(HelloEarth PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/mvs/HelloEarth
|
||||||
|
${CMAKE_SOURCE_DIR}/mvs/HelloEarth/stbi
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(HelloEarth PRIVATE
|
||||||
|
d3d12
|
||||||
|
dxgi
|
||||||
|
d3dcompiler
|
||||||
|
winmm
|
||||||
|
)
|
||||||
21
MVS/XCEngineDemo/CMakeLists.txt
Normal file
21
MVS/XCEngineDemo/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
add_executable(XCEngineDemo
|
||||||
|
WIN32
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(XCEngineDemo PRIVATE
|
||||||
|
UNICODE
|
||||||
|
_UNICODE
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(XCEngineDemo PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/engine/include
|
||||||
|
${CMAKE_SOURCE_DIR}/mvs/XCEngineDemo
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(XCEngineDemo PRIVATE
|
||||||
|
XCEngine
|
||||||
|
XCEngineD3D12
|
||||||
|
)
|
||||||
243
MVS/XCEngineDemo/main.cpp
Normal file
243
MVS/XCEngineDemo/main.cpp
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <RHI\IRHIDevice.h>
|
||||||
|
#include <RHI\IRHIResources.h>
|
||||||
|
#include <Rendering\Resources.h>
|
||||||
|
#include <Rendering\RenderContext.h>
|
||||||
|
#include <Rendering\StaticMeshComponent.h>
|
||||||
|
#include <Rendering\Shader.h>
|
||||||
|
#include <RHI\D3D12\D3D12RHI.h>
|
||||||
|
#include <RHI\D3D12\D3D12Resources.h>
|
||||||
|
|
||||||
|
#pragma comment(lib,"d3d12.lib")
|
||||||
|
#pragma comment(lib,"dxgi.lib")
|
||||||
|
#pragma comment(lib,"d3dcompiler.lib")
|
||||||
|
#pragma comment(lib,"winmm.lib")
|
||||||
|
|
||||||
|
using namespace XCEngine;
|
||||||
|
using namespace XCEngine::RHI;
|
||||||
|
|
||||||
|
LPCWSTR gWindowClassName = L"XCEngineDemo";
|
||||||
|
|
||||||
|
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
switch (msg) {
|
||||||
|
case WM_CLOSE:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hInstancePrev, LPWSTR lpCmdLine, int nShowCmd) {
|
||||||
|
AttachConsole(ATTACH_PARENT_PROCESS);
|
||||||
|
freopen("CONOUT$", "w", stdout);
|
||||||
|
freopen("CONOUT$", "w", stderr);
|
||||||
|
|
||||||
|
printf("=== XCEngine Demo Started ===\n");
|
||||||
|
printf("Registering window class...\n");
|
||||||
|
|
||||||
|
WNDCLASSEX wndClass = {};
|
||||||
|
wndClass.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wndClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
wndClass.hInstance = hInstance;
|
||||||
|
wndClass.lpszClassName = gWindowClassName;
|
||||||
|
wndClass.lpfnWndProc = WindowProc;
|
||||||
|
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
|
||||||
|
if (!RegisterClassEx(&wndClass)) {
|
||||||
|
printf("RegisterClassEx failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Window class registered\n");
|
||||||
|
printf("Creating window...\n");
|
||||||
|
|
||||||
|
int width = 1280;
|
||||||
|
int height = 720;
|
||||||
|
RECT rect = {0, 0, width, height};
|
||||||
|
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
|
||||||
|
|
||||||
|
HWND hwnd = CreateWindowExW(NULL, gWindowClassName, L"XCEngine Demo",
|
||||||
|
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);
|
||||||
|
|
||||||
|
if (!hwnd) {
|
||||||
|
printf("CreateWindowExW failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Window created\n");
|
||||||
|
printf("Creating D3D12Device...\n");
|
||||||
|
|
||||||
|
D3D12Device* device = new D3D12Device();
|
||||||
|
if (!device->Initialize(hwnd, width, height)) {
|
||||||
|
printf("D3D12Device Init Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("D3D12Device initialized\n");
|
||||||
|
|
||||||
|
RenderContext renderContext(device);
|
||||||
|
if (!renderContext.Initialize(width, height)) {
|
||||||
|
printf("RenderContext Init Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICommandList* cmdList = renderContext.GetCommandList();
|
||||||
|
|
||||||
|
ShaderBytecode vs, ps, gs = {};
|
||||||
|
if (!CompileShader("Res/Shader/gs.hlsl", "MainVS", "vs_5_1", vs)) {
|
||||||
|
printf("Compile VS Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!CompileShader("Res/Shader/gs.hlsl", "MainPS", "ps_5_1", ps)) {
|
||||||
|
printf("Compile PS Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!CompileShader("Res/Shader/gs.hlsl", "MainGS", "gs_5_1", gs)) {
|
||||||
|
printf("Compile GS Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Shaders compiled: VS=%llu, PS=%llu, GS=%llu\n",
|
||||||
|
(unsigned long long)vs.size, (unsigned long long)ps.size, (unsigned long long)gs.size);
|
||||||
|
|
||||||
|
RootParameter params[4] = {};
|
||||||
|
params[0].type = RootParameterType::CBV;
|
||||||
|
params[0].shaderRegister = 1;
|
||||||
|
params[0].registerSpace = 0;
|
||||||
|
params[0].visibility = ShaderVisibility::All;
|
||||||
|
|
||||||
|
params[1].type = RootParameterType::Constants;
|
||||||
|
params[1].shaderRegister = 0;
|
||||||
|
params[1].registerSpace = 0;
|
||||||
|
params[1].num32BitValues = 4;
|
||||||
|
params[1].visibility = ShaderVisibility::Vertex;
|
||||||
|
|
||||||
|
params[2].type = RootParameterType::DescriptorTable;
|
||||||
|
params[2].shaderRegister = 0;
|
||||||
|
params[2].registerSpace = 0;
|
||||||
|
params[2].visibility = ShaderVisibility::Pixel;
|
||||||
|
|
||||||
|
params[3].type = RootParameterType::SRV;
|
||||||
|
params[3].shaderRegister = 0;
|
||||||
|
params[3].registerSpace = 1;
|
||||||
|
params[3].visibility = ShaderVisibility::All;
|
||||||
|
|
||||||
|
RootSignatureDesc rsDesc = {};
|
||||||
|
rsDesc.parameters = params;
|
||||||
|
rsDesc.parameterCount = 4;
|
||||||
|
|
||||||
|
IRootSignature* rootSignature = nullptr;
|
||||||
|
if (!device->CreateRootSignature(&rootSignature, rsDesc)) {
|
||||||
|
printf("CreateRootSignature Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("RootSignature created\n");
|
||||||
|
|
||||||
|
InputElementDesc inputElements[4] = {};
|
||||||
|
inputElements[0].semanticName = "POSITION";
|
||||||
|
inputElements[0].semanticIndex = 0;
|
||||||
|
inputElements[0].format = Format::R32G32B32A32_Float;
|
||||||
|
inputElements[0].inputSlot = 0;
|
||||||
|
inputElements[0].alignedByteOffset = 0;
|
||||||
|
|
||||||
|
inputElements[1].semanticName = "TEXCOORD";
|
||||||
|
inputElements[1].semanticIndex = 0;
|
||||||
|
inputElements[1].format = Format::R32G32B32A32_Float;
|
||||||
|
inputElements[1].inputSlot = 0;
|
||||||
|
inputElements[1].alignedByteOffset = 16;
|
||||||
|
|
||||||
|
inputElements[2].semanticName = "NORMAL";
|
||||||
|
inputElements[2].semanticIndex = 0;
|
||||||
|
inputElements[2].format = Format::R32G32B32A32_Float;
|
||||||
|
inputElements[2].inputSlot = 0;
|
||||||
|
inputElements[2].alignedByteOffset = 32;
|
||||||
|
|
||||||
|
inputElements[3].semanticName = "TANGENT";
|
||||||
|
inputElements[3].semanticIndex = 0;
|
||||||
|
inputElements[3].format = Format::R32G32B32A32_Float;
|
||||||
|
inputElements[3].inputSlot = 0;
|
||||||
|
inputElements[3].alignedByteOffset = 48;
|
||||||
|
|
||||||
|
InputLayoutDesc inputLayout = {};
|
||||||
|
inputLayout.elements = inputElements;
|
||||||
|
inputLayout.elementCount = 4;
|
||||||
|
|
||||||
|
PipelineDesc psoDesc = {};
|
||||||
|
psoDesc.rootSignature = rootSignature;
|
||||||
|
psoDesc.vertexShader = vs;
|
||||||
|
psoDesc.pixelShader = ps;
|
||||||
|
psoDesc.geometryShader = gs;
|
||||||
|
psoDesc.inputLayout = inputLayout;
|
||||||
|
psoDesc.topologyType = PrimitiveTopologyType::Triangle;
|
||||||
|
psoDesc.numRenderTargets = 1;
|
||||||
|
psoDesc.rtvFormats[0] = Format::R8G8B8A8_UNorm;
|
||||||
|
psoDesc.dsvFormat = Format::D24_UNorm_S8_UInt;
|
||||||
|
|
||||||
|
IPipelineState* pso = nullptr;
|
||||||
|
printf("Creating PipelineState...\n");
|
||||||
|
if (!device->CreatePipelineState(&pso, psoDesc)) {
|
||||||
|
printf("CreatePipelineState Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("PipelineState created\n");
|
||||||
|
|
||||||
|
IConstantBuffer* cb = nullptr;
|
||||||
|
if (!CreateConstantBuffer(device, 65536, &cb)) {
|
||||||
|
printf("CreateConstantBuffer Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float matrices[64] = {};
|
||||||
|
matrices[0] = 1.0f; matrices[5] = 1.0f; matrices[10] = 1.0f; matrices[15] = 1.0f;
|
||||||
|
matrices[16] = 1.0f; matrices[21] = 1.0f; matrices[26] = 1.0f; matrices[31] = 1.0f;
|
||||||
|
matrices[32] = 1.0f; matrices[37] = 1.0f; matrices[42] = 1.0f; matrices[47] = 1.0f;
|
||||||
|
matrices[48] = 1.0f; matrices[53] = 1.0f; matrices[58] = 1.0f; matrices[63] = 1.0f;
|
||||||
|
UpdateConstantBuffer(cb, matrices, sizeof(matrices));
|
||||||
|
|
||||||
|
StaticMeshComponent mesh;
|
||||||
|
if (!mesh.Initialize(cmdList, "Res/Model/Sphere.lhsm")) {
|
||||||
|
printf("Load Mesh Failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdList->Close();
|
||||||
|
ICommandQueue* queue = device->GetCommandQueue();
|
||||||
|
void* cmdListPtr = cmdList->GetNativeCommandList();
|
||||||
|
queue->ExecuteCommandLists(&cmdListPtr, 1);
|
||||||
|
|
||||||
|
ShowWindow(hwnd, nShowCmd);
|
||||||
|
UpdateWindow(hwnd);
|
||||||
|
|
||||||
|
MSG msg = {};
|
||||||
|
while (true) {
|
||||||
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
if (msg.message == WM_QUIT) break;
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
} else {
|
||||||
|
renderContext.BeginFrame();
|
||||||
|
|
||||||
|
renderContext.SetViewport((float)width, (float)height);
|
||||||
|
renderContext.SetScissor(width, height);
|
||||||
|
|
||||||
|
float color[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||||
|
renderContext.ClearRenderTarget(color);
|
||||||
|
renderContext.ClearDepthStencil();
|
||||||
|
|
||||||
|
cmdList->SetPipelineState(pso);
|
||||||
|
cmdList->SetRootSignature(rootSignature);
|
||||||
|
cmdList->SetPrimitiveTopology(PrimitiveTopology::TriangleList);
|
||||||
|
|
||||||
|
mesh.Render(cmdList);
|
||||||
|
|
||||||
|
renderContext.EndFrame();
|
||||||
|
renderContext.Present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContext.Shutdown();
|
||||||
|
delete pso;
|
||||||
|
delete rootSignature;
|
||||||
|
delete cb;
|
||||||
|
delete device;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
#define NOMINMAX
|
|
||||||
#include "NanoVDBLoader.h"
|
|
||||||
#include <windows.h>
|
|
||||||
#include "BattleFireDirect.h"
|
|
||||||
#include <nanovdb/io/IO.h>
|
|
||||||
#include <nanovdb/GridHandle.h>
|
|
||||||
#include <nanovdb/HostBuffer.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
bool LoadNanoVDB(const char* filePath, NanoVDBData& outData, ID3D12GraphicsCommandList* cmdList, ID3D12CommandAllocator* cmdAlloc) {
|
|
||||||
try {
|
|
||||||
if (cmdAlloc && cmdList) {
|
|
||||||
cmdAlloc->Reset();
|
|
||||||
cmdList->Reset(cmdAlloc, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
nanovdb::GridHandle<nanovdb::HostBuffer> gridHandle = nanovdb::io::readGrid(filePath);
|
|
||||||
|
|
||||||
const uint64_t byteSize = gridHandle.buffer().bufferSize();
|
|
||||||
const uint64_t elementCount = byteSize / sizeof(uint32_t);
|
|
||||||
|
|
||||||
void* bufferData = malloc(byteSize);
|
|
||||||
if (!bufferData) {
|
|
||||||
std::cerr << "Failed to allocate memory for NanoVDB" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(bufferData, gridHandle.buffer().data(), byteSize);
|
|
||||||
|
|
||||||
double* bboxData = (double*)((char*)bufferData + 560);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
outData.worldBBox[i] = bboxData[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
double* voxelSizeData = (double*)((char*)bufferData + 608);
|
|
||||||
printf("[NanoVDB] Voxel size: [%.6f, %.6f, %.6f]\n", voxelSizeData[0], voxelSizeData[1], voxelSizeData[2]);
|
|
||||||
|
|
||||||
outData.cpuData = bufferData;
|
|
||||||
outData.byteSize = byteSize;
|
|
||||||
outData.elementCount = elementCount;
|
|
||||||
|
|
||||||
ID3D12Device* device = GetD3DDevice();
|
|
||||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
|
||||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
||||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
||||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC resourceDesc = {};
|
|
||||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
||||||
resourceDesc.Width = byteSize;
|
|
||||||
resourceDesc.Height = 1;
|
|
||||||
resourceDesc.DepthOrArraySize = 1;
|
|
||||||
resourceDesc.MipLevels = 1;
|
|
||||||
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
|
||||||
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
||||||
resourceDesc.SampleDesc.Count = 1;
|
|
||||||
|
|
||||||
HRESULT hr = device->CreateCommittedResource(
|
|
||||||
&heapProps,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&resourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&outData.gpuBuffer)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
std::cerr << "Failed to create GPU buffer for NanoVDB" << std::endl;
|
|
||||||
free(bufferData);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES uploadHeapProps = {};
|
|
||||||
uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
||||||
|
|
||||||
ID3D12Resource* uploadBuffer = nullptr;
|
|
||||||
hr = device->CreateCommittedResource(
|
|
||||||
&uploadHeapProps,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&resourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
nullptr,
|
|
||||||
IID_PPV_ARGS(&uploadBuffer)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
void* mappedData = nullptr;
|
|
||||||
D3D12_RANGE readRange = {0, 0};
|
|
||||||
uploadBuffer->Map(0, &readRange, &mappedData);
|
|
||||||
memcpy(mappedData, bufferData, byteSize);
|
|
||||||
uploadBuffer->Unmap(0, nullptr);
|
|
||||||
|
|
||||||
cmdList->CopyBufferRegion(outData.gpuBuffer, 0, uploadBuffer, 0, byteSize);
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
||||||
barrier.Transition.pResource = outData.gpuBuffer;
|
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
||||||
cmdList->ResourceBarrier(1, &barrier);
|
|
||||||
|
|
||||||
EndCommandList();
|
|
||||||
WaitForCompletionOfCommandList();
|
|
||||||
uploadBuffer->Release();
|
|
||||||
GetCommandAllocator()->Reset();
|
|
||||||
cmdList->Reset(GetCommandAllocator(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "[NanoVDB] Loaded: " << byteSize << " bytes, " << elementCount << " elements" << std::endl;
|
|
||||||
std::cout.flush();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
std::cerr << "[NanoVDB] Error: " << e.what() << std::endl;
|
|
||||||
std::cerr.flush();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeNanoVDB(NanoVDBData& data) {
|
|
||||||
if (data.gpuBuffer) {
|
|
||||||
data.gpuBuffer->Release();
|
|
||||||
data.gpuBuffer = nullptr;
|
|
||||||
}
|
|
||||||
if (data.cpuData) {
|
|
||||||
free(data.cpuData);
|
|
||||||
data.cpuData = nullptr;
|
|
||||||
}
|
|
||||||
data.byteSize = 0;
|
|
||||||
data.elementCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <d3d12.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct NanoVDBData {
|
|
||||||
ID3D12Resource* gpuBuffer;
|
|
||||||
void* cpuData;
|
|
||||||
uint64_t byteSize;
|
|
||||||
uint64_t elementCount;
|
|
||||||
double worldBBox[6];
|
|
||||||
};
|
|
||||||
|
|
||||||
bool LoadNanoVDB(const char* filePath, NanoVDBData& outData, ID3D12GraphicsCommandList* cmdList, ID3D12CommandAllocator* cmdAlloc = nullptr);
|
|
||||||
void FreeNanoVDB(NanoVDBData& data);
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,250 +0,0 @@
|
|||||||
#define PNANOVDB_HLSL
|
|
||||||
#define PNANOVDB_ADDRESS_32
|
|
||||||
#include "PNanoVDB.hlsl"
|
|
||||||
|
|
||||||
cbuffer CB0 : register(b1)
|
|
||||||
{
|
|
||||||
float4x4 _InverseViewProjection; // 64 bytes
|
|
||||||
float4 _CameraPos_Density; // xyz = CameraPos, w = DensityScale
|
|
||||||
float4 _BBoxMin_Step; // xyz = BBoxMin, w = StepSize
|
|
||||||
float4 _BBoxMax_MaxSteps; // xyz = BBoxMax, w = MaxSteps
|
|
||||||
float4 _Rotation_Pad_LightSamples; // x = RotationY, yzw = pad, but we'll use differently
|
|
||||||
float4 _LightDir_Samples; // xyz = LightDir, w = LightSamples
|
|
||||||
};
|
|
||||||
|
|
||||||
StructuredBuffer<uint> buf : register(t1);
|
|
||||||
|
|
||||||
struct VSInput
|
|
||||||
{
|
|
||||||
float2 position : POSITION;
|
|
||||||
float2 texcoord : TEXCOORD0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PSInput
|
|
||||||
{
|
|
||||||
float4 position : SV_POSITION;
|
|
||||||
float2 texcoord : TEXCOORD0;
|
|
||||||
float3 worldPos : TEXCOORD1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NanoVolume
|
|
||||||
{
|
|
||||||
pnanovdb_grid_handle_t grid;
|
|
||||||
pnanovdb_grid_type_t grid_type;
|
|
||||||
pnanovdb_readaccessor_t acc;
|
|
||||||
};
|
|
||||||
|
|
||||||
void initVolume(inout NanoVolume volume)
|
|
||||||
{
|
|
||||||
pnanovdb_grid_handle_t grid;
|
|
||||||
grid.address.byte_offset = 0;
|
|
||||||
|
|
||||||
pnanovdb_grid_type_t grid_type = pnanovdb_buf_read_uint32(buf, PNANOVDB_GRID_OFF_GRID_TYPE);
|
|
||||||
pnanovdb_tree_handle_t tree = pnanovdb_grid_get_tree(buf, grid);
|
|
||||||
pnanovdb_root_handle_t root = pnanovdb_tree_get_root(buf, tree);
|
|
||||||
pnanovdb_readaccessor_t acc;
|
|
||||||
pnanovdb_readaccessor_init(acc, root);
|
|
||||||
|
|
||||||
volume.grid = grid;
|
|
||||||
volume.grid_type = grid_type;
|
|
||||||
volume.acc = acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
float get_value_coord(inout pnanovdb_readaccessor_t acc, float3 pos)
|
|
||||||
{
|
|
||||||
pnanovdb_vec3_t p = pos;
|
|
||||||
pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(p);
|
|
||||||
pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk);
|
|
||||||
return pnanovdb_read_float(buf, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_dim_coord(inout pnanovdb_readaccessor_t acc, float3 pos)
|
|
||||||
{
|
|
||||||
pnanovdb_vec3_t p = pos;
|
|
||||||
pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(p);
|
|
||||||
return pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_hdda_hit(inout pnanovdb_readaccessor_t acc, inout float tmin, float3 origin, float3 direction, float tmax, out float valueAtHit)
|
|
||||||
{
|
|
||||||
pnanovdb_vec3_t p_origin = origin;
|
|
||||||
pnanovdb_vec3_t p_direction = direction;
|
|
||||||
float thit;
|
|
||||||
bool hit = pnanovdb_hdda_tree_marcher(
|
|
||||||
PNANOVDB_GRID_TYPE_FLOAT,
|
|
||||||
buf,
|
|
||||||
acc,
|
|
||||||
p_origin, tmin,
|
|
||||||
p_direction, tmax,
|
|
||||||
thit,
|
|
||||||
valueAtHit
|
|
||||||
);
|
|
||||||
tmin = thit;
|
|
||||||
return hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
float phase_function()
|
|
||||||
{
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint rand_xorshift(uint seed)
|
|
||||||
{
|
|
||||||
seed ^= (seed << 13);
|
|
||||||
seed ^= (seed >> 17);
|
|
||||||
seed ^= (seed << 5);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
float random_float(float3 pos)
|
|
||||||
{
|
|
||||||
uint seed = asuint(pos.x + pos.y + pos.z);
|
|
||||||
float res = float(rand_xorshift(seed)) * (1.0 / 4294967296.0);
|
|
||||||
res = float(rand_xorshift(asuint(res))) * (1.0 / 4294967296.0);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
float volumetric_shadow(float3 pos, float densityScale, inout pnanovdb_readaccessor_t acc)
|
|
||||||
{
|
|
||||||
float lightSamples = _LightDir_Samples.w;
|
|
||||||
if (lightSamples < 1) { return 0.0; }
|
|
||||||
|
|
||||||
float3 light_dir = _LightDir_Samples.xyz;
|
|
||||||
|
|
||||||
float shadow = 1.0;
|
|
||||||
float sigmaS = 0.0;
|
|
||||||
float sigmaE = 0.0;
|
|
||||||
float step_size = 1.0;
|
|
||||||
float jitter = 0;
|
|
||||||
|
|
||||||
int steps = 10;
|
|
||||||
for (int step = 0; step < steps; step++)
|
|
||||||
{
|
|
||||||
float3 sample_pos = pos + (jitter + step_size) * light_dir;
|
|
||||||
|
|
||||||
sigmaS = get_value_coord(acc, sample_pos) * densityScale;
|
|
||||||
sigmaE = max(0.000001, sigmaS);
|
|
||||||
sigmaE *= 0.3;
|
|
||||||
shadow *= exp(-sigmaE * step_size);
|
|
||||||
|
|
||||||
step_size *= 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSInput MainVS(VSInput input)
|
|
||||||
{
|
|
||||||
PSInput output;
|
|
||||||
output.position = float4(input.position, 0.0, 1.0);
|
|
||||||
output.texcoord = input.texcoord;
|
|
||||||
|
|
||||||
float4 worldPosH = mul(_InverseViewProjection, float4(input.position, 0.5, 1.0));
|
|
||||||
output.worldPos = worldPosH.xyz / worldPosH.w;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool intersectBox(float3 origin, float3 dir, float3 boxMin, float3 boxMax, out float tmin, out float tmax)
|
|
||||||
{
|
|
||||||
float3 invDir = 1.0 / dir;
|
|
||||||
float3 t1 = (boxMin - origin) * invDir;
|
|
||||||
float3 t2 = (boxMax - origin) * invDir;
|
|
||||||
|
|
||||||
tmin = max(max(min(t1.x, t2.x), min(t1.y, t2.y)), min(t1.z, t2.z));
|
|
||||||
tmax = min(min(max(t1.x, t2.x), max(t1.y, t2.y)), max(t1.z, t2.z));
|
|
||||||
|
|
||||||
return tmax >= tmin && tmax > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 MainPS(PSInput input) : SV_TARGET
|
|
||||||
{
|
|
||||||
float3 rayDir = normalize(input.worldPos - _CameraPos_Density.xyz);
|
|
||||||
|
|
||||||
float tmin = 0.01;
|
|
||||||
float tmax = 5000.0;
|
|
||||||
|
|
||||||
NanoVolume volume;
|
|
||||||
initVolume(volume);
|
|
||||||
|
|
||||||
float3 color = float3(0, 0, 0);
|
|
||||||
float transmittance = 1.0;
|
|
||||||
float acc_density = 0.0;
|
|
||||||
float3 ambient_light = 0.005;
|
|
||||||
|
|
||||||
float _DensityScale = _CameraPos_Density.w;
|
|
||||||
float _StepSize = _BBoxMin_Step.w;
|
|
||||||
float _MaxSteps = _BBoxMax_MaxSteps.w;
|
|
||||||
float _RotationY = _Rotation_Pad_LightSamples.x;
|
|
||||||
float _LightSamples = _LightDir_Samples.w;
|
|
||||||
|
|
||||||
float cosR = cos(_RotationY);
|
|
||||||
float sinR = sin(_RotationY);
|
|
||||||
float3x3 invRotY = float3x3(
|
|
||||||
cosR, 0, sinR,
|
|
||||||
0, 1, 0,
|
|
||||||
-sinR, 0, cosR
|
|
||||||
);
|
|
||||||
|
|
||||||
float3 localCameraPos = mul(invRotY, _CameraPos_Density.xyz);
|
|
||||||
float3 localRayDir = mul(invRotY, rayDir);
|
|
||||||
|
|
||||||
float not_used;
|
|
||||||
bool hit = get_hdda_hit(volume.acc, tmin, localCameraPos, localRayDir, tmax, not_used);
|
|
||||||
if (!hit) { return float4(0, 0, 0, 0); }
|
|
||||||
|
|
||||||
float skip = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < (int)_MaxSteps; i++) {
|
|
||||||
if (tmin >= tmax) break;
|
|
||||||
|
|
||||||
float3 localPos = localCameraPos + localRayDir * tmin;
|
|
||||||
|
|
||||||
uint dim = get_dim_coord(volume.acc, localPos);
|
|
||||||
if (dim > 1) {
|
|
||||||
float skip_step = 15.0;
|
|
||||||
tmin += skip_step;
|
|
||||||
skip = skip_step;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float density = get_value_coord(volume.acc, localPos) * _DensityScale;
|
|
||||||
|
|
||||||
if (density < 0.01) {
|
|
||||||
float skip_step = 5.0;
|
|
||||||
tmin += skip_step;
|
|
||||||
skip = skip_step;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skip > 0) {
|
|
||||||
tmin -= skip * 0.8;
|
|
||||||
localPos = localCameraPos + localRayDir * tmin;
|
|
||||||
skip = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float sigmaS = density;
|
|
||||||
float sigmaE = max(0.000001, sigmaS);
|
|
||||||
acc_density += sigmaS;
|
|
||||||
|
|
||||||
float shadow = volumetric_shadow(localPos, _DensityScale, volume.acc);
|
|
||||||
float3 S = sigmaS * phase_function() * shadow * float3(1, 1, 1);
|
|
||||||
float3 Sint = (S - S * exp(-sigmaE * _StepSize)) / sigmaE;
|
|
||||||
color += transmittance * Sint;
|
|
||||||
transmittance *= exp(-sigmaE * _StepSize);
|
|
||||||
|
|
||||||
if (acc_density > 1.0) break;
|
|
||||||
|
|
||||||
if (transmittance < 0.05)
|
|
||||||
{
|
|
||||||
transmittance = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmin += _StepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 final_color = (color + ambient_light) * acc_density;
|
|
||||||
final_color = pow(final_color, 1.0 / 2.2);
|
|
||||||
return float4(final_color, acc_density);
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
cbuffer CB0 : register(b1)
|
|
||||||
{
|
|
||||||
float4x4 _ViewProjection;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VSInput
|
|
||||||
{
|
|
||||||
float3 position : POSITION;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PSInput
|
|
||||||
{
|
|
||||||
float4 position : SV_POSITION;
|
|
||||||
};
|
|
||||||
|
|
||||||
PSInput MainVS(VSInput input)
|
|
||||||
{
|
|
||||||
PSInput output;
|
|
||||||
output.position = mul(_ViewProjection, float4(input.position, 1.0));
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 MainPS(PSInput input) : SV_TARGET
|
|
||||||
{
|
|
||||||
return float4(0.0, 1.0, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#include "StaticMeshComponent.h"
|
|
||||||
#include "BattleFireDirect.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void StaticMeshComponent::SetVertexCount(int inVertexCount) {
|
|
||||||
mVertexCount = inVertexCount;
|
|
||||||
mVertexData = new StaticMeshComponentVertexData[inVertexCount];
|
|
||||||
memset(mVertexData, 0, sizeof(StaticMeshComponentVertexData)*inVertexCount);
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::SetVertexPosition(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
|
|
||||||
mVertexData[inIndex].mPosition[0] = inX;
|
|
||||||
mVertexData[inIndex].mPosition[1] = inY;
|
|
||||||
mVertexData[inIndex].mPosition[2] = inZ;
|
|
||||||
mVertexData[inIndex].mPosition[3] = inW;
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::SetVertexTexcoord(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
|
|
||||||
mVertexData[inIndex].mTexcoord[0] = inX;
|
|
||||||
mVertexData[inIndex].mTexcoord[1] = inY;
|
|
||||||
mVertexData[inIndex].mTexcoord[2] = inZ;
|
|
||||||
mVertexData[inIndex].mTexcoord[3] = inW;
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::SetVertexNormal(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
|
|
||||||
mVertexData[inIndex].mNormal[0] = inX;
|
|
||||||
mVertexData[inIndex].mNormal[1] = inY;
|
|
||||||
mVertexData[inIndex].mNormal[2] = inZ;
|
|
||||||
mVertexData[inIndex].mNormal[3] = inW;
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::SetVertexTangent(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
|
|
||||||
mVertexData[inIndex].mTangent[0] = inX;
|
|
||||||
mVertexData[inIndex].mTangent[1] = inY;
|
|
||||||
mVertexData[inIndex].mTangent[2] = inZ;
|
|
||||||
mVertexData[inIndex].mTangent[3] = inW;
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::InitFromFile(ID3D12GraphicsCommandList* inCommandList, const char* inFilePath) {
|
|
||||||
FILE* pFile = nullptr;
|
|
||||||
errno_t err = fopen_s(&pFile, inFilePath, "rb");
|
|
||||||
if (err == 0) {
|
|
||||||
int temp = 0;
|
|
||||||
fread(&temp, 4, 1, pFile);
|
|
||||||
mVertexCount = temp;
|
|
||||||
mVertexData = new StaticMeshComponentVertexData[mVertexCount];
|
|
||||||
fread(mVertexData, 1, sizeof(StaticMeshComponentVertexData) * mVertexCount, pFile);
|
|
||||||
mVBO=CreateBufferObject(inCommandList,mVertexData,
|
|
||||||
sizeof(StaticMeshComponentVertexData) * mVertexCount,
|
|
||||||
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
|
|
||||||
mVBOView.BufferLocation = mVBO->GetGPUVirtualAddress();
|
|
||||||
mVBOView.SizeInBytes = sizeof(StaticMeshComponentVertexData) * mVertexCount;
|
|
||||||
mVBOView.StrideInBytes = sizeof(StaticMeshComponentVertexData);
|
|
||||||
|
|
||||||
while (!feof(pFile)) {
|
|
||||||
fread(&temp, 4, 1, pFile);
|
|
||||||
if (feof(pFile)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
char name[256] = {0};
|
|
||||||
fread(name, 1, temp, pFile);
|
|
||||||
fread(&temp, 4, 1, pFile);
|
|
||||||
SubMesh* submesh = new SubMesh;
|
|
||||||
submesh->mIndexCount = temp;
|
|
||||||
unsigned int *indexes = new unsigned int[temp];
|
|
||||||
fread(indexes, 1, sizeof(unsigned int) * temp, pFile);
|
|
||||||
submesh->mIBO = CreateBufferObject(inCommandList, indexes,
|
|
||||||
sizeof(unsigned int) * temp,
|
|
||||||
D3D12_RESOURCE_STATE_INDEX_BUFFER);
|
|
||||||
|
|
||||||
submesh->mIBView.BufferLocation = submesh->mIBO->GetGPUVirtualAddress();
|
|
||||||
submesh->mIBView.SizeInBytes = sizeof(unsigned int) * temp;
|
|
||||||
submesh->mIBView.Format = DXGI_FORMAT_R32_UINT;
|
|
||||||
mSubMeshes.insert(std::pair<std::string, SubMesh*>(name,submesh));
|
|
||||||
delete[]indexes;
|
|
||||||
}
|
|
||||||
fclose(pFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void StaticMeshComponent::Render(ID3D12GraphicsCommandList* inCommandList) {
|
|
||||||
D3D12_VERTEX_BUFFER_VIEW vbos[] = {
|
|
||||||
mVBOView
|
|
||||||
};
|
|
||||||
inCommandList->IASetVertexBuffers(0, 1, vbos);
|
|
||||||
if (mSubMeshes.empty()) {
|
|
||||||
inCommandList->DrawInstanced(mVertexCount, 1, 0, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (auto iter = mSubMeshes.begin();
|
|
||||||
iter != mSubMeshes.end(); iter++) {
|
|
||||||
inCommandList->IASetIndexBuffer(&iter->second->mIBView);
|
|
||||||
inCommandList->DrawIndexedInstanced(iter->second->mIndexCount, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <d3d12.h>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
|
||||||
struct StaticMeshComponentVertexData {
|
|
||||||
float mPosition[4];
|
|
||||||
float mTexcoord[4];
|
|
||||||
float mNormal[4];
|
|
||||||
float mTangent[4];
|
|
||||||
};
|
|
||||||
struct SubMesh {
|
|
||||||
ID3D12Resource* mIBO;
|
|
||||||
D3D12_INDEX_BUFFER_VIEW mIBView;
|
|
||||||
int mIndexCount;
|
|
||||||
};
|
|
||||||
class StaticMeshComponent{
|
|
||||||
public:
|
|
||||||
ID3D12Resource* mVBO;
|
|
||||||
D3D12_VERTEX_BUFFER_VIEW mVBOView;
|
|
||||||
StaticMeshComponentVertexData* mVertexData;
|
|
||||||
int mVertexCount;
|
|
||||||
std::unordered_map<std::string, SubMesh*> mSubMeshes;
|
|
||||||
void SetVertexCount(int inVertexCount);
|
|
||||||
void SetVertexPosition(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
|
|
||||||
void SetVertexTexcoord(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
|
|
||||||
void SetVertexNormal(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
|
|
||||||
void SetVertexTangent(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
|
|
||||||
void InitFromFile(ID3D12GraphicsCommandList*inCommandList,const char* inFilePath);
|
|
||||||
void Render(ID3D12GraphicsCommandList* inCommandList);
|
|
||||||
};
|
|
||||||
|
|
||||||
10
Utils.cpp
10
Utils.cpp
@@ -1,10 +0,0 @@
|
|||||||
#include "Utils.h"
|
|
||||||
#include <math.h>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
float srandom() {
|
|
||||||
float number = float(rand())/float(RAND_MAX);//0.0~1.0f
|
|
||||||
number *= 2.0f;//0.0~2.0
|
|
||||||
number -= 1.0f;//-1.0f~1.0f;
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
163
counter.py
163
counter.py
@@ -1,163 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def count_lines(file_path: Path) -> int:
|
|
||||||
try:
|
|
||||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
||||||
return sum(1 for _ in f)
|
|
||||||
except Exception:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def should_include(file_path: Path, extensions: list[str]) -> bool:
|
|
||||||
if not extensions:
|
|
||||||
return True
|
|
||||||
return file_path.suffix in extensions
|
|
||||||
|
|
||||||
|
|
||||||
def walk_dir(root_path: Path, extensions: list[str], exclude_dirs: set[str]):
|
|
||||||
results = []
|
|
||||||
total_lines = 0
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(root_path):
|
|
||||||
dirs[:] = [d for d in dirs if d not in exclude_dirs]
|
|
||||||
|
|
||||||
rel_root = Path(root).relative_to(root_path)
|
|
||||||
indent = len(rel_root.parts) if str(rel_root) != "." else 0
|
|
||||||
prefix = " " * indent
|
|
||||||
|
|
||||||
if indent > 0:
|
|
||||||
print(f"{prefix}└── {rel_root.name}/")
|
|
||||||
|
|
||||||
for i, file in enumerate(files):
|
|
||||||
file_path = Path(root) / file
|
|
||||||
|
|
||||||
if not should_include(file_path, extensions):
|
|
||||||
continue
|
|
||||||
|
|
||||||
lines = count_lines(file_path)
|
|
||||||
total_lines += lines
|
|
||||||
results.append((file_path, lines, indent + 1))
|
|
||||||
|
|
||||||
is_last = (i == len(files) - 1) and not any(
|
|
||||||
should_include(Path(root) / f, extensions) for f in dirs
|
|
||||||
)
|
|
||||||
connector = "└──" if is_last else "├──"
|
|
||||||
|
|
||||||
print(f"{' ' * (indent + 1)}{connector} {file} ({lines} lines)")
|
|
||||||
|
|
||||||
return total_lines
|
|
||||||
|
|
||||||
|
|
||||||
def main_all():
|
|
||||||
directories = {
|
|
||||||
".": [".cpp", ".h", ".hlsl"],
|
|
||||||
"docs": [".md"],
|
|
||||||
}
|
|
||||||
|
|
||||||
total_all = 0
|
|
||||||
results = []
|
|
||||||
|
|
||||||
for directory, extensions in directories.items():
|
|
||||||
root_path = Path(directory)
|
|
||||||
if not root_path.exists():
|
|
||||||
continue
|
|
||||||
|
|
||||||
exclude_dirs = {
|
|
||||||
".git",
|
|
||||||
"build",
|
|
||||||
"Release",
|
|
||||||
"bin",
|
|
||||||
"__pycache__",
|
|
||||||
".ruff_cache",
|
|
||||||
"stbi",
|
|
||||||
}
|
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
|
||||||
print(f"项目文件统计: {root_path}")
|
|
||||||
print(f"后缀过滤: {extensions}")
|
|
||||||
print(f"{'=' * 60}\n")
|
|
||||||
|
|
||||||
total = walk_dir(root_path, extensions, exclude_dirs)
|
|
||||||
results.append((directory, total))
|
|
||||||
total_all += total
|
|
||||||
|
|
||||||
# 单独统计 stbi
|
|
||||||
stbi_path = Path("stbi")
|
|
||||||
if stbi_path.exists():
|
|
||||||
exclude_dirs = {".git", "__pycache__"}
|
|
||||||
print(f"\n{'=' * 60}")
|
|
||||||
print(f"项目文件统计: stbi (第三方库)")
|
|
||||||
print(f"后缀过滤: ['.cpp', '.h']")
|
|
||||||
print(f"{'=' * 60}\n")
|
|
||||||
|
|
||||||
total = walk_dir(stbi_path, [".cpp", ".h"], exclude_dirs)
|
|
||||||
results.append(("stbi", total))
|
|
||||||
total_all += total
|
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
|
||||||
print("汇总统计")
|
|
||||||
print(f"{'=' * 60}")
|
|
||||||
for name, lines in results:
|
|
||||||
print(f"{name:15} {lines:>10,} 行")
|
|
||||||
print(f"{'=' * 60}")
|
|
||||||
print(f"{'总计':15} {total_all:>10,} 行")
|
|
||||||
print(f"{'=' * 60}\n")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="统计项目文件行数")
|
|
||||||
parser.add_argument(
|
|
||||||
"-e", "--extension", action="append", help="指定后缀名,如: .py .ts .js"
|
|
||||||
)
|
|
||||||
parser.add_argument("-d", "--directory", default=".", help="指定子文件夹路径")
|
|
||||||
parser.add_argument(
|
|
||||||
"-x", "--exclude", action="append", default=[], help="排除的文件夹"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--all",
|
|
||||||
action="store_true",
|
|
||||||
help="统计所有源码目录 (./docs/stbi)",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.all:
|
|
||||||
main_all()
|
|
||||||
else:
|
|
||||||
root_path = Path(args.directory).resolve()
|
|
||||||
extensions = args.extension
|
|
||||||
exclude_dirs = {
|
|
||||||
".git",
|
|
||||||
"build",
|
|
||||||
"Release",
|
|
||||||
"bin",
|
|
||||||
"__pycache__",
|
|
||||||
}
|
|
||||||
exclude_dirs.update(args.exclude)
|
|
||||||
|
|
||||||
if not root_path.exists():
|
|
||||||
print(f"错误: 目录 {root_path} 不存在")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
|
||||||
print(f"项目文件统计: {root_path}")
|
|
||||||
if extensions:
|
|
||||||
print(f"后缀过滤: {extensions}")
|
|
||||||
print(f"{'=' * 60}\n")
|
|
||||||
|
|
||||||
total = walk_dir(root_path, extensions, exclude_dirs)
|
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
|
||||||
print(f"总行数: {total}")
|
|
||||||
print(f"{'=' * 60}\n")
|
|
||||||
@@ -80,8 +80,25 @@ add_library(XCEngine STATIC
|
|||||||
src/Debug/FileLogSink.cpp
|
src/Debug/FileLogSink.cpp
|
||||||
src/Debug/Logger.cpp
|
src/Debug/Logger.cpp
|
||||||
src/Debug/Profiler.cpp
|
src/Debug/Profiler.cpp
|
||||||
|
|
||||||
|
# RHI
|
||||||
|
include/XCEngine/RHI/RHIDefines.h
|
||||||
|
include/XCEngine/RHI/IRHIResources.h
|
||||||
|
include/XCEngine/RHI/ICommandList.h
|
||||||
|
include/XCEngine/RHI/IRHIDevice.h
|
||||||
|
include/XCEngine/RHI/IResourceViews.h
|
||||||
|
include/XCEngine/RHI/RHISystem.h
|
||||||
|
|
||||||
|
# Rendering
|
||||||
|
include/XCEngine/Rendering/Resources.h
|
||||||
|
include/XCEngine/Rendering/RenderTarget.h
|
||||||
|
include/XCEngine/Rendering/Shader.h
|
||||||
|
include/XCEngine/Rendering/RenderContext.h
|
||||||
|
include/XCEngine/Rendering/StaticMeshComponent.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(src/RHI/D3D12)
|
||||||
|
|
||||||
target_include_directories(XCEngine PUBLIC
|
target_include_directories(XCEngine PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine
|
||||||
|
|||||||
44
engine/include/XCEngine/RHI/ICommandList.h
Normal file
44
engine/include/XCEngine/RHI/ICommandList.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RHIDefines.h"
|
||||||
|
#include "IRHIResources.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class IResource {
|
||||||
|
public:
|
||||||
|
virtual ~IResource() = default;
|
||||||
|
virtual void* GetNativeResource() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ICommandList {
|
||||||
|
public:
|
||||||
|
virtual ~ICommandList() = default;
|
||||||
|
|
||||||
|
virtual void Reset(void* allocator) = 0;
|
||||||
|
virtual void Close() = 0;
|
||||||
|
virtual void SetPipelineState(IPipelineState* pso) = 0;
|
||||||
|
virtual void SetRootSignature(IRootSignature* signature) = 0;
|
||||||
|
virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0;
|
||||||
|
virtual void SetVertexBuffer(uint32_t slot, IResource* buffer, uint32_t offset = 0, uint32_t stride = 0) = 0;
|
||||||
|
virtual void SetIndexBuffer(IResource* buffer, uint32_t offset = 0) = 0;
|
||||||
|
virtual void SetDescriptorHeap(IDescriptorHeap* heap) = 0;
|
||||||
|
virtual void SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) = 0;
|
||||||
|
virtual void SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) = 0;
|
||||||
|
virtual void DrawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) = 0;
|
||||||
|
virtual void DrawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) = 0;
|
||||||
|
virtual void Dispatch(uint32_t x, uint32_t y, uint32_t z) = 0;
|
||||||
|
virtual void SetViewports(const Viewport* viewports, uint32_t count) = 0;
|
||||||
|
virtual void SetScissorRects(const Rect* rects, uint32_t count) = 0;
|
||||||
|
virtual void SetRenderTargets(void** targets, uint32_t count, void* depthStencil) = 0;
|
||||||
|
virtual void ClearRenderTargetView(void* target, const float color[4]) = 0;
|
||||||
|
virtual void ClearDepthStencilView(void* depth, float depthValue, uint8_t stencil) = 0;
|
||||||
|
virtual void CopyResource(IResource* dst, const IResource* src) = 0;
|
||||||
|
virtual void CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) = 0;
|
||||||
|
virtual void ResourceBarrier(IResource* resource, ResourceStateFlag before, ResourceStateFlag after) = 0;
|
||||||
|
virtual void* GetNativeCommandList() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
161
engine/include/XCEngine/RHI/IRHIDevice.h
Normal file
161
engine/include/XCEngine/RHI/IRHIDevice.h
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RHIDefines.h"
|
||||||
|
#include "ICommandList.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
struct ShaderBytecode {
|
||||||
|
const void* bytecode = nullptr;
|
||||||
|
uint64_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputElementDesc {
|
||||||
|
const char* semanticName = nullptr;
|
||||||
|
uint32_t semanticIndex = 0;
|
||||||
|
Format format = Format::Unknown;
|
||||||
|
uint32_t inputSlot = 0;
|
||||||
|
uint32_t alignedByteOffset = 0;
|
||||||
|
uint32_t inputSlotClass = 0; // 0 = per-vertex
|
||||||
|
uint32_t instanceDataStepRate = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputLayoutDesc {
|
||||||
|
const InputElementDesc* elements = nullptr;
|
||||||
|
uint32_t elementCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PrimitiveTopologyType {
|
||||||
|
Undefined,
|
||||||
|
Point,
|
||||||
|
Line,
|
||||||
|
Triangle,
|
||||||
|
Patch
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BlendFactor {
|
||||||
|
Zero,
|
||||||
|
One,
|
||||||
|
SrcColor,
|
||||||
|
InvSrcColor,
|
||||||
|
SrcAlpha,
|
||||||
|
InvSrcAlpha,
|
||||||
|
DestAlpha,
|
||||||
|
InvDestAlpha,
|
||||||
|
DestColor,
|
||||||
|
InvDestColor
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BlendOp {
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
ReverseSubtract,
|
||||||
|
Min,
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ComparisonFunc {
|
||||||
|
Never,
|
||||||
|
Less,
|
||||||
|
Equal,
|
||||||
|
LessEqual,
|
||||||
|
Greater,
|
||||||
|
NotEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
Always
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CullMode {
|
||||||
|
None,
|
||||||
|
Front,
|
||||||
|
Back
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FillMode {
|
||||||
|
Wireframe,
|
||||||
|
Solid
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlendState {
|
||||||
|
bool enable = false;
|
||||||
|
BlendFactor srcBlend = BlendFactor::SrcAlpha;
|
||||||
|
BlendFactor destBlend = BlendFactor::InvSrcAlpha;
|
||||||
|
BlendOp blendOp = BlendOp::Add;
|
||||||
|
BlendFactor srcBlendAlpha = BlendFactor::One;
|
||||||
|
BlendFactor destBlendAlpha = BlendFactor::Zero;
|
||||||
|
BlendOp blendOpAlpha = BlendOp::Add;
|
||||||
|
uint8_t renderTargetWriteMask = 0xF;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DepthStencilState {
|
||||||
|
bool depthEnable = true;
|
||||||
|
bool stencilEnable = false;
|
||||||
|
ComparisonFunc depthFunc = ComparisonFunc::Less;
|
||||||
|
uint8_t depthWriteMask = 0xFF;
|
||||||
|
uint8_t stencilReadMask = 0xFF;
|
||||||
|
uint8_t stencilWriteMask = 0xFF;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RasterizerState {
|
||||||
|
FillMode fillMode = FillMode::Solid;
|
||||||
|
CullMode cullMode = CullMode::Back;
|
||||||
|
bool frontCounterClockwise = true;
|
||||||
|
int32_t depthBias = 0;
|
||||||
|
float depthBiasClamp = 0.0f;
|
||||||
|
float slopeScaledDepthBias = 0.0f;
|
||||||
|
bool depthClipEnable = true;
|
||||||
|
bool scissorEnable = false;
|
||||||
|
bool multisampleEnable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderState {
|
||||||
|
BlendState blendState;
|
||||||
|
DepthStencilState depthStencilState;
|
||||||
|
RasterizerState rasterizerState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineDesc {
|
||||||
|
IRootSignature* rootSignature = nullptr;
|
||||||
|
ShaderBytecode vertexShader;
|
||||||
|
ShaderBytecode pixelShader;
|
||||||
|
ShaderBytecode geometryShader;
|
||||||
|
ShaderBytecode computeShader;
|
||||||
|
RenderState renderState;
|
||||||
|
InputLayoutDesc inputLayout;
|
||||||
|
PrimitiveTopologyType topologyType = PrimitiveTopologyType::Triangle;
|
||||||
|
uint32_t numRenderTargets = 1;
|
||||||
|
Format rtvFormats[8] = { Format::Unknown };
|
||||||
|
Format dsvFormat = Format::Unknown;
|
||||||
|
SampleCount sampleCount = SampleCount::Count1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IRHIDevice {
|
||||||
|
public:
|
||||||
|
virtual ~IRHIDevice() = default;
|
||||||
|
|
||||||
|
virtual GraphicsAPI GetAPI() const = 0;
|
||||||
|
virtual const char* GetAPIName() const = 0;
|
||||||
|
|
||||||
|
virtual bool Initialize(void* windowHandle, uint32_t width, uint32_t height) = 0;
|
||||||
|
virtual void Shutdown() = 0;
|
||||||
|
|
||||||
|
virtual bool CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) = 0;
|
||||||
|
virtual bool CreateCommandAllocator(ICommandAllocator** allocator) = 0;
|
||||||
|
virtual bool CreateCommandList(ICommandList** list, ICommandAllocator* allocator) = 0;
|
||||||
|
virtual bool CreateFence(IFence** fence) = 0;
|
||||||
|
|
||||||
|
virtual bool CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) = 0;
|
||||||
|
|
||||||
|
virtual bool CreateRootSignature(IRootSignature** signature, const RootSignatureDesc& desc) = 0;
|
||||||
|
virtual bool CreatePipelineState(IPipelineState** pso, const PipelineDesc& desc) = 0;
|
||||||
|
|
||||||
|
virtual bool CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) = 0;
|
||||||
|
|
||||||
|
virtual ICommandQueue* GetCommandQueue() = 0;
|
||||||
|
virtual void* GetNativeDevice() const = 0;
|
||||||
|
virtual void* GetNativeAdapter() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
97
engine/include/XCEngine/RHI/IRHIResources.h
Normal file
97
engine/include/XCEngine/RHI/IRHIResources.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RHIDefines.h"
|
||||||
|
#include <unknwn.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class ICommandQueue {
|
||||||
|
public:
|
||||||
|
virtual ~ICommandQueue() = default;
|
||||||
|
|
||||||
|
virtual void ExecuteCommandLists(void** lists, uint32_t count) = 0;
|
||||||
|
virtual void Signal(void* fence, uint64_t value) = 0;
|
||||||
|
virtual void Wait(void* fence, uint64_t value) = 0;
|
||||||
|
virtual uint64_t GetTimestampFrequency() const = 0;
|
||||||
|
virtual IUnknown* GetNativeQueue() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ICommandAllocator {
|
||||||
|
public:
|
||||||
|
virtual ~ICommandAllocator() = default;
|
||||||
|
virtual void Reset() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IFence {
|
||||||
|
public:
|
||||||
|
virtual ~IFence() = default;
|
||||||
|
virtual uint64_t GetCompletedValue() const = 0;
|
||||||
|
virtual void Signal(uint64_t value) = 0;
|
||||||
|
virtual void Wait(uint64_t value) = 0;
|
||||||
|
virtual void Wait(uint64_t value, uint64_t timeoutMs) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IDescriptorHeap {
|
||||||
|
public:
|
||||||
|
virtual ~IDescriptorHeap() = default;
|
||||||
|
virtual DescriptorHeapType GetType() const = 0;
|
||||||
|
virtual uint32_t GetDescriptorCount() const = 0;
|
||||||
|
virtual void* GetCPUDescriptorHandle(uint32_t index) const = 0;
|
||||||
|
virtual uint64_t GetGPUDescriptorHandle(uint32_t index) const = 0;
|
||||||
|
virtual void SetName(const char* name) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISwapChain {
|
||||||
|
public:
|
||||||
|
virtual ~ISwapChain() = default;
|
||||||
|
virtual bool Initialize(const SwapChainDesc& desc, void* windowHandle) = 0;
|
||||||
|
virtual void Shutdown() = 0;
|
||||||
|
virtual bool Present() = 0;
|
||||||
|
virtual bool Resize(uint32_t width, uint32_t height) = 0;
|
||||||
|
virtual uint32_t GetCurrentBufferIndex() const = 0;
|
||||||
|
virtual void* GetBuffer(uint32_t index) = 0;
|
||||||
|
virtual void SetFullscreen(bool fullscreen) = 0;
|
||||||
|
virtual bool IsFullscreen() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RootParameterType {
|
||||||
|
DescriptorTable,
|
||||||
|
Constants,
|
||||||
|
CBV,
|
||||||
|
SRV,
|
||||||
|
UAV,
|
||||||
|
Sampler
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RootParameter {
|
||||||
|
RootParameterType type;
|
||||||
|
uint32_t shaderRegister = 0;
|
||||||
|
uint32_t registerSpace = 0;
|
||||||
|
uint32_t num32BitValues = 4;
|
||||||
|
ShaderVisibility visibility = ShaderVisibility::All;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RootSignatureDesc {
|
||||||
|
RootParameter* parameters = nullptr;
|
||||||
|
uint32_t parameterCount = 0;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IRootSignature {
|
||||||
|
public:
|
||||||
|
virtual ~IRootSignature() = default;
|
||||||
|
virtual bool Initialize(const RootSignatureDesc& desc) = 0;
|
||||||
|
virtual void SetName(const char* name) = 0;
|
||||||
|
virtual void* GetNativeRootSignature() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPipelineState {
|
||||||
|
public:
|
||||||
|
virtual ~IPipelineState() = default;
|
||||||
|
virtual void SetName(const char* name) = 0;
|
||||||
|
virtual void* GetNativePipelineState() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
27
engine/include/XCEngine/RHI/IResourceViews.h
Normal file
27
engine/include/XCEngine/RHI/IResourceViews.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RHIDefines.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class IShaderResourceView {
|
||||||
|
public:
|
||||||
|
virtual ~IShaderResourceView() = default;
|
||||||
|
virtual void* GetNativeSRV() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IRenderTargetView {
|
||||||
|
public:
|
||||||
|
virtual ~IRenderTargetView() = default;
|
||||||
|
virtual void* GetNativeRTV() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IDepthStencilView {
|
||||||
|
public:
|
||||||
|
virtual ~IDepthStencilView() = default;
|
||||||
|
virtual void* GetNativeDSV() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
226
engine/include/XCEngine/RHI/RHIDefines.h
Normal file
226
engine/include/XCEngine/RHI/RHIDefines.h
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#include <d3d12.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
enum class Format : uint32_t {
|
||||||
|
Unknown = 0,
|
||||||
|
R8_UNorm = 61,
|
||||||
|
R8G8_UNorm = 49,
|
||||||
|
R8G8B8A8_UNorm = 28,
|
||||||
|
R16G16B16A16_Float = 10,
|
||||||
|
R32G32B32A32_Float = 2,
|
||||||
|
R16_Float = 54,
|
||||||
|
R32_Float = 41,
|
||||||
|
D16_UNorm = 55,
|
||||||
|
D24_UNorm_S8_UInt = 45,
|
||||||
|
D32_Float = 40,
|
||||||
|
BC1_UNorm = 71,
|
||||||
|
BC2_UNorm = 74,
|
||||||
|
BC3_UNorm = 77,
|
||||||
|
BC4_UNorm = 80,
|
||||||
|
BC5_UNorm = 83,
|
||||||
|
BC6H_UF16 = 95,
|
||||||
|
BC7_UNorm = 98
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PrimitiveTopology : uint8_t {
|
||||||
|
Undefined = 0,
|
||||||
|
PointList = 1,
|
||||||
|
LineList = 2,
|
||||||
|
LineStrip = 3,
|
||||||
|
TriangleList = 4,
|
||||||
|
TriangleStrip = 5,
|
||||||
|
LineListAdj = 10,
|
||||||
|
LineStripAdj = 11,
|
||||||
|
TriangleListAdj = 12,
|
||||||
|
TriangleStripAdj = 13,
|
||||||
|
PatchList = 33
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GraphicsAPI : uint8_t {
|
||||||
|
Unknown,
|
||||||
|
Direct3D11,
|
||||||
|
Direct3D12,
|
||||||
|
Vulkan,
|
||||||
|
Metal,
|
||||||
|
OpenGL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CommandListType : uint8_t {
|
||||||
|
Direct,
|
||||||
|
Compute,
|
||||||
|
Copy,
|
||||||
|
Bundle
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ShaderVisibility : uint8_t {
|
||||||
|
All = 0,
|
||||||
|
Vertex = 1,
|
||||||
|
Hull = 2,
|
||||||
|
Domain = 3,
|
||||||
|
Geometry = 4,
|
||||||
|
Pixel = 5,
|
||||||
|
Amplification = 6,
|
||||||
|
Mesh = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DescriptorHeapType : uint8_t {
|
||||||
|
CBV_SRV_UAV,
|
||||||
|
Sampler,
|
||||||
|
RTV,
|
||||||
|
DSV
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class QueryType : uint8_t {
|
||||||
|
Occlusion,
|
||||||
|
Timestamp,
|
||||||
|
PipelineStatistics
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SampleCount : uint8_t {
|
||||||
|
Count1 = 1,
|
||||||
|
Count2 = 2,
|
||||||
|
Count4 = 4,
|
||||||
|
Count8 = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandQueueDesc {
|
||||||
|
CommandListType type = CommandListType::Direct;
|
||||||
|
int32_t priority = 0;
|
||||||
|
const char* name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DescriptorHeapDesc {
|
||||||
|
DescriptorHeapType type;
|
||||||
|
uint32_t count = 0;
|
||||||
|
bool shaderVisible = false;
|
||||||
|
const char* name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueryHeapDesc {
|
||||||
|
QueryType type;
|
||||||
|
uint32_t count = 0;
|
||||||
|
const char* name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwapChainDesc {
|
||||||
|
uint32_t width = 0;
|
||||||
|
uint32_t height = 0;
|
||||||
|
Format format = Format::Unknown;
|
||||||
|
uint32_t bufferCount = 2;
|
||||||
|
bool vsync = false;
|
||||||
|
bool fullscreen = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ResourceStateFlag : uint32_t {
|
||||||
|
Common = 0,
|
||||||
|
VertexBuffer = 1 << 0,
|
||||||
|
ConstantBuffer = 1 << 1,
|
||||||
|
IndexBuffer = 1 << 2,
|
||||||
|
RenderTarget = 1 << 3,
|
||||||
|
UnorderedAccess = 1 << 4,
|
||||||
|
DepthWrite = 1 << 5,
|
||||||
|
DepthRead = 1 << 6,
|
||||||
|
ShaderResource = 1 << 7,
|
||||||
|
IndirectArgument = 1 << 8,
|
||||||
|
CopyDest = 1 << 9,
|
||||||
|
CopySource = 1 << 10,
|
||||||
|
ResolveDest = 1 << 11,
|
||||||
|
ResolveSource = 1 << 12,
|
||||||
|
Present = 1 << 13,
|
||||||
|
RaytracingAccelerationStructure = 1 << 14,
|
||||||
|
ShadingRateSource = 1 << 15
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ResourceStateFlag operator|(ResourceStateFlag a, ResourceStateFlag b) {
|
||||||
|
return static_cast<ResourceStateFlag>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ResourceStateFlag operator&(ResourceStateFlag a, ResourceStateFlag b) {
|
||||||
|
return static_cast<ResourceStateFlag>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Viewport {
|
||||||
|
float topLeftX = 0.0f;
|
||||||
|
float topLeftY = 0.0f;
|
||||||
|
float width = 0.0f;
|
||||||
|
float height = 0.0f;
|
||||||
|
float minDepth = 0.0f;
|
||||||
|
float maxDepth = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rect {
|
||||||
|
int32_t left = 0;
|
||||||
|
int32_t top = 0;
|
||||||
|
int32_t right = 0;
|
||||||
|
int32_t bottom = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
float r = 0.0f;
|
||||||
|
float g = 0.0f;
|
||||||
|
float b = 0.0f;
|
||||||
|
float a = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClearValue {
|
||||||
|
Color color;
|
||||||
|
float depth = 1.0f;
|
||||||
|
uint8_t stencil = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DXGI_FORMAT FormatToDXGIFormat(Format format) {
|
||||||
|
switch (format) {
|
||||||
|
case Format::Unknown: return DXGI_FORMAT_UNKNOWN;
|
||||||
|
case Format::R8_UNorm: return DXGI_FORMAT_R8_UNORM;
|
||||||
|
case Format::R8G8_UNorm: return DXGI_FORMAT_R8G8_UNORM;
|
||||||
|
case Format::R8G8B8A8_UNorm: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case Format::R16G16B16A16_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||||
|
case Format::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||||
|
case Format::R16_Float: return DXGI_FORMAT_R16_FLOAT;
|
||||||
|
case Format::R32_Float: return DXGI_FORMAT_R32_FLOAT;
|
||||||
|
case Format::D16_UNorm: return DXGI_FORMAT_D16_UNORM;
|
||||||
|
case Format::D24_UNorm_S8_UInt: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
case Format::D32_Float: return DXGI_FORMAT_D32_FLOAT;
|
||||||
|
case Format::BC1_UNorm: return DXGI_FORMAT_BC1_UNORM;
|
||||||
|
case Format::BC2_UNorm: return DXGI_FORMAT_BC2_UNORM;
|
||||||
|
case Format::BC3_UNorm: return DXGI_FORMAT_BC3_UNORM;
|
||||||
|
case Format::BC4_UNorm: return DXGI_FORMAT_BC4_UNORM;
|
||||||
|
case Format::BC5_UNorm: return DXGI_FORMAT_BC5_UNORM;
|
||||||
|
case Format::BC6H_UF16: return DXGI_FORMAT_BC6H_UF16;
|
||||||
|
case Format::BC7_UNorm: return DXGI_FORMAT_BC7_UNORM;
|
||||||
|
default: return DXGI_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Format DXGIFormatToFormat(DXGI_FORMAT dxgiFormat) {
|
||||||
|
switch (dxgiFormat) {
|
||||||
|
case DXGI_FORMAT_UNKNOWN: return Format::Unknown;
|
||||||
|
case DXGI_FORMAT_R8_UNORM: return Format::R8_UNorm;
|
||||||
|
case DXGI_FORMAT_R8G8_UNORM: return Format::R8G8_UNorm;
|
||||||
|
case DXGI_FORMAT_R8G8B8A8_UNORM: return Format::R8G8B8A8_UNorm;
|
||||||
|
case DXGI_FORMAT_R16G16B16A16_FLOAT: return Format::R16G16B16A16_Float;
|
||||||
|
case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float;
|
||||||
|
case DXGI_FORMAT_R16_FLOAT: return Format::R16_Float;
|
||||||
|
case DXGI_FORMAT_R32_FLOAT: return Format::R32_Float;
|
||||||
|
case DXGI_FORMAT_D16_UNORM: return Format::D16_UNorm;
|
||||||
|
case DXGI_FORMAT_D24_UNORM_S8_UINT: return Format::D24_UNorm_S8_UInt;
|
||||||
|
case DXGI_FORMAT_D32_FLOAT: return Format::D32_Float;
|
||||||
|
case DXGI_FORMAT_BC1_UNORM: return Format::BC1_UNorm;
|
||||||
|
case DXGI_FORMAT_BC2_UNORM: return Format::BC2_UNorm;
|
||||||
|
case DXGI_FORMAT_BC3_UNORM: return Format::BC3_UNorm;
|
||||||
|
case DXGI_FORMAT_BC4_UNORM: return Format::BC4_UNorm;
|
||||||
|
case DXGI_FORMAT_BC5_UNORM: return Format::BC5_UNorm;
|
||||||
|
case DXGI_FORMAT_BC6H_UF16: return Format::BC6H_UF16;
|
||||||
|
case DXGI_FORMAT_BC7_UNORM: return Format::BC7_UNorm;
|
||||||
|
default: return Format::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
28
engine/include/XCEngine/RHI/RHISystem.h
Normal file
28
engine/include/XCEngine/RHI/RHISystem.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RHIDefines.h"
|
||||||
|
#include "IRHIDevice.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class RHISystem {
|
||||||
|
public:
|
||||||
|
static RHISystem& Get();
|
||||||
|
|
||||||
|
bool Initialize(GraphicsAPI api, void* windowHandle, uint32_t width, uint32_t height);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
IRHIDevice* GetDevice() { return m_device; }
|
||||||
|
GraphicsAPI GetAPI() const { return m_api; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RHISystem() = default;
|
||||||
|
~RHISystem() = default;
|
||||||
|
|
||||||
|
GraphicsAPI m_api = GraphicsAPI::Unknown;
|
||||||
|
IRHIDevice* m_device = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
46
engine/include/XCEngine/Rendering/RenderContext.h
Normal file
46
engine/include/XCEngine/Rendering/RenderContext.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RHI\IRHIDevice.h>
|
||||||
|
#include <RHI\IRHIResources.h>
|
||||||
|
#include <Rendering\RenderTarget.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class RenderContext {
|
||||||
|
public:
|
||||||
|
RenderContext(D3D12Device* device);
|
||||||
|
~RenderContext();
|
||||||
|
|
||||||
|
bool Initialize(uint32_t width, uint32_t height);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void BeginFrame();
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
ICommandList* GetCommandList() { return m_commandList; }
|
||||||
|
ISwapChain* GetSwapChain() { return m_swapChain; }
|
||||||
|
IRenderTarget* GetCurrentRenderTarget() { return m_currentRenderTarget; }
|
||||||
|
IDepthStencil* GetDepthStencil() { return m_depthStencil; }
|
||||||
|
|
||||||
|
void SetViewport(float width, float height);
|
||||||
|
void SetScissor(int32_t width, int32_t height);
|
||||||
|
void ClearRenderTarget(const float color[4]);
|
||||||
|
void ClearDepthStencil();
|
||||||
|
void Present();
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
ICommandAllocator* m_commandAllocator = nullptr;
|
||||||
|
ICommandList* m_commandList = nullptr;
|
||||||
|
IFence* m_fence = nullptr;
|
||||||
|
ISwapChain* m_swapChain = nullptr;
|
||||||
|
IRenderTarget* m_currentRenderTarget = nullptr;
|
||||||
|
IDepthStencil* m_depthStencil = nullptr;
|
||||||
|
uint64_t m_fenceValue = 0;
|
||||||
|
uint32_t m_width = 0;
|
||||||
|
uint32_t m_height = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
26
engine/include/XCEngine/Rendering/RenderTarget.h
Normal file
26
engine/include/XCEngine/Rendering/RenderTarget.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Rendering/Resources.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class D3D12Device;
|
||||||
|
class D3D12SwapChain;
|
||||||
|
|
||||||
|
class IDepthStencil : public ITexture2D {
|
||||||
|
public:
|
||||||
|
virtual ~IDepthStencil() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IRenderTarget : public ITexture2D {
|
||||||
|
public:
|
||||||
|
virtual ~IRenderTarget() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CreateDepthStencil(D3D12Device* device, uint32_t width, uint32_t height, Format format, IDepthStencil** outDepthStencil);
|
||||||
|
|
||||||
|
bool CreateRenderTargetFromSwapChain(D3D12Device* device, D3D12SwapChain* swapChain, uint32_t bufferIndex, IRenderTarget** outRenderTarget);
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
74
engine/include/XCEngine/Rendering/Resources.h
Normal file
74
engine/include/XCEngine/Rendering/Resources.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RHI\IRHIDevice.h>
|
||||||
|
#include <RHI\IRHIResources.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
struct BufferDesc {
|
||||||
|
uint64_t size = 0;
|
||||||
|
uint32_t stride = 0;
|
||||||
|
bool cpuAccessible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IBuffer : public IResource {
|
||||||
|
public:
|
||||||
|
virtual ~IBuffer() = default;
|
||||||
|
virtual const BufferDesc& GetDesc() const = 0;
|
||||||
|
virtual void* Map() = 0;
|
||||||
|
virtual void Unmap() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IVertexBuffer : public IBuffer {
|
||||||
|
public:
|
||||||
|
virtual ~IVertexBuffer() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IIndexBuffer : public IBuffer {
|
||||||
|
public:
|
||||||
|
virtual ~IIndexBuffer() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IConstantBuffer : public IBuffer {
|
||||||
|
public:
|
||||||
|
virtual ~IConstantBuffer() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureDesc {
|
||||||
|
uint32_t width = 0;
|
||||||
|
uint32_t height = 0;
|
||||||
|
uint32_t depth = 1;
|
||||||
|
uint32_t mipLevels = 1;
|
||||||
|
uint32_t arraySize = 1;
|
||||||
|
Format format = Format::Unknown;
|
||||||
|
bool renderTarget = false;
|
||||||
|
bool depthStencil = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ITexture2D : public IResource {
|
||||||
|
public:
|
||||||
|
virtual ~ITexture2D() = default;
|
||||||
|
virtual const TextureDesc& GetDesc() const = 0;
|
||||||
|
virtual void CreateSRV() = 0;
|
||||||
|
virtual void* GetSRV() = 0;
|
||||||
|
virtual void CreateRTV() = 0;
|
||||||
|
virtual void* GetRTV() = 0;
|
||||||
|
virtual void CreateDSV() = 0;
|
||||||
|
virtual void* GetDSV() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ITextureCube : public IResource {
|
||||||
|
public:
|
||||||
|
virtual ~ITextureCube() = default;
|
||||||
|
virtual const TextureDesc& GetDesc() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISampler {
|
||||||
|
public:
|
||||||
|
virtual ~ISampler() = default;
|
||||||
|
virtual void* GetNativeSampler() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
20
engine/include/XCEngine/Rendering/Shader.h
Normal file
20
engine/include/XCEngine/Rendering/Shader.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RHI\RHIDefines.h>
|
||||||
|
#include <RHI\IRHIDevice.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class IShader {
|
||||||
|
public:
|
||||||
|
virtual ~IShader() = default;
|
||||||
|
virtual const ShaderBytecode& GetBytecode() const = 0;
|
||||||
|
virtual const char* GetEntryPoint() const = 0;
|
||||||
|
virtual const char* GetTarget() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CompileShader(const char* filePath, const char* entryPoint, const char* target, ShaderBytecode& outBytecode);
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
41
engine/include/XCEngine/Rendering/StaticMeshComponent.h
Normal file
41
engine/include/XCEngine/Rendering/StaticMeshComponent.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <Rendering\Resources.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
struct MeshVertex {
|
||||||
|
float position[4];
|
||||||
|
float texcoord[4];
|
||||||
|
float normal[4];
|
||||||
|
float tangent[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubMesh {
|
||||||
|
IIndexBuffer* indexBuffer = nullptr;
|
||||||
|
uint32_t indexCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StaticMeshComponent {
|
||||||
|
public:
|
||||||
|
StaticMeshComponent();
|
||||||
|
~StaticMeshComponent();
|
||||||
|
|
||||||
|
bool Initialize(ICommandList* commandList, const char* filePath);
|
||||||
|
void Render(ICommandList* commandList);
|
||||||
|
|
||||||
|
IVertexBuffer* GetVertexBuffer() { return m_vertexBuffer; }
|
||||||
|
uint32_t GetVertexCount() const { return m_vertexCount; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
IVertexBuffer* m_vertexBuffer = nullptr;
|
||||||
|
uint32_t m_vertexCount = 0;
|
||||||
|
std::unordered_map<std::string, SubMesh*> m_subMeshes;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
24
engine/src/RHI/D3D12/CMakeLists.txt
Normal file
24
engine/src/RHI/D3D12/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
set(D3D12_SOURCES
|
||||||
|
D3D12Device.cpp
|
||||||
|
D3D12Resources.cpp
|
||||||
|
D3D12RenderTarget.cpp
|
||||||
|
D3D12Shader.cpp
|
||||||
|
D3D12RenderContext.cpp
|
||||||
|
D3D12StaticMeshComponent.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(XCEngineD3D12 STATIC ${D3D12_SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(XCEngineD3D12 PUBLIC
|
||||||
|
${CMAKE_SOURCE_DIR}/engine/include
|
||||||
|
${CMAKE_SOURCE_DIR}/engine/include/XCEngine
|
||||||
|
${CMAKE_SOURCE_DIR}/engine/src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(XCEngineD3D12 PUBLIC
|
||||||
|
dxguid
|
||||||
|
d3d12
|
||||||
|
d3dcompiler
|
||||||
|
)
|
||||||
860
engine/src/RHI/D3D12/D3D12Device.cpp
Normal file
860
engine/src/RHI/D3D12/D3D12Device.cpp
Normal file
@@ -0,0 +1,860 @@
|
|||||||
|
#include "D3D12RHI.h"
|
||||||
|
#include <RHI\RHIDefines.h>
|
||||||
|
#include <string>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
void EngineLog(const char* msg, ...) {
|
||||||
|
char buffer[1024];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
FILE* f = nullptr;
|
||||||
|
fopen_s(&f, "D:\\xcengine_debug.log", "a");
|
||||||
|
if (f) { fprintf(f, "%s\n", buffer); fclose(f); }
|
||||||
|
|
||||||
|
printf("%s\n", buffer);
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
D3D12Device::D3D12Device() {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Device::~D3D12Device() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateDXGIDevice(void* windowHandle) {
|
||||||
|
|
||||||
|
UINT dxgiFactoryFlags = 0;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
ID3D12Debug* debugController = nullptr;
|
||||||
|
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
||||||
|
debugController->EnableDebugLayer();
|
||||||
|
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HRESULT hr = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&m_dxgiFactory));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
||||||
|
int adapterIndex = 0;
|
||||||
|
bool adapterFound = false;
|
||||||
|
|
||||||
|
while (m_dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) {
|
||||||
|
DXGI_ADAPTER_DESC1 desc;
|
||||||
|
adapter->GetDesc1(&desc);
|
||||||
|
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
||||||
|
adapterIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
adapterFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
adapterIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adapterFound) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_adapter = adapter;
|
||||||
|
|
||||||
|
hr = D3D12CreateDevice(m_adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::Initialize(void* windowHandle, uint32_t width, uint32_t height) {
|
||||||
|
if (!CreateDXGIDevice(windowHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||||
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
queueDesc.Priority = 0;
|
||||||
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12CommandQueue> commandQueue;
|
||||||
|
HRESULT hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_commandQueue = new D3D12CommandQueue(this, commandQueue.Get());
|
||||||
|
|
||||||
|
SwapChainDesc swapChainDesc = {};
|
||||||
|
swapChainDesc.width = width;
|
||||||
|
swapChainDesc.height = height;
|
||||||
|
swapChainDesc.format = Format::R8G8B8A8_UNorm;
|
||||||
|
swapChainDesc.bufferCount = 2;
|
||||||
|
swapChainDesc.vsync = false;
|
||||||
|
swapChainDesc.fullscreen = false;
|
||||||
|
|
||||||
|
ISwapChain* swapChain = nullptr;
|
||||||
|
if (!CreateSwapChain(&swapChain, swapChainDesc, windowHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_swapChain = static_cast<D3D12SwapChain*>(swapChain);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Device::Shutdown() {
|
||||||
|
if (m_commandQueue) {
|
||||||
|
delete m_commandQueue;
|
||||||
|
m_commandQueue = nullptr;
|
||||||
|
}
|
||||||
|
if (m_swapChain) {
|
||||||
|
delete m_swapChain;
|
||||||
|
m_swapChain = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) {
|
||||||
|
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||||
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
queueDesc.Priority = desc.priority;
|
||||||
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12CommandQueue> commandQueue;
|
||||||
|
HRESULT hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*queue = new D3D12CommandQueue(this, commandQueue.Get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateCommandAllocator(ICommandAllocator** allocator) {
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> commandAllocator;
|
||||||
|
HRESULT hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*allocator = new D3D12CommandAllocator(this, commandAllocator.Get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateCommandList(ICommandList** list, ICommandAllocator* allocator) {
|
||||||
|
D3D12CommandAllocator* d3d12Allocator = static_cast<D3D12CommandAllocator*>(allocator);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||||
|
HRESULT hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
|
d3d12Allocator->GetNativeAllocator(), nullptr, IID_PPV_ARGS(&commandList));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*list = new D3D12CommandList(this, commandList.Get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateFence(IFence** fence) {
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Fence> d3dFence;
|
||||||
|
HRESULT hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3dFence));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fence = new D3D12Fence(this, d3dFence.Get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) {
|
||||||
|
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||||
|
heapDesc.NumDescriptors = desc.count;
|
||||||
|
heapDesc.Flags = desc.shaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
|
|
||||||
|
switch (desc.type) {
|
||||||
|
case DescriptorHeapType::CBV_SRV_UAV:
|
||||||
|
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||||
|
break;
|
||||||
|
case DescriptorHeapType::Sampler:
|
||||||
|
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||||
|
break;
|
||||||
|
case DescriptorHeapType::RTV:
|
||||||
|
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||||
|
break;
|
||||||
|
case DescriptorHeapType::DSV:
|
||||||
|
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> descriptorHeap;
|
||||||
|
HRESULT hr = m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&descriptorHeap));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*heap = new D3D12DescriptorHeap(this, descriptorHeap.Get(), desc.type);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateRootSignature(IRootSignature** signature, const RootSignatureDesc& desc) {
|
||||||
|
*signature = new D3D12RootSignature(this);
|
||||||
|
return (*signature)->Initialize(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreatePipelineState(IPipelineState** pso, const PipelineDesc& desc) {
|
||||||
|
*pso = new D3D12PipelineState(this);
|
||||||
|
return static_cast<D3D12PipelineState*>(*pso)->Initialize(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) {
|
||||||
|
*swapChain = new D3D12SwapChain(this);
|
||||||
|
bool result = (*swapChain)->Initialize(desc, windowHandle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandQueue::D3D12CommandQueue(D3D12Device* device, ID3D12CommandQueue* queue)
|
||||||
|
: m_device(device), m_commandQueue(queue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandQueue::~D3D12CommandQueue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandQueue::ExecuteCommandLists(void** lists, uint32_t count) {
|
||||||
|
ID3D12CommandList** d3dLists = reinterpret_cast<ID3D12CommandList**>(lists);
|
||||||
|
m_commandQueue->ExecuteCommandLists(count, d3dLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandQueue::Signal(void* fence, uint64_t value) {
|
||||||
|
ID3D12Fence* d3dFence = static_cast<ID3D12Fence*>(fence);
|
||||||
|
m_commandQueue->Signal(d3dFence, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandQueue::Wait(void* fence, uint64_t value) {
|
||||||
|
ID3D12Fence* d3dFence = static_cast<ID3D12Fence*>(fence);
|
||||||
|
m_commandQueue->Wait(d3dFence, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t D3D12CommandQueue::GetTimestampFrequency() const {
|
||||||
|
uint64_t frequency = 0;
|
||||||
|
m_commandQueue->GetTimestampFrequency(&frequency);
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandAllocator::D3D12CommandAllocator(D3D12Device* device, ID3D12CommandAllocator* allocator)
|
||||||
|
: m_device(device), m_commandAllocator(allocator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandAllocator::~D3D12CommandAllocator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandAllocator::Reset() {
|
||||||
|
m_commandAllocator->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Fence::D3D12Fence(D3D12Device* device, ID3D12Fence* fence)
|
||||||
|
: m_device(device), m_fence(fence) {
|
||||||
|
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Fence::~D3D12Fence() {
|
||||||
|
if (m_fenceEvent) {
|
||||||
|
CloseHandle(m_fenceEvent);
|
||||||
|
m_fenceEvent = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t D3D12Fence::GetCompletedValue() const {
|
||||||
|
return m_fence->GetCompletedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Fence::Signal(uint64_t value) {
|
||||||
|
m_fence->Signal(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Fence::Wait(uint64_t value) {
|
||||||
|
if (m_fence->GetCompletedValue() < value) {
|
||||||
|
m_fence->SetEventOnCompletion(value, m_fenceEvent);
|
||||||
|
WaitForSingleObject(m_fenceEvent, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Fence::Wait(uint64_t value, uint64_t timeoutMs) {
|
||||||
|
if (m_fence->GetCompletedValue() < value) {
|
||||||
|
m_fence->SetEventOnCompletion(value, m_fenceEvent);
|
||||||
|
WaitForSingleObject(m_fenceEvent, (DWORD)timeoutMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12DescriptorHeap::D3D12DescriptorHeap(D3D12Device* device, ID3D12DescriptorHeap* heap, DescriptorHeapType type)
|
||||||
|
: m_device(device), m_descriptorHeap(heap), m_type(type) {
|
||||||
|
m_descriptorCount = heap->GetDesc().NumDescriptors;
|
||||||
|
m_descriptorSize = device->GetD3D12Device()->GetDescriptorHandleIncrementSize(
|
||||||
|
type == DescriptorHeapType::CBV_SRV_UAV ? D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV :
|
||||||
|
type == DescriptorHeapType::Sampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER :
|
||||||
|
type == DescriptorHeapType::RTV ? D3D12_DESCRIPTOR_HEAP_TYPE_RTV : D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12DescriptorHeap::~D3D12DescriptorHeap() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12DescriptorHeap::GetCPUDescriptorHandle(uint32_t index) const {
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
handle.ptr += index * m_descriptorSize;
|
||||||
|
return (void*)handle.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t D3D12DescriptorHeap::GetGPUDescriptorHandle(uint32_t index) const {
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetGPUDescriptorHandleForHeapStart();
|
||||||
|
handle.ptr += index * m_descriptorSize;
|
||||||
|
return handle.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12DescriptorHeap::SetName(const char* name) {
|
||||||
|
if (name) {
|
||||||
|
m_descriptorHeap->SetName(std::wstring(name, name + strlen(name)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12SwapChain::D3D12SwapChain(D3D12Device* device)
|
||||||
|
: m_device(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12SwapChain::~D3D12SwapChain() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12SwapChain::Initialize(const SwapChainDesc& desc, void* windowHandle) {
|
||||||
|
m_bufferCount = desc.bufferCount;
|
||||||
|
m_vsync = desc.vsync;
|
||||||
|
m_fullscreen = desc.fullscreen;
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
|
||||||
|
swapChainDesc.BufferCount = desc.bufferCount;
|
||||||
|
swapChainDesc.BufferDesc.Width = desc.width;
|
||||||
|
swapChainDesc.BufferDesc.Height = desc.height;
|
||||||
|
swapChainDesc.BufferDesc.Format = FormatToDXGIFormat(desc.format);
|
||||||
|
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
|
swapChainDesc.OutputWindow = (HWND)windowHandle;
|
||||||
|
swapChainDesc.SampleDesc.Count = 1;
|
||||||
|
swapChainDesc.Windowed = !desc.fullscreen;
|
||||||
|
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGISwapChain> swapChain;
|
||||||
|
ID3D12CommandQueue* cmdQueue = (ID3D12CommandQueue*)m_device->GetCommandQueue()->GetNativeQueue();
|
||||||
|
HRESULT hr = m_device->GetDXGIFactory()->CreateSwapChain(
|
||||||
|
cmdQueue, &swapChainDesc, &swapChain);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = swapChain.As(&m_swapChain);
|
||||||
|
|
||||||
|
DescriptorHeapDesc rtvDesc = {};
|
||||||
|
rtvDesc.type = DescriptorHeapType::RTV;
|
||||||
|
rtvDesc.count = desc.bufferCount;
|
||||||
|
rtvDesc.shaderVisible = false;
|
||||||
|
|
||||||
|
if (!m_device->CreateDescriptorHeap((IDescriptorHeap**)&m_rtvHeap, rtvDesc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart;
|
||||||
|
rtvHeapStart.ptr = (UINT64)m_rtvHeap->GetCPUDescriptorHandle(0);
|
||||||
|
|
||||||
|
UINT rtvDescriptorSize = m_device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
|
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < desc.bufferCount; i++) {
|
||||||
|
hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_buffers[i]));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer;
|
||||||
|
rtvPointer.ptr = rtvHeapStart.ptr + i * rtvDescriptorSize;
|
||||||
|
m_device->GetD3D12Device()->CreateRenderTargetView(m_buffers[i].Get(), nullptr, rtvPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12SwapChain::Shutdown() {
|
||||||
|
m_buffers[0].Reset();
|
||||||
|
if (m_rtvHeap) {
|
||||||
|
delete m_rtvHeap;
|
||||||
|
m_rtvHeap = nullptr;
|
||||||
|
}
|
||||||
|
m_swapChain.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12SwapChain::Present() {
|
||||||
|
HRESULT hr = m_swapChain->Present(m_vsync ? 1 : 0, 0);
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12SwapChain::Resize(uint32_t width, uint32_t height) {
|
||||||
|
for (uint32_t i = 0; i < m_bufferCount; i++) {
|
||||||
|
m_buffers[i].Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr = m_swapChain->ResizeBuffers(m_bufferCount, width, height, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = *(D3D12_CPU_DESCRIPTOR_HANDLE*)m_rtvHeap->GetCPUDescriptorHandle(0);
|
||||||
|
for (uint32_t i = 0; i < m_bufferCount; i++) {
|
||||||
|
hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_buffers[i]));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device->GetD3D12Device()->CreateRenderTargetView(m_buffers[i].Get(), nullptr, rtvHandle);
|
||||||
|
rtvHandle.ptr += m_rtvHeap->GetDescriptorSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t D3D12SwapChain::GetCurrentBufferIndex() const {
|
||||||
|
return m_swapChain->GetCurrentBackBufferIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12SwapChain::GetBuffer(uint32_t index) {
|
||||||
|
return GetBufferResource(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12SwapChain::SetFullscreen(bool fullscreen) {
|
||||||
|
m_fullscreen = fullscreen;
|
||||||
|
m_swapChain->SetFullscreenState(fullscreen, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12SwapChain::IsFullscreen() const {
|
||||||
|
return m_fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12RootSignature::D3D12RootSignature(D3D12Device* device)
|
||||||
|
: m_device(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12RootSignature::~D3D12RootSignature() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12RootSignature::Initialize(const RootSignatureDesc& desc) {
|
||||||
|
EngineLog("RootSignature: Start init, paramCount=%u", desc.parameterCount);
|
||||||
|
D3D12_ROOT_PARAMETER rootParameters[16] = {};
|
||||||
|
D3D12_DESCRIPTOR_RANGE descriptorRanges[16] = {};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < desc.parameterCount && i < 16; i++) {
|
||||||
|
const RootParameter& param = desc.parameters[i];
|
||||||
|
|
||||||
|
switch (param.type) {
|
||||||
|
case RootParameterType::CBV:
|
||||||
|
rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||||
|
rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility;
|
||||||
|
rootParameters[i].Descriptor.RegisterSpace = param.registerSpace;
|
||||||
|
rootParameters[i].Descriptor.ShaderRegister = param.shaderRegister;
|
||||||
|
break;
|
||||||
|
case RootParameterType::SRV:
|
||||||
|
rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
|
||||||
|
rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility;
|
||||||
|
rootParameters[i].Descriptor.RegisterSpace = param.registerSpace;
|
||||||
|
rootParameters[i].Descriptor.ShaderRegister = param.shaderRegister;
|
||||||
|
break;
|
||||||
|
case RootParameterType::Constants:
|
||||||
|
rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
||||||
|
rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility;
|
||||||
|
rootParameters[i].Constants.RegisterSpace = param.registerSpace;
|
||||||
|
rootParameters[i].Constants.ShaderRegister = param.shaderRegister;
|
||||||
|
rootParameters[i].Constants.Num32BitValues = param.num32BitValues;
|
||||||
|
break;
|
||||||
|
case RootParameterType::DescriptorTable:
|
||||||
|
rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||||
|
rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility;
|
||||||
|
rootParameters[i].DescriptorTable.pDescriptorRanges = &descriptorRanges[i];
|
||||||
|
rootParameters[i].DescriptorTable.NumDescriptorRanges = 1;
|
||||||
|
|
||||||
|
descriptorRanges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||||
|
descriptorRanges[i].RegisterSpace = param.registerSpace;
|
||||||
|
descriptorRanges[i].BaseShaderRegister = 0;
|
||||||
|
descriptorRanges[i].NumDescriptors = 1;
|
||||||
|
descriptorRanges[i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rootParameters[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
EngineLog("RootParam[%d]: type=%d, visibility=%d, reg=%d, space=%d",
|
||||||
|
i, (int)param.type, (int)param.visibility, param.shaderRegister, param.registerSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
|
||||||
|
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
samplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
|
||||||
|
samplerDesc.RegisterSpace = 0;
|
||||||
|
samplerDesc.ShaderRegister = 0;
|
||||||
|
samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
|
D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
|
||||||
|
rootSignatureDesc.NumParameters = desc.parameterCount;
|
||||||
|
rootSignatureDesc.pParameters = rootParameters;
|
||||||
|
rootSignatureDesc.NumStaticSamplers = 1;
|
||||||
|
rootSignatureDesc.pStaticSamplers = &samplerDesc;
|
||||||
|
rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3DBlob> signature;
|
||||||
|
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||||
|
HRESULT hr = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &errorBlob);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (errorBlob) {
|
||||||
|
OutputDebugStringA((const char*)errorBlob->GetBufferPointer());
|
||||||
|
}
|
||||||
|
EngineLog("RootSignature: Serialize FAILED");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EngineLog("RootSignature: Serialize SUCCESS, size=%llu", (unsigned long long)signature->GetBufferSize());
|
||||||
|
|
||||||
|
hr = m_device->GetD3D12Device()->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
|
||||||
|
IID_PPV_ARGS(&m_rootSignature));
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
EngineLog("RootSignature: SUCCESS");
|
||||||
|
} else {
|
||||||
|
EngineLog("RootSignature: FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12RootSignature::SetName(const char* name) {
|
||||||
|
if (name && m_rootSignature) {
|
||||||
|
m_rootSignature->SetName(std::wstring(name, name + strlen(name)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12RootSignature::GetNativeRootSignature() const {
|
||||||
|
return m_rootSignature.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12PipelineState::D3D12PipelineState(D3D12Device* device)
|
||||||
|
: m_device(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12PipelineState::~D3D12PipelineState() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12PipelineState::Initialize(const PipelineDesc& desc) {
|
||||||
|
EngineLog("PipelineState: Start init");
|
||||||
|
|
||||||
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
||||||
|
|
||||||
|
if (desc.rootSignature) {
|
||||||
|
EngineLog("PipelineState: has rootSignature");
|
||||||
|
D3D12RootSignature* rs = static_cast<D3D12RootSignature*>(desc.rootSignature);
|
||||||
|
psoDesc.pRootSignature = rs->GetNative();
|
||||||
|
EngineLog("PipelineState: rootSignature ptr=%p", psoDesc.pRootSignature);
|
||||||
|
} else {
|
||||||
|
EngineLog("PipelineState: NO rootSignature!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc.vertexShader.size > 0 && desc.vertexShader.bytecode != nullptr) {
|
||||||
|
psoDesc.VS.pShaderBytecode = desc.vertexShader.bytecode;
|
||||||
|
psoDesc.VS.BytecodeLength = desc.vertexShader.size;
|
||||||
|
}
|
||||||
|
if (desc.pixelShader.size > 0 && desc.pixelShader.bytecode != nullptr) {
|
||||||
|
psoDesc.PS.pShaderBytecode = desc.pixelShader.bytecode;
|
||||||
|
psoDesc.PS.BytecodeLength = desc.pixelShader.size;
|
||||||
|
}
|
||||||
|
if (desc.geometryShader.size > 0 && desc.geometryShader.bytecode != nullptr) {
|
||||||
|
psoDesc.GS.pShaderBytecode = desc.geometryShader.bytecode;
|
||||||
|
psoDesc.GS.BytecodeLength = desc.geometryShader.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_INPUT_ELEMENT_DESC d3d12Elements[16] = {};
|
||||||
|
for (uint32_t i = 0; i < desc.inputLayout.elementCount && i < 16; i++) {
|
||||||
|
const InputElementDesc& src = desc.inputLayout.elements[i];
|
||||||
|
d3d12Elements[i].SemanticName = src.semanticName;
|
||||||
|
d3d12Elements[i].SemanticIndex = src.semanticIndex;
|
||||||
|
d3d12Elements[i].Format = FormatToDXGIFormat(src.format);
|
||||||
|
d3d12Elements[i].InputSlot = src.inputSlot;
|
||||||
|
d3d12Elements[i].AlignedByteOffset = src.alignedByteOffset;
|
||||||
|
d3d12Elements[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||||
|
d3d12Elements[i].InstanceDataStepRate = 0;
|
||||||
|
}
|
||||||
|
psoDesc.InputLayout.NumElements = desc.inputLayout.elementCount;
|
||||||
|
psoDesc.InputLayout.pInputElementDescs = d3d12Elements;
|
||||||
|
|
||||||
|
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||||
|
psoDesc.NumRenderTargets = 1;
|
||||||
|
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
psoDesc.SampleDesc.Count = 1;
|
||||||
|
psoDesc.SampleDesc.Quality = 0;
|
||||||
|
psoDesc.SampleMask = 0xffffffff;
|
||||||
|
|
||||||
|
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||||
|
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
|
||||||
|
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
||||||
|
|
||||||
|
psoDesc.DepthStencilState.DepthEnable = TRUE;
|
||||||
|
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
||||||
|
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||||
|
|
||||||
|
psoDesc.BlendState = { 0 };
|
||||||
|
D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc = {
|
||||||
|
FALSE,FALSE,
|
||||||
|
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
|
||||||
|
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
|
||||||
|
D3D12_LOGIC_OP_NOOP,
|
||||||
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
||||||
|
};
|
||||||
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
|
||||||
|
psoDesc.BlendState.RenderTarget[i] = rtBlendDesc;
|
||||||
|
|
||||||
|
EngineLog("PSO: VS=%p(%u), PS=%p(%u), RTV=%d, DSV=%d",
|
||||||
|
psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength,
|
||||||
|
psoDesc.PS.pShaderBytecode, psoDesc.PS.BytecodeLength,
|
||||||
|
psoDesc.RTVFormats[0], psoDesc.DSVFormat);
|
||||||
|
|
||||||
|
HRESULT hr = m_device->GetD3D12Device()->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
EngineLog("PipelineState: FAILED with HRESULT=%08lx", (unsigned long)hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EngineLog("PipelineState: SUCCESS");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12PipelineState::SetName(const char* name) {
|
||||||
|
if (name && m_pipelineState) {
|
||||||
|
m_pipelineState->SetName(std::wstring(name, name + strlen(name)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12PipelineState::GetNativePipelineState() const {
|
||||||
|
return m_pipelineState.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandList::D3D12CommandList(D3D12Device* device, ID3D12GraphicsCommandList* list)
|
||||||
|
: m_device(device), m_commandList(list) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12CommandList::~D3D12CommandList() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::Reset(void* allocator) {
|
||||||
|
ID3D12CommandAllocator* d3dAllocator = static_cast<ID3D12CommandAllocator*>(allocator);
|
||||||
|
m_commandList->Reset(d3dAllocator, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::Close() {
|
||||||
|
m_commandList->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetPipelineState(IPipelineState* pso) {
|
||||||
|
if (pso) {
|
||||||
|
D3D12PipelineState* d3dPso = static_cast<D3D12PipelineState*>(pso);
|
||||||
|
m_commandList->SetPipelineState(d3dPso->GetNative());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetRootSignature(IRootSignature* signature) {
|
||||||
|
if (signature) {
|
||||||
|
D3D12RootSignature* d3dRs = static_cast<D3D12RootSignature*>(signature);
|
||||||
|
m_commandList->SetGraphicsRootSignature(d3dRs->GetNative());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetPrimitiveTopology(PrimitiveTopology topology) {
|
||||||
|
D3D12_PRIMITIVE_TOPOLOGY d3dTopology;
|
||||||
|
switch (topology) {
|
||||||
|
case PrimitiveTopology::TriangleList:
|
||||||
|
d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||||
|
break;
|
||||||
|
case PrimitiveTopology::TriangleStrip:
|
||||||
|
d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||||
|
break;
|
||||||
|
case PrimitiveTopology::LineList:
|
||||||
|
d3dTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_commandList->IASetPrimitiveTopology(d3dTopology);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetVertexBuffer(uint32_t slot, IResource* buffer, uint32_t offset, uint32_t stride) {
|
||||||
|
if (buffer) {
|
||||||
|
D3D12Resource* d3dBuffer = static_cast<D3D12Resource*>(buffer);
|
||||||
|
D3D12_VERTEX_BUFFER_VIEW vbView = {};
|
||||||
|
vbView.BufferLocation = d3dBuffer->GetNative()->GetGPUVirtualAddress() + offset;
|
||||||
|
vbView.SizeInBytes = (UINT)stride;
|
||||||
|
vbView.StrideInBytes = stride;
|
||||||
|
m_commandList->IASetVertexBuffers(slot, 1, &vbView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetIndexBuffer(IResource* buffer, uint32_t offset) {
|
||||||
|
if (buffer) {
|
||||||
|
D3D12Resource* d3dBuffer = static_cast<D3D12Resource*>(buffer);
|
||||||
|
D3D12_INDEX_BUFFER_VIEW ibView = {};
|
||||||
|
ibView.BufferLocation = d3dBuffer->GetNative()->GetGPUVirtualAddress() + offset;
|
||||||
|
ibView.Format = DXGI_FORMAT_R32_UINT;
|
||||||
|
ibView.SizeInBytes = 0;
|
||||||
|
m_commandList->IASetIndexBuffer(&ibView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetDescriptorHeap(IDescriptorHeap* heap) {
|
||||||
|
if (heap) {
|
||||||
|
D3D12DescriptorHeap* d3dHeap = static_cast<D3D12DescriptorHeap*>(heap);
|
||||||
|
ID3D12DescriptorHeap* heaps[] = { d3dHeap->GetNativeHeap() };
|
||||||
|
m_commandList->SetDescriptorHeaps(1, heaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) {
|
||||||
|
m_commandList->SetGraphicsRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptor });
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) {
|
||||||
|
m_commandList->SetComputeRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptor });
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::DrawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) {
|
||||||
|
m_commandList->DrawInstanced(vertexCountPerInstance, instanceCount, startVertex, startInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::DrawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) {
|
||||||
|
m_commandList->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndex, baseVertex, startInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
||||||
|
m_commandList->Dispatch(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetViewports(const Viewport* viewports, uint32_t count) {
|
||||||
|
D3D12_VIEWPORT d3dViewports[16] = {};
|
||||||
|
for (uint32_t i = 0; i < count && i < 16; i++) {
|
||||||
|
d3dViewports[i].TopLeftX = viewports[i].topLeftX;
|
||||||
|
d3dViewports[i].TopLeftY = viewports[i].topLeftY;
|
||||||
|
d3dViewports[i].Width = viewports[i].width;
|
||||||
|
d3dViewports[i].Height = viewports[i].height;
|
||||||
|
d3dViewports[i].MinDepth = viewports[i].minDepth;
|
||||||
|
d3dViewports[i].MaxDepth = viewports[i].maxDepth;
|
||||||
|
}
|
||||||
|
m_commandList->RSSetViewports(count, d3dViewports);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetScissorRects(const Rect* rects, uint32_t count) {
|
||||||
|
D3D12_RECT d3dRects[16] = {};
|
||||||
|
for (uint32_t i = 0; i < count && i < 16; i++) {
|
||||||
|
d3dRects[i].left = rects[i].left;
|
||||||
|
d3dRects[i].top = rects[i].top;
|
||||||
|
d3dRects[i].right = rects[i].right;
|
||||||
|
d3dRects[i].bottom = rects[i].bottom;
|
||||||
|
}
|
||||||
|
m_commandList->RSSetScissorRects(count, d3dRects);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::SetRenderTargets(void** targets, uint32_t count, void* depthStencil) {
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandles[8] = {};
|
||||||
|
for (uint32_t i = 0; i < count && i < 8; i++) {
|
||||||
|
rtvHandles[i].ptr = (UINT64)targets[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = {};
|
||||||
|
if (depthStencil) {
|
||||||
|
dsvHandle.ptr = (UINT64)depthStencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_commandList->OMSetRenderTargets(count, rtvHandles, FALSE, depthStencil ? &dsvHandle : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::ClearRenderTargetView(void* target, const float color[4]) {
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { (UINT64)target };
|
||||||
|
m_commandList->ClearRenderTargetView(rtvHandle, color, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::ClearDepthStencilView(void* depth, float depthValue, uint8_t stencil) {
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = { (UINT64)depth };
|
||||||
|
m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, depthValue, stencil, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::CopyResource(IResource* dst, const IResource* src) {
|
||||||
|
D3D12Resource* d3dDst = static_cast<D3D12Resource*>(dst);
|
||||||
|
D3D12Resource* d3dSrc = static_cast<D3D12Resource*>(const_cast<IResource*>(src));
|
||||||
|
m_commandList->CopyResource(d3dDst->GetNative(), d3dSrc->GetNative());
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) {
|
||||||
|
D3D12Resource* d3dDst = static_cast<D3D12Resource*>(dst);
|
||||||
|
D3D12Resource* d3dSrc = static_cast<D3D12Resource*>(const_cast<IResource*>(src));
|
||||||
|
m_commandList->CopyBufferRegion(d3dDst->GetNative(), dstOffset, d3dSrc->GetNative(), srcOffset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12CommandList::ResourceBarrier(IResource* resource, ResourceStateFlag before, ResourceStateFlag after) {
|
||||||
|
D3D12Resource* d3dResource = static_cast<D3D12Resource*>(resource);
|
||||||
|
|
||||||
|
D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
|
||||||
|
if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::RenderTarget)) beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::DepthWrite)) beforeState = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::DepthRead)) beforeState = D3D12_RESOURCE_STATE_DEPTH_READ;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::ShaderResource)) beforeState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::CopyDest)) beforeState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::CopySource)) beforeState = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||||
|
else if (static_cast<uint32_t>(before) & static_cast<uint32_t>(ResourceStateFlag::Present)) beforeState = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
|
||||||
|
if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::RenderTarget)) afterState = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::DepthWrite)) afterState = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::DepthRead)) afterState = D3D12_RESOURCE_STATE_DEPTH_READ;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::ShaderResource)) afterState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::CopyDest)) afterState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::CopySource)) afterState = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||||
|
else if (static_cast<uint32_t>(after) & static_cast<uint32_t>(ResourceStateFlag::Present)) afterState = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
barrier.Transition.pResource = d3dResource->GetNative();
|
||||||
|
barrier.Transition.StateBefore = beforeState;
|
||||||
|
barrier.Transition.StateAfter = afterState;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
|
m_commandList->ResourceBarrier(1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12CommandList::GetNativeCommandList() const {
|
||||||
|
return m_commandList.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Resource::D3D12Resource(D3D12Device* device, ID3D12Resource* resource)
|
||||||
|
: m_device(device), m_resource(resource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Resource::~D3D12Resource() {
|
||||||
|
m_resource.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
237
engine/src/RHI/D3D12/D3D12RHI.h
Normal file
237
engine/src/RHI/D3D12/D3D12RHI.h
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RHI\IRHIDevice.h>
|
||||||
|
#include <RHI\IRHIResources.h>
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#include <wrl\client.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class D3D12Device;
|
||||||
|
|
||||||
|
class D3D12CommandQueue : public ICommandQueue {
|
||||||
|
public:
|
||||||
|
D3D12CommandQueue(D3D12Device* device, ID3D12CommandQueue* queue);
|
||||||
|
~D3D12CommandQueue() override;
|
||||||
|
|
||||||
|
void ExecuteCommandLists(void** lists, uint32_t count) override;
|
||||||
|
void Signal(void* fence, uint64_t value) override;
|
||||||
|
void Wait(void* fence, uint64_t value) override;
|
||||||
|
uint64_t GetTimestampFrequency() const override;
|
||||||
|
|
||||||
|
ID3D12CommandQueue* GetNativeQueue() const { return m_commandQueue.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12CommandAllocator : public ICommandAllocator {
|
||||||
|
public:
|
||||||
|
D3D12CommandAllocator(D3D12Device* device, ID3D12CommandAllocator* allocator);
|
||||||
|
~D3D12CommandAllocator() override;
|
||||||
|
|
||||||
|
void Reset() override;
|
||||||
|
|
||||||
|
ID3D12CommandAllocator* GetNativeAllocator() const { return m_commandAllocator.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocator;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12Fence : public IFence {
|
||||||
|
public:
|
||||||
|
D3D12Fence(D3D12Device* device, ID3D12Fence* fence);
|
||||||
|
~D3D12Fence() override;
|
||||||
|
|
||||||
|
uint64_t GetCompletedValue() const override;
|
||||||
|
void Signal(uint64_t value) override;
|
||||||
|
void Wait(uint64_t value) override;
|
||||||
|
void Wait(uint64_t value, uint64_t timeoutMs) override;
|
||||||
|
|
||||||
|
ID3D12Fence* GetNativeFence() const { return m_fence.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Fence> m_fence;
|
||||||
|
HANDLE m_fenceEvent = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12DescriptorHeap : public IDescriptorHeap {
|
||||||
|
public:
|
||||||
|
D3D12DescriptorHeap(D3D12Device* device, ID3D12DescriptorHeap* heap, DescriptorHeapType type);
|
||||||
|
~D3D12DescriptorHeap() override;
|
||||||
|
|
||||||
|
DescriptorHeapType GetType() const override { return m_type; }
|
||||||
|
uint32_t GetDescriptorCount() const override { return m_descriptorCount; }
|
||||||
|
void* GetCPUDescriptorHandle(uint32_t index) const override;
|
||||||
|
uint64_t GetGPUDescriptorHandle(uint32_t index) const override;
|
||||||
|
void SetName(const char* name) override;
|
||||||
|
|
||||||
|
ID3D12DescriptorHeap* GetNativeHeap() const { return m_descriptorHeap.Get(); }
|
||||||
|
uint32_t GetDescriptorSize() const { return m_descriptorSize; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_descriptorHeap;
|
||||||
|
DescriptorHeapType m_type;
|
||||||
|
uint32_t m_descriptorCount = 0;
|
||||||
|
uint32_t m_descriptorSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12SwapChain : public ISwapChain {
|
||||||
|
public:
|
||||||
|
D3D12SwapChain(D3D12Device* device);
|
||||||
|
~D3D12SwapChain() override;
|
||||||
|
|
||||||
|
bool Initialize(const SwapChainDesc& desc, void* windowHandle) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
bool Present() override;
|
||||||
|
bool Resize(uint32_t width, uint32_t height) override;
|
||||||
|
uint32_t GetCurrentBufferIndex() const override;
|
||||||
|
void* GetBuffer(uint32_t index) override;
|
||||||
|
void SetFullscreen(bool fullscreen) override;
|
||||||
|
bool IsFullscreen() const override;
|
||||||
|
|
||||||
|
IDXGISwapChain3* GetNativeSwapChain() const { return m_swapChain.Get(); }
|
||||||
|
ID3D12Resource* GetBufferResource(uint32_t index) const { return m_buffers[index].Get(); }
|
||||||
|
D3D12DescriptorHeap* GetRTVHeap() const { return m_rtvHeap; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<IDXGISwapChain3> m_swapChain;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_buffers[16];
|
||||||
|
D3D12DescriptorHeap* m_rtvHeap = nullptr;
|
||||||
|
uint32_t m_bufferCount = 0;
|
||||||
|
bool m_vsync = false;
|
||||||
|
bool m_fullscreen = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12RootSignature : public IRootSignature {
|
||||||
|
public:
|
||||||
|
D3D12RootSignature(D3D12Device* device);
|
||||||
|
~D3D12RootSignature() override;
|
||||||
|
|
||||||
|
bool Initialize(const RootSignatureDesc& desc) override;
|
||||||
|
void SetName(const char* name) override;
|
||||||
|
void* GetNativeRootSignature() const override;
|
||||||
|
|
||||||
|
ID3D12RootSignature* GetNative() const { return m_rootSignature.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12RootSignature> m_rootSignature;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12PipelineState : public IPipelineState {
|
||||||
|
public:
|
||||||
|
D3D12PipelineState(D3D12Device* device);
|
||||||
|
~D3D12PipelineState() override;
|
||||||
|
|
||||||
|
bool Initialize(const PipelineDesc& desc);
|
||||||
|
void SetName(const char* name) override;
|
||||||
|
void* GetNativePipelineState() const override;
|
||||||
|
|
||||||
|
ID3D12PipelineState* GetNative() const { return m_pipelineState.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12PipelineState> m_pipelineState;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12CommandList : public ICommandList {
|
||||||
|
public:
|
||||||
|
D3D12CommandList(D3D12Device* device, ID3D12GraphicsCommandList* list);
|
||||||
|
~D3D12CommandList() override;
|
||||||
|
|
||||||
|
void Reset(void* allocator) override;
|
||||||
|
void Close() override;
|
||||||
|
void SetPipelineState(IPipelineState* pso) override;
|
||||||
|
void SetRootSignature(IRootSignature* signature) override;
|
||||||
|
void SetPrimitiveTopology(PrimitiveTopology topology) override;
|
||||||
|
void SetVertexBuffer(uint32_t slot, IResource* buffer, uint32_t offset, uint32_t stride) override;
|
||||||
|
void SetIndexBuffer(IResource* buffer, uint32_t offset) override;
|
||||||
|
void SetDescriptorHeap(IDescriptorHeap* heap) override;
|
||||||
|
void SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) override;
|
||||||
|
void SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) override;
|
||||||
|
void DrawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) override;
|
||||||
|
void DrawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) override;
|
||||||
|
void Dispatch(uint32_t x, uint32_t y, uint32_t z) override;
|
||||||
|
void SetViewports(const Viewport* viewports, uint32_t count) override;
|
||||||
|
void SetScissorRects(const Rect* rects, uint32_t count) override;
|
||||||
|
void SetRenderTargets(void** targets, uint32_t count, void* depthStencil) override;
|
||||||
|
void ClearRenderTargetView(void* target, const float color[4]) override;
|
||||||
|
void ClearDepthStencilView(void* depth, float depthValue, uint8_t stencil) override;
|
||||||
|
void CopyResource(IResource* dst, const IResource* src) override;
|
||||||
|
void CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) override;
|
||||||
|
void ResourceBarrier(IResource* resource, ResourceStateFlag before, ResourceStateFlag after) override;
|
||||||
|
void* GetNativeCommandList() const override;
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* GetNative() const { return m_commandList.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12Resource : public IResource {
|
||||||
|
public:
|
||||||
|
D3D12Resource(D3D12Device* device, ID3D12Resource* resource);
|
||||||
|
~D3D12Resource() override;
|
||||||
|
|
||||||
|
void* GetNativeResource() const override { return m_resource.Get(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_resource.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_resource;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12Device : public IRHIDevice {
|
||||||
|
public:
|
||||||
|
D3D12Device();
|
||||||
|
~D3D12Device() override;
|
||||||
|
|
||||||
|
GraphicsAPI GetAPI() const override { return GraphicsAPI::Direct3D12; }
|
||||||
|
const char* GetAPIName() const override { return "Direct3D 12"; }
|
||||||
|
|
||||||
|
bool Initialize(void* windowHandle, uint32_t width, uint32_t height) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
bool CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) override;
|
||||||
|
bool CreateCommandAllocator(ICommandAllocator** allocator) override;
|
||||||
|
bool CreateCommandList(ICommandList** list, ICommandAllocator* allocator) override;
|
||||||
|
bool CreateFence(IFence** fence) override;
|
||||||
|
|
||||||
|
bool CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) override;
|
||||||
|
|
||||||
|
bool CreateRootSignature(IRootSignature** signature, const RootSignatureDesc& desc) override;
|
||||||
|
bool CreatePipelineState(IPipelineState** pso, const PipelineDesc& desc) override;
|
||||||
|
|
||||||
|
bool CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) override;
|
||||||
|
|
||||||
|
ICommandQueue* GetCommandQueue() override { return m_commandQueue; }
|
||||||
|
ISwapChain* GetSwapChain() { return m_swapChain; }
|
||||||
|
void* GetNativeDevice() const override { return m_device.Get(); }
|
||||||
|
void* GetNativeAdapter() const override { return m_adapter.Get(); }
|
||||||
|
|
||||||
|
ID3D12Device* GetD3D12Device() const { return m_device.Get(); }
|
||||||
|
IDXGIFactory4* GetDXGIFactory() const { return m_dxgiFactory.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CreateDXGIDevice(void* windowHandle);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Device> m_device;
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIAdapter1> m_adapter;
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIFactory4> m_dxgiFactory;
|
||||||
|
|
||||||
|
D3D12CommandQueue* m_commandQueue = nullptr;
|
||||||
|
D3D12SwapChain* m_swapChain = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
136
engine/src/RHI/D3D12/D3D12RenderContext.cpp
Normal file
136
engine/src/RHI/D3D12/D3D12RenderContext.cpp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#include <Rendering\RenderContext.h>
|
||||||
|
#include <RHI\D3D12\D3D12RHI.h>
|
||||||
|
#include <RHI\D3D12\D3D12Resources.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
RenderContext::RenderContext(D3D12Device* device) : m_device(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderContext::~RenderContext() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderContext::Initialize(uint32_t width, uint32_t height) {
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
|
||||||
|
if (!m_device->CreateCommandAllocator(&m_commandAllocator)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_device->CreateCommandList(&m_commandList, m_commandAllocator)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_device->CreateFence(&m_fence)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_swapChain = m_device->GetSwapChain();
|
||||||
|
if (!m_swapChain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateDepthStencil(m_device, width, height, Format::D24_UNorm_S8_UInt, &m_depthStencil)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::Shutdown() {
|
||||||
|
if (m_fence) {
|
||||||
|
m_fence->Wait(m_fenceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_commandList) delete m_commandList;
|
||||||
|
if (m_commandAllocator) delete m_commandAllocator;
|
||||||
|
if (m_fence) delete m_fence;
|
||||||
|
if (m_swapChain) delete m_swapChain;
|
||||||
|
if (m_currentRenderTarget) delete m_currentRenderTarget;
|
||||||
|
if (m_depthStencil) delete m_depthStencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::BeginFrame() {
|
||||||
|
m_commandAllocator->Reset();
|
||||||
|
m_commandList->Reset(m_commandAllocator);
|
||||||
|
|
||||||
|
uint32_t bufferIndex = m_swapChain->GetCurrentBufferIndex();
|
||||||
|
|
||||||
|
if (m_currentRenderTarget) delete m_currentRenderTarget;
|
||||||
|
CreateRenderTargetFromSwapChain(m_device, (D3D12SwapChain*)m_swapChain, bufferIndex, &m_currentRenderTarget);
|
||||||
|
|
||||||
|
D3D12CommandList* cmdList = (D3D12CommandList*)m_commandList;
|
||||||
|
ID3D12GraphicsCommandList* d3dCmdList = cmdList->GetNative();
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = ((D3D12RenderTarget*)m_currentRenderTarget)->GetNative();
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
d3dCmdList->ResourceBarrier(1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::EndFrame() {
|
||||||
|
D3D12CommandList* cmdList = (D3D12CommandList*)m_commandList;
|
||||||
|
ID3D12GraphicsCommandList* d3dCmdList = cmdList->GetNative();
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = ((D3D12RenderTarget*)m_currentRenderTarget)->GetNative();
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
d3dCmdList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
m_commandList->Close();
|
||||||
|
|
||||||
|
ICommandQueue* queue = m_device->GetCommandQueue();
|
||||||
|
void* cmdListPtr = m_commandList->GetNativeCommandList();
|
||||||
|
queue->ExecuteCommandLists(&cmdListPtr, 1);
|
||||||
|
|
||||||
|
m_fenceValue++;
|
||||||
|
queue->Signal(m_fence, m_fenceValue);
|
||||||
|
m_fence->Wait(m_fenceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::SetViewport(float width, float height) {
|
||||||
|
Viewport viewport = {};
|
||||||
|
viewport.topLeftX = 0;
|
||||||
|
viewport.topLeftY = 0;
|
||||||
|
viewport.width = width;
|
||||||
|
viewport.height = height;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
m_commandList->SetViewports(&viewport, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::SetScissor(int32_t width, int32_t height) {
|
||||||
|
Rect scissor = {};
|
||||||
|
scissor.left = 0;
|
||||||
|
scissor.top = 0;
|
||||||
|
scissor.right = width;
|
||||||
|
scissor.bottom = height;
|
||||||
|
m_commandList->SetScissorRects(&scissor, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::ClearRenderTarget(const float color[4]) {
|
||||||
|
D3D12RenderTarget* rt = (D3D12RenderTarget*)m_currentRenderTarget;
|
||||||
|
rt->CreateRTV();
|
||||||
|
m_commandList->ClearRenderTargetView(rt->GetRTV(), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::ClearDepthStencil() {
|
||||||
|
m_depthStencil->CreateDSV();
|
||||||
|
m_commandList->ClearDepthStencilView(m_depthStencil->GetDSV(), 1.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderContext::Present() {
|
||||||
|
m_swapChain->Present();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
73
engine/src/RHI/D3D12/D3D12RenderTarget.cpp
Normal file
73
engine/src/RHI/D3D12/D3D12RenderTarget.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include "D3D12Resources.h"
|
||||||
|
#include "Rendering\RenderTarget.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
void D3D12DepthStencil::CreateDSV() {
|
||||||
|
if (m_dsvHandle.ptr != 0) return;
|
||||||
|
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
||||||
|
dsvDesc.Format = FormatToDXGIFormat(m_desc.format);
|
||||||
|
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||||
|
m_device->GetD3D12Device()->CreateDepthStencilView(m_resource.Get(), &dsvDesc, m_dsvHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12RenderTarget::CreateRTV() {
|
||||||
|
if (m_rtvHandle.ptr != 0) return;
|
||||||
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
|
rtvDesc.Format = FormatToDXGIFormat(m_desc.format);
|
||||||
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
m_device->GetD3D12Device()->CreateRenderTargetView(m_resource.Get(), &rtvDesc, m_rtvHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateDepthStencil(D3D12Device* device, uint32_t width, uint32_t height, Format format, IDepthStencil** outDepthStencil) {
|
||||||
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
|
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||||
|
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
resourceDesc.Width = width;
|
||||||
|
resourceDesc.Height = height;
|
||||||
|
resourceDesc.DepthOrArraySize = 1;
|
||||||
|
resourceDesc.MipLevels = 1;
|
||||||
|
resourceDesc.Format = FormatToDXGIFormat(format);
|
||||||
|
resourceDesc.SampleDesc.Count = 1;
|
||||||
|
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||||
|
|
||||||
|
D3D12_CLEAR_VALUE clearValue = {};
|
||||||
|
clearValue.Format = FormatToDXGIFormat(format);
|
||||||
|
clearValue.DepthStencil.Depth = 1.0f;
|
||||||
|
clearValue.DepthStencil.Stencil = 0;
|
||||||
|
|
||||||
|
ID3D12Resource* resource = nullptr;
|
||||||
|
HRESULT hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(&resource));
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
TextureDesc desc = {};
|
||||||
|
desc.width = width;
|
||||||
|
desc.height = height;
|
||||||
|
desc.format = format;
|
||||||
|
desc.depthStencil = true;
|
||||||
|
|
||||||
|
*outDepthStencil = new D3D12DepthStencil(device, resource, desc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateRenderTargetFromSwapChain(D3D12Device* device, D3D12SwapChain* swapChain, uint32_t bufferIndex, IRenderTarget** outRenderTarget) {
|
||||||
|
ID3D12Resource* resource = swapChain->GetBufferResource(bufferIndex);
|
||||||
|
|
||||||
|
TextureDesc desc = {};
|
||||||
|
desc.width = 0;
|
||||||
|
desc.height = 0;
|
||||||
|
desc.format = Format::R8G8B8A8_UNorm;
|
||||||
|
desc.renderTarget = true;
|
||||||
|
|
||||||
|
*outRenderTarget = new D3D12RenderTarget(device, resource, desc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
378
engine/src/RHI/D3D12/D3D12Resources.cpp
Normal file
378
engine/src/RHI/D3D12/D3D12Resources.cpp
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
#include "D3D12Resources.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
D3D12Buffer::D3D12Buffer(D3D12Device* device, ID3D12Resource* resource, const BufferDesc& desc)
|
||||||
|
: m_device(device), m_resource(resource), m_desc(desc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Buffer::~D3D12Buffer() {
|
||||||
|
m_resource.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12Buffer::Map() {
|
||||||
|
void* data = nullptr;
|
||||||
|
D3D12_RANGE range = { 0, (SIZE_T)m_desc.size };
|
||||||
|
m_resource->Map(0, &range, &data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Buffer::Unmap() {
|
||||||
|
m_resource->Unmap(0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12VertexBuffer::D3D12VertexBuffer(D3D12Buffer* buffer) : m_buffer(buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12VertexBuffer::~D3D12VertexBuffer() {
|
||||||
|
delete m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12IndexBuffer::D3D12IndexBuffer(D3D12Buffer* buffer) : m_buffer(buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12IndexBuffer::~D3D12IndexBuffer() {
|
||||||
|
delete m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12ConstantBuffer::D3D12ConstantBuffer(D3D12Buffer* buffer) : m_buffer(buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12ConstantBuffer::~D3D12ConstantBuffer() {
|
||||||
|
delete m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Texture2D::D3D12Texture2D(D3D12Device* device, ID3D12Resource* resource, const TextureDesc& desc)
|
||||||
|
: m_device(device), m_resource(resource), m_desc(desc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12Texture2D::~D3D12Texture2D() {
|
||||||
|
m_resource.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Texture2D::CreateSRV() {
|
||||||
|
if (m_hasSRV) return;
|
||||||
|
|
||||||
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
|
srvDesc.Format = FormatToDXGIFormat(m_desc.format);
|
||||||
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = m_desc.mipLevels;
|
||||||
|
|
||||||
|
m_device->GetD3D12Device()->CreateShaderResourceView(m_resource.Get(), &srvDesc, m_srvHandle);
|
||||||
|
m_hasSRV = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12Texture2D::GetSRV() {
|
||||||
|
return (void*)m_srvHandle.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Texture2D::CreateRTV() {
|
||||||
|
if (m_hasRTV) return;
|
||||||
|
|
||||||
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
|
rtvDesc.Format = FormatToDXGIFormat(m_desc.format);
|
||||||
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
|
||||||
|
m_device->GetD3D12Device()->CreateRenderTargetView(m_resource.Get(), &rtvDesc, m_rtvHandle);
|
||||||
|
m_hasRTV = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12Texture2D::GetRTV() {
|
||||||
|
return (void*)m_rtvHandle.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12Texture2D::CreateDSV() {
|
||||||
|
if (m_hasDSV) return;
|
||||||
|
|
||||||
|
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
||||||
|
dsvDesc.Format = FormatToDXGIFormat(m_desc.format);
|
||||||
|
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||||
|
|
||||||
|
m_device->GetD3D12Device()->CreateDepthStencilView(m_resource.Get(), &dsvDesc, m_dsvHandle);
|
||||||
|
m_hasDSV = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* D3D12Texture2D::GetDSV() {
|
||||||
|
return (void*)m_dsvHandle.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateVertexBuffer(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* data, uint64_t size, uint32_t stride, IVertexBuffer** outBuffer) {
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
|
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||||
|
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
resourceDesc.Width = size;
|
||||||
|
resourceDesc.Height = 1;
|
||||||
|
resourceDesc.DepthOrArraySize = 1;
|
||||||
|
resourceDesc.MipLevels = 1;
|
||||||
|
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
resourceDesc.SampleDesc.Count = 1;
|
||||||
|
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
|
||||||
|
ID3D12Resource* bufferResource = nullptr;
|
||||||
|
HRESULT hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&bufferResource));
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC bufferDesc = bufferResource->GetDesc();
|
||||||
|
UINT64 memorySize = 0;
|
||||||
|
UINT64 rowSize = 0;
|
||||||
|
UINT rowCount = 0;
|
||||||
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
|
||||||
|
device->GetD3D12Device()->GetCopyableFootprints(&bufferDesc, 0, 1, 0, &footprint, &rowCount, &rowSize, &memorySize);
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES uploadHeapProps = {};
|
||||||
|
uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
|
||||||
|
ID3D12Resource* uploadResource = nullptr;
|
||||||
|
hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&uploadHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadResource));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
bufferResource->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8* uploadData = nullptr;
|
||||||
|
uploadResource->Map(0, nullptr, (void**)&uploadData);
|
||||||
|
|
||||||
|
UINT8* dst = uploadData + footprint.Offset;
|
||||||
|
const UINT8* src = (const UINT8*)data;
|
||||||
|
for (UINT i = 0; i < rowCount; i++) {
|
||||||
|
memcpy(dst + footprint.Footprint.RowPitch * i, src + rowSize * i, (SIZE_T)rowSize);
|
||||||
|
}
|
||||||
|
uploadResource->Unmap(0, nullptr);
|
||||||
|
|
||||||
|
D3D12CommandList* d3dCmdList = static_cast<D3D12CommandList*>(commandList);
|
||||||
|
d3dCmdList->GetNative()->CopyBufferRegion(bufferResource, 0, uploadResource, 0, size);
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = bufferResource;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
d3dCmdList->GetNative()->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
uploadResource->Release();
|
||||||
|
|
||||||
|
BufferDesc bufferDesc2 = {};
|
||||||
|
bufferDesc2.size = size;
|
||||||
|
bufferDesc2.stride = stride;
|
||||||
|
|
||||||
|
D3D12Buffer* buffer = new D3D12Buffer(device, bufferResource, bufferDesc2);
|
||||||
|
*outBuffer = new D3D12VertexBuffer(buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateIndexBuffer(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* data, uint64_t size, IIndexBuffer** outBuffer) {
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
|
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||||
|
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
resourceDesc.Width = size;
|
||||||
|
resourceDesc.Height = 1;
|
||||||
|
resourceDesc.DepthOrArraySize = 1;
|
||||||
|
resourceDesc.MipLevels = 1;
|
||||||
|
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
resourceDesc.SampleDesc.Count = 1;
|
||||||
|
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
|
||||||
|
ID3D12Resource* bufferResource = nullptr;
|
||||||
|
HRESULT hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&bufferResource));
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC bufferDesc = bufferResource->GetDesc();
|
||||||
|
UINT64 memorySize = 0;
|
||||||
|
UINT64 rowSize = 0;
|
||||||
|
UINT rowCount = 0;
|
||||||
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
|
||||||
|
device->GetD3D12Device()->GetCopyableFootprints(&bufferDesc, 0, 1, 0, &footprint, &rowCount, &rowSize, &memorySize);
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES uploadHeapProps = {};
|
||||||
|
uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
|
||||||
|
ID3D12Resource* uploadResource = nullptr;
|
||||||
|
hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&uploadHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadResource));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
bufferResource->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8* uploadData = nullptr;
|
||||||
|
uploadResource->Map(0, nullptr, (void**)&uploadData);
|
||||||
|
|
||||||
|
memcpy(uploadData + footprint.Offset, data, (SIZE_T)size);
|
||||||
|
uploadResource->Unmap(0, nullptr);
|
||||||
|
|
||||||
|
D3D12CommandList* d3dCmdList = static_cast<D3D12CommandList*>(commandList);
|
||||||
|
d3dCmdList->GetNative()->CopyBufferRegion(bufferResource, 0, uploadResource, 0, size);
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = bufferResource;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
d3dCmdList->GetNative()->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
uploadResource->Release();
|
||||||
|
|
||||||
|
BufferDesc bufferDesc2 = {};
|
||||||
|
bufferDesc2.size = size;
|
||||||
|
bufferDesc2.stride = 4;
|
||||||
|
|
||||||
|
D3D12Buffer* buffer = new D3D12Buffer(device, bufferResource, bufferDesc2);
|
||||||
|
*outBuffer = new D3D12IndexBuffer(buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateConstantBuffer(D3D12Device* device, uint64_t size, IConstantBuffer** outBuffer) {
|
||||||
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
|
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||||
|
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
resourceDesc.Width = size;
|
||||||
|
resourceDesc.Height = 1;
|
||||||
|
resourceDesc.DepthOrArraySize = 1;
|
||||||
|
resourceDesc.MipLevels = 1;
|
||||||
|
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
resourceDesc.SampleDesc.Count = 1;
|
||||||
|
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
|
||||||
|
ID3D12Resource* bufferResource = nullptr;
|
||||||
|
HRESULT hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bufferResource));
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
BufferDesc bufferDesc = {};
|
||||||
|
bufferDesc.size = size;
|
||||||
|
bufferDesc.stride = (uint32_t)size;
|
||||||
|
bufferDesc.cpuAccessible = true;
|
||||||
|
|
||||||
|
D3D12Buffer* buffer = new D3D12Buffer(device, bufferResource, bufferDesc);
|
||||||
|
*outBuffer = new D3D12ConstantBuffer(buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateTexture2D(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* pixels, uint32_t width, uint32_t height, Format format, ITexture2D** outTexture) {
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
|
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC resourceDesc = {};
|
||||||
|
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
resourceDesc.Width = width;
|
||||||
|
resourceDesc.Height = height;
|
||||||
|
resourceDesc.DepthOrArraySize = 1;
|
||||||
|
resourceDesc.MipLevels = 1;
|
||||||
|
resourceDesc.Format = FormatToDXGIFormat(format);
|
||||||
|
resourceDesc.SampleDesc.Count = 1;
|
||||||
|
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
|
||||||
|
ID3D12Resource* textureResource = nullptr;
|
||||||
|
HRESULT hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&heapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&textureResource));
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC texDesc = textureResource->GetDesc();
|
||||||
|
UINT64 memorySize = 0;
|
||||||
|
UINT64 rowSize = 0;
|
||||||
|
UINT rowCount = 0;
|
||||||
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
|
||||||
|
device->GetD3D12Device()->GetCopyableFootprints(&texDesc, 0, 1, 0, &footprint, &rowCount, &rowSize, &memorySize);
|
||||||
|
|
||||||
|
D3D12_HEAP_PROPERTIES uploadHeapProps = {};
|
||||||
|
uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC uploadDesc = {};
|
||||||
|
uploadDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
uploadDesc.Width = memorySize;
|
||||||
|
uploadDesc.Height = 1;
|
||||||
|
uploadDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
|
||||||
|
ID3D12Resource* uploadResource = nullptr;
|
||||||
|
hr = device->GetD3D12Device()->CreateCommittedResource(
|
||||||
|
&uploadHeapProps, D3D12_HEAP_FLAG_NONE, &uploadDesc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadResource));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
textureResource->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8* uploadData = nullptr;
|
||||||
|
uploadResource->Map(0, nullptr, (void**)&uploadData);
|
||||||
|
|
||||||
|
UINT8* dst = uploadData + footprint.Offset;
|
||||||
|
const UINT8* src = (const UINT8*)pixels;
|
||||||
|
for (UINT i = 0; i < rowCount; i++) {
|
||||||
|
memcpy(dst + footprint.Footprint.RowPitch * i, src + rowSize * i, (SIZE_T)rowSize);
|
||||||
|
}
|
||||||
|
uploadResource->Unmap(0, nullptr);
|
||||||
|
|
||||||
|
D3D12CommandList* d3dCmdList = static_cast<D3D12CommandList*>(commandList);
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
|
||||||
|
dstLoc.pResource = textureResource;
|
||||||
|
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
|
dstLoc.SubresourceIndex = 0;
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
|
||||||
|
srcLoc.pResource = uploadResource;
|
||||||
|
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
|
srcLoc.PlacedFootprint = footprint;
|
||||||
|
|
||||||
|
d3dCmdList->GetNative()->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = textureResource;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
d3dCmdList->GetNative()->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
uploadResource->Release();
|
||||||
|
|
||||||
|
TextureDesc texDesc2 = {};
|
||||||
|
texDesc2.width = width;
|
||||||
|
texDesc2.height = height;
|
||||||
|
texDesc2.format = format;
|
||||||
|
|
||||||
|
D3D12Texture2D* texture = new D3D12Texture2D(device, textureResource, texDesc2);
|
||||||
|
*outTexture = texture;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateConstantBuffer(IConstantBuffer* buffer, const void* data, uint64_t size) {
|
||||||
|
D3D12ConstantBuffer* d3dBuffer = static_cast<D3D12ConstantBuffer*>(buffer);
|
||||||
|
void* mapped = d3dBuffer->Map();
|
||||||
|
if (mapped) {
|
||||||
|
memcpy(mapped, data, (SIZE_T)size);
|
||||||
|
d3dBuffer->Unmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
170
engine/src/RHI/D3D12/D3D12Resources.h
Normal file
170
engine/src/RHI/D3D12/D3D12Resources.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Rendering\Resources.h>
|
||||||
|
#include <Rendering\RenderTarget.h>
|
||||||
|
#include <RHI\D3D12\D3D12RHI.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class D3D12Buffer : public IBuffer {
|
||||||
|
public:
|
||||||
|
D3D12Buffer(D3D12Device* device, ID3D12Resource* resource, const BufferDesc& desc);
|
||||||
|
~D3D12Buffer() override;
|
||||||
|
|
||||||
|
const BufferDesc& GetDesc() const override { return m_desc; }
|
||||||
|
void* Map() override;
|
||||||
|
void Unmap() override;
|
||||||
|
void* GetNativeResource() const override { return m_resource.Get(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_resource.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_resource;
|
||||||
|
BufferDesc m_desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12VertexBuffer : public IVertexBuffer {
|
||||||
|
public:
|
||||||
|
D3D12VertexBuffer(D3D12Buffer* buffer);
|
||||||
|
~D3D12VertexBuffer() override;
|
||||||
|
|
||||||
|
const BufferDesc& GetDesc() const override { return m_buffer->GetDesc(); }
|
||||||
|
void* Map() override { return m_buffer->Map(); }
|
||||||
|
void Unmap() override { m_buffer->Unmap(); }
|
||||||
|
void* GetNativeResource() const override { return m_buffer->GetNativeResource(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_buffer->GetNative(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Buffer* m_buffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12IndexBuffer : public IIndexBuffer {
|
||||||
|
public:
|
||||||
|
D3D12IndexBuffer(D3D12Buffer* buffer);
|
||||||
|
~D3D12IndexBuffer() override;
|
||||||
|
|
||||||
|
const BufferDesc& GetDesc() const override { return m_buffer->GetDesc(); }
|
||||||
|
void* Map() override { return m_buffer->Map(); }
|
||||||
|
void Unmap() override { m_buffer->Unmap(); }
|
||||||
|
void* GetNativeResource() const override { return m_buffer->GetNativeResource(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_buffer->GetNative(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Buffer* m_buffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12ConstantBuffer : public IConstantBuffer {
|
||||||
|
public:
|
||||||
|
D3D12ConstantBuffer(D3D12Buffer* buffer);
|
||||||
|
~D3D12ConstantBuffer() override;
|
||||||
|
|
||||||
|
const BufferDesc& GetDesc() const override { return m_buffer->GetDesc(); }
|
||||||
|
void* Map() override { return m_buffer->Map(); }
|
||||||
|
void Unmap() override { return m_buffer->Unmap(); }
|
||||||
|
void* GetNativeResource() const override { return m_buffer->GetNativeResource(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_buffer->GetNative(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Buffer* m_buffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12Texture2D : public ITexture2D {
|
||||||
|
public:
|
||||||
|
D3D12Texture2D(D3D12Device* device, ID3D12Resource* resource, const TextureDesc& desc);
|
||||||
|
~D3D12Texture2D() override;
|
||||||
|
|
||||||
|
const TextureDesc& GetDesc() const override { return m_desc; }
|
||||||
|
void CreateSRV() override;
|
||||||
|
void* GetSRV() override;
|
||||||
|
void CreateRTV() override;
|
||||||
|
void* GetRTV() override;
|
||||||
|
void CreateDSV() override;
|
||||||
|
void* GetDSV() override;
|
||||||
|
void* GetNativeResource() const override { return m_resource.Get(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_resource.Get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_resource;
|
||||||
|
TextureDesc m_desc;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_srvHandle = {};
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_rtvHandle = {};
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_dsvHandle = {};
|
||||||
|
bool m_hasSRV = false;
|
||||||
|
bool m_hasRTV = false;
|
||||||
|
bool m_hasDSV = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CreateVertexBuffer(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* data, uint64_t size, uint32_t stride, IVertexBuffer** outBuffer);
|
||||||
|
|
||||||
|
bool CreateIndexBuffer(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* data, uint64_t size, IIndexBuffer** outBuffer);
|
||||||
|
|
||||||
|
bool CreateConstantBuffer(D3D12Device* device, uint64_t size, IConstantBuffer** outBuffer);
|
||||||
|
|
||||||
|
bool CreateTexture2D(D3D12Device* device, ICommandList* commandList,
|
||||||
|
const void* pixels, uint32_t width, uint32_t height, Format format, ITexture2D** outTexture);
|
||||||
|
|
||||||
|
void UpdateConstantBuffer(IConstantBuffer* buffer, const void* data, uint64_t size);
|
||||||
|
|
||||||
|
class D3D12DepthStencil : public IDepthStencil {
|
||||||
|
public:
|
||||||
|
D3D12DepthStencil(D3D12Device* device, ID3D12Resource* resource, const TextureDesc& desc)
|
||||||
|
: m_device(device), m_resource(resource), m_desc(desc) {}
|
||||||
|
|
||||||
|
~D3D12DepthStencil() override {
|
||||||
|
m_resource.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextureDesc& GetDesc() const override { return m_desc; }
|
||||||
|
void* GetNativeResource() const override { return m_resource.Get(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_resource.Get(); }
|
||||||
|
|
||||||
|
void CreateSRV() override {}
|
||||||
|
void* GetSRV() override { return nullptr; }
|
||||||
|
void CreateRTV() override {}
|
||||||
|
void* GetRTV() override { return nullptr; }
|
||||||
|
void CreateDSV() override;
|
||||||
|
void* GetDSV() override { return (void*)m_dsvHandle.ptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_resource;
|
||||||
|
TextureDesc m_desc;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_dsvHandle = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12RenderTarget : public IRenderTarget {
|
||||||
|
public:
|
||||||
|
D3D12RenderTarget(D3D12Device* device, ID3D12Resource* resource, const TextureDesc& desc)
|
||||||
|
: m_device(device), m_resource(resource), m_desc(desc) {}
|
||||||
|
|
||||||
|
~D3D12RenderTarget() override {
|
||||||
|
m_resource.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextureDesc& GetDesc() const override { return m_desc; }
|
||||||
|
void* GetNativeResource() const override { return m_resource.Get(); }
|
||||||
|
ID3D12Resource* GetNative() const { return m_resource.Get(); }
|
||||||
|
|
||||||
|
void CreateSRV() override {}
|
||||||
|
void* GetSRV() override { return nullptr; }
|
||||||
|
void CreateRTV() override;
|
||||||
|
void* GetRTV() override { return (void*)m_rtvHandle.ptr; }
|
||||||
|
void CreateDSV() override {}
|
||||||
|
void* GetDSV() override { return nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Device* m_device = nullptr;
|
||||||
|
Microsoft::WRL::ComPtr<ID3D12Resource> m_resource;
|
||||||
|
TextureDesc m_desc;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_rtvHandle = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CreateDepthStencil(D3D12Device* device, uint32_t width, uint32_t height, Format format, IDepthStencil** outDepthStencil);
|
||||||
|
bool CreateRenderTargetFromSwapChain(D3D12Device* device, D3D12SwapChain* swapChain, uint32_t bufferIndex, IRenderTarget** outRenderTarget);
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
40
engine/src/RHI/D3D12/D3D12Shader.cpp
Normal file
40
engine/src/RHI/D3D12/D3D12Shader.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <Rendering\Shader.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#include <wrl/client.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
bool CompileShader(const char* filePath, const char* entryPoint, const char* target, ShaderBytecode& outBytecode) {
|
||||||
|
UINT flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||||
|
|
||||||
|
ID3DBlob* shaderBuffer = nullptr;
|
||||||
|
ID3DBlob* errorBuffer = nullptr;
|
||||||
|
|
||||||
|
HRESULT hr = D3DCompileFromFile(
|
||||||
|
std::wstring(filePath, filePath + strlen(filePath)).c_str(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
entryPoint,
|
||||||
|
target,
|
||||||
|
flags,
|
||||||
|
0,
|
||||||
|
&shaderBuffer,
|
||||||
|
&errorBuffer);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (errorBuffer) {
|
||||||
|
OutputDebugStringA((const char*)errorBuffer->GetBufferPointer());
|
||||||
|
errorBuffer->Release();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBytecode.bytecode = shaderBuffer->GetBufferPointer();
|
||||||
|
outBytecode.size = shaderBuffer->GetBufferSize();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
86
engine/src/RHI/D3D12/D3D12StaticMeshComponent.cpp
Normal file
86
engine/src/RHI/D3D12/D3D12StaticMeshComponent.cpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include <Rendering\StaticMeshComponent.h>
|
||||||
|
#include <RHI\D3D12\D3D12Resources.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
StaticMeshComponent::StaticMeshComponent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticMeshComponent::~StaticMeshComponent() {
|
||||||
|
if (m_vertexBuffer) {
|
||||||
|
delete m_vertexBuffer;
|
||||||
|
}
|
||||||
|
for (auto& pair : m_subMeshes) {
|
||||||
|
delete pair.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StaticMeshComponent::Initialize(ICommandList* commandList, const char* filePath) {
|
||||||
|
FILE* file = nullptr;
|
||||||
|
if (fopen_s(&file, filePath, "rb") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vertexCount = 0;
|
||||||
|
fread(&vertexCount, 4, 1, file);
|
||||||
|
m_vertexCount = vertexCount;
|
||||||
|
|
||||||
|
MeshVertex* vertices = new MeshVertex[vertexCount];
|
||||||
|
fread(vertices, sizeof(MeshVertex), vertexCount, file);
|
||||||
|
|
||||||
|
D3D12Device* device = nullptr;
|
||||||
|
|
||||||
|
CreateVertexBuffer(device, commandList, vertices, sizeof(MeshVertex) * vertexCount, sizeof(MeshVertex), &m_vertexBuffer);
|
||||||
|
|
||||||
|
delete[] vertices;
|
||||||
|
|
||||||
|
while (!feof(file)) {
|
||||||
|
int nameLength = 0;
|
||||||
|
fread(&nameLength, 4, 1, file);
|
||||||
|
if (feof(file)) break;
|
||||||
|
|
||||||
|
char name[256] = {0};
|
||||||
|
fread(name, 1, nameLength, file);
|
||||||
|
|
||||||
|
int indexCount = 0;
|
||||||
|
fread(&indexCount, 4, 1, file);
|
||||||
|
|
||||||
|
uint32_t* indices = new uint32_t[indexCount];
|
||||||
|
fread(indices, sizeof(uint32_t), indexCount, file);
|
||||||
|
|
||||||
|
IIndexBuffer* indexBuffer = nullptr;
|
||||||
|
CreateIndexBuffer(device, commandList, indices, sizeof(uint32_t) * indexCount, &indexBuffer);
|
||||||
|
|
||||||
|
delete[] indices;
|
||||||
|
|
||||||
|
SubMesh* submesh = new SubMesh();
|
||||||
|
submesh->indexBuffer = indexBuffer;
|
||||||
|
submesh->indexCount = indexCount;
|
||||||
|
m_subMeshes[std::string(name)] = submesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StaticMeshComponent::Render(ICommandList* commandList) {
|
||||||
|
if (!m_vertexBuffer) return;
|
||||||
|
|
||||||
|
commandList->SetVertexBuffer(0, m_vertexBuffer, 0, sizeof(MeshVertex));
|
||||||
|
|
||||||
|
if (m_subMeshes.empty()) {
|
||||||
|
commandList->DrawInstanced(m_vertexCount, 1, 0, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (auto& pair : m_subMeshes) {
|
||||||
|
SubMesh* submesh = pair.second;
|
||||||
|
commandList->SetIndexBuffer(submesh->indexBuffer, 0);
|
||||||
|
commandList->DrawIndexedInstanced(submesh->indexCount, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
24
imgui.ini
24
imgui.ini
@@ -1,24 +0,0 @@
|
|||||||
[Window][Scene View]
|
|
||||||
Pos=0,20
|
|
||||||
Size=880,480
|
|
||||||
|
|
||||||
[Window][Hierarchy]
|
|
||||||
Pos=0,20
|
|
||||||
Size=200,480
|
|
||||||
|
|
||||||
[Window][Inspector]
|
|
||||||
Pos=1080,20
|
|
||||||
Size=200,480
|
|
||||||
|
|
||||||
[Window][Project]
|
|
||||||
Pos=0,500
|
|
||||||
Size=640,150
|
|
||||||
|
|
||||||
[Window][Console]
|
|
||||||
Pos=640,500
|
|
||||||
Size=640,150
|
|
||||||
|
|
||||||
[Window][Debug##Default]
|
|
||||||
Pos=60,60
|
|
||||||
Size=400,400
|
|
||||||
|
|
||||||
308
main.cpp
308
main.cpp
@@ -1,308 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "BattleFireDirect.h"
|
|
||||||
#include "StaticMeshComponent.h"
|
|
||||||
#include "stbi/stb_image.h"
|
|
||||||
#include "Utils.h"
|
|
||||||
#include "NanoVDBLoader.h"
|
|
||||||
|
|
||||||
#pragma comment(lib,"d3d12.lib")
|
|
||||||
#pragma comment(lib,"dxgi.lib")
|
|
||||||
#pragma comment(lib,"d3dcompiler.lib")
|
|
||||||
#pragma comment(lib,"winmm.lib")
|
|
||||||
|
|
||||||
LPCWSTR gWindowClassName = L"BattleFire";
|
|
||||||
|
|
||||||
LRESULT CALLBACK WindowProc(HWND inHWND, UINT inMSG, WPARAM inWParam, LPARAM inLParam) {
|
|
||||||
switch (inMSG) {
|
|
||||||
case WM_CLOSE:
|
|
||||||
PostQuitMessage(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return DefWindowProc(inHWND, inMSG, inWParam, inLParam);
|
|
||||||
}
|
|
||||||
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int inShowCmd) {
|
|
||||||
AttachConsole(ATTACH_PARENT_PROCESS);
|
|
||||||
freopen("CONOUT$", "w", stdout);
|
|
||||||
freopen("CONOUT$", "w", stderr);
|
|
||||||
printf("XCVolumeRenderer started\n");
|
|
||||||
printf("Initializing D3D12...\n");
|
|
||||||
//register
|
|
||||||
WNDCLASSEX wndClassEx;
|
|
||||||
wndClassEx.cbSize = sizeof(WNDCLASSEX);
|
|
||||||
wndClassEx.style = CS_HREDRAW | CS_VREDRAW;
|
|
||||||
wndClassEx.cbClsExtra = NULL;//class
|
|
||||||
wndClassEx.cbWndExtra = NULL;//instance
|
|
||||||
wndClassEx.hInstance = hInstance;
|
|
||||||
wndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
||||||
wndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|
|
||||||
wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
wndClassEx.hbrBackground = NULL;
|
|
||||||
wndClassEx.lpszMenuName = NULL;
|
|
||||||
wndClassEx.lpszClassName = gWindowClassName;
|
|
||||||
wndClassEx.lpfnWndProc = WindowProc;
|
|
||||||
if (!RegisterClassEx(&wndClassEx)) {
|
|
||||||
MessageBox(NULL, L"Register Class Failed!", L"Error", MB_OK | MB_ICONERROR);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
//create
|
|
||||||
int viewportWidth = 1280;
|
|
||||||
int viewportHeight = 720;
|
|
||||||
RECT rect;
|
|
||||||
rect.left = 0;
|
|
||||||
rect.top = 0;
|
|
||||||
rect.right = viewportWidth;
|
|
||||||
rect.bottom = viewportHeight;
|
|
||||||
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
|
|
||||||
int windowWidth = rect.right - rect.left;
|
|
||||||
int windowHeight = rect.bottom - rect.top;
|
|
||||||
HWND hwnd = CreateWindowEx(NULL,
|
|
||||||
gWindowClassName,
|
|
||||||
L"My Render Window",
|
|
||||||
WS_OVERLAPPEDWINDOW,
|
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
||||||
windowWidth, windowHeight,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
hInstance,
|
|
||||||
NULL);
|
|
||||||
if (!hwnd) {
|
|
||||||
MessageBox(NULL, L"Create Window Failed!", L"Error", MB_OK | MB_ICONERROR);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
//show
|
|
||||||
InitD3D12(hwnd, 1280, 720);
|
|
||||||
printf("D3D12 initialized\n");
|
|
||||||
ID3D12GraphicsCommandList* commandList = GetCommandList();
|
|
||||||
ID3D12CommandAllocator* commandAllocator = GetCommandAllocator();
|
|
||||||
|
|
||||||
NanoVDBData nanoVDBData = {};
|
|
||||||
LoadNanoVDB("Res/NanoVDB/cloud.nvdb", nanoVDBData, commandList, commandAllocator);
|
|
||||||
printf("NanoVDB loaded: %llu bytes\n", (unsigned long long)nanoVDBData.byteSize);
|
|
||||||
printf("NanoVDB BBox: [%.2f, %.2f, %.2f] - [%.2f, %.2f, %.2f]\n",
|
|
||||||
nanoVDBData.worldBBox[0], nanoVDBData.worldBBox[1], nanoVDBData.worldBBox[2],
|
|
||||||
nanoVDBData.worldBBox[3], nanoVDBData.worldBBox[4], nanoVDBData.worldBBox[5]);
|
|
||||||
|
|
||||||
float bboxMin[3] = { (float)nanoVDBData.worldBBox[0], (float)nanoVDBData.worldBBox[1], (float)nanoVDBData.worldBBox[2] };
|
|
||||||
float bboxMax[3] = { (float)nanoVDBData.worldBBox[3], (float)nanoVDBData.worldBBox[4], (float)nanoVDBData.worldBBox[5] };
|
|
||||||
float bboxCenter[3] = { (bboxMin[0] + bboxMax[0]) / 2, (bboxMin[1] + bboxMax[1]) / 2, (bboxMin[2] + bboxMax[2]) / 2 };
|
|
||||||
float bboxSize[3] = { bboxMax[0] - bboxMin[0], bboxMax[1] - bboxMin[1], bboxMax[2] - bboxMin[2] };
|
|
||||||
printf("BBox center: [%.2f, %.2f, %.2f], size: [%.2f, %.2f, %.2f]\n",
|
|
||||||
bboxCenter[0], bboxCenter[1], bboxCenter[2],
|
|
||||||
bboxSize[0], bboxSize[1], bboxSize[2]);
|
|
||||||
|
|
||||||
float quadVertices[] = {
|
|
||||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
|
||||||
1.0f, -1.0f, 1.0f, 0.0f,
|
|
||||||
1.0f, 1.0f, 1.0f, 1.0f,
|
|
||||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
|
||||||
};
|
|
||||||
uint32_t quadIndices[] = { 0, 1, 2, 0, 2, 3 };
|
|
||||||
ID3D12Resource* quadVBO = CreateBufferObject(commandList, quadVertices, sizeof(quadVertices), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
|
|
||||||
ID3D12Resource* quadIBO = CreateBufferObject(commandList, quadIndices, sizeof(quadIndices), D3D12_RESOURCE_STATE_INDEX_BUFFER);
|
|
||||||
printf("Quad mesh created\n");
|
|
||||||
|
|
||||||
StaticMeshComponent staticMeshComponent;
|
|
||||||
staticMeshComponent.InitFromFile(commandList, "Res/Model/Sphere.lhsm");
|
|
||||||
printf("Mesh loaded\n");
|
|
||||||
|
|
||||||
ID3D12RootSignature* rootSignature = InitRootSignature();
|
|
||||||
printf("Root signature created\n");
|
|
||||||
D3D12_SHADER_BYTECODE vs,gs,ps;
|
|
||||||
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainVS", "vs_5_1", &vs);
|
|
||||||
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainGS", "gs_5_1", &gs);
|
|
||||||
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainPS", "ps_5_1", &ps);
|
|
||||||
ID3D12PipelineState*pso=CreatePSO(rootSignature, vs, ps, gs);
|
|
||||||
printf("PSO created\n");
|
|
||||||
|
|
||||||
ID3D12RootSignature* volumeRootSignature = InitVolumeRootSignature();
|
|
||||||
printf("Volume root signature created\n");
|
|
||||||
|
|
||||||
D3D12_SHADER_BYTECODE volumeVS, volumePS;
|
|
||||||
memset(&volumeVS, 0, sizeof(volumeVS));
|
|
||||||
memset(&volumePS, 0, sizeof(volumePS));
|
|
||||||
CreateShaderFromFile(L"Res/Shader/volume.hlsl", "MainVS", "vs_5_1", &volumeVS);
|
|
||||||
CreateShaderFromFile(L"Res/Shader/volume.hlsl", "MainPS", "ps_5_1", &volumePS);
|
|
||||||
printf("Volume VS: ptr=%p, size=%zu\n", volumeVS.pShaderBytecode, volumeVS.BytecodeLength);
|
|
||||||
printf("Volume PS: ptr=%p, size=%zu\n", volumePS.pShaderBytecode, volumePS.BytecodeLength);
|
|
||||||
|
|
||||||
ID3D12PipelineState* quadPSO = CreateQuadPSO(volumeRootSignature, volumeVS, volumePS);
|
|
||||||
if (!quadPSO) {
|
|
||||||
printf("Quad PSO creation failed!\n");
|
|
||||||
} else {
|
|
||||||
printf("Quad PSO created: %p\n", quadPSO);
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12Resource* volumeCB = CreateConstantBufferObject(65536);
|
|
||||||
|
|
||||||
ID3D12Resource* cb = CreateConstantBufferObject(65536);//1024x64(4x4)
|
|
||||||
DirectX::XMMATRIX projectionMatrix=DirectX::XMMatrixPerspectiveFovLH(
|
|
||||||
(45.0f*3.141592f)/180.0f,1280.0f/720.0f,0.1f,1000.0f);
|
|
||||||
DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookAtLH(
|
|
||||||
DirectX::XMVectorSet(-10.0f, 300.0f, -1200.0f, 1.0f),
|
|
||||||
DirectX::XMVectorSet(-10.0f, 73.0f, 0.0f, 1.0f),
|
|
||||||
DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f));
|
|
||||||
DirectX::XMMATRIX modelMatrix = DirectX::XMMatrixTranslation(0.0f,0.0f,5.0f);
|
|
||||||
//modelMatrix *= DirectX::XMMatrixRotationZ(90.0f*3.141592f/180.0f);
|
|
||||||
DirectX::XMFLOAT4X4 tempMatrix;
|
|
||||||
float matrices[64];
|
|
||||||
|
|
||||||
DirectX::XMStoreFloat4x4(&tempMatrix, projectionMatrix);
|
|
||||||
memcpy(matrices, &tempMatrix, sizeof(float) * 16);
|
|
||||||
DirectX::XMStoreFloat4x4(&tempMatrix, viewMatrix);
|
|
||||||
memcpy(matrices+16, &tempMatrix, sizeof(float) * 16);
|
|
||||||
DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix);
|
|
||||||
memcpy(matrices + 32, &tempMatrix, sizeof(float) * 16);;
|
|
||||||
DirectX::XMVECTOR determinant;
|
|
||||||
DirectX::XMMATRIX inverseModelMatrix = DirectX::XMMatrixInverse(&determinant, modelMatrix);
|
|
||||||
if (DirectX::XMVectorGetX(determinant) != 0.0f) {
|
|
||||||
DirectX::XMMATRIX normalMatrix = DirectX::XMMatrixTranspose(inverseModelMatrix);
|
|
||||||
DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix);
|
|
||||||
memcpy(matrices + 48, &tempMatrix, sizeof(float) * 16);;
|
|
||||||
}
|
|
||||||
UpdateConstantBuffer(cb, matrices, sizeof(float) * 64);
|
|
||||||
|
|
||||||
|
|
||||||
ID3D12Resource* sb = CreateConstantBufferObject(65536);//1024x64(4x4)
|
|
||||||
struct MaterialData {
|
|
||||||
float r;
|
|
||||||
};
|
|
||||||
MaterialData* materialDatas = new MaterialData[3000];
|
|
||||||
for (int i=0;i<3000;i++){
|
|
||||||
materialDatas[i].r = srandom() * 0.1f + 0.1f;//0.0~1.0
|
|
||||||
}
|
|
||||||
UpdateConstantBuffer(sb, materialDatas, sizeof(MaterialData) * 3000);
|
|
||||||
|
|
||||||
int imageWidth, imageHeight,imageChannel;
|
|
||||||
stbi_uc* pixels = stbi_load("Res/Image/earth_d.jpg", &imageWidth, &imageHeight, &imageChannel, 4);
|
|
||||||
printf("Texture loaded: %dx%d\n", imageWidth, imageHeight);
|
|
||||||
ID3D12Resource* texture = CreateTexture2D(commandList, pixels,
|
|
||||||
imageWidth * imageHeight * imageChannel, imageWidth, imageHeight,DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
delete[]pixels;
|
|
||||||
ID3D12Device* d3dDevice = GetD3DDevice();
|
|
||||||
|
|
||||||
ID3D12DescriptorHeap* srvHeap = nullptr;
|
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescSRV = {};
|
|
||||||
d3dDescriptorHeapDescSRV.NumDescriptors = 3;
|
|
||||||
d3dDescriptorHeapDescSRV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
||||||
d3dDescriptorHeapDescSRV.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
|
||||||
d3dDevice->CreateDescriptorHeap(&d3dDescriptorHeapDescSRV, IID_PPV_ARGS(&srvHeap));
|
|
||||||
|
|
||||||
ID3D12DescriptorHeap* descriptorHeaps[] = {srvHeap};
|
|
||||||
|
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
|
||||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
||||||
srvDesc.Texture2D.MipLevels = 1;
|
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE srvHeapPtr = srvHeap->GetCPUDescriptorHandleForHeapStart();
|
|
||||||
d3dDevice->CreateShaderResourceView(texture, &srvDesc, srvHeapPtr);
|
|
||||||
srvHeapPtr.ptr += d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
||||||
|
|
||||||
EndCommandList();
|
|
||||||
WaitForCompletionOfCommandList();
|
|
||||||
printf("All resources uploaded to GPU\n");
|
|
||||||
|
|
||||||
ShowWindow(hwnd, inShowCmd);
|
|
||||||
UpdateWindow(hwnd);
|
|
||||||
printf("Window shown, entering render loop\n");
|
|
||||||
float color[] = {0.5f,0.5f,0.5f,1.0f};
|
|
||||||
MSG msg;
|
|
||||||
DWORD last_time = timeGetTime();
|
|
||||||
DWORD appStartTime = last_time;
|
|
||||||
int frameCount = 0;
|
|
||||||
while (true){
|
|
||||||
ZeroMemory(&msg, sizeof(MSG));
|
|
||||||
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
|
||||||
if (msg.message == WM_QUIT) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
} else {
|
|
||||||
//rendering
|
|
||||||
WaitForCompletionOfCommandList();
|
|
||||||
DWORD current_time = timeGetTime();//ms
|
|
||||||
DWORD frameTime = current_time - last_time;
|
|
||||||
DWORD timeSinceAppStartInMS = current_time - appStartTime;
|
|
||||||
last_time = current_time;
|
|
||||||
float frameTimeInSecond = float(frameTime) / 1000.0f;//second
|
|
||||||
float timeSinceAppStartInSecond = float(timeSinceAppStartInMS) / 1000.0f;
|
|
||||||
color[0] = timeSinceAppStartInSecond;
|
|
||||||
commandAllocator->Reset();
|
|
||||||
commandList->Reset(commandAllocator, nullptr);
|
|
||||||
BeginRenderToSwapChain(commandList);
|
|
||||||
//draw
|
|
||||||
commandList->SetPipelineState(pso);
|
|
||||||
commandList->SetGraphicsRootSignature(rootSignature);
|
|
||||||
commandList->SetDescriptorHeaps(_countof(descriptorHeaps),descriptorHeaps);
|
|
||||||
commandList->SetGraphicsRootConstantBufferView(0, cb->GetGPUVirtualAddress());
|
|
||||||
commandList->SetGraphicsRoot32BitConstants(1, 4, color, 0);
|
|
||||||
commandList->SetGraphicsRootDescriptorTable(2, srvHeap->GetGPUDescriptorHandleForHeapStart());
|
|
||||||
commandList->SetGraphicsRootShaderResourceView(3, sb->GetGPUVirtualAddress());
|
|
||||||
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
||||||
if (frameCount == 1) {
|
|
||||||
printf("Drawing mesh with %d vertices, VBO=%p, subMeshes=%zu\n",
|
|
||||||
staticMeshComponent.mVertexCount, staticMeshComponent.mVBO, staticMeshComponent.mSubMeshes.size());
|
|
||||||
}
|
|
||||||
staticMeshComponent.Render(commandList);
|
|
||||||
|
|
||||||
DirectX::XMMATRIX viewProj = viewMatrix * projectionMatrix;
|
|
||||||
DirectX::XMMATRIX invViewProj = DirectX::XMMatrixInverse(nullptr, viewProj);
|
|
||||||
DirectX::XMFLOAT4X4 invViewProjMat;
|
|
||||||
DirectX::XMStoreFloat4x4(&invViewProjMat, invViewProj);
|
|
||||||
|
|
||||||
float volumeCBData[36];
|
|
||||||
memcpy(volumeCBData, &invViewProjMat, sizeof(float) * 16);
|
|
||||||
volumeCBData[16] = -10.0f;
|
|
||||||
volumeCBData[17] = 300.0f;
|
|
||||||
volumeCBData[18] = -1200.0f;
|
|
||||||
volumeCBData[19] = 0.2f; // DensityScale
|
|
||||||
volumeCBData[20] = (float)nanoVDBData.worldBBox[0];
|
|
||||||
volumeCBData[21] = (float)nanoVDBData.worldBBox[1];
|
|
||||||
volumeCBData[22] = (float)nanoVDBData.worldBBox[2];
|
|
||||||
volumeCBData[23] = 1.0f; // StepSize
|
|
||||||
volumeCBData[24] = (float)nanoVDBData.worldBBox[3];
|
|
||||||
volumeCBData[25] = (float)nanoVDBData.worldBBox[4];
|
|
||||||
volumeCBData[26] = (float)nanoVDBData.worldBBox[5];
|
|
||||||
volumeCBData[27] = 2000.0f; // MaxSteps as float
|
|
||||||
volumeCBData[28] = timeSinceAppStartInSecond * 0.3f; // RotationY
|
|
||||||
volumeCBData[29] = 0.0f; // Pad0
|
|
||||||
volumeCBData[30] = 0.0f; // Pad1
|
|
||||||
volumeCBData[31] = 0.0f; // Pad2
|
|
||||||
volumeCBData[32] = 0.5f; // LightDir X
|
|
||||||
volumeCBData[33] = 0.8f; // LightDir Y
|
|
||||||
volumeCBData[34] = 0.3f; // LightDir Z
|
|
||||||
volumeCBData[35] = 8.0f; // LightSamples as float
|
|
||||||
UpdateConstantBuffer(volumeCB, volumeCBData, sizeof(float) * 36);
|
|
||||||
if (frameCount == 1) {
|
|
||||||
printf("Volume BBox: [%.2f, %.2f, %.2f] - [%.2f, %.2f, %.2f]\n",
|
|
||||||
volumeCBData[20], volumeCBData[21], volumeCBData[22],
|
|
||||||
volumeCBData[24], volumeCBData[25], volumeCBData[26]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quadPSO) {
|
|
||||||
commandList->SetPipelineState(quadPSO);
|
|
||||||
commandList->SetGraphicsRootSignature(volumeRootSignature);
|
|
||||||
commandList->SetGraphicsRootConstantBufferView(0, volumeCB->GetGPUVirtualAddress());
|
|
||||||
commandList->SetGraphicsRootShaderResourceView(1, nanoVDBData.gpuBuffer->GetGPUVirtualAddress());
|
|
||||||
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
||||||
commandList->IASetVertexBuffers(0, 1, &D3D12_VERTEX_BUFFER_VIEW{ quadVBO->GetGPUVirtualAddress(), sizeof(quadVertices), sizeof(float) * 4 });
|
|
||||||
commandList->IASetIndexBuffer(&D3D12_INDEX_BUFFER_VIEW{ quadIBO->GetGPUVirtualAddress(), sizeof(quadIndices), DXGI_FORMAT_R32_UINT });
|
|
||||||
commandList->DrawIndexedInstanced(6, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndRenderToSwapChain(commandList);
|
|
||||||
EndCommandList();
|
|
||||||
SwapD3D12Buffers();
|
|
||||||
frameCount++;
|
|
||||||
if (frameCount <= 3) {
|
|
||||||
printf("Frame %d rendered\n", frameCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
3
run_demo.bat
Normal file
3
run_demo.bat
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d D:\Xuanchi\高斯泼溅\XCEngine\build\mvs\XCEngineDemo\Debug
|
||||||
|
XCEngineDemo.exe
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "stb_image.h"
|
|
||||||
7194
stbi/stb_image.h
7194
stbi/stb_image.h
File diff suppressed because it is too large
Load Diff
@@ -1,66 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
project(XCVolumeRendererUI2 VERSION 1.0 LANGUAGES CXX)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
add_definitions(-DUNICODE -D_UNICODE)
|
|
||||||
add_definitions(-DIMGUI_ENABLE_DOCKING)
|
|
||||||
|
|
||||||
include(FetchContent)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
|
||||||
imgui
|
|
||||||
GIT_REPOSITORY https://gitee.com/mirrors/imgui.git
|
|
||||||
GIT_TAG docking
|
|
||||||
GIT_SHALLOW TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
FetchContent_MakeAvailable(imgui)
|
|
||||||
|
|
||||||
set(IMGUI_SOURCES
|
|
||||||
${imgui_SOURCE_DIR}/imgui.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_demo.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_draw.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_tables.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_widgets.cpp
|
|
||||||
${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp
|
|
||||||
${imgui_SOURCE_DIR}/backends/imgui_impl_dx12.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} WIN32
|
|
||||||
src/main.cpp
|
|
||||||
src/Application.cpp
|
|
||||||
src/Theme.cpp
|
|
||||||
src/Managers/SceneManager.cpp
|
|
||||||
src/Managers/LogSystem.cpp
|
|
||||||
src/Managers/ProjectManager.cpp
|
|
||||||
src/panels/Panel.cpp
|
|
||||||
src/panels/MenuBar.cpp
|
|
||||||
src/panels/HierarchyPanel.cpp
|
|
||||||
src/panels/SceneViewPanel.cpp
|
|
||||||
src/panels/GameViewPanel.cpp
|
|
||||||
src/panels/InspectorPanel.cpp
|
|
||||||
src/panels/ConsolePanel.cpp
|
|
||||||
src/panels/ProjectPanel.cpp
|
|
||||||
${IMGUI_SOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
${imgui_SOURCE_DIR}
|
|
||||||
${imgui_SOURCE_DIR}/backends
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE UNICODE _UNICODE)
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /utf-8 /MT)
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
|
||||||
d3d12.lib
|
|
||||||
dxgi.lib
|
|
||||||
d3dcompiler.lib
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
|
||||||
)
|
|
||||||
@@ -1,303 +0,0 @@
|
|||||||
#include "Application.h"
|
|
||||||
#include <imgui_impl_win32.h>
|
|
||||||
#include <imgui_impl_dx12.h>
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
Application& Application::Get() {
|
|
||||||
static Application instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::Initialize(HWND hwnd) {
|
|
||||||
m_hwnd = hwnd;
|
|
||||||
|
|
||||||
if (!CreateDevice()) {
|
|
||||||
MessageBoxW(hwnd, L"Failed to create D3D12 device", L"Error", MB_OK | MB_ICONERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!CreateRenderTarget()) {
|
|
||||||
MessageBoxW(hwnd, L"Failed to create render target", L"Error", MB_OK | MB_ICONERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
|
||||||
|
|
||||||
io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 16.0f);
|
|
||||||
io.Fonts->AddFontDefault();
|
|
||||||
|
|
||||||
unsigned char* pixels;
|
|
||||||
int width, height;
|
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
|
||||||
|
|
||||||
ApplyUnityDarkTheme();
|
|
||||||
|
|
||||||
ImGui_ImplWin32_Init(hwnd);
|
|
||||||
ImGui_ImplDX12_Init(m_device, 3, DXGI_FORMAT_R8G8B8A8_UNORM, m_srvHeap,
|
|
||||||
m_srvHeap->GetCPUDescriptorHandleForHeapStart(),
|
|
||||||
m_srvHeap->GetGPUDescriptorHandleForHeapStart());
|
|
||||||
|
|
||||||
m_menuBar = std::make_unique<MenuBar>();
|
|
||||||
m_hierarchyPanel = std::make_unique<HierarchyPanel>();
|
|
||||||
m_sceneViewPanel = std::make_unique<SceneViewPanel>();
|
|
||||||
m_gameViewPanel = std::make_unique<GameViewPanel>();
|
|
||||||
m_inspectorPanel = std::make_unique<InspectorPanel>();
|
|
||||||
m_consolePanel = std::make_unique<ConsolePanel>();
|
|
||||||
m_projectPanel = std::make_unique<ProjectPanel>();
|
|
||||||
|
|
||||||
wchar_t exePath[MAX_PATH];
|
|
||||||
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
|
|
||||||
std::wstring exeDirW(exePath);
|
|
||||||
size_t pos = exeDirW.find_last_of(L"\\/");
|
|
||||||
if (pos != std::wstring::npos) {
|
|
||||||
exeDirW = exeDirW.substr(0, pos);
|
|
||||||
}
|
|
||||||
std::string exeDir;
|
|
||||||
int len = WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
|
||||||
if (len > 0) {
|
|
||||||
exeDir.resize(len - 1);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, &exeDir[0], len, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
m_projectPanel->Initialize(exeDir);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::Shutdown() {
|
|
||||||
ImGui_ImplDX12_Shutdown();
|
|
||||||
ImGui_ImplWin32_Shutdown();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
|
|
||||||
CleanupRenderTarget();
|
|
||||||
|
|
||||||
if (m_fence) m_fence->Release();
|
|
||||||
if (m_commandList) m_commandList->Release();
|
|
||||||
if (m_commandAllocator) m_commandAllocator->Release();
|
|
||||||
if (m_commandQueue) m_commandQueue->Release();
|
|
||||||
if (m_rtvHeap) m_rtvHeap->Release();
|
|
||||||
if (m_srvHeap) m_srvHeap->Release();
|
|
||||||
if (m_swapChain) m_swapChain->Release();
|
|
||||||
if (m_device) m_device->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::Render() {
|
|
||||||
ImGui_ImplDX12_NewFrame();
|
|
||||||
ImGui_ImplWin32_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
SetupDockspace();
|
|
||||||
RenderUI();
|
|
||||||
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
|
|
||||||
m_commandAllocator->Reset();
|
|
||||||
m_commandList->Reset(m_commandAllocator, nullptr);
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
||||||
barrier.Transition.pResource = m_renderTargets[m_frameIndex];
|
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
||||||
m_commandList->ResourceBarrier(1, &barrier);
|
|
||||||
|
|
||||||
float clearColor[4] = { 0.12f, 0.12f, 0.12f, 1.0f };
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
|
|
||||||
rtvHandle.ptr += m_frameIndex * m_rtvDescriptorSize;
|
|
||||||
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
|
|
||||||
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
|
|
||||||
|
|
||||||
ID3D12DescriptorHeap* heaps[] = { m_srvHeap };
|
|
||||||
m_commandList->SetDescriptorHeaps(1, heaps);
|
|
||||||
|
|
||||||
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), m_commandList);
|
|
||||||
|
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
|
||||||
m_commandList->ResourceBarrier(1, &barrier);
|
|
||||||
|
|
||||||
m_commandList->Close();
|
|
||||||
ID3D12CommandList* cmdLists[] = { m_commandList };
|
|
||||||
m_commandQueue->ExecuteCommandLists(1, cmdLists);
|
|
||||||
|
|
||||||
m_swapChain->Present(1, 0);
|
|
||||||
|
|
||||||
m_fenceValue++;
|
|
||||||
m_commandQueue->Signal(m_fence, m_fenceValue);
|
|
||||||
if (m_fence->GetCompletedValue() < m_fenceValue) {
|
|
||||||
m_fence->SetEventOnCompletion(m_fenceValue, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::OnResize(int width, int height) {
|
|
||||||
if (width <= 0 || height <= 0) return;
|
|
||||||
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
|
|
||||||
CleanupRenderTarget();
|
|
||||||
|
|
||||||
if (m_swapChain) {
|
|
||||||
DXGI_SWAP_CHAIN_DESC desc;
|
|
||||||
m_swapChain->GetDesc(&desc);
|
|
||||||
m_swapChain->ResizeBuffers(3, width, height, desc.BufferDesc.Format, desc.Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateRenderTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::CreateDevice() {
|
|
||||||
HRESULT hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
|
||||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
|
||||||
queueDesc.Priority = 0;
|
|
||||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
||||||
queueDesc.NodeMask = 0;
|
|
||||||
hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&m_commandList));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
m_commandList->Close();
|
|
||||||
|
|
||||||
hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
IDXGIFactory4* factory = nullptr;
|
|
||||||
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
|
||||||
swapChainDesc.BufferCount = 3;
|
|
||||||
swapChainDesc.Width = m_width;
|
|
||||||
swapChainDesc.Height = m_height;
|
|
||||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
||||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
||||||
swapChainDesc.SampleDesc.Count = 1;
|
|
||||||
|
|
||||||
IDXGISwapChain1* swapChain1 = nullptr;
|
|
||||||
hr = factory->CreateSwapChainForHwnd(m_commandQueue, m_hwnd, &swapChainDesc, nullptr, nullptr, &swapChain1);
|
|
||||||
factory->Release();
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
hr = swapChain1->QueryInterface(IID_PPV_ARGS(&m_swapChain));
|
|
||||||
swapChain1->Release();
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {};
|
|
||||||
rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
||||||
rtvDesc.NumDescriptors = 3;
|
|
||||||
rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
||||||
hr = m_device->CreateDescriptorHeap(&rtvDesc, IID_PPV_ARGS(&m_rtvHeap));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
||||||
|
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC srvDesc = {};
|
|
||||||
srvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
||||||
srvDesc.NumDescriptors = 1;
|
|
||||||
srvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
|
||||||
hr = m_device->CreateDescriptorHeap(&srvDesc, IID_PPV_ARGS(&m_srvHeap));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::CreateRenderTarget() {
|
|
||||||
if (!m_swapChain || !m_device || !m_rtvHeap) return false;
|
|
||||||
|
|
||||||
for (UINT i = 0; i < 3; i++) {
|
|
||||||
HRESULT hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_renderTargets[i]));
|
|
||||||
if (FAILED(hr)) return false;
|
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
|
|
||||||
rtvHandle.ptr += i * m_rtvDescriptorSize;
|
|
||||||
m_device->CreateRenderTargetView(m_renderTargets[i], nullptr, rtvHandle);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::CleanupRenderTarget() {
|
|
||||||
for (UINT i = 0; i < 3; i++) {
|
|
||||||
if (m_renderTargets[i]) {
|
|
||||||
m_renderTargets[i]->Release();
|
|
||||||
m_renderTargets[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::SetupDockspace() {
|
|
||||||
static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_NoWindowMenuButton;
|
|
||||||
|
|
||||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
|
||||||
|
|
||||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
|
||||||
ImGui::SetNextWindowPos(viewport->Pos);
|
|
||||||
ImGui::SetNextWindowSize(viewport->Size);
|
|
||||||
ImGui::SetNextWindowViewport(viewport->ID);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
|
||||||
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
|
||||||
windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::Begin("MainDockspace", nullptr, windowFlags);
|
|
||||||
ImGui::PopStyleVar();
|
|
||||||
ImGui::PopStyleVar(2);
|
|
||||||
|
|
||||||
ImGuiID dockspaceId = ImGui::GetID("MyDockspace");
|
|
||||||
ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
|
||||||
|
|
||||||
static bool firstTime = true;
|
|
||||||
if (firstTime) {
|
|
||||||
firstTime = false;
|
|
||||||
ImGui::DockBuilderRemoveNode(dockspaceId);
|
|
||||||
ImGui::DockBuilderAddNode(dockspaceId, dockspaceFlags | ImGuiDockNodeFlags_DockSpace);
|
|
||||||
ImGui::DockBuilderSetNodeSize(dockspaceId, viewport->Size);
|
|
||||||
|
|
||||||
ImGuiID dockMain = dockspaceId;
|
|
||||||
ImGuiID dockBottom = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Down, 0.25f, nullptr, &dockMain);
|
|
||||||
ImGuiID dockLeft = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Left, 0.15f, nullptr, &dockMain);
|
|
||||||
ImGuiID dockRight = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Right, 0.25f, nullptr, &dockMain);
|
|
||||||
|
|
||||||
ImGui::DockBuilderDockWindow("Hierarchy", dockLeft);
|
|
||||||
ImGui::DockBuilderDockWindow("Scene", dockMain);
|
|
||||||
ImGui::DockBuilderDockWindow("Game", dockMain);
|
|
||||||
ImGui::DockBuilderDockWindow("Inspector", dockRight);
|
|
||||||
ImGui::DockBuilderDockWindow("Console", dockBottom);
|
|
||||||
ImGui::DockBuilderDockWindow("Project", dockBottom);
|
|
||||||
|
|
||||||
ImGui::DockBuilderFinish(dockspaceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::RenderUI() {
|
|
||||||
m_menuBar->Render();
|
|
||||||
|
|
||||||
m_hierarchyPanel->Render();
|
|
||||||
m_sceneViewPanel->Render();
|
|
||||||
m_gameViewPanel->Render();
|
|
||||||
m_inspectorPanel->Render();
|
|
||||||
m_consolePanel->Render();
|
|
||||||
m_projectPanel->Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <d3d12.h>
|
|
||||||
#include <dxgi1_6.h>
|
|
||||||
|
|
||||||
#include "Theme.h"
|
|
||||||
#include "panels/Panel.h"
|
|
||||||
#include "panels/MenuBar.h"
|
|
||||||
#include "panels/HierarchyPanel.h"
|
|
||||||
#include "panels/SceneViewPanel.h"
|
|
||||||
#include "panels/GameViewPanel.h"
|
|
||||||
#include "panels/InspectorPanel.h"
|
|
||||||
#include "panels/ConsolePanel.h"
|
|
||||||
#include "panels/ProjectPanel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class Application {
|
|
||||||
public:
|
|
||||||
static Application& Get();
|
|
||||||
|
|
||||||
bool Initialize(HWND hwnd);
|
|
||||||
void Shutdown();
|
|
||||||
void Render();
|
|
||||||
void OnResize(int width, int height);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Application() = default;
|
|
||||||
~Application() = default;
|
|
||||||
|
|
||||||
bool CreateDevice();
|
|
||||||
bool CreateRenderTarget();
|
|
||||||
void CleanupRenderTarget();
|
|
||||||
void SetupDockspace();
|
|
||||||
void RenderUI();
|
|
||||||
|
|
||||||
HWND m_hwnd = nullptr;
|
|
||||||
int m_width = 1280;
|
|
||||||
int m_height = 720;
|
|
||||||
|
|
||||||
ID3D12Device* m_device = nullptr;
|
|
||||||
ID3D12CommandQueue* m_commandQueue = nullptr;
|
|
||||||
ID3D12CommandAllocator* m_commandAllocator = nullptr;
|
|
||||||
ID3D12GraphicsCommandList* m_commandList = nullptr;
|
|
||||||
IDXGISwapChain3* m_swapChain = nullptr;
|
|
||||||
ID3D12DescriptorHeap* m_rtvHeap = nullptr;
|
|
||||||
ID3D12DescriptorHeap* m_srvHeap = nullptr;
|
|
||||||
ID3D12Resource* m_renderTargets[3] = {};
|
|
||||||
ID3D12Fence* m_fence = nullptr;
|
|
||||||
UINT64 m_fenceValue = 0;
|
|
||||||
UINT m_rtvDescriptorSize = 0;
|
|
||||||
UINT m_frameIndex = 0;
|
|
||||||
|
|
||||||
std::unique_ptr<MenuBar> m_menuBar;
|
|
||||||
std::unique_ptr<HierarchyPanel> m_hierarchyPanel;
|
|
||||||
std::unique_ptr<SceneViewPanel> m_sceneViewPanel;
|
|
||||||
std::unique_ptr<GameViewPanel> m_gameViewPanel;
|
|
||||||
std::unique_ptr<InspectorPanel> m_inspectorPanel;
|
|
||||||
std::unique_ptr<ConsolePanel> m_consolePanel;
|
|
||||||
std::unique_ptr<ProjectPanel> m_projectPanel;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
struct AssetItem {
|
|
||||||
std::string name;
|
|
||||||
std::string type;
|
|
||||||
bool isFolder;
|
|
||||||
std::string fullPath;
|
|
||||||
std::vector<std::shared_ptr<AssetItem>> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
using AssetItemPtr = std::shared_ptr<AssetItem>;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
class Event {
|
|
||||||
public:
|
|
||||||
using HandlerID = size_t;
|
|
||||||
using Handler = std::function<void(Args...)>;
|
|
||||||
|
|
||||||
HandlerID Subscribe(Handler handler) {
|
|
||||||
HandlerID id = m_nextId++;
|
|
||||||
m_handlers.emplace_back(id, std::move(handler));
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unsubscribe(HandlerID id) {
|
|
||||||
m_handlers.erase(
|
|
||||||
std::remove_if(m_handlers.begin(), m_handlers.end(),
|
|
||||||
[id](const auto& pair) { return pair.first == id; }),
|
|
||||||
m_handlers.end()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Invoke(Args... args) {
|
|
||||||
for (const auto& pair : m_handlers) {
|
|
||||||
pair.second(args...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(Args... args) {
|
|
||||||
Invoke(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear() {
|
|
||||||
m_handlers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
HandlerID m_nextId = 0;
|
|
||||||
std::vector<std::pair<HandlerID, Handler>> m_handlers;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <functional>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
using EntityID = uint64_t;
|
|
||||||
constexpr EntityID INVALID_ENTITY = 0;
|
|
||||||
|
|
||||||
class Component {
|
|
||||||
public:
|
|
||||||
virtual ~Component() = default;
|
|
||||||
virtual std::string GetName() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TransformComponent : public Component {
|
|
||||||
public:
|
|
||||||
float position[3] = {0.0f, 0.0f, 0.0f};
|
|
||||||
float rotation[3] = {0.0f, 0.0f, 0.0f};
|
|
||||||
float scale[3] = {1.0f, 1.0f, 1.0f};
|
|
||||||
|
|
||||||
std::string GetName() const override { return "Transform"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class MeshRendererComponent : public Component {
|
|
||||||
public:
|
|
||||||
std::string materialName = "Default-Material";
|
|
||||||
std::string meshName = "";
|
|
||||||
|
|
||||||
std::string GetName() const override { return "Mesh Renderer"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Entity {
|
|
||||||
EntityID id = INVALID_ENTITY;
|
|
||||||
std::string name;
|
|
||||||
EntityID parent = INVALID_ENTITY;
|
|
||||||
std::vector<EntityID> children;
|
|
||||||
std::vector<std::unique_ptr<Component>> components;
|
|
||||||
bool selected = false;
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
T* AddComponent(Args&&... args) {
|
|
||||||
auto comp = std::make_unique<T>(std::forward<Args>(args)...);
|
|
||||||
T* ptr = comp.get();
|
|
||||||
components.push_back(std::move(comp));
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* GetComponent() {
|
|
||||||
for (auto& comp : components) {
|
|
||||||
if (auto casted = dynamic_cast<T*>(comp.get())) {
|
|
||||||
return casted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using ComponentInspectorFn = std::function<void(Component*)>;
|
|
||||||
|
|
||||||
struct ComponentInspectorInfo {
|
|
||||||
std::string name;
|
|
||||||
ComponentInspectorFn renderFn;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ComponentRegistry {
|
|
||||||
public:
|
|
||||||
static ComponentRegistry& Get() {
|
|
||||||
static ComponentRegistry instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void RegisterComponent(const std::string& name, ComponentInspectorFn inspectorFn) {
|
|
||||||
m_inspectors[name] = {name, inspectorFn};
|
|
||||||
m_factories[name] = []() -> std::unique_ptr<Component> {
|
|
||||||
return std::make_unique<T>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentInspectorInfo* GetInspector(const std::string& name) {
|
|
||||||
auto it = m_inspectors.find(name);
|
|
||||||
if (it != m_inspectors.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ComponentRegistry() = default;
|
|
||||||
std::unordered_map<std::string, ComponentInspectorInfo> m_inspectors;
|
|
||||||
std::unordered_map<std::string, std::function<std::unique_ptr<Component>()>> m_factories;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
struct LogEntry {
|
|
||||||
enum class Level { Info, Warning, Error };
|
|
||||||
Level level;
|
|
||||||
std::string message;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#include "LogSystem.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
LogSystem& LogSystem::Get() {
|
|
||||||
static LogSystem instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogSystem::AddLog(LogEntry::Level level, const std::string& message) {
|
|
||||||
m_logs.push_back({level, message});
|
|
||||||
if (m_callback) m_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogSystem::Clear() {
|
|
||||||
m_logs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Core/LogEntry.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class LogSystem {
|
|
||||||
public:
|
|
||||||
static LogSystem& Get();
|
|
||||||
|
|
||||||
void AddLog(LogEntry::Level level, const std::string& message);
|
|
||||||
void Clear();
|
|
||||||
const std::vector<LogEntry>& GetLogs() const { return m_logs; }
|
|
||||||
|
|
||||||
void SetCallback(std::function<void()> callback) { m_callback = callback; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
LogSystem() = default;
|
|
||||||
|
|
||||||
std::vector<LogEntry> m_logs;
|
|
||||||
std::function<void()> m_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
#include "ProjectManager.h"
|
|
||||||
#include <filesystem>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
ProjectManager& ProjectManager::Get() {
|
|
||||||
static ProjectManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<AssetItemPtr>& ProjectManager::GetCurrentItems() {
|
|
||||||
if (m_path.empty()) {
|
|
||||||
static std::vector<AssetItemPtr> empty;
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
return m_path.back()->children;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::NavigateToFolder(const AssetItemPtr& folder) {
|
|
||||||
m_path.push_back(folder);
|
|
||||||
m_selectedIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::NavigateBack() {
|
|
||||||
if (m_path.size() > 1) {
|
|
||||||
m_path.pop_back();
|
|
||||||
m_selectedIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::NavigateToIndex(size_t index) {
|
|
||||||
if (index >= m_path.size()) return;
|
|
||||||
while (m_path.size() > index + 1) {
|
|
||||||
m_path.pop_back();
|
|
||||||
}
|
|
||||||
m_selectedIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ProjectManager::GetCurrentPath() const {
|
|
||||||
if (m_path.empty()) return "Assets";
|
|
||||||
std::string result = "Assets";
|
|
||||||
for (size_t i = 1; i < m_path.size(); i++) {
|
|
||||||
result += "/";
|
|
||||||
result += m_path[i]->name;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ProjectManager::GetPathName(size_t index) const {
|
|
||||||
if (index >= m_path.size()) return "";
|
|
||||||
return m_path[index]->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::wstring Utf8ToWstring(const std::string& str) {
|
|
||||||
if (str.empty()) return L"";
|
|
||||||
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
|
|
||||||
if (len <= 0) return L"";
|
|
||||||
std::wstring result(len - 1, 0);
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &result[0], len);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string WstringToUtf8(const std::wstring& wstr) {
|
|
||||||
if (wstr.empty()) return "";
|
|
||||||
int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
|
||||||
if (len <= 0) return "";
|
|
||||||
std::string result(len - 1, 0);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &result[0], len, nullptr, nullptr);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::Initialize(const std::string& projectPath) {
|
|
||||||
m_projectPath = projectPath;
|
|
||||||
|
|
||||||
std::wstring projectPathW = Utf8ToWstring(projectPath);
|
|
||||||
fs::path assetsPath = fs::path(projectPathW) / L"Assets";
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!fs::exists(assetsPath)) {
|
|
||||||
fs::create_directories(assetsPath);
|
|
||||||
fs::create_directories(assetsPath / L"Textures");
|
|
||||||
fs::create_directories(assetsPath / L"Models");
|
|
||||||
fs::create_directories(assetsPath / L"Scripts");
|
|
||||||
fs::create_directories(assetsPath / L"Materials");
|
|
||||||
fs::create_directories(assetsPath / L"Scenes");
|
|
||||||
|
|
||||||
std::ofstream((assetsPath / L"Textures" / L"Grass.png").wstring());
|
|
||||||
std::ofstream((assetsPath / L"Textures" / L"Stone.png").wstring());
|
|
||||||
std::ofstream((assetsPath / L"Models" / L"Character.fbx").wstring());
|
|
||||||
std::ofstream((assetsPath / L"Scripts" / L"PlayerController.cs").wstring());
|
|
||||||
std::ofstream((assetsPath / L"Scenes" / L"Main.unity").wstring());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rootFolder = ScanDirectory(assetsPath.wstring());
|
|
||||||
m_rootFolder->name = "Assets";
|
|
||||||
m_rootFolder->fullPath = WstringToUtf8(assetsPath.wstring());
|
|
||||||
|
|
||||||
m_path.clear();
|
|
||||||
m_path.push_back(m_rootFolder);
|
|
||||||
m_selectedIndex = -1;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
m_rootFolder = std::make_shared<AssetItem>();
|
|
||||||
m_rootFolder->name = "Assets";
|
|
||||||
m_rootFolder->isFolder = true;
|
|
||||||
m_rootFolder->type = "Folder";
|
|
||||||
m_path.push_back(m_rootFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring ProjectManager::GetCurrentFullPathW() const {
|
|
||||||
if (m_path.empty()) return Utf8ToWstring(m_projectPath);
|
|
||||||
|
|
||||||
std::wstring fullPath = Utf8ToWstring(m_projectPath);
|
|
||||||
for (size_t i = 0; i < m_path.size(); i++) {
|
|
||||||
fullPath += L"/" + Utf8ToWstring(m_path[i]->name);
|
|
||||||
}
|
|
||||||
return fullPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::RefreshCurrentFolder() {
|
|
||||||
if (m_path.empty()) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto newFolder = ScanDirectory(GetCurrentFullPathW());
|
|
||||||
m_path.back()->children = newFolder->children;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::CreateFolder(const std::string& name) {
|
|
||||||
try {
|
|
||||||
std::wstring fullPath = GetCurrentFullPathW();
|
|
||||||
fs::path newFolderPath = fs::path(fullPath) / Utf8ToWstring(name);
|
|
||||||
fs::create_directory(newFolderPath);
|
|
||||||
RefreshCurrentFolder();
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectManager::DeleteItem(int index) {
|
|
||||||
if (m_path.empty()) return;
|
|
||||||
auto& items = m_path.back()->children;
|
|
||||||
if (index < 0 || index >= (int)items.size()) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
std::wstring fullPath = GetCurrentFullPathW();
|
|
||||||
fs::path itemPath = fs::path(fullPath) / Utf8ToWstring(items[index]->name);
|
|
||||||
fs::remove_all(itemPath);
|
|
||||||
m_selectedIndex = -1;
|
|
||||||
RefreshCurrentFolder();
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProjectManager::MoveItem(const std::string& sourceFullPath, const std::string& destFolderFullPath) {
|
|
||||||
try {
|
|
||||||
fs::path sourcePath = Utf8ToWstring(sourceFullPath);
|
|
||||||
fs::path destPath = fs::path(Utf8ToWstring(destFolderFullPath)) / sourcePath.filename();
|
|
||||||
|
|
||||||
if (!fs::exists(sourcePath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fs::exists(destPath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::rename(sourcePath, destPath);
|
|
||||||
RefreshCurrentFolder();
|
|
||||||
return true;
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetItemPtr ProjectManager::ScanDirectory(const std::wstring& path) {
|
|
||||||
auto folder = std::make_shared<AssetItem>();
|
|
||||||
folder->name = WstringToUtf8(fs::path(path).filename().wstring());
|
|
||||||
folder->isFolder = true;
|
|
||||||
folder->type = "Folder";
|
|
||||||
|
|
||||||
if (!fs::exists(path)) return folder;
|
|
||||||
|
|
||||||
std::vector<AssetItemPtr> items;
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (const auto& entry : fs::directory_iterator(path)) {
|
|
||||||
std::wstring nameW = entry.path().filename().wstring();
|
|
||||||
bool isFolder = entry.is_directory();
|
|
||||||
items.push_back(CreateAssetItem(entry.path().wstring(), nameW, isFolder));
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(items.begin(), items.end(), [](const AssetItemPtr& a, const AssetItemPtr& b) {
|
|
||||||
if (a->isFolder != b->isFolder) return a->isFolder;
|
|
||||||
return a->name < b->name;
|
|
||||||
});
|
|
||||||
|
|
||||||
folder->children = items;
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetItemPtr ProjectManager::CreateAssetItem(const std::wstring& path, const std::wstring& nameW, bool isFolder) {
|
|
||||||
auto item = std::make_shared<AssetItem>();
|
|
||||||
item->name = WstringToUtf8(nameW);
|
|
||||||
item->isFolder = isFolder;
|
|
||||||
item->fullPath = WstringToUtf8(path);
|
|
||||||
|
|
||||||
if (isFolder) {
|
|
||||||
item->type = "Folder";
|
|
||||||
try {
|
|
||||||
auto subFolder = ScanDirectory(path);
|
|
||||||
item->children = subFolder->children;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::wstring ext = fs::path(path).extension().wstring();
|
|
||||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower);
|
|
||||||
|
|
||||||
if (ext == L".png" || ext == L".jpg" || ext == L".tga" || ext == L".bmp") {
|
|
||||||
item->type = "Texture";
|
|
||||||
} else if (ext == L".fbx" || ext == L".obj" || ext == L".gltf" || ext == L".glb") {
|
|
||||||
item->type = "Model";
|
|
||||||
} else if (ext == L".cs" || ext == L".cpp" || ext == L".h") {
|
|
||||||
item->type = "Script";
|
|
||||||
} else if (ext == L".mat") {
|
|
||||||
item->type = "Material";
|
|
||||||
} else if (ext == L".unity" || ext == L".scene") {
|
|
||||||
item->type = "Scene";
|
|
||||||
} else if (ext == L".prefab") {
|
|
||||||
item->type = "Prefab";
|
|
||||||
} else {
|
|
||||||
item->type = "File";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Core/AssetItem.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class ProjectManager {
|
|
||||||
public:
|
|
||||||
static ProjectManager& Get();
|
|
||||||
|
|
||||||
std::vector<AssetItemPtr>& GetCurrentItems();
|
|
||||||
int GetSelectedIndex() const { return m_selectedIndex; }
|
|
||||||
void SetSelectedIndex(int index) { m_selectedIndex = index; }
|
|
||||||
|
|
||||||
void NavigateToFolder(const AssetItemPtr& folder);
|
|
||||||
void NavigateBack();
|
|
||||||
void NavigateToIndex(size_t index);
|
|
||||||
bool CanNavigateBack() const { return m_path.size() > 1; }
|
|
||||||
|
|
||||||
std::string GetCurrentPath() const;
|
|
||||||
size_t GetPathDepth() const { return m_path.size(); }
|
|
||||||
std::string GetPathName(size_t index) const;
|
|
||||||
|
|
||||||
void Initialize(const std::string& projectPath);
|
|
||||||
void RefreshCurrentFolder();
|
|
||||||
|
|
||||||
void CreateFolder(const std::string& name);
|
|
||||||
void DeleteItem(int index);
|
|
||||||
bool MoveItem(const std::string& sourceFullPath, const std::string& destFolderFullPath);
|
|
||||||
|
|
||||||
const std::string& GetProjectPath() const { return m_projectPath; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
ProjectManager() = default;
|
|
||||||
|
|
||||||
AssetItemPtr ScanDirectory(const std::wstring& path);
|
|
||||||
AssetItemPtr CreateAssetItem(const std::wstring& path, const std::wstring& nameW, bool isFolder);
|
|
||||||
std::wstring GetCurrentFullPathW() const;
|
|
||||||
|
|
||||||
AssetItemPtr m_rootFolder;
|
|
||||||
std::vector<AssetItemPtr> m_path;
|
|
||||||
int m_selectedIndex = -1;
|
|
||||||
std::string m_projectPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
#include "SceneManager.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
EntityID SceneManager::CreateEntity(const std::string& name, EntityID parent) {
|
|
||||||
EntityID id = m_nextEntityId++;
|
|
||||||
Entity entity;
|
|
||||||
entity.id = id;
|
|
||||||
entity.name = name;
|
|
||||||
entity.parent = parent;
|
|
||||||
m_entities[id] = std::move(entity);
|
|
||||||
|
|
||||||
if (parent != INVALID_ENTITY) {
|
|
||||||
m_entities[parent].children.push_back(id);
|
|
||||||
} else {
|
|
||||||
m_rootEntities.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnEntityCreated.Invoke(id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneManager::DeleteEntity(EntityID id) {
|
|
||||||
auto it = m_entities.find(id);
|
|
||||||
if (it == m_entities.end()) return;
|
|
||||||
|
|
||||||
Entity& entity = it->second;
|
|
||||||
|
|
||||||
std::vector<EntityID> childrenToDelete = entity.children;
|
|
||||||
for (EntityID childId : childrenToDelete) {
|
|
||||||
DeleteEntity(childId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.parent != INVALID_ENTITY) {
|
|
||||||
auto* parent = GetEntity(entity.parent);
|
|
||||||
if (parent) {
|
|
||||||
auto& siblings = parent->children;
|
|
||||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SelectionManager::Get().GetSelectedEntity() == id) {
|
|
||||||
SelectionManager::Get().ClearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_entities.erase(it);
|
|
||||||
OnEntityDeleted.Invoke(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClipboardData SceneManager::CopyEntityRecursive(const Entity* entity) {
|
|
||||||
ClipboardData data;
|
|
||||||
data.name = entity->name;
|
|
||||||
|
|
||||||
for (const auto& comp : entity->components) {
|
|
||||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
|
||||||
auto newComp = std::make_unique<TransformComponent>();
|
|
||||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
|
||||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
|
||||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
|
||||||
data.components.push_back(std::move(newComp));
|
|
||||||
}
|
|
||||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
|
||||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
|
||||||
newComp->materialName = meshRenderer->materialName;
|
|
||||||
newComp->meshName = meshRenderer->meshName;
|
|
||||||
data.components.push_back(std::move(newComp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (EntityID childId : entity->children) {
|
|
||||||
const Entity* child = GetEntity(childId);
|
|
||||||
if (child) {
|
|
||||||
data.children.push_back(CopyEntityRecursive(child));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneManager::CopyEntity(EntityID id) {
|
|
||||||
const Entity* entity = GetEntity(id);
|
|
||||||
if (!entity) return;
|
|
||||||
|
|
||||||
m_clipboard = CopyEntityRecursive(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityID SceneManager::PasteEntityRecursive(const ClipboardData& data, EntityID parent) {
|
|
||||||
EntityID newId = CreateEntity(data.name, parent);
|
|
||||||
Entity* newEntity = GetEntity(newId);
|
|
||||||
|
|
||||||
if (newEntity) {
|
|
||||||
newEntity->components.clear();
|
|
||||||
for (const auto& comp : data.components) {
|
|
||||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
|
||||||
auto newComp = std::make_unique<TransformComponent>();
|
|
||||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
|
||||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
|
||||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
|
||||||
newEntity->components.push_back(std::move(newComp));
|
|
||||||
}
|
|
||||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
|
||||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
|
||||||
newComp->materialName = meshRenderer->materialName;
|
|
||||||
newComp->meshName = meshRenderer->meshName;
|
|
||||||
newEntity->components.push_back(std::move(newComp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& childData : data.children) {
|
|
||||||
PasteEntityRecursive(childData, newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newId;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityID SceneManager::PasteEntity(EntityID parent) {
|
|
||||||
if (!m_clipboard) return INVALID_ENTITY;
|
|
||||||
return PasteEntityRecursive(*m_clipboard, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityID SceneManager::DuplicateEntity(EntityID id) {
|
|
||||||
CopyEntity(id);
|
|
||||||
const Entity* entity = GetEntity(id);
|
|
||||||
if (!entity) return INVALID_ENTITY;
|
|
||||||
return PasteEntity(entity->parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneManager::MoveEntity(EntityID id, EntityID newParent) {
|
|
||||||
Entity* entity = GetEntity(id);
|
|
||||||
if (!entity || id == newParent) return;
|
|
||||||
|
|
||||||
if (entity->parent != INVALID_ENTITY) {
|
|
||||||
Entity* oldParent = GetEntity(entity->parent);
|
|
||||||
if (oldParent) {
|
|
||||||
auto& siblings = oldParent->children;
|
|
||||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
entity->parent = newParent;
|
|
||||||
|
|
||||||
if (newParent != INVALID_ENTITY) {
|
|
||||||
Entity* newParentEntity = GetEntity(newParent);
|
|
||||||
if (newParentEntity) {
|
|
||||||
newParentEntity->children.push_back(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_rootEntities.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnEntityChanged.Invoke(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneManager::CreateDemoScene() {
|
|
||||||
m_entities.clear();
|
|
||||||
m_rootEntities.clear();
|
|
||||||
m_nextEntityId = 1;
|
|
||||||
m_clipboard.reset();
|
|
||||||
|
|
||||||
EntityID camera = CreateEntity("Main Camera");
|
|
||||||
GetEntity(camera)->AddComponent<TransformComponent>();
|
|
||||||
|
|
||||||
EntityID light = CreateEntity("Directional Light");
|
|
||||||
|
|
||||||
EntityID cube = CreateEntity("Cube");
|
|
||||||
GetEntity(cube)->AddComponent<TransformComponent>();
|
|
||||||
GetEntity(cube)->AddComponent<MeshRendererComponent>()->meshName = "Cube Mesh";
|
|
||||||
|
|
||||||
EntityID sphere = CreateEntity("Sphere");
|
|
||||||
GetEntity(sphere)->AddComponent<TransformComponent>();
|
|
||||||
GetEntity(sphere)->AddComponent<MeshRendererComponent>()->meshName = "Sphere Mesh";
|
|
||||||
|
|
||||||
EntityID player = CreateEntity("Player");
|
|
||||||
EntityID weapon = CreateEntity("Weapon", player);
|
|
||||||
|
|
||||||
OnSceneChanged.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Core/GameObject.h"
|
|
||||||
#include "SelectionManager.h"
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
struct ClipboardData {
|
|
||||||
std::string name;
|
|
||||||
std::vector<std::unique_ptr<Component>> components;
|
|
||||||
std::vector<ClipboardData> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SceneManager {
|
|
||||||
public:
|
|
||||||
static SceneManager& Get() {
|
|
||||||
static SceneManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY);
|
|
||||||
|
|
||||||
Entity* GetEntity(EntityID id) {
|
|
||||||
auto it = m_entities.find(id);
|
|
||||||
if (it != m_entities.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Entity* GetEntity(EntityID id) const {
|
|
||||||
auto it = m_entities.find(id);
|
|
||||||
if (it != m_entities.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<EntityID>& GetRootEntities() const {
|
|
||||||
return m_rootEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteEntity(EntityID id);
|
|
||||||
|
|
||||||
void RenameEntity(EntityID id, const std::string& newName) {
|
|
||||||
auto* entity = GetEntity(id);
|
|
||||||
if (entity) {
|
|
||||||
entity->name = newName;
|
|
||||||
OnEntityChanged.Invoke(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CopyEntity(EntityID id);
|
|
||||||
|
|
||||||
EntityID PasteEntity(EntityID parent = INVALID_ENTITY);
|
|
||||||
|
|
||||||
EntityID DuplicateEntity(EntityID id);
|
|
||||||
|
|
||||||
void MoveEntity(EntityID id, EntityID newParent);
|
|
||||||
|
|
||||||
void CreateDemoScene();
|
|
||||||
|
|
||||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
|
||||||
|
|
||||||
Event<EntityID> OnEntityCreated;
|
|
||||||
Event<EntityID> OnEntityDeleted;
|
|
||||||
Event<EntityID> OnEntityChanged;
|
|
||||||
Event<> OnSceneChanged;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SceneManager() = default;
|
|
||||||
|
|
||||||
ClipboardData CopyEntityRecursive(const Entity* entity);
|
|
||||||
EntityID PasteEntityRecursive(const ClipboardData& data, EntityID parent);
|
|
||||||
|
|
||||||
EntityID m_nextEntityId = 1;
|
|
||||||
std::unordered_map<EntityID, Entity> m_entities;
|
|
||||||
std::vector<EntityID> m_rootEntities;
|
|
||||||
std::optional<ClipboardData> m_clipboard;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Core/GameObject.h"
|
|
||||||
#include "Core/Event.h"
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class SelectionManager {
|
|
||||||
public:
|
|
||||||
static SelectionManager& Get() {
|
|
||||||
static SelectionManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityID GetSelectedEntity() const { return m_selectedEntity; }
|
|
||||||
|
|
||||||
void SetSelectedEntity(EntityID id) {
|
|
||||||
m_selectedEntity = id;
|
|
||||||
OnSelectionChanged.Invoke(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearSelection() {
|
|
||||||
SetSelectedEntity(INVALID_ENTITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSelected(EntityID id) const {
|
|
||||||
return m_selectedEntity == id;
|
|
||||||
}
|
|
||||||
|
|
||||||
Event<EntityID> OnSelectionChanged;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SelectionManager() = default;
|
|
||||||
EntityID m_selectedEntity = INVALID_ENTITY;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
#include "Theme.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
void ApplyUnityDarkTheme() {
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
|
||||||
ImVec4* colors = style.Colors;
|
|
||||||
|
|
||||||
colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
|
||||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_WindowBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.18f, 0.18f, 0.18f, 0.94f);
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.12f, 0.12f, 0.12f, 0.75f);
|
|
||||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.10f, 0.10f, 0.53f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.80f, 0.80f, 1.00f);
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
|
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
|
||||||
colors[ImGuiCol_Tab] = ImVec4(0.18f, 0.18f, 0.18f, 0.86f);
|
|
||||||
colors[ImGuiCol_TabHovered] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.15f, 0.15f, 0.15f, 0.97f);
|
|
||||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
|
|
||||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.40f, 0.40f, 0.40f, 0.70f);
|
|
||||||
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
|
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.40f, 0.40f, 0.40f, 0.50f);
|
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(0.60f, 0.60f, 0.60f, 0.90f);
|
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
|
||||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
|
||||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
|
||||||
|
|
||||||
style.WindowRounding = 4.0f;
|
|
||||||
style.ChildRounding = 4.0f;
|
|
||||||
style.FrameRounding = 4.0f;
|
|
||||||
style.GrabRounding = 4.0f;
|
|
||||||
style.PopupRounding = 4.0f;
|
|
||||||
style.ScrollbarRounding = 4.0f;
|
|
||||||
style.TabRounding = 4.0f;
|
|
||||||
style.WindowBorderSize = 1.0f;
|
|
||||||
style.ChildBorderSize = 1.0f;
|
|
||||||
style.FrameBorderSize = 0.0f;
|
|
||||||
style.WindowPadding = ImVec2(8.0f, 8.0f);
|
|
||||||
style.FramePadding = ImVec2(6.0f, 4.0f);
|
|
||||||
style.ItemSpacing = ImVec2(8.0f, 4.0f);
|
|
||||||
style.ItemInnerSpacing = ImVec2(6.0f, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
void ApplyUnityDarkTheme();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
#include "Application.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) {
|
|
||||||
AllocConsole();
|
|
||||||
freopen("CONOUT$", "w", stdout);
|
|
||||||
printf("Starting UI application...\n");
|
|
||||||
|
|
||||||
WNDCLASSEXW wc = {};
|
|
||||||
wc.cbSize = sizeof(wc);
|
|
||||||
wc.style = CS_CLASSDC;
|
|
||||||
wc.lpfnWndProc = WndProc;
|
|
||||||
wc.hInstance = GetModuleHandle(nullptr);
|
|
||||||
wc.lpszClassName = L"XCVolumeRendererUI2";
|
|
||||||
|
|
||||||
if (!RegisterClassExW(&wc)) {
|
|
||||||
printf("Failed to register window class, error: %lu\n", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Window class registered.\n");
|
|
||||||
|
|
||||||
HWND hwnd = CreateWindowExW(
|
|
||||||
0, wc.lpszClassName, L"XCVolumeRenderer - Unity Style Editor",
|
|
||||||
WS_OVERLAPPEDWINDOW, 100, 100, 1280, 720,
|
|
||||||
nullptr, nullptr, wc.hInstance, nullptr
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!hwnd) {
|
|
||||||
printf("Failed to create window, error: %lu\n", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Window created.\n");
|
|
||||||
|
|
||||||
ShowWindow(hwnd, nCmdShow);
|
|
||||||
UpdateWindow(hwnd);
|
|
||||||
printf("Window shown.\n");
|
|
||||||
|
|
||||||
printf("Initializing application...\n");
|
|
||||||
if (!UI::Application::Get().Initialize(hwnd)) {
|
|
||||||
printf("Failed to initialize application!\n");
|
|
||||||
UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
|
||||||
system("pause");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Application initialized successfully.\n");
|
|
||||||
|
|
||||||
MSG msg = {};
|
|
||||||
int frameCount = 0;
|
|
||||||
while (msg.message != WM_QUIT) {
|
|
||||||
if (PeekMessageW(&msg, nullptr, 0U, 0U, PM_REMOVE)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessageW(&msg);
|
|
||||||
} else {
|
|
||||||
UI::Application::Get().Render();
|
|
||||||
frameCount++;
|
|
||||||
if (frameCount % 100 == 0) {
|
|
||||||
printf("Frame %d\n", frameCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Shutting down...\n");
|
|
||||||
UI::Application::Get().Shutdown();
|
|
||||||
UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
|
||||||
|
|
||||||
printf("Press any key to exit...\n");
|
|
||||||
system("pause");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
|
||||||
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
switch (msg) {
|
|
||||||
case WM_SIZE:
|
|
||||||
if (wParam != SIZE_MINIMIZED) {
|
|
||||||
UI::Application::Get().OnResize((int)LOWORD(lParam), (int)HIWORD(lParam));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case WM_SYSCOMMAND:
|
|
||||||
if ((wParam & 0xfff0) == SC_KEYMENU)
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case WM_DESTROY:
|
|
||||||
PostQuitMessage(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#include "ConsolePanel.h"
|
|
||||||
#include "Managers/LogSystem.h"
|
|
||||||
#include "Core/LogEntry.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
ConsolePanel::ConsolePanel() : Panel("Console") {
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Engine initialized successfully");
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Loading default scene...");
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Warning, "Missing material on object 'Cube'");
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Error, "Failed to load texture: 'Assets/Textures/missing.png'");
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Scene loaded successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsolePanel::Render() {
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
if (ImGui::Button("Clear")) {
|
|
||||||
LogSystem::Get().Clear();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Info")) {
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Test info message");
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Warn")) {
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Warning, "Test warning message");
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Error")) {
|
|
||||||
LogSystem::Get().AddLog(LogEntry::Level::Error, "Test error message");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
ImGui::BeginChild("LogScroll", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
|
|
||||||
|
|
||||||
for (const auto& log : LogSystem::Get().GetLogs()) {
|
|
||||||
ImVec4 color;
|
|
||||||
const char* prefix;
|
|
||||||
|
|
||||||
switch (log.level) {
|
|
||||||
case LogEntry::Level::Info:
|
|
||||||
color = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
|
|
||||||
prefix = "[Info] ";
|
|
||||||
break;
|
|
||||||
case LogEntry::Level::Warning:
|
|
||||||
color = ImVec4(1.0f, 0.8f, 0.0f, 1.0f);
|
|
||||||
prefix = "[Warn] ";
|
|
||||||
break;
|
|
||||||
case LogEntry::Level::Error:
|
|
||||||
color = ImVec4(1.0f, 0.3f, 0.3f, 1.0f);
|
|
||||||
prefix = "[Error]";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextColored(color, "%s%s", prefix, log.message.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_scrollToBottom) {
|
|
||||||
ImGui::SetScrollHereY(1.0f);
|
|
||||||
m_scrollToBottom = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class ConsolePanel : public Panel {
|
|
||||||
public:
|
|
||||||
ConsolePanel();
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_scrollToBottom = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#include "GameViewPanel.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
GameViewPanel::GameViewPanel() : Panel("Game") {}
|
|
||||||
|
|
||||||
void GameViewPanel::Render() {
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
RenderGameView();
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameViewPanel::RenderGameView() {
|
|
||||||
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
|
|
||||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
|
||||||
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
|
|
||||||
|
|
||||||
ImU32 bgColor = IM_COL32(20, 20, 25, 255);
|
|
||||||
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
|
|
||||||
|
|
||||||
const char* text = "Game View (Press Play)";
|
|
||||||
ImVec2 textSize = ImGui::CalcTextSize(text);
|
|
||||||
ImVec2 textPos(canvasPos.x + (canvasSize.x - textSize.x) * 0.5f, canvasPos.y + (canvasSize.y - textSize.y) * 0.5f);
|
|
||||||
drawList->AddText(textPos, IM_COL32(128, 128, 128, 255), text);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class GameViewPanel : public Panel {
|
|
||||||
public:
|
|
||||||
GameViewPanel();
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenderGameView();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,345 +0,0 @@
|
|||||||
#include "HierarchyPanel.h"
|
|
||||||
#include "Managers/SceneManager.h"
|
|
||||||
#include "Managers/SelectionManager.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
HierarchyPanel::HierarchyPanel() : Panel("Hierarchy") {
|
|
||||||
SceneManager::Get().CreateDemoScene();
|
|
||||||
|
|
||||||
m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](EntityID) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
HierarchyPanel::~HierarchyPanel() {
|
|
||||||
SelectionManager::Get().OnSelectionChanged.Unsubscribe(m_selectionHandlerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::Render() {
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
RenderSearchBar();
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
HandleKeyboardShortcuts();
|
|
||||||
|
|
||||||
std::string filter = m_searchBuffer;
|
|
||||||
|
|
||||||
ImGui::BeginChild("EntityList");
|
|
||||||
|
|
||||||
for (EntityID id : SceneManager::Get().GetRootEntities()) {
|
|
||||||
RenderEntity(id, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(0) && !ImGui::IsAnyItemHovered()) {
|
|
||||||
if (!m_renaming) {
|
|
||||||
SelectionManager::Get().ClearSelection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
|
||||||
RenderCreateMenu(INVALID_ENTITY);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::InvisibleButton("##DragTarget", ImVec2(-1, -1));
|
|
||||||
if (ImGui::BeginDragDropTarget()) {
|
|
||||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
|
||||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
|
||||||
if (sourceId != INVALID_ENTITY) {
|
|
||||||
const Entity* sourceEntity = SceneManager::Get().GetEntity(sourceId);
|
|
||||||
if (sourceEntity && sourceEntity->parent != INVALID_ENTITY) {
|
|
||||||
SceneManager::Get().MoveEntity(sourceId, INVALID_ENTITY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::RenderSearchBar() {
|
|
||||||
ImGui::SetNextItemWidth(-1);
|
|
||||||
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::RenderEntity(EntityID id, const std::string& filter) {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
Entity* entity = sceneManager.GetEntity(id);
|
|
||||||
if (!entity) return;
|
|
||||||
|
|
||||||
if (!filter.empty() && !PassesFilter(id, filter)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PushID(static_cast<int>(id));
|
|
||||||
|
|
||||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
|
|
||||||
|
|
||||||
if (entity->children.empty()) {
|
|
||||||
flags |= ImGuiTreeNodeFlags_Leaf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SelectionManager::Get().IsSelected(id)) {
|
|
||||||
flags |= ImGuiTreeNodeFlags_Selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_renaming && m_renamingEntity == id) {
|
|
||||||
if (m_renameJustStarted) {
|
|
||||||
ImGui::SetKeyboardFocusHere();
|
|
||||||
m_renameJustStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(-1);
|
|
||||||
if (ImGui::InputText("##Rename", m_renameBuffer, sizeof(m_renameBuffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
|
||||||
if (strlen(m_renameBuffer) > 0) {
|
|
||||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
|
||||||
}
|
|
||||||
m_renaming = false;
|
|
||||||
m_renamingEntity = INVALID_ENTITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
|
|
||||||
if (strlen(m_renameBuffer) > 0) {
|
|
||||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
|
||||||
}
|
|
||||||
m_renaming = false;
|
|
||||||
m_renamingEntity = INVALID_ENTITY;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bool isOpen = ImGui::TreeNodeEx(entity->name.c_str(), flags);
|
|
||||||
|
|
||||||
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
|
||||||
SelectionManager::Get().SetSelectedEntity(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
|
||||||
m_renaming = true;
|
|
||||||
m_renamingEntity = id;
|
|
||||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
|
||||||
m_renameJustStarted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleDragDrop(id);
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupContextItem("EntityContextMenu")) {
|
|
||||||
RenderContextMenu(id);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOpen) {
|
|
||||||
for (EntityID childId : entity->children) {
|
|
||||||
RenderEntity(childId, filter);
|
|
||||||
}
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::RenderContextMenu(EntityID id) {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
auto& selectionManager = SelectionManager::Get();
|
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Create")) {
|
|
||||||
RenderCreateMenu(id);
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Rename", "F2")) {
|
|
||||||
const Entity* entity = sceneManager.GetEntity(id);
|
|
||||||
if (entity) {
|
|
||||||
m_renaming = true;
|
|
||||||
m_renamingEntity = id;
|
|
||||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
|
||||||
m_renameJustStarted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Delete", "Delete")) {
|
|
||||||
sceneManager.DeleteEntity(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Copy", "Ctrl+C")) {
|
|
||||||
sceneManager.CopyEntity(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Paste", "Ctrl+V", false, sceneManager.HasClipboardData())) {
|
|
||||||
sceneManager.PasteEntity(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Duplicate", "Ctrl+D")) {
|
|
||||||
EntityID newId = sceneManager.DuplicateEntity(id);
|
|
||||||
if (newId != INVALID_ENTITY) {
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::RenderCreateMenu(EntityID parent) {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
auto& selectionManager = SelectionManager::Get();
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Empty Object")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("GameObject", parent);
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Camera")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("Camera", parent);
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Light")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("Light", parent);
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Cube")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("Cube", parent);
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Cube";
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Sphere")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("Sphere", parent);
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Sphere";
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Plane")) {
|
|
||||||
EntityID newId = sceneManager.CreateEntity("Plane", parent);
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
|
||||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Plane";
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::HandleDragDrop(EntityID id) {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
|
||||||
m_dragSource = id;
|
|
||||||
ImGui::SetDragDropPayload("ENTITY_ID", &id, sizeof(EntityID));
|
|
||||||
const Entity* entity = sceneManager.GetEntity(id);
|
|
||||||
if (entity) {
|
|
||||||
ImGui::Text("%s", entity->name.c_str());
|
|
||||||
}
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropTarget()) {
|
|
||||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
|
||||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
|
||||||
if (sourceId != id && sourceId != INVALID_ENTITY) {
|
|
||||||
const Entity* targetEntity = sceneManager.GetEntity(id);
|
|
||||||
const Entity* sourceEntity = sceneManager.GetEntity(sourceId);
|
|
||||||
|
|
||||||
bool isValidMove = true;
|
|
||||||
EntityID checkParent = targetEntity ? targetEntity->parent : INVALID_ENTITY;
|
|
||||||
while (checkParent != INVALID_ENTITY) {
|
|
||||||
if (checkParent == sourceId) {
|
|
||||||
isValidMove = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const Entity* parentEntity = sceneManager.GetEntity(checkParent);
|
|
||||||
checkParent = parentEntity ? parentEntity->parent : INVALID_ENTITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isValidMove && sourceEntity && sourceEntity->parent != id) {
|
|
||||||
sceneManager.MoveEntity(sourceId, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HierarchyPanel::HandleKeyboardShortcuts() {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
auto& selectionManager = SelectionManager::Get();
|
|
||||||
|
|
||||||
EntityID selectedId = selectionManager.GetSelectedEntity();
|
|
||||||
|
|
||||||
if (ImGui::IsWindowFocused()) {
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
|
||||||
if (selectedId != INVALID_ENTITY) {
|
|
||||||
sceneManager.DeleteEntity(selectedId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_F2)) {
|
|
||||||
if (selectedId != INVALID_ENTITY) {
|
|
||||||
const Entity* entity = sceneManager.GetEntity(selectedId);
|
|
||||||
if (entity) {
|
|
||||||
m_renaming = true;
|
|
||||||
m_renamingEntity = selectedId;
|
|
||||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
|
||||||
m_renameJustStarted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
if (io.KeyCtrl) {
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
|
|
||||||
if (selectedId != INVALID_ENTITY) {
|
|
||||||
sceneManager.CopyEntity(selectedId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_V)) {
|
|
||||||
if (sceneManager.HasClipboardData()) {
|
|
||||||
sceneManager.PasteEntity(selectedId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
|
|
||||||
if (selectedId != INVALID_ENTITY) {
|
|
||||||
EntityID newId = sceneManager.DuplicateEntity(selectedId);
|
|
||||||
if (newId != INVALID_ENTITY) {
|
|
||||||
selectionManager.SetSelectedEntity(newId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HierarchyPanel::PassesFilter(EntityID id, const std::string& filter) {
|
|
||||||
auto& sceneManager = SceneManager::Get();
|
|
||||||
const Entity* entity = sceneManager.GetEntity(id);
|
|
||||||
if (!entity) return false;
|
|
||||||
|
|
||||||
if (entity->name.find(filter) != std::string::npos) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (EntityID childId : entity->children) {
|
|
||||||
if (PassesFilter(childId, filter)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
#include "Core/Event.h"
|
|
||||||
#include "Core/GameObject.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class HierarchyPanel : public Panel {
|
|
||||||
public:
|
|
||||||
HierarchyPanel();
|
|
||||||
~HierarchyPanel();
|
|
||||||
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenderSearchBar();
|
|
||||||
void RenderEntity(EntityID id, const std::string& filter);
|
|
||||||
void RenderContextMenu(EntityID id);
|
|
||||||
void RenderCreateMenu(EntityID parent);
|
|
||||||
void HandleDragDrop(EntityID id);
|
|
||||||
void HandleKeyboardShortcuts();
|
|
||||||
bool PassesFilter(EntityID id, const std::string& filter);
|
|
||||||
|
|
||||||
Event<EntityID>::HandlerID m_selectionHandlerId = 0;
|
|
||||||
|
|
||||||
char m_searchBuffer[256] = "";
|
|
||||||
bool m_renaming = false;
|
|
||||||
EntityID m_renamingEntity = INVALID_ENTITY;
|
|
||||||
char m_renameBuffer[256] = "";
|
|
||||||
bool m_renameJustStarted = false;
|
|
||||||
EntityID m_dragSource = INVALID_ENTITY;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#include "InspectorPanel.h"
|
|
||||||
#include "Managers/SceneManager.h"
|
|
||||||
#include "Managers/SelectionManager.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
InspectorPanel::InspectorPanel() : Panel("Inspector") {
|
|
||||||
m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](EntityID) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
InspectorPanel::~InspectorPanel() {
|
|
||||||
SelectionManager::Get().OnSelectionChanged.Unsubscribe(m_selectionHandlerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InspectorPanel::Render() {
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
EntityID selectedId = SelectionManager::Get().GetSelectedEntity();
|
|
||||||
Entity* entity = SceneManager::Get().GetEntity(selectedId);
|
|
||||||
|
|
||||||
if (entity) {
|
|
||||||
RenderEntity(entity);
|
|
||||||
} else {
|
|
||||||
ImGui::Text("No object selected");
|
|
||||||
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Select an object in Hierarchy");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InspectorPanel::RenderEntity(Entity* entity) {
|
|
||||||
ImGui::Text("%s", entity->name.c_str());
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
for (auto& component : entity->components) {
|
|
||||||
RenderComponent(component.get());
|
|
||||||
ImGui::Separator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InspectorPanel::RenderComponent(Component* component) {
|
|
||||||
if (!component) return;
|
|
||||||
|
|
||||||
const char* name = component->GetName().c_str();
|
|
||||||
|
|
||||||
std::string headerId = name + std::string("##") + std::to_string(reinterpret_cast<uintptr_t>(component));
|
|
||||||
|
|
||||||
if (ImGui::CollapsingHeader(headerId.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
|
||||||
ImGui::Indent(10.0f);
|
|
||||||
|
|
||||||
if (auto* transform = dynamic_cast<TransformComponent*>(component)) {
|
|
||||||
ImGui::Text("Position");
|
|
||||||
ImGui::SameLine(80);
|
|
||||||
ImGui::SetNextItemWidth(180);
|
|
||||||
ImGui::DragFloat3("##Position", transform->position, 0.1f);
|
|
||||||
|
|
||||||
ImGui::Text("Rotation");
|
|
||||||
ImGui::SameLine(80);
|
|
||||||
ImGui::SetNextItemWidth(180);
|
|
||||||
ImGui::DragFloat3("##Rotation", transform->rotation, 1.0f);
|
|
||||||
|
|
||||||
ImGui::Text("Scale");
|
|
||||||
ImGui::SameLine(80);
|
|
||||||
ImGui::SetNextItemWidth(180);
|
|
||||||
ImGui::DragFloat3("##Scale", transform->scale, 0.1f);
|
|
||||||
}
|
|
||||||
else if (auto* meshRenderer = dynamic_cast<MeshRendererComponent*>(component)) {
|
|
||||||
char materialBuffer[256] = {};
|
|
||||||
strncpy_s(materialBuffer, meshRenderer->materialName.c_str(), sizeof(materialBuffer) - 1);
|
|
||||||
ImGui::Text("Material");
|
|
||||||
ImGui::SameLine(80);
|
|
||||||
ImGui::SetNextItemWidth(180);
|
|
||||||
if (ImGui::InputText("##Material", materialBuffer, sizeof(materialBuffer))) {
|
|
||||||
meshRenderer->materialName = materialBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
char meshBuffer[256] = {};
|
|
||||||
strncpy_s(meshBuffer, meshRenderer->meshName.c_str(), sizeof(meshBuffer) - 1);
|
|
||||||
ImGui::Text("Mesh");
|
|
||||||
ImGui::SameLine(80);
|
|
||||||
ImGui::SetNextItemWidth(180);
|
|
||||||
if (ImGui::InputText("##Mesh", meshBuffer, sizeof(meshBuffer))) {
|
|
||||||
meshRenderer->meshName = meshBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Unindent(10.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
#include "Core/Event.h"
|
|
||||||
#include "Core/GameObject.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class InspectorPanel : public Panel {
|
|
||||||
public:
|
|
||||||
InspectorPanel();
|
|
||||||
~InspectorPanel();
|
|
||||||
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenderEntity(Entity* entity);
|
|
||||||
void RenderComponent(Component* component);
|
|
||||||
|
|
||||||
Event<EntityID>::HandlerID m_selectionHandlerId = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#include "MenuBar.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
MenuBar::MenuBar() : Panel("MenuBar") {}
|
|
||||||
|
|
||||||
void MenuBar::Render() {
|
|
||||||
if (ImGui::BeginMainMenuBar()) {
|
|
||||||
ShowFileMenu();
|
|
||||||
ShowEditMenu();
|
|
||||||
ShowViewMenu();
|
|
||||||
ShowHelpMenu();
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuBar::ShowFileMenu() {
|
|
||||||
if (ImGui::BeginMenu("File")) {
|
|
||||||
if (ImGui::MenuItem("New Scene", "Ctrl+N")) {}
|
|
||||||
if (ImGui::MenuItem("Open Scene", "Ctrl+O")) {}
|
|
||||||
if (ImGui::MenuItem("Save Scene", "Ctrl+S")) {}
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::MenuItem("Exit", "Alt+F4")) {}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuBar::ShowEditMenu() {
|
|
||||||
if (ImGui::BeginMenu("Edit")) {
|
|
||||||
if (ImGui::MenuItem("Undo", "Ctrl+Z")) {}
|
|
||||||
if (ImGui::MenuItem("Redo", "Ctrl+Y")) {}
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::MenuItem("Cut", "Ctrl+X")) {}
|
|
||||||
if (ImGui::MenuItem("Copy", "Ctrl+C")) {}
|
|
||||||
if (ImGui::MenuItem("Paste", "Ctrl+V")) {}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuBar::ShowViewMenu() {
|
|
||||||
if (ImGui::BeginMenu("View")) {
|
|
||||||
if (ImGui::MenuItem("Reset Layout")) {}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuBar::ShowHelpMenu() {
|
|
||||||
if (ImGui::BeginMenu("Help")) {
|
|
||||||
if (ImGui::MenuItem("About")) {}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class MenuBar : public Panel {
|
|
||||||
public:
|
|
||||||
MenuBar();
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ShowFileMenu();
|
|
||||||
void ShowEditMenu();
|
|
||||||
void ShowViewMenu();
|
|
||||||
void ShowHelpMenu();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#include "Panel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class Panel {
|
|
||||||
public:
|
|
||||||
Panel(const std::string& name) : m_name(name), m_isOpen(true) {}
|
|
||||||
virtual ~Panel() = default;
|
|
||||||
|
|
||||||
virtual void Render() = 0;
|
|
||||||
|
|
||||||
const std::string& GetName() const { return m_name; }
|
|
||||||
bool IsOpen() const { return m_isOpen; }
|
|
||||||
void SetOpen(bool open) { m_isOpen = open; }
|
|
||||||
void Toggle() { m_isOpen = !m_isOpen; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string m_name;
|
|
||||||
bool m_isOpen;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
#include "ProjectPanel.h"
|
|
||||||
#include "Managers/ProjectManager.h"
|
|
||||||
#include "Core/AssetItem.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
const char* DRAG_DROP_TYPE = "ASSET_ITEM";
|
|
||||||
|
|
||||||
ProjectPanel::ProjectPanel() : Panel("Project") {
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectPanel::Initialize(const std::string& projectPath) {
|
|
||||||
ProjectManager::Get().Initialize(projectPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectPanel::Render() {
|
|
||||||
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
|
|
||||||
if (payload && payload->IsDataType(DRAG_DROP_TYPE)) {
|
|
||||||
m_draggingPath = (const char*)payload->Data;
|
|
||||||
} else if (!ImGui::IsMouseDown(0)) {
|
|
||||||
m_draggingPath.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
auto& manager = ProjectManager::Get();
|
|
||||||
|
|
||||||
bool canGoBack = manager.CanNavigateBack();
|
|
||||||
ImGui::BeginDisabled(!canGoBack);
|
|
||||||
if (ImGui::Button("<")) {
|
|
||||||
if (canGoBack) {
|
|
||||||
manager.NavigateBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
|
|
||||||
size_t pathDepth = manager.GetPathDepth();
|
|
||||||
for (size_t i = 0; i < pathDepth; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text("/");
|
|
||||||
ImGui::SameLine();
|
|
||||||
}
|
|
||||||
std::string name = manager.GetPathName(i);
|
|
||||||
if (i < pathDepth - 1) {
|
|
||||||
if (ImGui::Button(name.c_str())) {
|
|
||||||
manager.NavigateToIndex(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ImGui::Text("%s", name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::PopStyleColor(2);
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f);
|
|
||||||
if (ImGui::Button("Refresh")) {
|
|
||||||
manager.RefreshCurrentFolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
ImGui::PushItemWidth(-1);
|
|
||||||
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 10));
|
|
||||||
|
|
||||||
float buttonWidth = 80.0f;
|
|
||||||
float padding = 10.0f;
|
|
||||||
float panelWidth = ImGui::GetContentRegionAvail().x;
|
|
||||||
int columns = (int)(panelWidth / (buttonWidth + padding));
|
|
||||||
if (columns < 1) columns = 1;
|
|
||||||
|
|
||||||
auto& items = manager.GetCurrentItems();
|
|
||||||
std::string searchStr = m_searchBuffer;
|
|
||||||
int itemIndex = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < (int)items.size(); i++) {
|
|
||||||
if (!searchStr.empty()) {
|
|
||||||
if (items[i]->name.find(searchStr) == std::string::npos) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemIndex > 0 && itemIndex % columns != 0) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
}
|
|
||||||
RenderAssetItem(items[i], itemIndex);
|
|
||||||
itemIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopStyleVar();
|
|
||||||
|
|
||||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered()) {
|
|
||||||
manager.SetSelectedIndex(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopup("ItemContextMenu")) {
|
|
||||||
if (m_contextMenuIndex >= 0 && m_contextMenuIndex < (int)items.size()) {
|
|
||||||
auto& item = items[m_contextMenuIndex];
|
|
||||||
if (item->isFolder) {
|
|
||||||
if (ImGui::MenuItem("Open")) {
|
|
||||||
manager.NavigateToFolder(item);
|
|
||||||
}
|
|
||||||
ImGui::Separator();
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Delete")) {
|
|
||||||
manager.DeleteItem(m_contextMenuIndex);
|
|
||||||
m_contextMenuIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(1) && !ImGui::IsAnyItemHovered()) {
|
|
||||||
ImGui::OpenPopup("EmptyContextMenu");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopup("EmptyContextMenu")) {
|
|
||||||
if (ImGui::MenuItem("Create Folder")) {
|
|
||||||
m_showCreateFolderPopup = true;
|
|
||||||
strcpy_s(m_newFolderName, "NewFolder");
|
|
||||||
}
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::MenuItem("Refresh")) {
|
|
||||||
manager.RefreshCurrentFolder();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
if (m_showCreateFolderPopup) {
|
|
||||||
ImGui::OpenPopup("Create Folder");
|
|
||||||
m_showCreateFolderPopup = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal("Create Folder", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::InputText("Name", m_newFolderName, sizeof(m_newFolderName));
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::Button("Create", ImVec2(80, 0))) {
|
|
||||||
CreateNewFolder(m_newFolderName);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Cancel", ImVec2(80, 0))) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
|
|
||||||
auto& manager = ProjectManager::Get();
|
|
||||||
bool isSelected = (manager.GetSelectedIndex() == index);
|
|
||||||
|
|
||||||
ImGui::PushID(index);
|
|
||||||
|
|
||||||
if (isSelected) {
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.40f, 0.40f, 0.40f, 0.50f));
|
|
||||||
} else {
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.30f, 0.30f, 0.30f, 0.40f));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVec2 buttonSize(80.0f, 90.0f);
|
|
||||||
|
|
||||||
if (ImGui::Button("##AssetBtn", buttonSize)) {
|
|
||||||
manager.SetSelectedIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool doubleClicked = false;
|
|
||||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
|
||||||
doubleClicked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openContextMenu = false;
|
|
||||||
if (ImGui::IsItemClicked(1)) {
|
|
||||||
manager.SetSelectedIndex(index);
|
|
||||||
m_contextMenuIndex = index;
|
|
||||||
openContextMenu = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSelected) {
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
} else {
|
|
||||||
ImGui::PopStyleColor(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVec2 min = ImGui::GetItemRectMin();
|
|
||||||
ImVec2 max = ImVec2(min.x + buttonSize.x, min.y + buttonSize.y);
|
|
||||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
|
||||||
|
|
||||||
if (!m_draggingPath.empty() && item->fullPath == m_draggingPath) {
|
|
||||||
drawList->AddRectFilled(min, max, IM_COL32(0, 0, 0, 60), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImU32 iconColor;
|
|
||||||
if (item->isFolder) {
|
|
||||||
iconColor = IM_COL32(200, 180, 100, 255);
|
|
||||||
} else if (item->type == "Texture") {
|
|
||||||
iconColor = IM_COL32(150, 200, 150, 255);
|
|
||||||
} else if (item->type == "Model") {
|
|
||||||
iconColor = IM_COL32(150, 150, 200, 255);
|
|
||||||
} else if (item->type == "Script") {
|
|
||||||
iconColor = IM_COL32(200, 150, 150, 255);
|
|
||||||
} else if (item->type == "Scene") {
|
|
||||||
iconColor = IM_COL32(200, 200, 150, 255);
|
|
||||||
} else {
|
|
||||||
iconColor = IM_COL32(100, 150, 200, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
float iconSize = 40.0f;
|
|
||||||
ImVec2 iconMin(min.x + (80.0f - iconSize) * 0.5f, min.y + 10.0f);
|
|
||||||
ImVec2 iconMax(iconMin.x + iconSize, iconMin.y + iconSize);
|
|
||||||
drawList->AddRectFilled(iconMin, iconMax, iconColor, 4.0f);
|
|
||||||
|
|
||||||
ImVec4 textColor = isSelected ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0.8f, 0.8f, 0.8f, 1.0f);
|
|
||||||
ImVec2 textSize = ImGui::CalcTextSize(item->name.c_str());
|
|
||||||
float textOffset = std::max(0.0f, (80.0f - textSize.x) * 0.5f);
|
|
||||||
|
|
||||||
ImGui::PushClipRect(min, ImVec2(min.x + 80.0f, min.y + 90.0f), true);
|
|
||||||
drawList->AddText(ImVec2(min.x + textOffset, min.y + 60.0f), ImGui::GetColorU32(textColor), item->name.c_str());
|
|
||||||
ImGui::PopClipRect();
|
|
||||||
|
|
||||||
if (item->isFolder) {
|
|
||||||
if (ImGui::BeginDragDropTarget()) {
|
|
||||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(DRAG_DROP_TYPE)) {
|
|
||||||
const char* draggedPath = (const char*)payload->Data;
|
|
||||||
std::string sourcePath(draggedPath);
|
|
||||||
manager.MoveItem(sourcePath, item->fullPath);
|
|
||||||
}
|
|
||||||
ImGui::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
|
|
||||||
ImDrawList* hoverDrawList = ImGui::GetWindowDrawList();
|
|
||||||
hoverDrawList->AddRect(min, ImVec2(min.x + buttonSize.x, min.y + buttonSize.y), IM_COL32(255, 255, 255, 80), 4.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item->fullPath.empty()) {
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
|
||||||
ImGui::SetDragDropPayload(DRAG_DROP_TYPE, item->fullPath.c_str(), item->fullPath.length() + 1);
|
|
||||||
|
|
||||||
ImU32 iconColor;
|
|
||||||
if (item->isFolder) {
|
|
||||||
iconColor = IM_COL32(200, 180, 100, 100);
|
|
||||||
} else if (item->type == "Texture") {
|
|
||||||
iconColor = IM_COL32(150, 200, 150, 100);
|
|
||||||
} else if (item->type == "Model") {
|
|
||||||
iconColor = IM_COL32(150, 150, 200, 100);
|
|
||||||
} else if (item->type == "Script") {
|
|
||||||
iconColor = IM_COL32(200, 150, 150, 100);
|
|
||||||
} else if (item->type == "Scene") {
|
|
||||||
iconColor = IM_COL32(200, 200, 150, 100);
|
|
||||||
} else {
|
|
||||||
iconColor = IM_COL32(100, 150, 200, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVec2 previewMin = ImGui::GetMousePos();
|
|
||||||
ImVec2 previewMax = ImVec2(previewMin.x + 40, previewMin.y + 40);
|
|
||||||
ImGui::GetForegroundDrawList()->AddRectFilled(previewMin, previewMax, iconColor, 4.0f);
|
|
||||||
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doubleClicked && item->isFolder) {
|
|
||||||
manager.NavigateToFolder(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
|
|
||||||
if (openContextMenu) {
|
|
||||||
ImGui::OpenPopup("ItemContextMenu");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProjectPanel::CreateNewFolder(const std::string& name) {
|
|
||||||
auto& manager = ProjectManager::Get();
|
|
||||||
manager.CreateFolder(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProjectPanel::HandleDrop(const AssetItemPtr& targetFolder) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
#include "Core/AssetItem.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class ProjectPanel : public Panel {
|
|
||||||
public:
|
|
||||||
ProjectPanel();
|
|
||||||
void Render() override;
|
|
||||||
void Initialize(const std::string& projectPath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenderAssetItem(const AssetItemPtr& item, int index);
|
|
||||||
void CreateNewFolder(const std::string& name);
|
|
||||||
bool HandleDrop(const AssetItemPtr& targetFolder);
|
|
||||||
|
|
||||||
char m_searchBuffer[256] = "";
|
|
||||||
bool m_showCreateFolderPopup = false;
|
|
||||||
char m_newFolderName[256] = "NewFolder";
|
|
||||||
int m_contextMenuIndex = -1;
|
|
||||||
std::string m_draggingPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include "SceneViewPanel.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
|
|
||||||
|
|
||||||
void SceneViewPanel::Render() {
|
|
||||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
||||||
|
|
||||||
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
|
|
||||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
|
||||||
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
|
|
||||||
|
|
||||||
ImU32 bgColor = IM_COL32(30, 30, 30, 255);
|
|
||||||
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
|
|
||||||
|
|
||||||
RenderGrid();
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneViewPanel::RenderGrid() {
|
|
||||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
|
||||||
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
|
|
||||||
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
|
|
||||||
|
|
||||||
float gridSize = 50.0f;
|
|
||||||
ImU32 gridColor = IM_COL32(50, 50, 50, 255);
|
|
||||||
|
|
||||||
for (float x = fmodf(0, gridSize); x < canvasSize.x; x += gridSize) {
|
|
||||||
drawList->AddLine(
|
|
||||||
ImVec2(canvasPos.x + x, canvasPos.y),
|
|
||||||
ImVec2(canvasPos.x + x, canvasPos.y + canvasSize.y),
|
|
||||||
gridColor
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (float y = fmodf(0, gridSize); y < canvasSize.y; y += gridSize) {
|
|
||||||
drawList->AddLine(
|
|
||||||
ImVec2(canvasPos.x, canvasPos.y + y),
|
|
||||||
ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + y),
|
|
||||||
gridColor
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* label = "Scene View";
|
|
||||||
ImVec2 labelSize = ImGui::CalcTextSize(label);
|
|
||||||
ImVec2 labelPos(canvasPos.x + 10, canvasPos.y + 10);
|
|
||||||
drawList->AddText(labelPos, IM_COL32(100, 100, 100, 255), label);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Panel.h"
|
|
||||||
|
|
||||||
namespace UI {
|
|
||||||
|
|
||||||
class SceneViewPanel : public Panel {
|
|
||||||
public:
|
|
||||||
SceneViewPanel();
|
|
||||||
void Render() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenderGrid();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user