/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
    matrix normalMatrix;
	float4 diffuse;
    float4 camera;
};

//////////////
// TYPEDEFS //
//////////////
struct VIn
{
    float4 position : POSITION;
    float4 normal : NORMAL;
    float2 uv : TEXCOORD;
};
struct VOut
{
    float4 position : POSITION;
    float4 sv_position : SV_POSITION;
	float4 normal : NORMAL;
    float2 uv : TEXCOORD;
    float4 color : COLOR;
};
struct Material
{
    float Ka, Kd, Ks, A;
};

////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
VOut VShader(VIn IN)
{
    VOut OUT;

    OUT.position = mul(IN.position, worldMatrix);
    OUT.sv_position = mul(OUT.position, viewMatrix);
    OUT.sv_position = mul(OUT.sv_position, projectionMatrix);

    OUT.normal = normalize(IN.normal);
    OUT.uv = IN.uv;
    OUT.color = diffuse;

    //float4 light = normalize(float4(1, 1, 1, 1));
    //OUT.color = max(0, dot(mul(IN.normal, worldMatrix) - OUT.position, light)) * diffuse * 3;
    //OUT.color.a = diffuse.a;

    return OUT;
}

// Lambertian reflectance
float Lambert(float3 normal, float3 view, float3 light, float materialPower)
{
    return saturate(dot(normal, light));
}

// Phong reflection model
float Phong(float3 normal, float3 view, float3 light, float materialPower)
{
    float3 reflected = reflect(-light, normal);
    return pow(saturate(dot(reflected, view)), materialPower);
}

// Blinn D1 (Phong) specular distribution
float BlinnPhong(float3 normal, float3 view, float3 light, float materialPower)
{
    float3 halfway = normalize(light + view);
    return pow(saturate(dot(normal, halfway)), materialPower * 4);
}

// Blinn D2 (Torrance-Sparrow/Gauss) specular distribution
float TorranceSparrow(float3 normal, float3 view, float3 light, float materialPower)
{
    float3 halfway = normalize(light + view);
    float normalDotHalfway = dot(normal, halfway);
    float alpha = acos(normalDotHalfway);
    return exp(-2 * materialPower * pow(alpha, 2));
}

// Blinn D3 (Trowbridge-Reitz) specular distribution
float TrowbridgeReitz(float3 normal, float3 view, float3 light, float materialPower)
{
    float3 halfway = normalize(light + view);
    float normalDotHalfway = saturate(dot(normal, halfway));
    return pow(1 / (1 + (1 - pow(normalDotHalfway, 2)) * materialPower), 2);
}

// Lyon/Blinn halfway method 1 for k = 2 and D = H* - N
float Lyon(float3 normal, float3 view, float3 light, float materialPower)
{
    float3 halfway = normalize(light + view);
    float3 difference = halfway - normal;
    float xs = saturate(dot(difference, difference) * materialPower / 2);
    return pow(1 - xs, 3);
}
//--------------------------------------------------------------------------------------
// Generic lighting function
//--------------------------------------------------------------------------------------
float4 Lighting(Material M, float4 LColor, float4 normal, float3 lightpos, float3 pos)
{
    float3 lightdir = normalize(lightpos - pos);
    float lightdist = length(lightpos - pos);

    float3 n = (normal);
    float3 v = normalize(camera - pos);

    float4 Ia = M.Ka * float4(1, 1, 1, 1);
    float4 Id = M.Kd * saturate(dot(n, lightdir));

    //float3 h = normalize(lightdir + v);
    float4 Is = M.Ks * Lyon(n, v, lightdir, M.A); //pow(saturate(dot(n, h)), M.A);

    return Ia + (Id + Is) * LColor / lightdist;
}

////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 PShader(VOut IN) : SV_TARGET
{
    float4 OUT = IN.color;

    //float4 wnormal = normalize(mul(IN.normal, normalMatrix));
    float4 wnormal = normalize(mul(IN.normal, normalMatrix));

    //float4 ldir = normalize(light - IN.position);
    //float ldiff = saturate(dot(-wnormal, -ldir)); // per pixel diffuse lighting
    //ldiff *= ((length(ldir) * length(ldir)) / dot(light - IN.position, light - IN.position));
    //float4 h = normalize(normalize(camera - IN.position) - ldir);
    //float lspec = -pow(saturate(dot(h, wnormal)), 2.0f);
    //OUT = saturate(ambient + diffuse * (ldiff * 0.6f + lspec * 0.5f));

    //float4 Ia = M.Ka * ambientLight;
    //float4 Id = M.Kd * saturate(dot(N, L));
    //float4 Is = M.Ks * pow(saturate(dot(N, H)), M.A);
    //return Ia + (Id + Is) * LColor;

    float3 lightpos = float3(1, 1, 1);

    Material M;
    M.Ka = 0.1f;
    M.Kd = 1.0f;
    M.Ks = 10.0f;
    M.A = 10.0f;

    float4 lightcolor = float4(1, 1, 1, 1);
    OUT = diffuse * Lighting(M, lightcolor, wnormal, lightpos, IN.position);

    ///

    //OUT += max(0, dot(wnormal, light * lintensity)) * diffuse;
    //OUT = wnormal;
    OUT.a = diffuse.a;

    return OUT;
}