module external.directx;

public import external.directx.com;
public import external.directx.d3d11;
public import external.directx.d3d11on12;
public import external.directx.d3d11sdklayers;
public import external.directx.d3d11shader;
public import external.directx.d3d11shadertracing;
public import external.directx.d3d12;
public import external.directx.d3d12sdklayers;
public import external.directx.d3d12shader;
public import external.directx.d3d12video;
public import external.directx.d3dcommon;
public import external.directx.d3dcompiler;
public import external.directx.d3dukmdt;
public import external.directx.dxgi;
public import external.directx.dxgicommon;
public import external.directx.dxgiddi;
public import external.directx.dxgidebug;
public import external.directx.dxgiformat;
public import external.directx.dxgimessages;
public import external.directx.dxgitype;
public import external.directx.win32;
public import external.directx.xaudio2;
public import external.directx.xinput;

pragma(lib, "d3dcompiler.lib");
pragma(lib, "D3D12.lib");
pragma(lib, "dxgi.lib");

void setName(ID3D12Object* pObject, string name)
{
    pObject.SetName(cast(wchar*) name.ptr);
}

uint calculateConstantBufferByteSize(uint byteSize)
{
    // Constant buffer size is required to be aligned.
    return (byteSize + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1);
}

ID3DBlob* compileShader(const ref wstring filename, const D3D_SHADER_MACRO* defines, const ref string entrypoint, const ref string target)
{
    uint compileFlags = 0;
    debug
    {
        compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
    }

    ID3DBlob* byteCode = null;
    ID3DBlob* errors;
    HRESULT hr = D3DCompileFromFile(filename.ptr, defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, entrypoint.ptr, target.ptr, compileFlags, 0, &byteCode, &errors);

    if(errors !is null)
    {
        OutputDebugStringA(cast(char*) errors.GetBufferPointer());
    }
    ThrowIfFailed(hr);
    return byteCode;
}

void ThrowIfFailed(HRESULT result)
{
    if (FAILED(result))
    {
        throw new Exception("Exception on line " ~ __LINE__ ~ " in file: " ~ __FILE__);
    }
}

void ThrowIfFailed(HRESULT result, string exception)
{
    if (FAILED(result))
    {
        throw new Exception(exception ~ " on line " ~ __LINE__ ~ " in file: " ~ __FILE__);
    }
}

string hrToString(HRESULT hr)
{
    import std.format : format;
    return format("HRESULT of 0x%d", cast(uint) hr);
}