#include"CVertexShaderCompiler0000.h"

#include"DefaultVertexShader.h"
#include"../../../../../CResourceNameGenerator.h"

namespace Maid
{
	using namespace VERTEXSHADERNAME;

	//	字数が長くなるので省略
#define MAKEPSNAME( type ) ( GeneratDefault(type) )

SPVERTEXSHADERBUFFER CVertexShaderCompiler0000::Compile( const SPD3DDEVICE& pDevice, const mstring& Name )
{
	IVertexShaderBuffer* pRet = NULL;

	if( Name==MAKEPSNAME(RHWCOLOR ) )	{ pRet = new VS_RHWCOLOR;	}
	ef( Name==MAKEPSNAME(SPRITE   ) )	{ pRet = new VS_SPRITE;		}
	ef( Name==MAKEPSNAME(SPRITE3D ) )	{ pRet = new VS_XYZSPRITE;	}
	ef( Name==MAKEPSNAME(SPRITE3DMASK ) )	{ pRet = new VS_XYZSPRITEMASK;	}
	ef( Name==MAKEPSNAME(COLOR3D  ) )	{ pRet = new VS_XYZCOLOR;	}
	ef( Name==MAKEPSNAME(MODEL_COLOR) )
	{
		const char* code =
		{
			"vs.1.1\n"
			"dcl_position	v0\n"

			"m4x4	oPos,	v0,		c0\n"	//	world * view * proj
			"mov	oD0,			c4\n"	//	マテリアル計算
		};

		SPD3DVERTEXSHADERBUFFER pShader = Assemble( pDevice, code );
		pRet = new VS_SOFTWARE( pShader );	
	}
	ef( Name==MAKEPSNAME(MODEL_TEXTURE) )
	{
		const char* code =
		{
			"vs.1.1\n"
			"dcl_position	v0\n"
			"dcl_texcoord	v1\n"

			"def c5, 1.0f, 0,0,0 \n"

			"m4x4	oPos	,v0		,c0		\n"	//	world * view * proj
			"mov	oD0		,c4				\n"	//	マテリアル計算

			//	データのＵＶとDirectXのＵＶは Ｖの方向が反対なので、つじつまを合わせる
			"mov	oT0.x	,v1.x			\n"
			"sub	oT0.y	,c5.x	,v1.y	\n"
		};

		SPD3DVERTEXSHADERBUFFER pShader = Assemble( pDevice, code );
		pRet = new VS_SOFTWARE( pShader );	
	}
	ef( Name==MAKEPSNAME(MODELTONE_COLOR) )
	{
		const char* code =
		{
			"vs.1.1\n"
			"dcl_position	v0\n"

			"m4x4	oPos,	v0,		c0\n"	//	world * view * proj
			"mov	oD0,			c4\n"	//	マテリアル計算
		};

		SPD3DVERTEXSHADERBUFFER pShader = Assemble( pDevice, code );
		pRet = new VS_SOFTWARE( pShader );	
	}
	ef( Name==MAKEPSNAME(MODELTONE_TEXTURE) )
	{
		const char* code =
		{
			"vs.1.1\n"
			"dcl_position	v0\n"
			"dcl_normal		v1\n"
			"dcl_texcoord	v7\n"

			//def c0-c3 world * view * proj
			//def c4 平行光源の向き * world.inv()
			//def c5 マテリアル

			"def c6, 1.0f, 0.5f, 0.0f, 0 \n"

			"m4x4	oPos		,v0		,c0		\n"	//	world * view * proj

			"dp3	r0.x	,v1		,-c4	\n"	//	光源計算( 光の強さが分かった:範囲 -1〜1)

			"mov	oD0.rgb	,c6.xxx			\n"	//	マテリアル rgb は1.0f 固定
			"mov	oD0.a	,c5.a			\n"	//	マテリアルはそのまま流す

			//	データのＵＶとDirectXのＵＶは Ｖの方向が反対なので、つじつまを合わせる
			"mov	oT0.x	,v7.x			\n"
			"sub	oT0.y	,c6.x	,v7.y	\n"

			//	光の強さをＵＶに渡す
			//	光の強さは -1..1なので、 0..2 にして /2 で 0..1 にする
			"add	r0.x	,r0.x	,c6.x	\n"
			"mul	r0.x	,r0.x	,c6.y	\n"

			"mov	oT1.x	,r0.x			\n"
			"mov	oT1.y	,c6.z			\n"	//	oT1.y は使わないんだけど、一応0にしておく
		};

		SPD3DVERTEXSHADERBUFFER pShader = Assemble( pDevice, code );
		pRet = new VS_SOFTWARE( pShader );	
	}
	ef( Name==MAKEPSNAME(MODELTONE_LINE) )
	{
		//	トゥーンシェードの輪郭線
		//	http://web.archive.org/web/20040507145244/home.att.ne.jp/yellow/hide_n/programming/vstoon03.html
		const char* code =
		{
			"vs.1.1\n"
			"dcl_position	v0\n"
			"dcl_normal	v2\n"
			
			"def c0, 0.0f, 0.0f, 0.0f, 0.0f\n"

			"m4x4	r0,	v0,		c4\n"	//	world * view * proj
			"m3x2    r1, v2, c4\n"		// 法線のx,y成分のみ変換
			"mov r1.zw, c0\n"			//	z,w成分は0で初期化
			"dp3 r2.x, r1, r1\n"		//	r2.x = r1.x^2 + r1.y^2   (r1.z = 0)

			"rsq r2, r2.x\n"			//	r2 = 1/sqrt(r1^2)
			"mul r1, r1, r2\n"			//	r1を正規化

			"mul r1, r1, c1.x\n"		// 線の太さを掛ける
			"mad oPos, r1, r0.w, r0\n"	// v + dv*w
			"mov	oD0,	c2\n"		//	輪郭線の色
		};
/*
	L"ToneMask:10",
		L"vs.1.1\n"
		L"dcl_position	v0\n"
		L"dcl_normal	v2\n"
		
		L"def c0, 0.0f, 0.0f, 0.0f, 0.0f\n"

		L"m4x4	r0,	v0,		c4\n"	//	world * view * proj
		L"m3x2    r1, v2, c4\n"		// 法線のx,y成分のみ変換
		L"mov r1.zw, c0\n"			//	z,w成分は0で初期化
		L"dp3 r2.x, r1, r1\n"		//	r2.x = r1.x^2 + r1.y^2   (r1.z = 0)

		L"rsq r2, r2.x\n"			//	r2 = 1/sqrt(r1^2)
		L"mul r1, r1, r2\n"			//	r1を正規化

		L"mul r1, r1, c1.x\n"		// 線の太さを掛ける
		L"mad oPos, r1, r0.w, r0\n"	// v + dv*w
		L"mov	oD0,	c2\n"		//	輪郭線の色
*/
		SPD3DVERTEXSHADERBUFFER pShader = Assemble( pDevice, code );
		pRet = new VS_SOFTWARE( pShader );	
	}


//MODELTONE_LINE
	return SPVERTEXSHADERBUFFER(pRet);
}

SPVERTEXSHADERBUFFER CVertexShaderCompiler0000::Compile( const SPD3DDEVICE& pDevice, const MySTL::vector<unt08>& Code, IVideoCardDriver::SHADERCOMPILE type )
{
	MAID_ASSERT( true, MAIDTEXT("未実装") );
	return SPVERTEXSHADERBUFFER();
}


SPD3DVERTEXSHADERBUFFER CVertexShaderCompiler0000::Assemble( const SPD3DDEVICE& pDevice, const MySTL::string& code )
{
	com_ptr<ID3DXBuffer> pShader;

	{
		ID3DXBuffer* buf;
		ID3DXBuffer* Error;
		const HRESULT ret = D3DXAssembleShader( code.c_str(), (UINT)code.length(), NULL, NULL, 0, &buf, &Error );

		if ( FAILED(ret) ) 
		{
			MAID_ASSERT( true, MAIDTEXT("シェーダーのコンパイルに失敗\n") << (char*)Error->GetBufferPointer() );
			Error->Release();
			MAID_THROWEXCEPTION(MAIDTEXT("D3DXAssembleShader()"));
		}
		pShader.reset(buf);
	}

	SPD3DVERTEXSHADERBUFFER pRet;

	{
		IDirect3DVertexShader9* p;

		const HRESULT ret = pDevice->CreateVertexShader( (const DWORD*)pShader->GetBufferPointer(), &p );
		if ( FAILED(ret) ) { MAID_THROWEXCEPTION(MAIDTEXT("IDirect3DVertexBuffer9::CreateVertexShader()")); }
		pRet.reset(p);
	}

	return pRet;
}


}