#include "CurveWorld.fx"
#include "Lib/Reflection.fx"
#include "Lib/Math.fx"
#include "Lib/Skinning.fx"

float4x4 gWorld : WORLD;
float4x4 gWorldViewProj : WORLDVIEWPROJECTION;
float4x4 gMatrixViewInverse : VIEWINVERSE;
float4x4 gProjection : PROJECTION;

Texture2D gTexture;
TextureCube gCubeEnv;
float4 gColor;
float2 gScreenSize;
bool gRenderInUI = true;

struct VS_INPUT
{
    float3 pos : POSITION;
    float3 normal : NORMAL;
    float2 texCoord : TEXCOORD0;
    float4 boneIndices : BLENDINDICES;
    float4 boneWeights : BLENDWEIGHTS;
};

struct VS_OUTPUT
{
    float4 pos : SV_POSITION;
    float4 worldPosition : COLOR0;
    float3 normal : NORMAL;
    float2 texCoord : TEXCOORD0;
};

DepthStencilState EnableDepth
{
    DepthEnable = TRUE;
    DepthWriteMask = ALL;
};

RasterizerState BackCulling
{
    FillMode = SOLID;
    CullMode = FRONT;
};

BlendState EnableBlending
{
    BlendEnable[0] = TRUE;
    SrcBlend = SRC_ALPHA;
    DestBlend = INV_SRC_ALPHA;
};

SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap; // or Mirror or Clamp or Border
    AddressV = Wrap; // or Mirror or Clamp or Border
};

VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
    
    float2x4 animatedVertex = GetTransformedVertex(input.boneIndices, input.boneWeights, input.pos, input.normal);
    
    if (gRenderInUI)
    {
        float3 pos = mul(float4(animatedVertex[0].xyz, 1), gWorld).xyz;
        pos.x = (pos.x / gScreenSize.x * 2 - 1);
        pos.y = (1 - pos.y / gScreenSize.y * 2);
        // make sure the z value stays inside buffer values
        pos.z = pos.z + 500;

        output.pos = float4(pos, 1);
        output.pos.z /= 1000;
    }
    else
    {
        
        output.pos = CurveWorld(animatedVertex[0].xyz, gMatrixViewInverse, gWorld, gWorldViewProj);
    }
    
    output.worldPosition = mul(float4(animatedVertex[0].xyz, 1.0), gWorld);
    output.texCoord = input.texCoord;
    output.normal = normalize(mul(animatedVertex[1].xyz, (float3x3) gWorld));
    return output;
}

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    float4 tex = gTexture.Sample(samLinear, input.texCoord);
    
    float3 viewDir = CalculateViewDirection(input.worldPosition.xyz, gMatrixViewInverse);
    float3 reflection = Reflection(gCubeEnv, input.normal, viewDir, input.texCoord, 0.1f);
    
    float3 color = lerp(reflection, gColor.rgb, tex.rgb);
    return float4(color, tex.a);
}

technique11 Default
{
    pass P0
    {
        SetRasterizerState(BackCulling);
        SetDepthStencilState(EnableDepth, 0);

        SetVertexShader(CompileShader(vs_4_0, VS()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, PS()));
    }
}