#pragma once
#include "DX12Buffer.h"

#include "d3dx12.h"
#include "DX12CommandQueue.h"

using namespace Framework;

// Konstruktor
// eSize: Die Länge eines Elementes in Bytes
DX12Buffer::DX12Buffer(
    int eSize, ID3D12Device* device, ID3D12GraphicsCommandList* list, int flags)
    : DXBuffer(eSize),
      buffer(0),
      intermediate(0),
      device(device),
      list(list)
{
    description = new D3D12_RESOURCE_DESC();
    ZeroMemory(description, sizeof(D3D12_RESOURCE_DESC));
    description->Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    description->Height = 1;
    description->DepthOrArraySize = 1;
    description->MipLevels = 1;
    description->Format = DXGI_FORMAT_UNKNOWN;
    description->SampleDesc.Count = 1;
    description->Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    description->Flags = (D3D12_RESOURCE_FLAGS)flags;
}

// Destruktor
DX12Buffer::~DX12Buffer()
{
    if (intermediate) intermediate->Release();
    if (buffer) buffer->Release();
    delete description;
}

// Kopiert die Daten in den Buffer, fals sie sich verändert haben
void DX12Buffer::copieren(int byteCount)
{
    if (!len) return;
    if (byteCount < 0) byteCount = len;
    if (description->Width < len)
    {
        if (intermediate) intermediate->Release();
        if (buffer) buffer->Release();
        buffer = 0;
        description->Width = len;
    }
    if (!buffer)
    {
        D3D12_HEAP_PROPERTIES hprop;
        hprop.Type = D3D12_HEAP_TYPE_UPLOAD;
        hprop.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
        hprop.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
        hprop.CreationNodeMask = 1;
        hprop.VisibleNodeMask = 1;
        device->CreateCommittedResource(&hprop,
            D3D12_HEAP_FLAG_NONE,
            description,
            D3D12_RESOURCE_STATE_GENERIC_READ,
            0,
            __uuidof(ID3D12Resource),
            (void**)&buffer);
        hprop.Type = D3D12_HEAP_TYPE_UPLOAD;
        device->CreateCommittedResource(&hprop,
            D3D12_HEAP_FLAG_NONE,
            description,
            D3D12_RESOURCE_STATE_GENERIC_READ,
            0,
            __uuidof(ID3D12Resource),
            (void**)&intermediate);
        if (data) changed = 1;
    }
    if (changed && data)
    {
        BYTE* pData;
        D3D12_RANGE r;
        r.Begin = 0;
        r.End = 0;
        buffer->Map(0, &r, (void**)&pData);
        memcpy(pData, data, byteCount);
        r.End = byteCount;
        buffer->Unmap(0, &r);
        // list->CopyBufferRegion( buffer, 0, intermediate, 0, len );
        changed = 0;
    }
}

// Gibt den Buffer zurück
ID3D12Resource* DX12Buffer::zBuffer() const
{
    return buffer;
}

DX12IndexBuffer::DX12IndexBuffer(int eSize,
    ID3D12Device* device,
    DX12CopyCommandQueue* copy,
    DX12DirectCommandQueue* direct)
    : DX12Buffer(
        eSize, device, copy->getCommandList(), D3D12_RESOURCE_FLAG_NONE),
      copy(copy),
      direct(direct)
{
    ibs = 0;
}

DX12IndexBuffer::~DX12IndexBuffer() {}

// Kopiert die Daten in den Buffer, fals sie sich verändert haben
void DX12IndexBuffer::copieren(int byteCount)
{
    /*if( ibs )
    {
        D3D12_RESOURCE_BARRIER barrier;
        barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
        barrier.Transition.pResource = buffer;
        barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_INDEX_BUFFER;
        barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
        barrier.Transition.Subresource = 0;
        barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
        direct->getCommandList()->ResourceBarrier( 1, &barrier );
        direct->execute();
        ibs = 0;
    }*/
    DX12Buffer::copieren(byteCount);
    // copy->execute();
    /*D3D12_RESOURCE_BARRIER barrier;
    barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    barrier.Transition.pResource = buffer;
    barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
    barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
    barrier.Transition.Subresource = 0;
    barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    direct->getCommandList()->ResourceBarrier( 1, &barrier );
    direct->execute();
    ibs = 1;*/
}

DX12VertexBuffer::DX12VertexBuffer(int eSize,
    ID3D12Device* device,
    DX12CopyCommandQueue* copy,
    DX12DirectCommandQueue* direct)
    : DX12Buffer(
        eSize, device, copy->getCommandList(), D3D12_RESOURCE_FLAG_NONE),
      copy(copy),
      direct(direct)
{
    vbs = 0;
}

DX12VertexBuffer::~DX12VertexBuffer() {}

// Kopiert die Daten in den Buffer, fals sie sich verändert haben
void DX12VertexBuffer::copieren(int byteCount)
{
    /*if( vbs )
    {
        D3D12_RESOURCE_BARRIER barrier;
        barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
        barrier.Transition.pResource = buffer;
        barrier.Transition.StateBefore =
    D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
        barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
        barrier.Transition.Subresource = 0;
        barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
        direct->getCommandList()->ResourceBarrier( 1, &barrier );
        direct->execute();
        vbs = 0;
    }*/
    DX12Buffer::copieren(byteCount);
    // copy->execute();
    /*D3D12_RESOURCE_BARRIER barrier;
    barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    barrier.Transition.pResource = buffer;
    barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
    barrier.Transition.StateAfter =
    D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
    barrier.Transition.Subresource = 0;
    barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    direct->getCommandList()->ResourceBarrier( 1, &barrier );
    direct->execute();
    vbs = 1;*/
}