#include "MyDX11Renderer.h"
#include <d3dcompiler.h>
#pragma comment(lib,"d3dcompiler.lib")
#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"dxgi.lib")
#pragma comment( lib, "dxguid.lib")
#include <wincodec.h> 
#include <stdio.h>
#include <time.h>
#include <shellscalingapi.h>
#include <ShlObj_core.h>
#pragma comment(lib,"shcore.lib")
#ifdef _DEBUG
#define MYCHECK(hrcall) if(FAILED(hr = (hrcall)))MyDX11ShowError(hr,#hrcall,__LINE__,__FILE__)
#else
#define MYCHECK(hrcall) hrcall
#endif 
#define UTF16ToUTF8(wstr,str) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, _countof(str), 0, 0);
#define UTF8ToUTF16(str,wstr) MultiByteToWideChar(CP_UTF8,0,str,-1,wstr,_countof(wstr))

#ifndef NONUSE_SDL2
bool bMySDLTool_Inited = false;
#pragma comment(lib,"sdl2.lib")
#pragma comment(lib,"sdl2_ttf.lib")
#pragma comment(lib,"sdl2_mixer.lib")
#pragma comment(lib,"sdl2_image.lib")
#endif

//笔的输入顶点格式
const D3D11_INPUT_ELEMENT_DESC penIed[] =
{
    {"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},//"POSITION"是顶点着色器里的参数语义
    {"COLOR",0,DXGI_FORMAT_R8G8B8A8_UNORM,0,12u,D3D11_INPUT_PER_VERTEX_DATA,0},//"COLOR"是顶点着色器里的参数语义
};
//贴图笔的输入顶点格式
const D3D11_INPUT_ELEMENT_DESC tPenIed[] =
{
    {"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},//"POSITION"是顶点着色器里的参数语义
    {"COLOR",0,DXGI_FORMAT_R8G8B8A8_UNORM,0,12u,D3D11_INPUT_PER_VERTEX_DATA,0},//"COLOR"是顶点着色器里的参数语义
    {"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,16u,D3D11_INPUT_PER_VERTEX_DATA,0},//"TEXCOORD"是顶点着色器里的参数语义
};

void ErrorDescription(HRESULT hr, wchar_t* buff_max_path)
{
    if (FACILITY_WINDOWS == HRESULT_FACILITY(hr))
        hr = HRESULT_CODE(hr);
    wchar_t* szErrMsg;

    if (FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&szErrMsg, 0, NULL) != 0)
    {
        swprintf_s(buff_max_path, MAX_PATH, L"%s", szErrMsg);
        LocalFree(szErrMsg);
    }
    else
        swprintf_s(buff_max_path, MAX_PATH, L"[Could not find a description for error # %#x.]\n", hr); 
}

MyDX11Renderer::~MyDX11Renderer()
{
    CoUninitialize();
    if (pDevice)
        pDevice->Release();
    if (pDSS)
        pDSS->Release();
    if (pSamplerState_default)
        pSamplerState_default->Release();
    if (pBlendState_default)
        pBlendState_default->Release();
    if (pBlendState_add)
        pBlendState_add->Release();
    if (pRasterizerState_CullBack)
        pRasterizerState_CullBack->Release();
    if (pRasterizerState_CullNone)
        pRasterizerState_CullNone->Release();
    if (pSwap)
        pSwap->Release();
    if (pContext)
        pContext->Release();
    if (pRTV)
        pRTV->Release();
    if (pDST)
        pDST->Release();
    if (pDSV)
        pDSV->Release();
    if (penVertexShader)
        penVertexShader->Release();
    if (penVSBlob)
        penVSBlob->Release();
    if (penInputLayout)
        penInputLayout->Release();
    if (penPixelShader)
        penPixelShader->Release();
    if (penVertexBuffer)
        penVertexBuffer->Release();
    if (tPenVertexShader)
        tPenVertexShader->Release();
    if (tPenVSBlob)
        tPenVSBlob->Release();
    if (tPenInputLayout)
        tPenInputLayout->Release();
    if (tPenPixelShader)
        tPenPixelShader->Release();
    if (tPenVertexBuffer)
        tPenVertexBuffer->Release();
    if (penConstBuffer)
        penConstBuffer->Release();
    if (penConstBuffer2)
        penConstBuffer2->Release();
    if (lastSrc)
        delete lastSrc;
    if (lastDst)
        delete lastDst;
}
/*---------------------------------MyRenderer类-----------------------------------------------------*/
void MyDX11Renderer::Init(HWND hwnd)
{
    HRESULT hr = S_OK;
    this->hwnd = hwnd;
    lastSrc = new MyRect();
    lastDst = new MyRect();
    CoInitialize(nullptr);//运行多线程使用COM组件
    /*--------------------Direct3D11初始化--------------------------*/
    //创建设备、交换连、上下文
    DXGI_SWAP_CHAIN_DESC sd = {};
    sd.BufferDesc.Width = 0;
    sd.BufferDesc.Height = 0;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;//颜色格式
    sd.BufferDesc.RefreshRate.Numerator = 0;
    sd.BufferDesc.RefreshRate.Denominator = 0;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;//不使用抗锯齿
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = 1;
    sd.OutputWindow = hwnd;
    sd.Windowed = true;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags = 0;

    UINT creationFlags = 0;
#ifdef _DEBUG
    creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    hr = D3D11CreateDeviceAndSwapChain(
        nullptr,
        D3D_DRIVER_TYPE_HARDWARE,
        nullptr,
        creationFlags,
        nullptr,
        0,
        D3D11_SDK_VERSION,
        &sd,
        &pSwap,
        &pDevice,
        nullptr,
        &pContext);
    // 硬件模式失败时自动回退到WARP
    if (FAILED(hr))
    {
        D3D11CreateDeviceAndSwapChain(
            nullptr,
            D3D_DRIVER_TYPE_WARP,
            nullptr,
            creationFlags,
            nullptr,
            0,
            D3D11_SDK_VERSION,
            &sd,
            &pSwap,
            &pDevice,
            nullptr,
            &pContext);
    }
    //禁用alt+enter全屏切换
    IDXGIDevice* pDXGIDevice = nullptr;
    if (!FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&pDXGIDevice))))
    {
        IDXGIAdapter* pAdapter = nullptr;
        if (!FAILED(pDXGIDevice->GetParent(IID_PPV_ARGS(&pAdapter))))
        {
            IDXGIFactory* pDXGIFactory = nullptr;
            pAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory));
            pDXGIFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);
            if (pDXGIFactory)
                pDXGIFactory->Release();
        }
        if (pAdapter)
            pAdapter->Release();
    }
    if (pDXGIDevice)
        pDXGIDevice->Release();

    //创建深度模板状态
    MyCreateDSS(&pDSS);
    //创建采样器
    MyCreateSamplerState(&pSamplerState_default);
    //创建混合模式
    MyCreateBlendState(&pBlendState_default);
    MyCreateBlendState_AddMode(&pBlendState_add);
    //创建光栅模式
    MyCreateRasterizerState(&pRasterizerState_CullBack, D3D11_CULL_BACK);
    MyCreateRasterizerState(&pRasterizerState_CullNone, D3D11_CULL_NONE);
    //取窗口大小
    RECT rect;
    GetClientRect(hwnd, &rect);
    window_w = rect.right - rect.left;
    window_h = rect.bottom - rect.top;
    //取背后缓冲区
    ID3D11Texture2D* pSwapBuffer = nullptr;
    MYCHECK(pSwap->GetBuffer(0, IID_PPV_ARGS(&pSwapBuffer)));
    //创建渲染目标视图
    MyCreateRTV(&pRTV, pSwapBuffer);
    pSwapBuffer->Release();
    //设置深度模板状态
    pContext->OMSetDepthStencilState(pDSS, 1u);
    //创建深度模板贴图
    MyCreateDST(&pDST, window_w, window_h);
    //创建深度模板视图
    MyCreateDSV(&pDSV, pDST);
    //设置渲染目标
    ID3D11RenderTargetView* rtvArr = pRTV;
    pContext->OMSetRenderTargets(1u, &rtvArr, pDSV);
    //设置视口和裁剪矩形
    MySetVP(0, 0, (FLOAT)window_w, (FLOAT)window_h, 0, 1);
    SetScissorRect();
    //设置采样器
    SetSamplerState_Default();
    //设置混合模式
    SetBlendMode_Default();
    //设置光栅模式
    pContext->RSSetState(pRasterizerState_CullNone);
    //设置画笔的默认矩阵
    SetPenMVPDefault();
    //取消深度测试
    DrawEnableDSV(false);
    //初始化默认画笔着色器
    penVertexShader = penVertexShader_default = GetPenVertexShader();
    penPixelShader = penPixelShader_default = GetPenPixelShader();
    tPenVertexShader = tPenVertexShader_default = GetTPenVertexShader();
    tPenPixelShader = tPenPixelShader_default = GetTPenPixelShader();
    ZeroMemory(HSV, sizeof(HSV));
    /*-----------------------------SDL2辅助部分------------------------------------*/
#ifndef USING_SDL2
    if (bMySDLTool_Inited == false)
    {
        if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
        {
            MessageBox(hwnd, L"SDL2初始化失败", L"渲染器初始化失败", MB_ICONERROR);
            exit(0);
        }
        if (TTF_Init() != 0)
        {
            MessageBox(hwnd, L"SDL2_TTF初始化失败", L"渲染器初始化失败", MB_ICONERROR);
            exit(0);
        }
        if (Mix_Init(MIX_INIT_OGG) == 0)
        {
            MessageBox(hwnd, L"SDL2_MIX初始化失败", L"渲染器初始化失败", MB_ICONERROR);
            exit(0);
        }
        if (IMG_Init(IMG_INIT_PNG) == 0)
        {
            MessageBox(hwnd, L"SDL2_IMG初始化失败", L"渲染器初始化失败", MB_ICONERROR);
            exit(0);
        }
        bMySDLTool_Inited = true;
    }
#endif
}

HWND MyDX11Renderer::GetHwnd()
{
    return hwnd;
}

ID3D11Device* MyDX11Renderer::GetDevice()
{
    return pDevice;
}

ID3D11DeviceContext* MyDX11Renderer::GetContext()
{
    return pContext;
}

void MyDX11Renderer::OnSize(UINT w, UINT h, bool minimized)
{
    if ((w == window_w && h == window_h)
        || minimized
        || (pSwap == nullptr)
        || (w == 0)
        || (h == 0))
        return;
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    window_w = w;
    window_h = h;
    //取消渲染目标
    pContext->OMSetRenderTargets(0, NULL, NULL);
    if (pRTV)
    {
        pRTV->Release();
        pRTV = nullptr;
    }
    if (pDSV)
    {
        pDSV->Release();
        pDSV = nullptr;
    }
    if (pDSV)
    {
        pDSV->Release();
        pDSV = nullptr;
    }
    if (pDST)
    {
        pDST->Release();
        pDST = nullptr;
    }
    pContext->Flush();
    //取背后缓冲区
    ID3D11Resource* pSwapBuffer = nullptr;
    pSwap->ResizeBuffers(1, w, h, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
    MYCHECK(pSwap->GetBuffer(0, IID_PPV_ARGS(&pSwapBuffer)));
    //重新创建渲染目标视图
    MyCreateRTV(&pRTV, pSwapBuffer);
    pSwapBuffer->Release();
    //重新创建深度模板贴图
    MyCreateDST(&pDST, w, h);
    //重新创建深度模板视图
    MyCreateDSV(&pDSV, pDST);
    //重新设置渲染目标
    ID3D11RenderTargetView* rtvArr = pRTV;
    pContext->OMSetRenderTargets(1u, &rtvArr, enableDSV ? pDSV : nullptr);
    //重新设置视口和裁剪矩形
    MySetVP(0, 0, (FLOAT)w, (FLOAT)h, 0, 1);
    SetScissorRect();
    //调整笔的投影矩阵
    SetPenMVPDefault();
}

void MyDX11Renderer::GetWindowSize(UINT* w, UINT* h)
{
    if (w)
        *w = window_w;
    if (h)
        *h = window_h;
}

void MyDX11Renderer::MyDX11ShowError(HRESULT hr, const char* msg, int lineNum, const char* srcfile)
{
    wchar_t err_title[MAX_PATH];
    ErrorDescription(hr, err_title);

    char buff2[MAX_PATH];
    wchar_t err[MAX_PATH];
    sprintf_s(buff2, "在文件%s\n第%d行发生错误\n%s", srcfile, lineNum, msg);
    UTF8ToUTF16(buff2, err);
    MessageBoxW(hwnd, err, err_title, MB_ICONWARNING);
}

void MyDX11Renderer::RenderPresent()
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    MYCHECK(pSwap->Present(bVSync, 0));
    ScreenShot();
}

void MyDX11Renderer::RenderClear(float r, float g, float b, float a)
{
    const float color[] = { r,g,b,a };
    pContext->ClearRenderTargetView(pRTV, color);
    pContext->ClearDepthStencilView(pDSV, D3D11_CLEAR_DEPTH, 1.0f, 0);
}

void MyDX11Renderer::RenderClearRTV(ID3D11RenderTargetView* pRTV, float r, float g, float b, float a)
{
    const float color[] = { r,g,b,a };
    pContext->ClearRenderTargetView(pRTV, color);
}

void MyDX11Renderer::SetPenDraw()
{
    penVertexBuff.clear();
    //设置常量缓存
    auto constbuff = GetPenConstBuffer();
    pContext->VSSetConstantBuffers(0, 1, &constbuff);
    //设置顶点着色器
    pContext->VSSetShader(GetPenVertexShader(), NULL, 0);
    //设置顶点输入层
    pContext->IASetInputLayout(GetPenInputLayout());
    //设置像素着色器
    pContext->PSSetShader(GetPenPixelShader(), NULL, 0);
}

void MyDX11Renderer::AddVertex(const MyDX11PenVertex* vertex)
{
    penVertexBuff.push_back(*vertex);
}

void MyDX11Renderer::AddLine(const MyDX11PenVertex& v1, const MyDX11PenVertex& v2)
{
    AddLine(&v1, &v2);
}

void MyDX11Renderer::AddLine(const MyDX11PenVertex* v1, const MyDX11PenVertex* v2)
{
    penVertexBuff.push_back(*v1);
    penVertexBuff.push_back(*v2);
}

void MyDX11Renderer::AddRect(const MyRect* rect, DWORD c)
{
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->top, rect->z, c));
}

void MyDX11Renderer::DrawLine()
{
    if (penVertexBuff.empty())
        return;
    //取顶点缓存
    auto vertexbuff = GetPenVertexBuffer((UINT)penVertexBuff.size());
    //设置顶点数据
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(vertexbuff, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    //写入数据
    memcpy(ms.pData, penVertexBuff.data(), sizeof(MyDX11PenVertex) * penVertexBuff.size());
    pContext->Unmap(vertexbuff, 0);
    //设置顶点缓存
    UINT pStrides = sizeof(MyDX11PenVertex);
    UINT pOffset = 0;
    pContext->IASetVertexBuffers(0, 1, &vertexbuff, &pStrides, &pOffset);
    //设置图元拓扑
    pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
    //设置渲染目标视图
    DrawSetPenRTV();
    //绘制
    pContext->Draw((UINT)penVertexBuff.size(), 0);
}

void MyDX11Renderer::AddFillRect(const MyRect* rect, DWORD c)
{
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->top, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->right, rect->bottom, rect->z, c));
    penVertexBuff.push_back(MyDX11PenVertex(rect->left, rect->bottom, rect->z, c));
}

void MyDX11Renderer::DrawFillRect()
{
    if (penVertexBuff.empty())
        return;
    //取顶点缓存
    auto vertexbuff = GetPenVertexBuffer((UINT)penVertexBuff.size());
    //设置顶点数据
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(vertexbuff, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    //写入数据
    memcpy(ms.pData, penVertexBuff.data(), sizeof(MyDX11PenVertex) * penVertexBuff.size());
    pContext->Unmap(vertexbuff, 0);
    //设置顶点缓存
    UINT pStrides = sizeof(MyDX11PenVertex);
    UINT pOffset = 0;
    pContext->IASetVertexBuffers(0, 1, &vertexbuff, &pStrides, &pOffset);
    //设置图元拓扑
    pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    //设置渲染目标视图
    DrawSetPenRTV();
    //绘制
    pContext->Draw((UINT)penVertexBuff.size(), 0);
}

void MyDX11Renderer::SetTPenDraw(ID3D11ShaderResourceView* pTextureView, 
    ID3D11ShaderResourceView* pTextureView2,
    ID3D11ShaderResourceView* pTextureView3,
    ID3D11ShaderResourceView* pTextureView4)
{
    if (pTextureView)
    {
        //取贴图长宽尺寸
        ID3D11Resource* pRes;
        pTextureView->GetResource(&pRes);
        D3D11_TEXTURE2D_DESC desc;
        ID3D11Texture2D* pTexture;
        pRes->QueryInterface(&pTexture);
        pTexture->GetDesc(&desc);
        tPenTexture_w = (float)desc.Width;
        tPenTexture_h = (float)desc.Height;
        if (pRes)
            pRes->Release();
        if (pTexture)
            pTexture->Release();
    }
    else
    {
        tPenTexture_w = (float)window_w;
        tPenTexture_h = (float)window_h;
    }
    //清空顶点缓存
    tPenVertexBuff.clear();
    //设置顶点着色器常量缓存
    if (penConstBuffer2)
    {
        ID3D11Buffer* constbuff[2] = { GetPenConstBuffer() ,penConstBuffer2 };
        pContext->VSSetConstantBuffers(0, 2, constbuff);
    }
    else
    {
        auto constbuff = GetPenConstBuffer();
        pContext->VSSetConstantBuffers(0, 1, &constbuff);
    }
    //设置像素着色器常量缓存
    if (penConstBuffer2)
    {
        ID3D11Buffer* constbuff[2] = { GetPenConstBuffer() ,penConstBuffer2 };
        pContext->PSSetConstantBuffers(0, 2, constbuff);
    }
    else
    {
        auto constbuff = GetPenConstBuffer();
        pContext->PSSetConstantBuffers(0, 1, &constbuff);
    }
    //设置顶点着色器
    pContext->VSSetShader(GetTPenVertexShader(), NULL, 0);
    //设置顶点输入层
    pContext->IASetInputLayout(GetTPenInputLayout());
    //设置像素着色器
    pContext->PSSetShader(GetTPenPixelShader(), NULL, 0);
    //设置图元拓扑
    pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    //资源视图绑定到像素着色器上
    ID3D11ShaderResourceView* arr[4] = { pTextureView ,pTextureView2,pTextureView3,pTextureView4 };
    pContext->PSSetShaderResources(0, _countof(arr), arr);
}

void MyDX11Renderer::AddGeometry(const MyDX11TPenVertex* vertices, size_t num)
{
    for (size_t i = 0; i < num; i++)
        tPenVertexBuff.push_back(vertices[i]);
}

void MyDX11Renderer::AddRenderCopy(const MyRect* src, const MyRect* dst, DWORD c)
{
    //取贴图长宽尺寸
    MyRect settingSrc;
    MyRect settingDst;
    if (src)
        settingSrc = *src;
    else
    {
        settingSrc.left = settingSrc.top = 0;
        settingSrc.right = tPenTexture_w;
        settingSrc.bottom = tPenTexture_h;
    }
    if (dst)
        settingDst = *dst;
    else
    {
        settingDst.left = settingDst.top = 0;
        settingDst.right = (float)window_w;
        settingDst.bottom = (float)window_h;
    }
    //uv渲染偏移 防止渲染到相邻的uv图案
    settingSrc.right -= 0.01f;
    settingSrc.bottom -= 0.01f;
    settingSrc.left += 0.01f;
    settingSrc.top += 0.01f;
    *lastSrc = settingSrc;
    *lastDst = settingDst;
    //设置顶点数据(顺时针)
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.left, settingDst.top, settingDst.z, c, (float)settingSrc.left / tPenTexture_w, (float)settingSrc.top / tPenTexture_h));
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.right, settingDst.top, settingDst.z, c, (float)settingSrc.right / tPenTexture_w, (float)settingSrc.top / tPenTexture_h));
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.right, settingDst.bottom, settingDst.z, c, (float)settingSrc.right / tPenTexture_w, (float)settingSrc.bottom / tPenTexture_h));
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.left, settingDst.top, settingDst.z, c, (float)settingSrc.left / tPenTexture_w, (float)settingSrc.top / tPenTexture_h));
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.right, settingDst.bottom, settingDst.z, c, (float)settingSrc.right / tPenTexture_w, (float)settingSrc.bottom / tPenTexture_h));
    tPenVertexBuff.push_back(MyDX11TPenVertex(settingDst.left, settingDst.bottom, settingDst.z, c, (float)settingSrc.left / tPenTexture_w, (float)settingSrc.bottom / tPenTexture_h));
}

void MyDX11Renderer::DrawRenderCopy()
{
    if (tPenVertexBuff.empty())
        return;
    //取顶点缓存
    auto vertexbuff = GetTPenVertexBuffer((UINT)tPenVertexBuff.size());
    //设置顶点数据
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(vertexbuff, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    //写入数据
    memcpy(ms.pData, tPenVertexBuff.data(), sizeof(MyDX11TPenVertex) * tPenVertexBuff.size());
    pContext->Unmap(vertexbuff, 0);
    //设置顶点缓存
    UINT pStrides = sizeof(MyDX11TPenVertex);
    UINT pOffset = 0;
    pContext->IASetVertexBuffers(0, 1, &vertexbuff, &pStrides, &pOffset);
    //设置渲染目标视图
    DrawSetPenRTV();
    //绘制
    pContext->Draw((UINT)tPenVertexBuff.size(), 0);
}

void MyDX11Renderer::GetRenderCopyDefaultRect(ID3D11ShaderResourceView* pTextureView, MyRect* outSrc, MyRect* outDst)
{
    ID3D11Resource* pRes;
    pTextureView->GetResource(&pRes);
    D3D11_TEXTURE2D_DESC desc;
    ID3D11Texture2D* pTexture;
    pRes->QueryInterface(&pTexture);
    pTexture->GetDesc(&desc);
    float texture_w = (float)desc.Width;
    float texture_h = (float)desc.Height;
    if (outSrc)
    {
        auto& settingSrc = outSrc;
        settingSrc->left = settingSrc->top = 0;
        settingSrc->right = texture_w;
        settingSrc->bottom = texture_h;
    }
    if (outDst)
    {
        auto& settingDst = outDst;
        settingDst->left = settingDst->top = 0;
        settingDst->right = (float)window_w;
        settingDst->bottom = (float)window_h;
    }
    if (pRes)
        pRes->Release();
    if (pTexture)
        pTexture->Release();
}

void MyDX11Renderer::MySetVP(FLOAT offx, FLOAT offy, FLOAT width, FLOAT height, FLOAT minDepth, FLOAT maxDepth)
{
    D3D11_VIEWPORT vp;
    vp.TopLeftX = offx;
    vp.TopLeftY = offy;
    vp.Width = width;
    vp.Height = height;
    vp.MinDepth = minDepth;
    vp.MaxDepth = maxDepth;
    pContext->RSSetViewports(1u, &vp);
}

void MyDX11Renderer::DrawEnableDSV(bool enable)
{
    ID3D11RenderTargetView* rtvArr = pRTV;
    if (enable)
        pContext->OMSetRenderTargets(1u, &rtvArr, pDSV);
    else
        pContext->OMSetRenderTargets(1u, &rtvArr, nullptr);
    enableDSV = enable;
}

void MyDX11Renderer::DrawEnableBackCull(bool enable)
{
    if (enable)
        pContext->RSSetState(pRasterizerState_CullBack);
    else
        pContext->RSSetState(pRasterizerState_CullNone);
}

void MyDX11Renderer::SetPenRTV(ID3D11RenderTargetView* pPenRTV)
{
    this->pPenRTV = pPenRTV;
    //显式清除绑定
    ClearRenderResourceBind();
}

ID3D11RenderTargetView* MyDX11Renderer::GetPenRTV()
{
    return pPenRTV;
}

void MyDX11Renderer::SetClipVpMVP(FLOAT width, FLOAT height)
{
    MyRect rc;
    rc.Set1(0, 0, width, height);
    SetScissorRect(&rc);
    MySetVP(0, 0, width, height, 0, 1);
    penMVP = XMMatrixOrthographicOffCenterLH(0, width, height, 0, -10000, 10000);
}

void MyDX11Renderer::ResetClipVpMVP()
{
    SetScissorRect();
    MySetVP(0, 0, (float)window_w, (float)window_h, 0, 1);
    penMVP = XMMatrixOrthographicOffCenterLH(0, (float)window_w, (float)window_h, 0, -10000, 10000);
}

HRESULT MyDX11Renderer::CompileShaderFromFile(const WCHAR* szFileName, const D3D_SHADER_MACRO* defines, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
    if (!szFileName || !szEntryPoint || !szShaderModel || !ppBlobOut)
        return E_INVALIDARG;

    *ppBlobOut = nullptr;

    UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
    flags |= D3DCOMPILE_DEBUG;
#endif

    ID3DBlob* shaderBlob = nullptr;
    ID3DBlob* errorBlob = nullptr;
    HRESULT hr = D3DCompileFromFile(szFileName, defines, D3D_COMPILE_STANDARD_FILE_INCLUDE,
        szEntryPoint, szShaderModel,
        flags, 0, &shaderBlob, &errorBlob);
    if (FAILED(hr))
    {
        if (errorBlob != NULL)
        {
            char name[MAX_PATH];
            WideCharToMultiByte(CP_ACP, 0, szFileName, -1, name, _countof(name), 0, 0);

            char title[MAX_PATH];
            sprintf_s(title, "%s着色器编译错误", name);
            MessageBoxA(nullptr, (char*)errorBlob->GetBufferPointer(), title, MB_ICONWARNING);
        }
        if (errorBlob)
            errorBlob->Release();
        return hr;
    }
    if (errorBlob)
        errorBlob->Release();
    *ppBlobOut = shaderBlob;
    return S_OK;
}

void MyDX11Renderer::MyCreateRTV(ID3D11RenderTargetView** outRTV, ID3D11Resource* pTexture)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    //创建渲染目标视图
    MYCHECK(pDevice->CreateRenderTargetView(pTexture, nullptr, outRTV));
}

void MyDX11Renderer::MyCreateDSS(ID3D11DepthStencilState** outDSS)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_DEPTH_STENCIL_DESC dsDesc = {};
    dsDesc.DepthEnable = TRUE;
    dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
    //创建深度模板状态
    MYCHECK(pDevice->CreateDepthStencilState(&dsDesc, outDSS));
}

void MyDX11Renderer::MyCreateDST(ID3D11Texture2D** outDST, UINT width, UINT height)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_TEXTURE2D_DESC descDepth = {};
    descDepth.Width = width;
    descDepth.Height = height;
    descDepth.MipLevels = 1u;
    descDepth.ArraySize = 1u;
    descDepth.Format = DXGI_FORMAT_D32_FLOAT;
    descDepth.SampleDesc.Count = 1u;
    descDepth.SampleDesc.Quality = 0u;
    descDepth.Usage = D3D11_USAGE_DEFAULT;
    descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    //创建深度模板贴图
    MYCHECK(pDevice->CreateTexture2D(&descDepth, nullptr, outDST));
}

void MyDX11Renderer::MyCreateDSV(ID3D11DepthStencilView** outDSV, ID3D11Texture2D* pDST)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
    descDSV.Format = DXGI_FORMAT_D32_FLOAT;
    descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0u;
    //创建深度模板视图
    MYCHECK(pDevice->CreateDepthStencilView(pDST, &descDSV, outDSV));
}

void MyDX11Renderer::MyCreateVertexBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT structSize, UINT Offset, D3D11_USAGE Usage, UINT CPUAccessFlags)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_BUFFER_DESC bd = {};
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.Usage = Usage;//GPU可读写
    bd.CPUAccessFlags = CPUAccessFlags;
    bd.MiscFlags = 0u;
    bd.ByteWidth = allSize;
    bd.StructureByteStride = structSize;
    //子资源数据说明
    D3D11_SUBRESOURCE_DATA sd = {};
    sd.pSysMem = data;
    //创建顶点缓存
    MYCHECK(pDevice->CreateBuffer(&bd, &sd, outBuffer));
}

void MyDX11Renderer::MyCreateIndexBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT structSize, D3D11_USAGE Usage, UINT CPUAccessFlags)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_BUFFER_DESC ibd = {};
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.Usage = Usage;//GPU可读写
    ibd.CPUAccessFlags = CPUAccessFlags;
    ibd.MiscFlags = 0u;
    ibd.ByteWidth = allSize;
    ibd.StructureByteStride = structSize;
    //子资源数据说明
    D3D11_SUBRESOURCE_DATA isd = {};
    isd.pSysMem = data;
    //创建顶点索引缓存
    MYCHECK(pDevice->CreateBuffer(&ibd, &isd, outBuffer));
}

void MyDX11Renderer::MyCreateConstBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT StartSlot, D3D11_USAGE Usage, UINT CPUAccessFlags)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_BUFFER_DESC cbd = {};
    cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    cbd.Usage = Usage;
    cbd.CPUAccessFlags = CPUAccessFlags;
    cbd.MiscFlags = 0u;
    cbd.ByteWidth = allSize;
    cbd.StructureByteStride = 0u;
    //子资源数据说明
    D3D11_SUBRESOURCE_DATA csd = {};
    csd.pSysMem = data;
    //创建常量缓存
    MYCHECK(pDevice->CreateBuffer(&cbd, &csd, outBuffer));
}

void MyDX11Renderer::MyCreateVertexShader(ID3D11VertexShader** outVertexShader, const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob, const char* mode)
{
    HRESULT hr;
    wchar_t wstr[MAX_PATH];
    UTF8ToUTF16(hlslfile, wstr);
    //创建顶点着色器
    ID3DBlob* pBlob;
    static const D3D_SHADER_MACRO defines[] =
    {
        "VERTEXSHADER",NULL,
            NULL, NULL
    };
    hr = CompileShaderFromFile(wstr, defines, mainFuncName, mode, &pBlob);
    if (pBlob == nullptr)
    {
        wchar_t err[MAX_PATH];
        swprintf_s(err, L"编译着色器失败：%s", wstr);
        wchar_t err_title[MAX_PATH];
        ErrorDescription(hr, err_title);
        MessageBoxW(hwnd, err, err_title, MB_ICONWARNING);
        exit(0);
    }
    MYCHECK(pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, outVertexShader));
    if (outBlob)
        *outBlob = pBlob;
    else
        pBlob->Release();
}

void MyDX11Renderer::MyCreateInputLayout(ID3D11InputLayout** outInputLayout, const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, ID3DBlob* pVSBlob)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    //创建顶点输入层
    MYCHECK(pDevice->CreateInputLayout(pInputElementDescs, NumElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), outInputLayout));
}

void MyDX11Renderer::MyCreatePixelShader(ID3D11PixelShader** outPixelShader,const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob, const char* mode)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    wchar_t wstr[MAX_PATH];
    UTF8ToUTF16(hlslfile, wstr);
    //创建像素着色器
    ID3DBlob* pBlob;
    static const D3D_SHADER_MACRO defines[] =
    {
        "PIXELSHADER",NULL,
            NULL, NULL
    };
    CompileShaderFromFile(wstr, defines, mainFuncName, mode, &pBlob);
    MYCHECK(pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, outPixelShader));
    pBlob->Release();
    if (outBlob)
        *outBlob = pBlob;
    else
        pBlob->Release();
}

void MyDX11Renderer::MyCreateSamplerState(ID3D11SamplerState** outSamplerState)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_SAMPLER_DESC samplerDesc = {};
    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    MYCHECK(pDevice->CreateSamplerState(&samplerDesc, outSamplerState));
}

void MyDX11Renderer::MyCreateBlendState(ID3D11BlendState** outBlendState)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_BLEND_DESC bd = {};
    auto& brt = bd.RenderTarget[0];
    brt.BlendEnable = TRUE;

    //src * (src.a) + dst * (1- src.a)
    brt.SrcBlend = D3D11_BLEND_SRC_ALPHA;
    brt.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    brt.BlendOp = D3D11_BLEND_OP_ADD;
    brt.SrcBlendAlpha = D3D11_BLEND_ONE;
    brt.DestBlendAlpha = D3D11_BLEND_ONE;
    brt.BlendOpAlpha = D3D11_BLEND_OP_ADD;

    brt.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    MYCHECK(pDevice->CreateBlendState(&bd, outBlendState));
}

void MyDX11Renderer::MyCreateBlendState_AddMode(ID3D11BlendState** outBlendState)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_BLEND_DESC bd = {};
    auto& brt = bd.RenderTarget[0];
    brt.BlendEnable = TRUE;
    brt.SrcBlend = D3D11_BLEND_ONE;
    brt.DestBlend = D3D11_BLEND_ONE;
    brt.BlendOp = D3D11_BLEND_OP_ADD;
    brt.SrcBlendAlpha = D3D11_BLEND_ONE;
    brt.DestBlendAlpha = D3D11_BLEND_ONE;
    brt.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    brt.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    MYCHECK(pDevice->CreateBlendState(&bd, outBlendState));
}

void MyDX11Renderer::MyCreateRasterizerState(ID3D11RasterizerState** outRasterizerState, D3D11_CULL_MODE cullMode)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT{});
    rd.CullMode = cullMode;
    rd.ScissorEnable = true;//启用剪切矩形
    MYCHECK(pDevice->CreateRasterizerState(&rd, outRasterizerState));
}

void MyDX11Renderer::MyCreateComputeShader(ID3D11ComputeShader** outComputeShader, const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob, const char* mode)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    wchar_t wstr[MAX_PATH];
    UTF8ToUTF16(hlslfile, wstr);
    //创建像素着色器
    ID3DBlob* pBlob;
    static const D3D_SHADER_MACRO defines[] =
    {
        "COMPUTESHADER",NULL,
            NULL, NULL
    };
    CompileShaderFromFile(wstr, defines, mainFuncName, mode, &pBlob);
    MYCHECK(pDevice->CreateComputeShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, outComputeShader));
    pBlob->Release();
    if (outBlob)
        *outBlob = pBlob;
    else
        pBlob->Release();
}

struct WICTranslate
{
    GUID wic;
    DXGI_FORMAT format;
};

static WICTranslate g_WICFormats[] =
{//WIC格式与DXGI像素格式的对应表，该表中的格式为被支持的格式
    { GUID_WICPixelFormat128bppRGBAFloat,       DXGI_FORMAT_R32G32B32A32_FLOAT },

    { GUID_WICPixelFormat64bppRGBAHalf,         DXGI_FORMAT_R16G16B16A16_FLOAT },
    { GUID_WICPixelFormat64bppRGBA,             DXGI_FORMAT_R16G16B16A16_UNORM },

    { GUID_WICPixelFormat32bppRGBA,             DXGI_FORMAT_R8G8B8A8_UNORM },
    { GUID_WICPixelFormat32bppBGRA,             DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
    { GUID_WICPixelFormat32bppBGR,              DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1

    { GUID_WICPixelFormat32bppRGBA1010102XR,    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
    { GUID_WICPixelFormat32bppRGBA1010102,      DXGI_FORMAT_R10G10B10A2_UNORM },

    { GUID_WICPixelFormat16bppBGRA5551,         DXGI_FORMAT_B5G5R5A1_UNORM },
    { GUID_WICPixelFormat16bppBGR565,           DXGI_FORMAT_B5G6R5_UNORM },

    { GUID_WICPixelFormat32bppGrayFloat,        DXGI_FORMAT_R32_FLOAT },
    { GUID_WICPixelFormat16bppGrayHalf,         DXGI_FORMAT_R16_FLOAT },
    { GUID_WICPixelFormat16bppGray,             DXGI_FORMAT_R16_UNORM },
    { GUID_WICPixelFormat8bppGray,              DXGI_FORMAT_R8_UNORM },

    { GUID_WICPixelFormat8bppAlpha,             DXGI_FORMAT_A8_UNORM },
};

// WIC 像素格式转换表.
struct WICConvert
{
    GUID source;
    GUID target;
};

static WICConvert g_WICConvert[] =
{
    // 目标格式一定是最接近的被支持的格式
    { GUID_WICPixelFormatBlackWhite,            GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM

    { GUID_WICPixelFormat1bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat2bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat4bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat8bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM

    { GUID_WICPixelFormat2bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
    { GUID_WICPixelFormat4bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM

    { GUID_WICPixelFormat16bppGrayFixedPoint,   GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
    { GUID_WICPixelFormat32bppGrayFixedPoint,   GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT

    { GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM

    { GUID_WICPixelFormat32bppBGR101010,        GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM

    { GUID_WICPixelFormat24bppBGR,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat24bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat32bppPBGRA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat32bppPRGBA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM

    { GUID_WICPixelFormat48bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat48bppBGR,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat64bppBGRA,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat64bppPRGBA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat64bppPBGRA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM

    { GUID_WICPixelFormat48bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat48bppBGRFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat64bppRGBAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat64bppBGRAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat64bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat48bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
    { GUID_WICPixelFormat64bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT

    { GUID_WICPixelFormat128bppPRGBAFloat,      GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
    { GUID_WICPixelFormat128bppRGBFloat,        GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
    { GUID_WICPixelFormat128bppRGBAFixedPoint,  GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
    { GUID_WICPixelFormat128bppRGBFixedPoint,   GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
    { GUID_WICPixelFormat32bppRGBE,             GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT

    { GUID_WICPixelFormat32bppCMYK,             GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat64bppCMYK,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat40bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat80bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM

    { GUID_WICPixelFormat32bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
    { GUID_WICPixelFormat64bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
    { GUID_WICPixelFormat64bppPRGBAHalf,        GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
};

bool GetTargetPixelFormat(const GUID* pSourceFormat, GUID* pTargetFormat)
{//查表确定兼容的最接近格式是哪个
    *pTargetFormat = *pSourceFormat;
    for (size_t i = 0; i < _countof(g_WICConvert); ++i)
    {
        if (InlineIsEqualGUID(g_WICConvert[i].source, *pSourceFormat))
        {
            *pTargetFormat = g_WICConvert[i].target;
            return true;
        }
    }
    return false;
}

DXGI_FORMAT GetDXGIFormatFromPixelFormat(const GUID* pPixelFormat)
{//查表确定最终对应的DXGI格式是哪一个
    for (size_t i = 0; i < _countof(g_WICFormats); ++i)
    {
        if (InlineIsEqualGUID(g_WICFormats[i].wic, *pPixelFormat))
        {
            return g_WICFormats[i].format;
        }
    }
    return DXGI_FORMAT_UNKNOWN;
}

void MyDX11Renderer::MyLoadTexture(ID3D11Texture2D** outTexture, const char* filename, int* outW, int* outH)
{
#ifndef USING_SDL2
    //优先使用SDL2辅助载入
    auto sur = IMG_Load(filename);
    if (sur)
    {
        MyCreateTextureFromSDLSurface(outTexture, sur);
        if (outW)
            *outW = sur->w;
        if (outH)
            *outH = sur->h;
        SDL_FreeSurface(sur);
        return;
    }
#endif
    wchar_t wstr[MAX_PATH];
    UTF8ToUTF16(filename, wstr);

    wchar_t errorTitle[MAX_PATH];
    swprintf_s(errorTitle, L"加载纹理%s失败", wstr);

    //确认文件是否存在
    FILE* fp;
    fopen_s(&fp, filename, "rb");
    if (fp)
        fclose(fp);
    else
    {
        wchar_t errorinfo[MAX_PATH];
        swprintf_s(errorinfo, L"无法读取文件%s", wstr);
        MessageBoxW(hwnd, errorinfo, errorTitle, MB_ICONWARNING);
        return;
    }

    //1.创建WIC工厂
    IWICImagingFactory* pIWICFactory = nullptr;//WIC工厂
    if (FAILED(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICFactory))))
        MessageBoxW(hwnd, L"WIC工厂创建失败", errorTitle, MB_ICONWARNING);

    //2.创建解码器
    IWICBitmapDecoder* pIWICDecoder = nullptr;//解码器
    if (FAILED(pIWICFactory->CreateDecoderFromFilename(
        wstr,                            // 文件名
        NULL,                            // 不指定解码器，使用默认
        GENERIC_READ,                    // 访问权限
        WICDecodeMetadataCacheOnDemand,  // 若需要就缓冲数据 
        &pIWICDecoder                    // 解码器对象
    )))
        MessageBoxW(hwnd, L"图片解码器创建失败", errorTitle, MB_ICONWARNING);
    
    //3.取图片的第index帧
    IWICBitmapFrameDecode* pIWICFrame = nullptr;
    if (FAILED(pIWICDecoder->GetFrame(0, &pIWICFrame)))
        MessageBoxW(hwnd, L"图片编码器取第一帧失败", errorTitle, MB_ICONWARNING);

    //4.取图片的WIC格式
    WICPixelFormatGUID wpf = {};
    if (FAILED(pIWICFrame->GetPixelFormat(&wpf)))
        MessageBoxW(hwnd, L"获取图片格式失败", errorTitle, MB_ICONWARNING);


    //5.转换成等价的DXGI格式
    GUID tgFormat = {};
    DXGI_FORMAT texture_format = DXGI_FORMAT_UNKNOWN;
    if (GetTargetPixelFormat(&wpf, &tgFormat))
        texture_format = GetDXGIFormatFromPixelFormat(&tgFormat);
    if (texture_format == DXGI_FORMAT_UNKNOWN)
    {
        //再次搜索
        for (size_t i = 0; i < _countof(g_WICFormats); i ++)
        {
            if (g_WICFormats[i].wic == tgFormat)
            {
                texture_format = g_WICFormats[i].format;
                break;
            }
        }
    }
    if (texture_format == DXGI_FORMAT_UNKNOWN)
        MessageBoxW(hwnd, L"不支持的图片格式", errorTitle, MB_ICONWARNING);
    //6.将图片转换为位图格式
    IWICBitmapSource* pIBMP = nullptr;
    if (!InlineIsEqualGUID(wpf, tgFormat))
    {
        //如果原WIC格式不是直接能转换为DXGI格式的图片时
        //需要做的就是转换图片格式为能够直接对应DXGI格式的形式
        //创建图片格式转换器
        IWICFormatConverter* pIConverter = nullptr;
        if (FAILED(pIWICFactory->CreateFormatConverter(&pIConverter)))
            MessageBoxW(hwnd, L"图片格式转换器创建失败", errorTitle, MB_ICONWARNING);

        //初始化一个图片转换器，实际也就是将图片数据进行了格式转换
        if (FAILED(pIConverter->Initialize(
            pIWICFrame,                // 输入原图片数据
            tgFormat,						 // 指定待转换的目标格式
            WICBitmapDitherTypeNone,         // 指定位图是否有调色板，现代都是真彩位图，不用调色板，所以为None
            NULL,                            // 指定调色板指针
            0.f,                             // 指定Alpha阀值
            WICBitmapPaletteTypeCustom       // 调色板类型，实际没有使用，所以指定为Custom
        )))
            MessageBoxW(hwnd, L"图片格式转换失败", errorTitle, MB_ICONWARNING);
        // 调用QueryInterface方法获得对象的位图数据源接口
        if (FAILED(pIConverter->QueryInterface(&pIBMP)))
            MessageBoxW(hwnd, L"输出到位图失败", errorTitle, MB_ICONWARNING);
        if (pIConverter)
            pIConverter->Release();
    }
    else
    {
        //图片数据格式不需要转换，直接获取其位图数据源接口
        if (FAILED(pIWICFrame->QueryInterface(&pIBMP)))
            MessageBoxW(hwnd, L"输出到位图失败", errorTitle, MB_ICONWARNING);
    }

    //7.获得图片大小
    UINT texture_w = 0u, texture_h = 0u;
    if (FAILED(pIBMP->GetSize(&texture_w, &texture_h)))
        MessageBoxW(hwnd, L"获得图片大小失败", errorTitle, MB_ICONWARNING);

    //8.创建组件信息提取器
    IWICComponentInfo* pIWICmntinfo = nullptr;
    if (FAILED(pIWICFactory->CreateComponentInfo(tgFormat, &pIWICmntinfo)))
        MessageBoxW(hwnd, L"创建组件信息提取器失败", errorTitle, MB_ICONWARNING);

    //9.取组件信息提取器类型
    WICComponentType type;
    if (FAILED(pIWICmntinfo->GetComponentType(&type)))
        MessageBoxW(hwnd, L"取组件类型失败", errorTitle, MB_ICONWARNING);
    if (type != WICPixelFormat)
        MessageBoxW(hwnd, L"这不是一个像素信息提取器", errorTitle, MB_ICONWARNING);

    //10.提取像素信息
    IWICPixelFormatInfo* pIWICPixelinfo = nullptr;
    if (FAILED(pIWICmntinfo->QueryInterface(&pIWICPixelinfo)))
        MessageBoxW(hwnd, L"取像素信息失败", errorTitle, MB_ICONWARNING);

    //11.取BPP
    UINT nBPP = 0u;
    if (FAILED(pIWICPixelinfo->GetBitsPerPixel(&nBPP)))
        MessageBoxW(hwnd, L"取BPP信息失败", errorTitle, MB_ICONWARNING);

    //12.分配内存从图片读取信息
    UINT nPicRowPitch = (texture_w * nBPP + 7u) / 8u;
    std::vector<BYTE> data;
    data.resize(nPicRowPitch * texture_h);
    if (FAILED(pIBMP->CopyPixels(nullptr,
        nPicRowPitch,
        nPicRowPitch * texture_h,   //注意这里才是图片数据真实的大小，这个值通常小于缓冲的大小,
        data.data())))
        MessageBoxW(hwnd, L"从图片中读取出数据失败", errorTitle, MB_ICONWARNING);
    
    //13.创建贴图资源
    D3D11_TEXTURE2D_DESC textureDesc = {};
    textureDesc.Width = texture_w;
    textureDesc.Height = texture_h;
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = texture_format;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Usage = D3D11_USAGE_IMMUTABLE;//GPU读写
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;//所有着色器可见
    textureDesc.CPUAccessFlags = 0;
    textureDesc.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA sd = {};
    sd.pSysMem = data.data();
    sd.SysMemPitch = nPicRowPitch;
    if (FAILED(pDevice->CreateTexture2D(&textureDesc, &sd, outTexture)))
        MessageBoxW(hwnd, L"创建贴图资源失败", errorTitle, MB_ICONWARNING);
    if (outW)
        *outW = texture_w;
    if (outH)
        *outH = texture_h;
    //清除数据
    if (pIWICFactory)
        pIWICFactory->Release();
    if (pIWICDecoder)
        pIWICDecoder->Release();
    if (pIWICFrame)
        pIWICFrame->Release();
    if (pIBMP)
        pIBMP->Release();
    if (pIWICmntinfo)
        pIWICmntinfo->Release();
    if (pIWICPixelinfo)
        pIWICPixelinfo->Release();
}

void MyDX11Renderer::MySaveTexture(ID3D11Texture2D* pTexture, const char* filename)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    //创建读回贴图
    D3D11_TEXTURE2D_DESC textureDesc;
    pTexture->GetDesc(&textureDesc);
    ID3D11Texture2D* readbackTexture = nullptr;
    MyCreateTexture(&readbackTexture, textureDesc.Width, textureDesc.Height, textureDesc.Format, D3D11_USAGE_STAGING, 0, D3D11_CPU_ACCESS_READ);//创建一个读回贴图
    pContext->CopyResource(readbackTexture, pTexture);
    //读取原贴图数据
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(readbackTexture, 0, D3D11_MAP_READ, 0, &ms);
    size_t pngSize = textureDesc.Height * ms.RowPitch;
    std::vector<BYTE> surfaceData;
    surfaceData.resize(pngSize);
    memcpy(surfaceData.data(), ms.pData, pngSize);
    pContext->Unmap(readbackTexture, 0);
    //释放读回贴图
    if (readbackTexture)
        readbackTexture->Release();

    //保存为PNG文件
    wchar_t wstr[MAX_PATH];
    UTF8ToUTF16(filename, wstr);
    wchar_t errorTitle[MAX_PATH];
    swprintf_s(errorTitle, L"加载纹理%s失败", wstr);

     //1.创建WIC工厂
    IWICImagingFactory* pIWICFactory = nullptr;//WIC工厂
    MYCHECK(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICFactory)));
    //2.创建位图
    IWICBitmap* pIWICBitmap = nullptr;
    MYCHECK(pIWICFactory->CreateBitmap(textureDesc.Width, textureDesc.Height, GUID_WICPixelFormat32bppRGBA, WICBitmapCacheOnLoad, &pIWICBitmap));
    IWICBitmapLock* pLock = nullptr;
    MYCHECK(pIWICBitmap->Lock(nullptr, WICBitmapLockWrite, &pLock));
    UINT strideSize;
    MYCHECK(pLock->GetStride(&strideSize));//取一行的尺寸
    WICInProcPointer pCopyDst;
    UINT dstSize;
    MYCHECK(pLock->GetDataPointer(&dstSize, &pCopyDst));
    for (size_t y = 0; y < textureDesc.Height; y++)
        memcpy(pCopyDst + y * strideSize, surfaceData.data() + y * ms.RowPitch, strideSize);
    if (pLock)
        pLock->Release();
    //3.创建输出流
    IWICStream* pIWICStream = nullptr;
    MYCHECK(pIWICFactory->CreateStream(&pIWICStream));
    MYCHECK(pIWICStream->InitializeFromFilename(wstr, GENERIC_WRITE));
    //4.创建编码器
    IWICBitmapEncoder* pIWICBitmapEncoder = nullptr;//解码器
    MYCHECK(pIWICFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &pIWICBitmapEncoder));
    MYCHECK(pIWICBitmapEncoder->Initialize(pIWICStream, WICBitmapEncoderNoCache));
    //5.创建位图编码器
    IWICBitmapFrameEncode* pIWICFrameEncoder = nullptr;
    MYCHECK(pIWICBitmapEncoder->CreateNewFrame(&pIWICFrameEncoder, NULL));
    MYCHECK(pIWICFrameEncoder->Initialize(nullptr));
    MYCHECK(pIWICFrameEncoder->SetSize(textureDesc.Width, textureDesc.Height));
    WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
    MYCHECK(pIWICFrameEncoder->SetPixelFormat(&format));
    //6.写入数据并提交
    MYCHECK(pIWICFrameEncoder->WriteSource(pIWICBitmap, nullptr));
    MYCHECK(pIWICFrameEncoder->Commit());
    MYCHECK(pIWICBitmapEncoder->Commit());

    //清除数据
    if (pIWICFactory)
        pIWICFactory->Release();
    if (pIWICBitmap)
        pIWICBitmap->Release();
    if (pIWICStream)
        pIWICStream->Release();
    if (pIWICBitmapEncoder)
        pIWICBitmapEncoder->Release();
    if (pIWICFrameEncoder)
        pIWICFrameEncoder->Release();
}

void MyDX11Renderer::MyCreateTexture(ID3D11Texture2D** outTexture, UINT width, UINT height, DXGI_FORMAT Format, D3D11_USAGE Usage, UINT BindFlags, UINT CPUAccessFlags, UINT MiscFlags)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    //13.创建贴图资源
    D3D11_TEXTURE2D_DESC textureDesc = {};
    textureDesc.Width = width;
    textureDesc.Height = height;
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = Format;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Usage = Usage;//不可变数据GPU只读
    textureDesc.BindFlags = BindFlags;//所有着色器可见
    textureDesc.CPUAccessFlags = CPUAccessFlags;
    textureDesc.MiscFlags = MiscFlags;//跨设备的共享纹理
    MYCHECK(pDevice->CreateTexture2D(&textureDesc,nullptr, outTexture));
}

void MyDX11Renderer::MyCreateShaderResourceView(ID3D11ShaderResourceView** outSRV, ID3D11Texture2D* pTexture)
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    D3D11_TEXTURE2D_DESC textureDesc;
    pTexture->GetDesc(&textureDesc);
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Format = textureDesc.Format;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MostDetailedMip = 0;
    srvDesc.Texture2D.MipLevels = 1;
    MYCHECK(pDevice->CreateShaderResourceView(pTexture, &srvDesc, outSRV));
}

const char* MyLoadFontTexture_ReadField(const char* text, const char* fieldName,int* outVal)
{
    if (text == nullptr)
        return nullptr;
    char intbuff[16];
    const char* ptr = strstr(text, fieldName);
    if (ptr == nullptr)
        return 0;
    ptr += strlen(fieldName) + 1;//跳过一个等于号
    //取下一个空格的位置
    const char *p_r, *p_n, *p_sp;//"\r""\n""space"
    p_r = strchr(ptr, '\r');
    if (p_r == nullptr)
        p_r = (const char*)UINT64_MAX;
    p_n = strchr(ptr, '\n');
    if (p_n == nullptr)
        p_n = (const char*)UINT64_MAX;
    p_sp = strchr(ptr, ' ');
    if (p_sp == nullptr)
        p_sp = (const char*)UINT64_MAX;
    const char* nextPtr = min(min(p_r, p_n), p_sp);
    if (nextPtr == (const char*)UINT64_MAX)
        return nullptr;
    int intLen = (int)(nextPtr - ptr);
    strncpy_s(intbuff, ptr, intLen);
    sscanf_s(intbuff, "%d", outVal);
    return nextPtr;
}

ID3D11VertexShader* MyDX11Renderer::GetPenVertexShader()
{
    if (penVertexShader == nullptr)
    {
        if (penVSBlob)
            penVSBlob->Release();
        MyCreateVertexShader(&penVertexShader, MYDX11RENDERER_PENSHADER_PATH, "VSMain", &penVSBlob);
    }
    return penVertexShader;
}

void MyDX11Renderer::SetPenVertexShader(ID3D11VertexShader* penVertexShader)
{
    if (penVertexShader)
        this->penVertexShader = penVertexShader;
    else
        this->penVertexShader = penVertexShader_default;
}

ID3D11InputLayout* MyDX11Renderer::GetPenInputLayout()
{
    if (penInputLayout == nullptr)
    {
        if (penVSBlob)
            MyCreateInputLayout(&penInputLayout, penIed, _countof(penIed), penVSBlob);
    }
    return penInputLayout;
}

ID3D11PixelShader* MyDX11Renderer::GetPenPixelShader()
{
    if (penPixelShader == nullptr)
    {
        MyCreatePixelShader(&penPixelShader, MYDX11RENDERER_PENSHADER_PATH, "PSMain");
    }
    return penPixelShader;
}

void MyDX11Renderer::SetPenPixelShader(ID3D11PixelShader* penPixelShader)
{
    if (penPixelShader)
        this->penPixelShader = penPixelShader;
    else
        this->penPixelShader = penPixelShader_default;
}

ID3D11VertexShader* MyDX11Renderer::GetTPenVertexShader()
{
    if (tPenVertexShader == nullptr)
    {
        if (tPenVSBlob)
            tPenVSBlob->Release();
        MyCreateVertexShader(&tPenVertexShader, MYDX11RENDERER_TPENSHADER_PATH, "VSMain", &tPenVSBlob);
    }
    return tPenVertexShader;
}

void MyDX11Renderer::SetTPenVertexShader(ID3D11VertexShader* tPenVertexShader)
{
    if (tPenVertexShader)
        this->tPenVertexShader = tPenVertexShader;
    else
        this->tPenVertexShader = tPenVertexShader_default;
}

ID3D11InputLayout* MyDX11Renderer::GetTPenInputLayout()
{
    if (tPenInputLayout == nullptr)
    {
        if (tPenVSBlob)
            MyCreateInputLayout(&tPenInputLayout, tPenIed, _countof(tPenIed), tPenVSBlob);
    }
    return tPenInputLayout;
}

ID3D11PixelShader* MyDX11Renderer::GetTPenPixelShader()
{
    if (tPenPixelShader == nullptr)
    {
        MyCreatePixelShader(&tPenPixelShader, MYDX11RENDERER_TPENSHADER_PATH, "PSMain");
    }
    return tPenPixelShader;
}

void MyDX11Renderer::SetTPenPixelShader(ID3D11PixelShader* tPenPixelShader)
{
    if (tPenPixelShader)
        this->tPenPixelShader = tPenPixelShader;
    else
        this->tPenPixelShader = tPenPixelShader_default;
}

void MyDX11Renderer::SetPenMVPDefault()
{
    penMVP = XMMatrixOrthographicOffCenterLH(0, (float)window_w, (float)window_h, 0, -10000, 10000);
    auto pConstBuffer = GetPenConstBuffer();
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(pConstBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    memcpy(ms.pData, &penMVP, sizeof(penMVP));
    pContext->Unmap(pConstBuffer, 0);
}

void MyDX11Renderer::SetScissorRect(MyRect* rc)
{
    if (rc)
    {
        clip.left = (LONG)rc->left;
        clip.top = (LONG)rc->top;
        clip.right = (LONG)rc->right;
        clip.bottom = (LONG)rc->bottom;
    }
    else
    {
        clip.left = 0;
        clip.top = 0;
        clip.right = window_w;
        clip.bottom = window_h;
    }
    pContext->RSSetScissorRects(1, &clip);
}

void MyDX11Renderer::GetRenderCopyLastRect(MyRect* src, MyRect* dst)
{
    if (src)
        *src = *lastSrc;
    if (dst)
        *dst = *lastDst;
}

void MyDX11Renderer::MapPenConstBuffer2(void* data, UINT dataSize)
{
    if (dataSize > penConstBuffer2Size)
    {
        if (penConstBuffer2)
        {
            penConstBuffer2->Release();
            penConstBuffer2 = nullptr;
        }
    }
    if (penConstBuffer2 == nullptr)
    {
        if (dataSize > penConstBuffer2Size)
            penConstBuffer2Size = dataSize;
        std::vector<BYTE> buff;
        buff.resize(penConstBuffer2Size);
        MyCreateConstBuffer(&penConstBuffer2, buff.data(), penConstBuffer2Size);
    }
    //设置顶点数据
    D3D11_MAPPED_SUBRESOURCE ms;
    pContext->Map(penConstBuffer2, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    //写入数据
    memcpy(ms.pData, data, dataSize);
    pContext->Unmap(penConstBuffer2, 0);
}

void MyDX11Renderer::GameSetScale(float scale)
{
    this->scale = scale;
}

void MyDX11Renderer::GameSetOffset(float offX, float offY)
{
    this->offX = offX;
    this->offY = offY;
}

void MyDX11Renderer::GameSetHSV(float h, float s, float v)
{
    HSV[0] = h;
    HSV[1] = s;
    HSV[2] = v;
}

void MyDX11Renderer::GameSetDayLight(float dayLight)
{
    this->dayLight = dayLight;
}

void MyDX11Renderer::GameSetZBuffer(float z)
{
    zBuffer = z;
}

void MyDX11Renderer::SetBlendMode_Default()
{
    pContext->OMSetBlendState(pBlendState_default, nullptr, UINT_MAX);
}

void MyDX11Renderer::SetBlendMode_Add()
{
    pContext->OMSetBlendState(pBlendState_add, nullptr, UINT_MAX);
}
void MyDX11Renderer::SetSamplerState_Default()
{
    pContext->PSSetSamplers(0, 1, &pSamplerState_default);
}

void MyDX11Renderer::SetVSync(bool enableVSync)
{
    bVSync = enableVSync ? 1 : 0;
}

bool MyDX11Renderer::GetVSync()
{
    return bVSync != 0;
}

void MyDX11Renderer::SetScreenSlot()
{
    bScreenshot = true;
}

void MyDX11Renderer::SetBufferSize(UINT w, UINT h, ExTextureBuffer* exBuffer, const char* debugName)
{
    if (w == 0 || h == 0)
        return;
    auto& pTexture2D = exBuffer->pBuffer;
    auto& buffer_w = exBuffer->w;
    auto& buffer_h = exBuffer->h;
    auto& pSRV = exBuffer->pSRV;
    auto& pRTV = exBuffer->pRTV;
    if (pTexture2D &&
        w == buffer_w &&
        h == buffer_h)
        return;
    if (pTexture2D)
        pTexture2D->Release();
    if (pSRV)
        pSRV->Release();
    if (pRTV)
        pRTV->Release();
    buffer_w = w;
    buffer_h = h;
    MyCreateTexture(&pTexture2D, buffer_w, buffer_h,
        DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_USAGE_DEFAULT,
        D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
    char buff[MAX_PATH];
    sprintf_s(buff, "%s", debugName);
    pTexture2D->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(buff), buff);
    MyCreateShaderResourceView(&pSRV, pTexture2D);
    sprintf_s(buff, "%s_SRV", debugName);
    pSRV->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(buff), buff);
    MyCreateRTV(&pRTV, pTexture2D);
    sprintf_s(buff, "%s_RTV", debugName);
    pRTV->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(buff), buff);
}

void MyDX11Renderer::ClearBuffer(ExTextureBuffer* exBuffer)
{
    if (exBuffer->pBuffer)
        exBuffer->pBuffer->Release();
    if (exBuffer->pSRV)
        exBuffer->pSRV->Release();
    if (exBuffer->pRTV)
        exBuffer->pRTV->Release();
}

ID3D11Buffer* MyDX11Renderer::GetPenVertexBuffer(UINT vertexNum)
{
    if (penVertexBuffer == nullptr)
    {
        if (vertexNum > penVertexNumMax)
            penVertexNumMax = vertexNum;
        std::vector<BYTE> buff;
        buff.resize(penVertexNumMax * sizeof(MyDX11PenVertex));
        ZeroMemory(buff.data(), penVertexNumMax * sizeof(MyDX11PenVertex));
        MyCreateVertexBuffer(&penVertexBuffer, buff.data(), penVertexNumMax * sizeof(MyDX11PenVertex), sizeof(MyDX11PenVertex), 0u, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
    }
    else if (vertexNum > penVertexNumMax)
    {
        penVertexNumMax = vertexNum;
        if (penVertexBuffer)
            penVertexBuffer->Release();
        std::vector<BYTE> buff;
        buff.resize(penVertexNumMax * sizeof(MyDX11PenVertex));
        ZeroMemory(buff.data(), penVertexNumMax * sizeof(MyDX11PenVertex));
        MyCreateVertexBuffer(&penVertexBuffer, buff.data(), penVertexNumMax * sizeof(MyDX11PenVertex), sizeof(MyDX11PenVertex), 0u, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
    }
    return penVertexBuffer;
}

ID3D11Buffer* MyDX11Renderer::GetTPenVertexBuffer(UINT vertexNum)
{
    if (tPenVertexBuffer == nullptr)
    {
        if (vertexNum > tPenVertexNumMax)
            tPenVertexNumMax = vertexNum;
        std::vector<BYTE> buff;
        buff.resize(tPenVertexNumMax * sizeof(MyDX11TPenVertex));
        ZeroMemory(buff.data(), tPenVertexNumMax * sizeof(MyDX11TPenVertex));
        MyCreateVertexBuffer(&tPenVertexBuffer, buff.data(), tPenVertexNumMax * sizeof(MyDX11TPenVertex), sizeof(MyDX11TPenVertex), 0u, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
    }
    else if (vertexNum > tPenVertexNumMax)
    {
        tPenVertexNumMax = vertexNum;
        if (tPenVertexBuffer)
            tPenVertexBuffer->Release();
        std::vector<BYTE> buff;
        buff.resize(tPenVertexNumMax * sizeof(MyDX11TPenVertex));
        ZeroMemory(buff.data(), tPenVertexNumMax * sizeof(MyDX11TPenVertex));
        MyCreateVertexBuffer(&tPenVertexBuffer, buff.data(), tPenVertexNumMax * sizeof(MyDX11TPenVertex), sizeof(MyDX11TPenVertex), 0u, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
    }
    return tPenVertexBuffer;
}

ID3D11Buffer* MyDX11Renderer::GetPenConstBuffer()
{
    //取笔的常量缓存并更新贴图尺寸
    struct CBuff
    {
        XMMATRIX mvp;
        float window_w;
        float window_h;
        float scale;
        float offX;
        float offY;
        float texture_w;
        float texture_h;
        float zBuffer;
        float HSV[3];
        float dayLight;
    };
    CBuff buff;
    buff.mvp = penMVP;
    buff.window_w = (float)window_w;
    buff.window_h = (float)window_h;
    buff.scale = scale;
    buff.offX = offX;
    buff.offY = offY;
    buff.texture_w = tPenTexture_w;
    buff.texture_h = tPenTexture_h;
    buff.zBuffer = zBuffer;
    buff.HSV[0] = HSV[0];
    buff.HSV[1] = HSV[1];
    buff.HSV[2] = HSV[2];
    buff.dayLight = dayLight;
    if (penConstBuffer == nullptr)
    {
        //创建常量缓冲
        MyCreateConstBuffer(&penConstBuffer, &buff, sizeof(buff));
    }
    else
    {
        //更新常量缓冲
         //设置顶点数据
        D3D11_MAPPED_SUBRESOURCE ms;
        pContext->Map(penConstBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
        //写入数据
        memcpy(ms.pData, &buff, sizeof(buff));
        pContext->Unmap(penConstBuffer, 0);
    }
    return penConstBuffer;
}

#ifndef NONUSE_SDL2

void MyDX11Renderer::DrawSetPenRTV()
{
    ID3D11RenderTargetView* rtvArr = pPenRTV == nullptr ? pRTV : pPenRTV;
    pContext->OMSetRenderTargets(1u, &rtvArr, enableDSV ? pDSV : nullptr);
}

void MyDX11Renderer::ScreenShot()
{
#ifdef _DEBUG
    HRESULT hr;
#endif // _DEBUG
    if (bScreenshot)
    {
        bScreenshot = false;
        //取背后缓冲区
        ID3D11Texture2D* pSwapBuffer = nullptr;
        MYCHECK(pSwap->GetBuffer(0, IID_PPV_ARGS(&pSwapBuffer)));
        //取当前时间
        time_t now;
        tm local;
        // 获取当前时间
        time(&now);
        // 转换为本地时间
        localtime_s(&local, &now);
        char filename[MAX_PATH];
        char buff[MAX_PATH];
        SHGetFolderPathA(nullptr, CSIDL_MYPICTURES, nullptr, 0, buff);
        sprintf_s(filename, "%s\\%d%02d%02d-%02d%02d%02d-%d.png",
            buff,
            local.tm_year + 1900,
            local.tm_mon + 1,
            local.tm_mday,
            local.tm_hour,
            local.tm_min,
            local.tm_sec, clock());
        MySaveTexture(pSwapBuffer, filename);
        pSwapBuffer->Release();
    }
}

void MyDX11Renderer::ClearRenderResourceBind()
{
    //显式清除绑定
    ID3D11ShaderResourceView* pSRVArr[4];
    ZeroMemory(pSRVArr, sizeof(pSRVArr));
    pContext->PSSetShaderResources(0, 4u, pSRVArr);
    pContext->OMSetRenderTargets(0u, nullptr, nullptr);
}

void MyDX11Renderer::MyCreateTextureFromSDLSurface(ID3D11Texture2D** outTexture, SDL_Surface* pSurface)
{
    SDL_Surface* copySurface = nullptr;
    SDL_Surface* lockedSurface = nullptr;
    if (pSurface->format->format != SDL_PIXELFORMAT_RGBA8888)
    {
        copySurface = SDL_ConvertSurfaceFormat(pSurface, SDL_PIXELFORMAT_RGBA32, 0);
        lockedSurface = copySurface;
    }
    else
    {
        lockedSurface = pSurface;
    }
    SDL_LockSurface(lockedSurface);

    D3D11_TEXTURE2D_DESC textureDesc = {};
    textureDesc.Width = lockedSurface->w;
    textureDesc.Height = lockedSurface->h;
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Usage = D3D11_USAGE_IMMUTABLE;//GPU读写
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;//所有着色器可见
    textureDesc.CPUAccessFlags = 0;
    textureDesc.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA sd = {};
    sd.pSysMem = lockedSurface->pixels;
    sd.SysMemPitch = lockedSurface->pitch;
    if (FAILED(pDevice->CreateTexture2D(&textureDesc, &sd, outTexture)))
        MessageBoxW(hwnd, L"创建贴图资源失败", L"CreateD3D11TextureFromSDLSurface里发生错误", MB_ICONWARNING);
    SDL_UnlockSurface(lockedSurface);
    if (copySurface != nullptr)
        SDL_FreeSurface(copySurface);
}

TTF_Font* MyDX11Renderer::MyLoadFont(const char* name, int ptsize)
{
    //取字体
    char fontFolder[MAX_PATH];
    sprintf_s(fontFolder, "./data/font/%s.ttf", name);//取游戏资源目录
    auto font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "./data/font/%s.ttc", name);//取游戏资源目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "./data/font/%s.otf", name);//取游戏资源目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;

    sprintf_s(fontFolder, "C:\\Windows\\Fonts\\%s.ttf", name);//取系统目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "C:\\Windows\\Fonts\\%s.ttc", name);//取系统目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "C:\\Windows\\Fonts\\%s.otf", name);//取系统目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;

    char username[MAX_PATH + 1];
    DWORD username_len = MAX_PATH + 1;
    GetUserNameA(username, &username_len);

    sprintf_s(fontFolder, "C:\\Users\\%s\\AppData\\Local\\Microsoft\\Windows\\Fonts\\%s.ttf", username, name);//取安装目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "C:\\Users\\%s\\AppData\\Local\\Microsoft\\Windows\\Fonts\\%s.ttc", username, name);//取安装目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;
    sprintf_s(fontFolder, "C:\\Users\\%s\\AppData\\Local\\Microsoft\\Windows\\Fonts\\%s.otf", username, name);//取安装目录
    font = TTF_OpenFont(fontFolder, ptsize);
    if (font)
        return font;

    char err[MAX_PATH];
    sprintf_s(err, "找不到字体：%s", name);
    MessageBoxA(hwnd, err, "资源缺失", MB_ICONWARNING);
    return nullptr;
}

void MyDX11Renderer::DrawText_Unicode(std::unordered_map<wchar_t, MyFontData>* pFontMap, TTF_Font* pFont, const wchar_t* str, float nextlineOffx, float* nextX, float* nextY, DWORD color, float scale, bool solid)
{
    auto len = wcslen(str);
    float offx = *nextX;
    float offy = *nextY;
    MyRect rc;
    float ln_offx = nextlineOffx < 0 ? *nextX : nextlineOffx;//下一行的起始位置
    for (size_t i = 0; i < len; i++)
    {
        wchar_t c = str[i];
        if (pFontMap->find(c) == pFontMap->end())
        {
            MyFontData fontData;
            //加载字
            SDL_Color sdl_color;
            sdl_color.r = sdl_color.g = sdl_color.b = sdl_color.a = 0xff;
            SDL_Surface* s = nullptr;
            if (solid)
                s = TTF_RenderGlyph_Solid(pFont, c, sdl_color);
            else
                s = TTF_RenderGlyph_Blended(pFont, c, sdl_color);
            MyCreateTextureFromSDLSurface(&fontData.pTexture, s);
            MyCreateShaderResourceView(&fontData.pSRV, fontData.pTexture);
            fontData.w = s->w;
            fontData.h = s->h;
            SDL_FreeSurface(s);
            pFontMap->insert(std::make_pair(c, fontData));
        }
        MyFontData& fontData = pFontMap->at(c);
        if (c == L'\n')//如果遇到换行符则换行
        {
            offy += (float)fontData.h * scale;
            offx = ln_offx;
            continue;
        }
        SetTPenDraw(fontData.pSRV);
        rc.Set1(offx, offy, (float)fontData.w * scale, (float)fontData.h * scale);
        AddRenderCopy(nullptr, &rc, color);
        DrawRenderCopy();
        offx += (float)fontData.w * scale;
    }
    *nextX = offx;
    *nextY = offy;
}
void MyDX11Renderer::DrawText_Unicode_AdjustInRect(std::unordered_map<wchar_t, MyFontData>* pFontMap, TTF_Font* pFont, const wchar_t* str, float offX, float offY, MyRect* adjustRect, DWORD color, bool solid)
{
    auto len = wcslen(str);
    float needW = 0, needH = 0;
    float penX = 0;
    bool setFirstH = true;
    //计算总共所需Rect大小
    for (size_t i = 0; i < len; i++)
    {
        wchar_t c = str[i];
        if (pFontMap->find(c) == pFontMap->end())
        {
            MyFontData fontData;
            //加载字
            SDL_Color sdl_color;
            sdl_color.r = sdl_color.g = sdl_color.b = sdl_color.a = 0xff;
            SDL_Surface* s = nullptr;
            if (solid)
                s = TTF_RenderGlyph_Solid(pFont, c, sdl_color);
            else
                s = TTF_RenderGlyph_Blended(pFont, c, sdl_color);
            MyCreateTextureFromSDLSurface(&fontData.pTexture, s);
            MyCreateShaderResourceView(&fontData.pSRV, fontData.pTexture);
            fontData.w = s->w;
            fontData.h = s->h;
            SDL_FreeSurface(s);
            pFontMap->insert(std::make_pair(c, fontData));
        }
        MyFontData& fontData = pFontMap->at(c);
        if (c == L'\n')//如果遇到换行符则换行
        {
            needH += (float)fontData.h;
            penX = 0;
            continue;
        }
        penX += (float)fontData.w;
        if (penX > needW)
            needW = penX;
        if (setFirstH)
        {
            needH += (float)fontData.h;
            setFirstH = false;
        }
    }
    MyRect rc;
    rc.Set1(0, 0, needW, needH);
    rc.AdjustIn(*adjustRect);
    float nextlineOffx = rc.left;
    float nextX = rc.left;
    float nextY = rc.top;
    float scale;
    if (needW > needH)
        scale = adjustRect->GetWidth() / needW;
    else
        scale = adjustRect->GetHeight() / needH;
    DrawText_Unicode(pFontMap, pFont, str, nextlineOffx, &nextX, &nextY, color, scale,solid);
}
void MyDX11Renderer::DrawText_UnicodeLen(MyRect* outRect, std::unordered_map<wchar_t, MyFontData>* pFontMap, TTF_Font* pFont, const wchar_t* str, bool solid)
{
    auto len = wcslen(str);
    float needW = 0, needH = 0;
    float penX = 0;
    bool setFirstH = true;
    //计算总共所需Rect大小
    for (size_t i = 0; i < len; i++)
    {
        wchar_t c = str[i];
        if (pFontMap->find(c) == pFontMap->end())
        {
            MyFontData fontData;
            //加载字
            SDL_Color sdl_color;
            sdl_color.r = sdl_color.g = sdl_color.b = sdl_color.a = 0xff;
            SDL_Surface* s = nullptr;
            if(solid)
                s = TTF_RenderGlyph_Solid(pFont, c, sdl_color);
            else
                s = TTF_RenderGlyph_Blended(pFont, c, sdl_color);
            MyCreateTextureFromSDLSurface(&fontData.pTexture, s);
            MyCreateShaderResourceView(&fontData.pSRV, fontData.pTexture);
            fontData.w = s->w;
            fontData.h = s->h;
            SDL_FreeSurface(s);
            pFontMap->insert(std::make_pair(c, fontData));
        }
        MyFontData& fontData = pFontMap->at(c);
        if (c == L'\n')//如果遇到换行符则换行
        {
            needH += (float)fontData.h;
            penX = 0;
            continue;
        }
        penX += (float)fontData.w;
        if (penX > needW)
            needW = penX;
        if (setFirstH)
        {
            needH += (float)fontData.h;
            setFirstH = false;
        }
    }
    outRect->Set1(0, 0, needW, needH);
}
#endif

MyDX11PenVertex::MyDX11PenVertex(float x, float y, float z, DWORD c)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = c;
}

void MyDX11PenVertex::Set(float x, float y, float z, DWORD c)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = c;
}

MyDX11TPenVertex::MyDX11TPenVertex(float x, float y, float z, float u, float v)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = RGBA(0xff, 0xff, 0xff, 0xff);
    this->u = u;
    this->v = v;
}

MyDX11TPenVertex::MyDX11TPenVertex(float x, float y, float z, DWORD c, float u, float v)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = c;
    this->u = u;
    this->v = v;
}

void MyDX11TPenVertex::Set(float x, float y, float z, float u, float v)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = RGBA(0xff, 0xff, 0xff, 0xff);
    this->u = u;
    this->v = v;
}

void MyDX11TPenVertex::Set(float x, float y, float z, DWORD c, float u, float v)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->c = c;
    this->u = u;
    this->v = v;
}

MyRect::MyRect(float x, float y, float w, float h)
{
    this->left = x;
    this->right = x + w;
    this->top = y;
    this->bottom = y + h;
}

void MyRect::Set1(float x, float y, float w, float h)
{
    this->left = x;
    this->right = x + w;
    this->top = y;
    this->bottom = y + h;
}

void MyRect::Set2(float left, float right, float top, float bottom)
{
    this->left = left;
    this->right = right;
    this->top = top;
    this->bottom = bottom;
}

void MyRect::Set3(ID3D11Texture2D* pTexture)
{
    D3D11_TEXTURE2D_DESC desc;
    pTexture->GetDesc(&desc);
    Set1(0, 0, (float)desc.Width, (float)desc.Height);
}

float MyRect::GetWidth()
{
    return right - left;
}

float MyRect::GetHeight()
{
    return bottom - top;
}

void MyRect::AdjustBk(MyRect& displayRect)
{
    float srcW = displayRect.GetWidth();
    float srcH = displayRect.GetHeight();
    float dstH = srcW / GetWidth() * GetHeight();
    float dstW = srcH / GetHeight() * GetWidth();
    if (dstH > srcH)
        Set1(displayRect.left, displayRect.top - (dstH - srcH) / 2, srcW, dstH);
    else if (dstW > srcW)
        Set1(displayRect.left - (dstW - srcW) / 2, displayRect.top, dstW, srcH);
}

void MyRect::AdjustIn(MyRect& displayRect)
{
    float srcW = GetWidth();
    float srcH = GetHeight();
    float dstW = displayRect.GetWidth();
    float dstH = displayRect.GetHeight();
    if (srcW / srcH < dstW / dstH)
    {
        float dw = dstH * srcW / srcH;
        Set1(displayRect.left + (dstW - dw) / 2, displayRect.top, dw, dstH);
    }
    else
    {
        float dh = dstW * srcH / srcW;
        Set1(displayRect.left, displayRect.top + (dstH - dh) / 2, dstW, dh);
    }
}

bool MyRect::IntersectRect(const MyRect* rc)
{
    if (right <= rc->left || left >= rc->right ||
        bottom <= rc->top || top >= rc->bottom)
        return false;
    return true;
}

bool MyRect::IntersectRect2(const MyRect* rc)
{
    if (right < rc->left || left > rc->right ||
        bottom < rc->top || top > rc->bottom)
        return false;
    return true;
}

bool operator==(const MyRect& l, const MyRect& r)
{
    return l.left == r.left &&
        l.right == r.right &&
        l.top == r.top &&
        l.bottom == r.bottom;
}

void MySetupDPIAwareness()
{
    SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
}

int MyGetDPI()
{
    HMONITOR monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTONEAREST);
    UINT xScale, yScale;
    GetDpiForMonitor(monitor, MDT_DEFAULT, &xScale, &yScale);
    return xScale;
    return 1;
}

