#pragma once
#include <d3d11.h>
#include <DirectXMath.h>
using namespace DirectX;
#include <map>
#include <unordered_map>
#include <vector>
//SDL2辅助
#ifndef NONUSE_SDL2
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_mixer.h>
#include <SDL_image.h>
#endif // !NONUSE_SDL2

//DirectX 11绘制类
#define RGBA(r,g,b,a) ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)|(((DWORD)(BYTE)(a))<<24)))
#define MYDX11RENDERER_PENSHADER_PATH "./data/shader/sys_pen.hlsl"
#define MYDX11RENDERER_TPENSHADER_PATH "./data/shader/sys_tPen.hlsl"
#define PROJ_MIN 0.1f
#define PROJ_MAX D3D11_FLOAT32_MAX
//前置声明
struct MyDX11PenVertex;
struct MyDX11TPenVertex;
struct MyRect;
struct MyFontData;
struct ExTextureBuffer;
//我的DX11渲染器
class MyDX11Renderer
{
public:
	MyDX11Renderer() = default;
	MyDX11Renderer(const MyDX11Renderer&) = delete;//禁止对象实例复制
	MyDX11Renderer& operator=(const MyDX11Renderer&) = delete;//禁止对象实例复制
	virtual ~MyDX11Renderer();
	//设备初始化
	void Init(HWND hwnd);
	/*-------------------------------取成员变量--------------------------------------*/
	HWND GetHwnd();
	ID3D11Device* GetDevice();
	ID3D11DeviceContext* GetContext();
	/*-------------------------------窗口--------------------------------------*/
	void OnSize(UINT w, UINT h, bool minimized);//对窗口尺寸变换处理
	void GetWindowSize(UINT* w, UINT* h);
	/*-------------------------------调试--------------------------------------*/
	void MyDX11ShowError(HRESULT hr, const char* msg, int lineNum, const char* srcfile);//显示错误信息
	/*-------------------------------显示输出--------------------------------------*/
	void RenderPresent();//显示图像
	void RenderClear(float r = 0, float g = 0, float b = 0, float a = 0);//清除背后缓冲区
	void RenderClearRTV(ID3D11RenderTargetView* pRTV, float r = 0, float g = 0, float b = 0, float a = 0);//清除特定渲染目标视图
	/*-------------------------------绘制图形--------------------------------------*/
	void SetPenDraw();//设置使用笔来绘制（设置笔的着色器和常量缓存）
	//画线
	void AddVertex(const MyDX11PenVertex* vertex);//直接添加顶点
	void AddLine(const MyDX11PenVertex& v1, const MyDX11PenVertex& v2);//顶点缓存中添加线
	void AddLine(const MyDX11PenVertex* v1, const MyDX11PenVertex* v2);//顶点缓存中添加线
	void AddRect(const MyRect* rect, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff));//顶点缓存中添加矩形线框
	void DrawLine();//画线
	//画填充矩形
	void AddFillRect(const MyRect* rect, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff));//顶点缓存中添加填充矩形
	void DrawFillRect();//画填充矩形
	//画贴图
	void SetTPenDraw(ID3D11ShaderResourceView* pTextureView = nullptr,
		ID3D11ShaderResourceView* pTextureView2 = nullptr,
		ID3D11ShaderResourceView* pTextureView3 = nullptr,
		ID3D11ShaderResourceView* pTextureView4 = nullptr);//设置使用贴图笔来绘制（设置贴图笔的着色器和常量缓存）
	//画贴图
	void AddGeometry(const MyDX11TPenVertex* vertices, size_t num);
	void AddRenderCopy(const MyRect* src = nullptr, const MyRect* dst = nullptr, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff));
	void DrawRenderCopy();
	void GetRenderCopyDefaultRect(ID3D11ShaderResourceView* pTextureView, MyRect* outSrc, MyRect* outDst);//取默认的绘制矩形
	//绘制选项
	void MySetVP(FLOAT offx, FLOAT offy, FLOAT width, FLOAT height, FLOAT minDepth, FLOAT maxDepth);
	void DrawEnableDSV(bool enable);
	void DrawEnableBackCull(bool enable);
	void SetPenRTV(ID3D11RenderTargetView* pPenRTV = nullptr);
	ID3D11RenderTargetView* GetPenRTV();
	void SetClipVpMVP(FLOAT width, FLOAT height);
	void ResetClipVpMVP();
	/*-------------------------------创建接口--------------------------------------*/
	HRESULT CompileShaderFromFile(const WCHAR* szFileName, const D3D_SHADER_MACRO* defines, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut);
	void MyCreateRTV(ID3D11RenderTargetView** outRTV, ID3D11Resource* pTexture);
	void MyCreateDSS(ID3D11DepthStencilState** outDSS);
	void MyCreateDST(ID3D11Texture2D** outDST, UINT width, UINT height);
	void MyCreateDSV(ID3D11DepthStencilView** outDSV, ID3D11Texture2D* pDST);
	void MyCreateVertexBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT structSize, UINT Offset = 0, D3D11_USAGE Usage = D3D11_USAGE_DEFAULT, UINT CPUAccessFlags = 0u);
	void MyCreateIndexBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT structSize, D3D11_USAGE Usage = D3D11_USAGE_DEFAULT, UINT CPUAccessFlags = 0u);
	void MyCreateConstBuffer(ID3D11Buffer** outBuffer, const void* data, UINT allSize, UINT StartSlot = 0, D3D11_USAGE Usage = D3D11_USAGE_DYNAMIC, UINT CPUAccessFlags = D3D11_CPU_ACCESS_WRITE);
	void MyCreateVertexShader(ID3D11VertexShader** outVertexShader, const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob, const char* mode = "vs_5_0");
	void MyCreateInputLayout(ID3D11InputLayout** outInputLayout, const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, ID3DBlob* pVSBlob);
	void MyCreatePixelShader(ID3D11PixelShader** outPixelShader, const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob = nullptr, const char* mode = "ps_5_0");
	void MyCreateSamplerState(ID3D11SamplerState** outSamplerState);
	void MyCreateBlendState(ID3D11BlendState** outBlendState);
	void MyCreateBlendState_AddMode(ID3D11BlendState** outBlendState);
	void MyCreateRasterizerState(ID3D11RasterizerState** outRasterizerState, D3D11_CULL_MODE cullMode);
	void MyCreateComputeShader(ID3D11ComputeShader** outComputeShader, const char* hlslfile, const char* mainFuncName, ID3DBlob** outBlob = nullptr, const char* mode = "cs_5_0");
	/*-------------------------------贴图--------------------------------------*/
	void MyLoadTexture(ID3D11Texture2D** outTexture, const char* filename, int* outW = nullptr, int* outH = nullptr);//从文件系统中载入贴图
	void MySaveTexture(ID3D11Texture2D* pTexture, const char* filename);//保存贴图到文件系统中
	void MyCreateTexture(ID3D11Texture2D** outTexture, UINT width, UINT height, DXGI_FORMAT Format = DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_USAGE Usage = D3D11_USAGE_DEFAULT, UINT BindFlags = D3D11_BIND_SHADER_RESOURCE, UINT CPUAccessFlags = 0, UINT MiscFlags = 0);
	void MyCreateShaderResourceView(ID3D11ShaderResourceView** outSRV, ID3D11Texture2D* pTexture);//给贴图创建SRV供着色器使用
	/*-------------------------------画笔--------------------------------------*/
	ID3D11VertexShader* GetPenVertexShader();//取画笔用的顶点着色器
	void SetPenVertexShader(ID3D11VertexShader* penVertexShader = nullptr);
	ID3D11InputLayout* GetPenInputLayout();//取画笔用的顶点输入层
	ID3D11PixelShader* GetPenPixelShader();//取画笔用像素着色器
	void SetPenPixelShader(ID3D11PixelShader* penPixelShader = nullptr);//设置画笔用的像素着色器
	/*-------------------------------贴图画笔--------------------------------------*/
	ID3D11VertexShader* GetTPenVertexShader();//取贴图画笔用的顶点着色器
	void SetTPenVertexShader(ID3D11VertexShader* tPenVertexShader = nullptr);//设置贴图画笔用的顶点着色器
	ID3D11InputLayout* GetTPenInputLayout();//取贴图画笔用的顶点输入层
	ID3D11PixelShader* GetTPenPixelShader();//取贴图画笔用像素着色器
	void SetTPenPixelShader(ID3D11PixelShader* tPenPixelShader = nullptr);//设置贴图画笔用的像素着色器
	/*-------------------------------画笔矩阵--------------------------------------*/
	void SetPenMVPDefault();//矩阵设置为默认值（默认正交投影）
	/*--------------------------------其他-----------------------------------------*/
	void SetScissorRect(MyRect* rc = nullptr);//设置裁剪矩形
	void GetRenderCopyLastRect(MyRect* src, MyRect* dst);
	void MapPenConstBuffer2(void* data, UINT dataSize);//映射常量缓存
	void GameSetScale(float scale);
	void GameSetOffset(float offX, float offY);
	void GameSetHSV(float h, float s, float v);
	void GameSetDayLight(float dayLight);
	void GameSetZBuffer(float z);
	void SetBlendMode_Default();
	void SetBlendMode_Add();
	void SetSamplerState_Default();
	void SetVSync(bool enableVSync);//启用或关闭垂直同步
	bool GetVSync();//取垂直同步设置
	/*--------------------------------截图-----------------------------------------*/
	void SetScreenSlot();
	/*------------------------------缓冲--------------------------------------*/
	void SetBufferSize(UINT w, UINT h, ExTextureBuffer* exBuffer, const char* debugName = nullptr);
	void ClearBuffer(ExTextureBuffer* exBuffer);
private:
	/*-------------------------------Windows--------------------------------------*/
	HWND hwnd = nullptr;//目标窗口
	UINT window_w = 0, window_h = 0;
	/*-------------------------------DirectX11--------------------------------------*/
	ID3D11Device* pDevice = nullptr;//图形设备
	ID3D11DepthStencilState* pDSS = nullptr;//深度模板状态
	ID3D11SamplerState* pSamplerState_default = nullptr;//采样模式
	ID3D11BlendState* pBlendState_default = nullptr;//混合模式
	ID3D11BlendState* pBlendState_add = nullptr;//混合模式
	ID3D11RasterizerState* pRasterizerState_CullBack = nullptr;//光栅模式
	ID3D11RasterizerState* pRasterizerState_CullNone = nullptr;//光栅模式
	bool enableDSV = true;
	IDXGISwapChain* pSwap = nullptr;//交换链
	ID3D11DeviceContext* pContext = nullptr;//图形上下文
	ID3D11RenderTargetView* pRTV = nullptr;//渲染目标视图
	ID3D11Texture2D* pDST = nullptr;//深度模板贴图
	ID3D11DepthStencilView* pDSV = nullptr;//深度模板视图
	/*-------------------------------画笔--------------------------------------*/
	ID3D11VertexShader* penVertexShader = nullptr;//画笔使用的顶点着色器
	ID3D11VertexShader* penVertexShader_default = nullptr;//画笔默认顶点着色器
	ID3DBlob* penVSBlob = nullptr;
	ID3D11InputLayout* penInputLayout = nullptr;//画笔用的顶点输入层
	ID3D11PixelShader* penPixelShader = nullptr;
	ID3D11PixelShader* penPixelShader_default = nullptr;//画笔默认像素着色器
	ID3D11Buffer* penVertexBuffer = nullptr;//画笔使用的顶点缓存
	ID3D11Buffer* GetPenVertexBuffer(UINT vertexNum);//取画笔用的顶点缓存
	UINT penVertexNumMax = 2;//当前画笔用的顶点个数最大值
	std::vector<MyDX11PenVertex> penVertexBuff;//顶点缓存
	/*-------------------------------贴图画笔--------------------------------------*/
	ID3D11VertexShader* tPenVertexShader = nullptr;//贴图画笔使用的顶点着色器
	ID3D11VertexShader* tPenVertexShader_default = nullptr;//贴图画笔默认顶点着色器
	ID3DBlob* tPenVSBlob = nullptr;
	ID3D11InputLayout* tPenInputLayout = nullptr;//贴图画笔用的顶点输入层
	ID3D11PixelShader* tPenPixelShader = nullptr;//贴图画笔使用的像素着色器
	ID3D11PixelShader* tPenPixelShader_default = nullptr;//贴图画笔默认像素着色器
	ID3D11Buffer* tPenVertexBuffer = nullptr;//贴图画笔使用的顶点缓存
	ID3D11Buffer* GetTPenVertexBuffer(UINT vertexNum);//取贴图画笔用的顶点缓存
	UINT tPenVertexNumMax = 2;//当前贴图画笔用的顶点个数最大值
	std::vector<MyDX11TPenVertex> tPenVertexBuff;//顶点缓存
	float tPenTexture_w, tPenTexture_h;
	/*-------------------------------画笔矩阵--------------------------------------*/
	XMMATRIX penMVP;
	ID3D11Buffer* penConstBuffer = nullptr;//画笔使用的顶点缓存
	ID3D11Buffer* GetPenConstBuffer();//取画笔用的常量缓存
	ID3D11Buffer* penConstBuffer2 = nullptr;//画笔使用的2号顶点缓存
	UINT penConstBuffer2Size = sizeof(XMMATRIX);//二号缓存
	/*--------------------------------其他-----------------------------------------*/
	MyRect* lastSrc = nullptr, * lastDst = nullptr;
	D3D11_RECT clip;
	ID3D11RenderTargetView* pPenRTV = nullptr;
	UINT bVSync = 1;
	float scale = 1;
	float offX = 0, offY = 0;
	float HSV[3] = { 0 };
	float dayLight = 1.0f;
	float zBuffer = 0.0f;
	void DrawSetPenRTV();
	/*--------------------------------截图-----------------------------------------*/
	bool bScreenshot = false;
	void ScreenShot();
	/*--------------------------------其他-----------------------------------------*/
	void ClearRenderResourceBind();
	/*-----------------------------SDL2辅助部分------------------------------------*/
#ifndef NONUSE_SDL2
public:
	void MyCreateTextureFromSDLSurface(ID3D11Texture2D** outTexture, SDL_Surface* pSurface);//从SDL Surface创建D3D11纹理
	TTF_Font* MyLoadFont(const char* name, int ptsize);
	//画文本
	void DrawText_Unicode(std::unordered_map<wchar_t, MyFontData>* pFontMap, TTF_Font* pFont, const wchar_t* str, float nextlineOffx, float* nextX, float* nextY, DWORD color = RGBA(0xff, 0xff, 0xff, 0xff), float scale = 1.0f, bool solid = false);
	void 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 = RGBA(0xff, 0xff, 0xff, 0xff), bool solid = false);
	void DrawText_UnicodeLen(MyRect* outRect, std::unordered_map<wchar_t, MyFontData>* pFontMap, TTF_Font* pFont, const wchar_t* str, bool solid = false);
#endif
};
//笔的顶点格式
struct MyDX11PenVertex
{
	float x = 0, y = 0, z = 0;//顶点
	DWORD c = 0;//颜色
	MyDX11PenVertex() = default;
	MyDX11PenVertex(float x, float y, float z = 0, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff));
	void Set(float x, float y, float z = 0, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff));
};
//贴图笔的顶点格式
struct MyDX11TPenVertex
{
	float x = 0, y = 0, z = 0;//顶点
	DWORD c = 0;//颜色
	float u = 0, v = 0;//贴图坐标
	MyDX11TPenVertex() = default;
	MyDX11TPenVertex(float x, float y, float z = 0, float u = 0, float v = 0);
	MyDX11TPenVertex(float x, float y, float z = 0, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff), float u = 0, float v = 0);
	void Set(float x, float y, float z = 0, float u = 0, float v = 0);
	void Set(float x, float y, float z = 0, DWORD c = RGBA(0xff, 0xff, 0xff, 0xff), float u = 0, float v = 0);
};
//矩形
struct MyRect
{
	float left = 0, right = 0, top = 0, bottom = 0, z = 1;
	MyRect() = default;
	MyRect(float x, float y, float w, float h);
	void Set1(float x, float y, float w, float h);
	void Set2(float left, float right, float top, float bottom);
	void Set3(ID3D11Texture2D* pTexture);
	float GetWidth();
	float GetHeight();
	void AdjustBk(MyRect& displayRect);
	void AdjustIn(MyRect& displayRect);
	bool IntersectRect(const MyRect* rc);//判断两矩形是否相交
	bool IntersectRect2(const MyRect* rc);//判断两矩形是否相交包括相邻点
};
bool operator==(const MyRect& l, const MyRect& r);

struct MyFontData
{
	ID3D11Texture2D* pTexture;
	ID3D11ShaderResourceView* pSRV;
	int w, h;
};

void MySetupDPIAwareness();//使程序不受系统DPI缩放影响
int MyGetDPI();//取DPI缩放

struct ExTextureBuffer
{
	ID3D11Texture2D* pBuffer = nullptr;
	UINT w = 0;
	UINT h = 0;
	ID3D11ShaderResourceView* pSRV = nullptr;
	ID3D11RenderTargetView* pRTV = nullptr;
};