#include "D3DRenderTarget.h"


D3DRenderTarget::D3DRenderTarget(uint32 width, uint32 height, uint32 sampleCount, ID3D10Device1* device)
: _renderTarget(0), _shaderResourceView(0), _renderTargetView(0)
{
    _width = width; 
    _height = height; 
    _mipLevelCount = 1;
    _sampleCount = sampleCount;
    _device = device;

    createSurface(&_renderTarget, &_shaderResourceView, &_renderTargetView, DXGI_FORMAT_R32G32B32A32_FLOAT, _mipLevelCount, _sampleCount, _width, _height);
}

D3DRenderTarget::~D3DRenderTarget()
{
    safeRelease(&_renderTargetView);
    safeRelease(&_shaderResourceView);
    safeRelease(&_renderTarget);
}

void D3DRenderTarget::resize(uint32 width, uint32 height)
{
    if ((_width != width) || (_height != height)) {
        _width = width;
        _height = height;

        createSurface(&_renderTarget, &_shaderResourceView, &_renderTargetView, DXGI_FORMAT_R32G32B32A32_FLOAT, _mipLevelCount, _sampleCount, _width, _height);
    }
}

void D3DRenderTarget::resolve(RenderTarget* resolveTarget)
{
    if (D3DRenderTarget* renderTarget = dynamic_cast<D3DRenderTarget*>(resolveTarget)) {
        _device->ResolveSubresource(renderTarget->_renderTarget, 0, _renderTarget, 0, DXGI_FORMAT_R32G32B32A32_FLOAT); 
    }
}

void D3DRenderTarget::generateMipmaps()
{
    _device->GenerateMips(_shaderResourceView);
}

ID3D10ShaderResourceView* D3DRenderTarget::getShaderResourceView()
{
    return _shaderResourceView;
}

ID3D10RenderTargetView* D3DRenderTarget::getRenderTargetView()
{
    return _renderTargetView;
}

HRESULT D3DRenderTarget::createSurface(ID3D10Texture2D** ppTexture, ID3D10ShaderResourceView** ppTextureSRV, ID3D10RenderTargetView** ppTextureRTV, DXGI_FORMAT format, uint32& mipLevelCount, uint32 sampleCount, uint32 width, uint32 height)
{
    HRESULT hr;
    D3D10_TEXTURE2D_DESC Desc;
    D3D10_SHADER_RESOURCE_VIEW_DESC SRDesc;
    D3D10_RENDER_TARGET_VIEW_DESC RTDesc;

    safeRelease( ppTexture );
    safeRelease( ppTextureSRV );
    safeRelease( ppTextureRTV );

    ZeroMemory( &Desc, sizeof( Desc ) );
    ZeroMemory( &SRDesc, sizeof( SRDesc ) );
    ZeroMemory( &RTDesc, sizeof( RTDesc ) );

    uint32 w = width, h = height;
    mipLevelCount = 1;

    while ((w != 1) && (h != 1)) {
        if (w > 1) w /= 2;
        if (h > 1) h /= 2;
        mipLevelCount++;
    }

    Desc.Width = width;
    Desc.Height = height;
    if (sampleCount > 1) Desc.MipLevels = 1;
    else Desc.MipLevels = mipLevelCount;
    Desc.ArraySize = 1;
    Desc.Format = format;
    Desc.SampleDesc.Count = sampleCount;
    Desc.SampleDesc.Quality = 0;
    Desc.Usage = D3D10_USAGE_DEFAULT;
    Desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    Desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS;

    hr = _device->CreateTexture2D( &Desc, NULL, ppTexture );
    if (FAILED(hr)) {
        MessageBox(GetActiveWindow(), L"Unable to create texture.", L"D3DRenderTarget::createSurface()", MB_OK | MB_ICONERROR);     
        return hr;
    }

    SRDesc.Format = format;
    if (sampleCount == 1) {
        SRDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
        SRDesc.Texture2D.MostDetailedMip = 0;
        SRDesc.Texture2D.MipLevels = mipLevelCount;
    }
    else {
        SRDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DMS;
    }
    hr = _device->CreateShaderResourceView( *ppTexture, &SRDesc, ppTextureSRV );
    if (FAILED(hr)) {
        MessageBox(GetActiveWindow(), L"Unable to create shader resource view.", L"D3DRenderTarget::createSurface()", MB_OK | MB_ICONERROR);
        return hr;
    }

    RTDesc.Format = format;
    if (sampleCount == 1) {
        RTDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
    }
    else {
        RTDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2DMS;
    }
    RTDesc.Texture2D.MipSlice = 0;
    
    hr = _device->CreateRenderTargetView( *ppTexture, &RTDesc, ppTextureRTV );
    if (FAILED(hr)) {
        MessageBox(GetActiveWindow(), L"Unable to create render target view.", L"D3DRenderTarget::createSurface()", MB_OK | MB_ICONERROR);
        return hr;
    }

    return hr;
}