#include "DirectXBuffers.h"

#include "DirectXDescriptors.h"

#include "FileLogger.h"

#include <dxgi.h>
#include <dxgi1_6.h>
#include <d3d12.h>
#include <directx/d3dx12.h>

DirectXBuffers::DirectXBuffers(UINT frameCount)
    : mFrameCount(frameCount)
{

}

void DirectXBuffers::clear()
{
    for (auto& buffer : mBackBuffers)
    {
        auto count = buffer.Reset();
    }
    mBackBuffers.clear();
    mDepthStencilBuffer.Reset();

    mInitialized = false;
}

bool DirectXBuffers::isInitialized()
{
    return mInitialized;
}

UINT DirectXBuffers::getCurrentBackBufferIndex() const
{
    return mBackBufferIndex;
}

ID3D12Resource* DirectXBuffers::getCurrentBackBuffer() const
{
	return mBackBuffers[mBackBufferIndex].Get();
}

ID3D12Resource* DirectXBuffers::getBackBuffer(UINT index) const
{
    return mBackBuffers[index].Get();
}

ID3D12Resource* DirectXBuffers::getDepthStencilBuffer() const
{
    return mDepthStencilBuffer.Get();
}

void DirectXBuffers::updateBackbufferIndex(UINT index)
{
	mBackBufferIndex = index;
}

void DirectXBuffers::setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors)
{
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_heap_handle(descriptors->getRtvHandle());
    for (UINT i = 0; i < mFrameCount; i++)
    {
        mBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D12Resource>());

        swapChain->GetBuffer(i, IID_PPV_ARGS(&mBackBuffers[mBackBuffers.size()-1]));
        device->CreateRenderTargetView(mBackBuffers[mBackBuffers.size() - 1].Get(), nullptr, rtv_heap_handle);
        
        rtv_heap_handle.Offset(1, descriptors->getRtvDescriptorSize());

    }
    mInitialized = true;
}

void DirectXBuffers::setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height)
{
    D3D12_RESOURCE_DESC depthStencilDesc;
    depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    depthStencilDesc.Alignment = 0;
    depthStencilDesc.Width = width;
    depthStencilDesc.Height = height;
    depthStencilDesc.DepthOrArraySize = 1;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    depthStencilDesc.SampleDesc.Count = 1;
    depthStencilDesc.SampleDesc.Quality = 0;
    depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

    D3D12_CLEAR_VALUE optClear;
    optClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    optClear.DepthStencil.Depth = 1.0f;
    optClear.DepthStencil.Stencil = 0;

    auto props = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
    device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE,
        &depthStencilDesc, D3D12_RESOURCE_STATE_COMMON, &optClear, IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf()));
}

void DirectXBuffers::setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors)
{
    D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
    dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
    dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
    dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    dsvDesc.Texture2D.MipSlice = 0;
    device->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, descriptors->getDsvHandle());
}