////////////////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros
////////////////////////////////////////////////////////////////////////////////////////////////////

//MIX_SM_3 : Shader model 3
//MIX_SM_4 : Shader model 4
//MIX_SM_5 : Shader model 5

#define MIX_SM_LOW ( MIX_SM_3 )
#define MIX_SM_HIGH ( MIX_SM_4 || MIX_SM_5 )

//Output target
#if MIX_SM_3

	#define MSV_POSITION POSITION

	#define MSV_TARGET0 COLOR0
	#define MSV_TARGET1 COLOR1
	#define MSV_TARGET2 COLOR2
	#define MSV_TARGET3 COLOR3

#else //MIX_SM_3

	#define MSV_POSITION SV_POSITION

	#define MSV_TARGET0 SV_TARGET0
	#define MSV_TARGET1 SV_TARGET1
	#define MSV_TARGET2 SV_TARGET2
	#define MSV_TARGET3 SV_TARGET3

#endif //MIX_SM_3

////////////////////////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////////////////////////

static const float3 X_AXIS = float3( 1.0, 0.0, 0.0 );
static const float3 Y_AXIS = float3( 0.0, 1.0, 0.0 );
static const float3 Z_AXIS = float3( 0.0, 0.0, 1.0 );

////////////////////////////////////////////////////////////////////////////////////////////////////
// Grobal values
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	/****************************************
		Reserved : b0
	****************************************/
	
	//

	/****************************************
		General : b1
	****************************************/

	cbuffer cbGeneral : register( b1 )
	{
		float4x4 g_ViewMat;      // View matrix
		float4x4 g_ViewProjMat;  // View * Projection matrix
		float4x4 g_LightMat;     // Light matrix (ProjectionShadow)
		float4x4 g_LightBiasMat; // Light * Bias matrix (ProjectionCamera)
	};

	/****************************************
		Transform : b2
	****************************************/

	cbuffer cbTransform : register( b2 )
	{
		float4x4 g_WorldMat[20]; // World matrix ( skining )
	};

	/****************************************
		LocalLight : b3
	****************************************/
	
	//

	/****************************************
		Material : b4
	****************************************/
	
	//
	
#else //MIX_SM_HIGH

	/****************************************
		Reserved : c0 - c15
	****************************************/
	
	//

	/****************************************
		General : c16 - c111
	****************************************/

	float4x4 g_ViewMat      : register( c16 ); // View matrix
	float4x4 g_ViewProjMat  : register( c20 ); // View * Projection matrix
	float4x4 g_LightMat     : register( c24 ); // Light matrix (ProjectionShadow)
	float4x4 g_LightBiasMat : register( c28 ); // Light * Bias matrix (ProjectionCamera)

	float4x4 g_WorldMat[20] : register( c32 ); // World matrix ( skining )

	/****************************************
		LocalLight : c112 - c131
	****************************************/
	
	//

	/****************************************
		Material : c132 - ?
	****************************************/
	
	//

#endif //MIX_SM_HIGH

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros : Global values
////////////////////////////////////////////////////////////////////////////////////////////////////

#define VIEW_MAT_3x3 ( float3x3 )g_ViewMat
#define VIEW_PROJ_MAT_4x4 g_ViewProjMat

#define LIGHT_MAT_4x4 g_LightMat
#define LIGHT_BIAS_MAT_4x4 g_LightBiasMat

#define WORLD_MAT_4x4 g_WorldMat[0]
#define WORLD_MAT_3x3 ( float3x3 )g_WorldMat[0]
#define WORLD_MAT_4x4_ARRAY( index ) g_WorldMat[index]
#define WORLD_MAT_3x3_ARRAY( index ) ( float3x3 )g_WorldMat[index]

////////////////////////////////////////////////////////////////////////////////////////////////////
// Functions
////////////////////////////////////////////////////////////////////////////////////////////////////

// Skining //

#if ENABLE_SKINNING

	// World transform position
	float4 BoneTransformPosition( float4 pos, uint4 indices, float4 weights )
	{
		float4 ret =	( mul( pos, WORLD_MAT_4x4_ARRAY( indices.x ) ) * weights.x ) +
						( mul( pos, WORLD_MAT_4x4_ARRAY( indices.y ) ) * weights.y ) +
						( mul( pos, WORLD_MAT_4x4_ARRAY( indices.z ) ) * weights.z ) +
						( mul( pos, WORLD_MAT_4x4_ARRAY( indices.w ) ) * weights.w );

		return float4( ret.xyz, 1.0 );
	}

	// World transform normal
	float3 BoneTransformNormal( float3 norm, uint4 indices, float4 weights )
	{
		float3 ret =	( mul( norm, WORLD_MAT_3x3_ARRAY( indices.x ) ) * weights.x ) +
						( mul( norm, WORLD_MAT_3x3_ARRAY( indices.y ) ) * weights.y ) +
						( mul( norm, WORLD_MAT_3x3_ARRAY( indices.z ) ) * weights.z ) +
						( mul( norm, WORLD_MAT_3x3_ARRAY( indices.w ) ) * weights.w );

		return ret;
	}

#endif //ENABLE_SKINNING


////////////////////////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////////////////////////

#define TRANSPARENCY_THRESHOLD 0.001 // Ɣʂŏl

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros
////////////////////////////////////////////////////////////////////////////////////////////////////

#define ENABLE_PROJ_TEX ( ENABLE_REFRACT_CLIP || ENABLE_REFRACT_MAPPING || ENABLE_SOFTPARTICLE ) // Projection UV
#define ENABLE_FRESNEL ( ENABLE_DIFFUSE_FRESNEL || ENABLE_REFLECT_FRESNEL ) // tlʂ̗L

#define ENABLE_N_DOT_L ( ENABLE_LIGHTING || ( ENABLE_SHADOW && ENABLE_SHADOW_RECEIVE ) ) // BumpNormal . LightDirection
#define ENABLE_N_DOT_E ( ENABLE_RIM_LIGHTING || ENABLE_COOK_TORRANCE ) // BumpNormal . EyeDirection
#define ENABLE_N_DOT_E_PLANE ( ENABLE_WATER || ENABLE_FRESNEL ) // FaceNormal . EyeDirection

#define ENABLE_SPECULAR ( ENABLE_PHONG || ENABLE_BLINN_PHONG || ENABLE_COOK_TORRANCE ) // XyL̗L
#define ENABLE_TRANSPARENCY_CLIP ( ENABLE_WATER == 0 ) // Ȃ̂Nbv邩ǂ

////////////////////////////////////////////////////////////////////////////////////////////////////
// Structures
////////////////////////////////////////////////////////////////////////////////////////////////////

// Input : Model
struct VS_MODEL_INPUT
{
	float3 pos   : POSITION;
	float4 color : COLOR;

#if ENABLE_NORMAL
	float3 normal : NORMAL;
#endif //ENABLE_NORMAL

#if ENABLE_TANGENT_SPACE
	float3 tangent  : TANGENT;
	float3 binormal : BINORMAL;
#endif //ENABLE_TANGENT_SPACE

#if ENABLE_TEXTURE
	float2 tex : TEXCOORD;
#endif //ENABLE_TEXTURE

#if ENABLE_SKINNING
	uint4  indices : BLENDINDICES;
	float4 weights : BLENDWEIGHT;
#endif //ENABLE_SKINNING
};

// Output : ColorModel
struct VS_COLOR_MODEL_OUTPUT
{
	float4 pos   : MSV_POSITION;
	float4 color : COLOR0;

	float4 worldPos : TEXCOORD0;
	float4 projPos  : TEXCOORD1;

#if ENABLE_LIGHTING

	#if ENABLE_BUMP
		float3 tangent  : TEXCOORD2;
		float3 binormal : TEXCOORD3;
	#endif //ENABLE_BUMP

	float3 normal : TEXCOORD4;

	#if ENABLE_SSAO
		float3 viewNormal : TEXCOORD5;
	#endif //ENABLE_SSAO

#endif //ENABLE_LIGHTING

#if ENABLE_TEXTURE
	float2 tex : TEXCOORD6;
#endif //ENABLE_TEXTURE

#if ENABLE_SHADOW_RECEIVE
	float4 shadowDepth : TEXCOORD7;
	float4 shadowTex   : TEXCOORD8;
#endif //ENABLE_SHADOW_RECEIVE
};

// Output : MaskModel
struct VS_MASK_MODEL_OUTPUT
{
	float4 pos     : MSV_POSITION;
	float4 projPos : TEXCOORD0;
};

// Output : ShadowModel
struct VS_SHADOW_MODEL_OUTPUT
{
    float4 pos   : MSV_POSITION;
    float4 color : COLOR0;

#if ENABLE_TEXTURE
    float2 tex   : TEXCOORD0;
#endif //ENABLE_TEXTURE

    float4 depth : TEXCOORD1;
};

// Output : SelectModel
struct VS_SELECT_MODEL_OUTPUT
{
    float4 pos : MSV_POSITION;
};


////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : ColorModel
////////////////////////////////////////////////////////////////////////////////////////////////////

VS_COLOR_MODEL_OUTPUT mainColorModel( VS_MODEL_INPUT input )
{
	VS_COLOR_MODEL_OUTPUT output = ( VS_COLOR_MODEL_OUTPUT )0;

	//////////////////////////////////////////////////
	// World transform position
	//////////////////////////////////////////////////

#if ENABLE_SKINNING
	float4 pos = BoneTransformPosition( float4( input.pos, 1.0 ), input.indices, input.weights );
#else //ENABLE_SKINNING
	float4 pos = mul( float4( input.pos, 1.0f ), WORLD_MAT_4x4 );
#endif //ENABLE_SKINNING

	//////////////////////////////////////////////////
	// Output position(WVP)
	//////////////////////////////////////////////////

	output.pos = mul( pos, VIEW_PROJ_MAT_4x4 );

	//////////////////////////////////////////////////
	// Output color
	//////////////////////////////////////////////////

	output.color = input.color;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Output position(W)
	////////////////////////////////////////////////////////////////////////////////////////////////////

	output.worldPos = pos;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Output position(P)
	////////////////////////////////////////////////////////////////////////////////////////////////////

	output.projPos = output.pos;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Output tangentSpace and normal
	////////////////////////////////////////////////////////////////////////////////////////////////////

#if ENABLE_LIGHTING

	#if ENABLE_SKINNING

		#if ENABLE_BUMP
			output.tangent  = BoneTransformNormal( input.tangent,  input.indices, input.weights );
			output.binormal = BoneTransformNormal( input.binormal, input.indices, input.weights );
		#endif //ENABLE_BUMP

		output.normal = BoneTransformNormal( input.normal, input.indices, input.weights );

	#else //ENABLE_SKINNING

		#if ENABLE_BUMP
			output.tangent  = mul( input.tangent, WORLD_MAT_3x3 );
			output.binormal = mul( input.binormal, WORLD_MAT_3x3 );
		#endif //ENABLE_BUMP

		output.normal = mul( input.normal, WORLD_MAT_3x3 );

	#endif //ENABLE_SKINNING

	#if ENABLE_BUMP
		output.tangent = normalize( output.tangent );
		output.binormal = normalize( output.binormal );
	#endif //ENABLE_BUMP

	output.normal = normalize( output.normal );

	#if ENABLE_SSAO
		output.viewNormal = mul( output.normal, VIEW_MAT_3x3 );
	#endif //ENABLE_SSAO

#endif //ENABLE_LIGHTING

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Output texture
	////////////////////////////////////////////////////////////////////////////////////////////////////

#if ENABLE_TEXTURE
	output.tex = input.tex;
#endif //ENABLE_TEXTURE

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Output shadow
	////////////////////////////////////////////////////////////////////////////////////////////////////

#if ENABLE_SHADOW_RECEIVE
	output.shadowDepth = mul( pos, LIGHT_MAT_4x4 );
	output.shadowTex   = mul( pos, LIGHT_BIAS_MAT_4x4 );
#endif //ENABLE_SHADOW_RECEIVE

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : MaskModel
////////////////////////////////////////////////////////////////////////////////////////////////////

VS_MASK_MODEL_OUTPUT mainMaskModel( VS_MODEL_INPUT input )
{
	VS_MASK_MODEL_OUTPUT output = ( VS_MASK_MODEL_OUTPUT )0;

#if ENABLE_SKINNING
	output.pos = BoneTransformPosition( float4( input.pos, 1.0 ), input.indices, input.weights );
#else //ENABLE_SKINNING
	output.pos = mul( float4( input.pos, 1.0f ), WORLD_MAT_4x4 );
#endif //ENABLE_SKINNING

	output.pos = mul( output.pos, VIEW_PROJ_MAT_4x4 );

	output.projPos = output.pos;

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : ShadowModel
////////////////////////////////////////////////////////////////////////////////////////////////////

VS_SHADOW_MODEL_OUTPUT mainShadowModel( VS_MODEL_INPUT input )
{
	VS_SHADOW_MODEL_OUTPUT output;

#if ENABLE_SKINNING
	output.pos = BoneTransformPosition( float4( input.pos, 1.0 ), input.indices, input.weights );
#else //ENABLE_SKINNING
	output.pos = mul( float4( input.pos, 1.0f ), WORLD_MAT_4x4 );
#endif //ENABLE_SKINNING

	output.pos = mul( output.pos, LIGHT_MAT_4x4 );

	output.color = input.color;

#if ENABLE_TEXTURE
	output.tex = input.tex;
#endif //ENABLE_TEXTURE

	output.depth = output.pos;

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : SelectModel
////////////////////////////////////////////////////////////////////////////////////////////////////

VS_SELECT_MODEL_OUTPUT mainSelectModel( VS_MODEL_INPUT input )
{
	VS_SELECT_MODEL_OUTPUT output = (VS_SELECT_MODEL_OUTPUT)0;

#if ENABLE_SKINNING
	output.pos = BoneTransformPosition( float4( input.pos, 1.0 ), input.indices, input.weights );
#else //ENABLE_SKINNING
	output.pos = mul( float4( input.pos, 1.0f ), WORLD_MAT_4x4 );
#endif //ENABLE_SKINNING

	output.pos = mul( output.pos, VIEW_PROJ_MAT_4x4 );

	return output;
}
