#include "shadow_map.h"

#include "dx_exception.h" // 替换为你自己的 ThrowIfFailed 所在文件

void ShadowMap::Initialize(ID3D11Device *device, const std::uint32_t resolution) {
    m_resolution = resolution;

    // 使用 Typeless 格式，使同一张纹理可以：
    // 1. 作为 D32_FLOAT 深度缓冲
    // 2. 作为 R32_FLOAT Shader Resource
    D3D11_TEXTURE2D_DESC textureDesc{};
    textureDesc.Width = resolution;
    textureDesc.Height = resolution;
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = DXGI_FORMAT_R32_TYPELESS;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Usage = D3D11_USAGE_DEFAULT;
    textureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;

    ThrowIfFailed(device->CreateTexture2D(
        &textureDesc,
        nullptr,
        m_texture.GetAddressOf()));

    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc{};
    dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    dsvDesc.Texture2D.MipSlice = 0;

    ThrowIfFailed(device->CreateDepthStencilView(
        m_texture.Get(), &dsvDesc, m_dsv.GetAddressOf()));

    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
    srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MostDetailedMip = 0;
    srvDesc.Texture2D.MipLevels = 1;

    ThrowIfFailed(device->CreateShaderResourceView(
        m_texture.Get(),
        &srvDesc,
        m_srv.GetAddressOf()));

    D3D11_SAMPLER_DESC samplerDesc{};

    // Comparison Sampler 可以直接进行深度比较。
    // MIN_MAG_LINEAR 会提供基础硬件 PCF。
    samplerDesc.Filter =
            D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;

    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;

    // 采样超出阴影贴图时返回 1，即认为完全受光。
    samplerDesc.BorderColor[0] = 1.0f;
    samplerDesc.BorderColor[1] = 1.0f;
    samplerDesc.BorderColor[2] = 1.0f;
    samplerDesc.BorderColor[3] = 1.0f;

    samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
    samplerDesc.MinLOD = 0.0f;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    ThrowIfFailed(device->CreateSamplerState(
        &samplerDesc,
        m_comparisonSampler.GetAddressOf()));

    m_viewport.TopLeftX = 0.0f;
    m_viewport.TopLeftY = 0.0f;
    m_viewport.Width = static_cast<float>(resolution);
    m_viewport.Height = static_cast<float>(resolution);
    m_viewport.MinDepth = 0.0f;
    m_viewport.MaxDepth = 1.0f;
}
