#include "Lib/Math.fx"
float3 gDielectric = 0.04f;

SamplerState samLinearPBR
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
    AddressW = WRAP;
};

float3 GetViewDirection(float3 worldPosition, float4x4 viewInverse)
{
    return normalize(worldPosition.xyz - viewInverse[3].xyz);

}

float3 GetMetalColor(float metalness, float3 rgb)
{
    return lerp(gDielectric, rgb, metalness);
}

float3 CalculateNormal(float3 tangent, float3 normal, float2 texCoord, Texture2D normalMap)
{
	
    float3 binormal = cross(tangent, normal);
    binormal = -binormal;
	
    float3x3 tangentMatrix;
    tangentMatrix._m00_m01_m02 = tangent;
    tangentMatrix._m10_m11_m12 = binormal;
    tangentMatrix._m20_m21_m22 = normal;
	
    float3 sampledNormal = (normalMap.Sample(samLinearPBR, texCoord) * 2) - 1;
	
    return normalize(mul(sampledNormal, tangentMatrix));
}

float3 GetHalfVector(float3 light, float3 view)
{
    return normalize(light + view);
}

float3 BRDFLambert(float3 light, float3 normal, float3 lightRGB, float3 diffuseColor)
{
    return clamp(lightRGB * diffuseColor * dot(normal, -light), 0, 1);
}

float NormalDistribution(float3 light, float3 normal, float3 view, float roughness)
{
    float alpha = roughness * roughness;
    float alphaSq = alpha * alpha;
    float3 h = GetHalfVector(light, view);
    float nDotH = dot(normal, h);
    float denom = nDotH * nDotH * (alphaSq - 1) + 1;
    return alphaSq / (PI * denom * denom);
}

float3 Fresnel(float3 normal, float3 view, float3 reflect)
{
    float rhs = pow(1 - dot(view, -normal), 2);
    return max(reflect + (1 - reflect) * rhs, 0);
}

float3 Geometry(float3 normal, float3 view, float roughness)
{
    float alpha = roughness * roughness;
    float k = ((alpha + 1) * (alpha + 1)) / 8;
    float nDotV = dot(normal, view);
    return nDotV / (nDotV * (1 - k) + k);
}

float3 BRDFSpecular(float3 light, float3 normal, float3 viewDirection, float roughness, float3 reflectColor)
{
    roughness = max(roughness, 0.1f);
    float3 D = NormalDistribution(light, normal, viewDirection, roughness);
    float3 F = Fresnel(normal, viewDirection, reflectColor);
    float3 G = Geometry(normal, viewDirection, roughness) * Geometry(normal, light, roughness);
    
    return (D * F * G) / (4 * dot(viewDirection, normal) * dot(light, normal));
}

float3 Shade(float3 lambert, float3 specular)
{
    return lambert + specular;
}
