// ---------------------------------------------------------------------------
//  M88 カスタマイズプロジェクト
//  Copyright (C) 2026 M88 カスタマイズプロジェクト.
//  2条項BSDライセンスの下で配布する。
// ---------------------------------------------------------------------------
//	Direct3D 11 による画面描画 (CRT フィルタ用)
// ---------------------------------------------------------------------------

#pragma once

#include <d3d11.h>
#include <dxgi.h>
#include <string>
#include "windraw.h"

// ---------------------------------------------------------------------------
//	crt.hlsl の cbuffer CRTParams (register b0) に対応する C++ 構造体。
//	16バイト境界を手で数えて確認済み (合計64バイト)。
//	詳細は docs/crt-shader-port.md §5。変更時は必ず数え直すこと
// ---------------------------------------------------------------------------
struct CRTParams
{
	float SourceSize[2];			//  0  (640, 400)
	float SourceSizeInv[2];			//  8  (1/640, 1/400)

	float OutputSize[2];			// 16  描画先のピクセルサイズ
	float OutputSizeInv[2];			// 24

	float ScanlineStrength;			// 32
	float VignetteStrength;			// 36
	float AberrationPx;				// 40
	float CurvatureAmount;			// 44

	float ScanlineNativeHeight;		// 48
	float SmoothstepEnabled;			// 52  0.0 / 1.0
	float MasterEnable;				// 56  0.0 / 1.0
	float pad0;						// 60
};									// sizeof = 64
static_assert(sizeof(CRTParams) == 64, "CRTParams のレイアウトが崩れています");

class WinDrawD3D : public WinDrawSub
{
public:
	WinDrawD3D();
	~WinDrawD3D();

	bool Init(HWND hwnd, uint w, uint h, GUID*);
	bool Resize(uint width, uint height);
	bool Cleanup();
	void SetPalette(PALETTEENTRY* pal, int index, int nentries);
	void DrawScreen(const RECT& rect, bool refresh);
	bool Lock(uint8** pimage, int* pbpl);
	bool Unlock();

	void SetCRTParams(const CRTEffectParams& params);
	bool ReloadShader();

private:
	bool CreateDevice();
	bool CreateSwapChain(uint w, uint h);
	bool CreateBackBufferRTV();
	bool CreateResources();			// Index/Palette テクスチャ・オフスクリーンRT・サンプラ・定数バッファ
	bool CompileShaders();				// palette.hlsl (Pass1) / crt.hlsl (Pass2) の実行時コンパイル
	bool CompileShaderSet(ID3D11VertexShader** vs, ID3D11PixelShader** palettePS, ID3D11PixelShader** crtPS);
	void UpdateTextures();				// CPU側バッファ → GPUテクスチャ (Map/Unmap)
	void UpdateCRTParamsBuffer();		// m_effectParams → 定数バッファ (Map/Unmap)
	void RenderPass1();				// パレット展開。オフスクリーンRTへ描画する
	void RenderPass2();				// オフスクリーンRTをバックバッファへ拡大描画する (CRTエフェクト)
	void ComputeDestRect(RECT& rect);	// 出力面に 8:5 で内接する矩形 (レターボックス)

	std::wstring FindShaderPath(const wchar_t* filename);

	HWND m_hWnd;						// 親ウインドウ
	HWND m_hCWnd;						// 表示専用の子ウインドウ (D2D と同じ流儀)
	uint m_width;						// 出力サイズ(子ウインドウのクライアントサイズ)
	uint m_height;

	ID3D11Device*			m_dev;
	ID3D11DeviceContext*	m_ctx;
	IDXGISwapChain*			m_swap;
	ID3D11RenderTargetView*	m_backbufferRTV;

	// Pass1 入力
	ID3D11Texture2D*			m_indexTex;		// R8_UNORM        640x400 (DYNAMIC)
	ID3D11ShaderResourceView*	m_indexSRV;
	ID3D11Texture2D*			m_paletteTex;	// R8G8B8A8_UNORM  256x1  (DYNAMIC)
	ID3D11ShaderResourceView*	m_paletteSRV;

	// Pass1 出力 = Pass2 入力 (640x400 固定。出力サイズには依存しない)
	ID3D11Texture2D*			m_rgbTex;		// R8G8B8A8_UNORM  640x400 (DEFAULT)
	ID3D11RenderTargetView*	m_rgbRTV;
	ID3D11ShaderResourceView*	m_rgbSRV;

	ID3D11VertexShader*	m_vsFullscreen;
	ID3D11PixelShader*		m_psPalette;
	ID3D11PixelShader*		m_psCRT;			// crt.hlsl PSMain (Pass2)
	ID3D11Buffer*			m_cbCRT;			// CRTParams (DYNAMIC, 64バイト)
	ID3D11SamplerState*	m_sampPoint;

	CRTEffectParams	m_effectParams;		// Config から渡されたパラメータ (都合のよい型)

	// CPU 側のバッファ (Lock/Unlock で公開する。エミュレータが直接書き込む)
	uint8*			m_image;			// 640*400
	int				m_bpl;
	PALETTEENTRY	m_palette[256];
	bool			m_paletteDirty;
	bool			m_imageDirty;

	static const uint SRCW = 640;		// 転送元サイズ(固定)
	static const uint SRCH = 400;
};
