#include "CommonParams.h"
#include "UserShader.fx"
#include "Light.fx"

struct vertexInput
{
    float4 Position : POSITION0;
    float3 Normal   : NORMAL0;
#if NUM_USER_TEXCOORDS
    float2 TexCoords[NUM_USER_TEXCOORDS] : TEXCOORD0;
#endif
};

struct InstanceParams
{
    float4 Color     : COLOR0;
    float3 vX        : COLOR1;
    float3 vY        : COLOR2;
    float3 vZ        : COLOR3;
    float3 vWorldPos : COLOR4;
    float4 vUVInfo   : COLOR5; // z ????????
};

struct vertexOutput
{
    float4 outPosition      : POSITION;
    float4 WorldPosition    : TEXCOORD0;
    float4 Normal           : TEXCOORD1; // Normal.w ... fog
    float4 ScreenPosition   : TEXCOORD2;
    float4 VertexPosition   : TEXCOORD3;
    float3 VertexNormal     : TEXCOORD4;
#if NUM_USER_TEXCOORDS
    float2 TexCoords[NUM_USER_TEXCOORDS] : TEXCOORD5;
#endif
    float4 Color            : COLOR0;
};

MaterialVertexParameters GetMaterialVertexParameters(vertexInput Input, InstanceParams Instance)
{
    MaterialVertexParameters Params = (MaterialVertexParameters)0;
    float3x3 matLocal;
    matLocal[0] = Instance.vX;
    matLocal[1] = Instance.vY;
    matLocal[2] = Instance.vZ;
    
    float3 pos = Input.Position;
    pos = mul(pos, matLocal);
    pos += Instance.vWorldPos;

    Params.WorldPosition  = pos;
    Params.VertexColor    = Instance.Color;
    Params.VertexPosition = Input.Position.xyz;
    Params.VertexNormal   = Input.Normal.xyz;
    return Params;
}

MaterialPixelParameters GetMaterialParameters(vertexOutput Input)
{
    MaterialPixelParameters Params = (MaterialPixelParameters)0;
#if NUM_USER_TEXCOORDS
    [unroll(NUM_USER_TEXCOORDS)]for (int i = 0; i < NUM_USER_TEXCOORDS; i++)
        Params.TexCoords[i] = Input.TexCoords[i];
#endif
    Params.VertexColor = Input.Color;
    Params.WorldNormal = Input.Normal.xyz;
    Params.VertexPosition = Input.VertexPosition.xyz;
    Params.VertexNormal = Input.VertexNormal.xyz;
	Params.ScreenPosition = Input.ScreenPosition;
	Params.WorldPosition = Input.WorldPosition.xyz;
    return Params;
}

vertexOutput VertexShaderMain(vertexInput Input, InstanceParams Instance)
{
    vertexOutput Output = (vertexOutput)0;
    MaterialVertexParameters Params = GetMaterialVertexParameters(Input, Instance);
	ParamsMainVertexNode VertexMainNode = (ParamsMainVertexNode)0;
	CalculateMainVertexNode(Params, VertexMainNode);
    float4 position = float4(Params.WorldPosition, 1.0f) + float4(VertexMainNode.WorldPositionOffset, 0.0f);
    Output.WorldPosition = float4(Params.WorldPosition, 1.0f);
    Output.ScreenPosition = mul(float4(Params.WorldPosition, 1.0f), wvp);
    Output.outPosition = Output.ScreenPosition;
    Output.VertexPosition = Input.Position;
    Output.VertexNormal = Input.Normal.xyz;
    Output.Color = Instance.Color;
#if NUM_USER_TEXCOORDS
    [unroll(NUM_USER_TEXCOORDS)]for (int i = 0; i < NUM_USER_TEXCOORDS; i++)
    {
        Output.TexCoords[i].x = Input.TexCoords[i].x * Instance.vUVInfo.z + Instance.vUVInfo.x;
        Output.TexCoords[i].y = Input.TexCoords[i].y * Instance.vUVInfo.w + Instance.vUVInfo.y;		
    }
#endif
    float3 normal = Input.Normal;
    if(!any(normal))
        normal = float3(0.0f, 1.0f, 0.0f);
        
    Output.Normal.xyz = normal;
    Output.Normal.w   = CalFogFactor(Output.outPosition.z);
    return Output;
}

float4 PixelShaderMain(vertexOutput Input 
                    #ifdef SHADOWMAP
                       ,float4 screenSpace : VPOS
                    #endif    
                       ) : COLOR0
{
    float4 retColor = 0;
    MaterialPixelParameters Params = GetMaterialParameters(Input);
	ParamsMainPixelNode PixelMainNode = (ParamsMainPixelNode)0;
	CalculateMainPixelNode(Params, PixelMainNode);
    
#ifdef CUSTOMLIGHTING
    retColor = GetCustomLighting(Params);
#else 
    float3 color = 0;
    color = PixelMainNode.Diffuse;
    color +=  PixelMainNode.Ambient;
    color +=  PixelMainNode.Emissive;
    retColor.rgb = color;
    retColor.a   = PixelMainNode.Opacity;
#endif    
#ifdef FOG
    retColor = CalFogColor(retColor, Input.Normal.w);
#endif
    return retColor;
}

technique Color
{
    pass p0
    {
        VertexShader = compile vs_3_0 VertexShaderMain(); 
        PixelShader = compile ps_3_0  PixelShaderMain();
        
        AlphaBlendEnable = true; 
        SRCBLEND  = SrcAlpha;
        DestBlend = InvSrcAlpha; 
        CullMode  = CW; 
        ZEnable   = true; 
        ZWriteEnable = false;
        ZFunc = LessEqual;
    }
}    

float4 PixelShaderShockWave(vertexOutput Input) : COLOR0
{
    float4 retColor = 0;
    MaterialPixelParameters Params = GetMaterialParameters(Input);
    
	retColor.rg = GetDistortion(Params);
	retColor.a  = GetOpacityColor(Params);
    return retColor;
}

technique ShockWave
{
    pass p0
    {
        VertexShader = compile vs_3_0 VertexShaderMain(); 
        PixelShader = compile ps_3_0 PixelShaderShockWave();
        
        AlphaBlendEnable = false; 
        CullMode  = CW; 
        ZEnable = true; 
        ZWriteEnable = false;
    }
}