// ================ //
// ================ //
// CUSTOM SETTINGS  //
// ================ //
// ================ //

static float CarSaturation       = 1.15;
static float ReflectionIntensity = 2.6;
static float GlobalBrightness    = 1.5;
static float AmbientFloor        = 0.2;

// ================ //
// ================ //

int BlendState[5] : BLENDSTATE;
row_major float4x4 WorldViewProj : WORLDVIEWPROJECTION;
row_major float4x4 WorldView     : WORLDVIEW;
float4 LocalEyePos               : LOCALEYEPOS;

float4 HarmonicCoeff[10] : HARMONIC;
int    AmbientCoeff      : AMBIENTCOEFF;

float4 DiffuseMin    : DIFFUSEMIN;
float4 DiffuseRange  : DIFFUSERANGE;
float4 SpecularMin   : SPECULARMIN;
float4 SpecularRange : SPECULARRANGE;
float4 EnvmapMin     : ENVMAPMIN;
float4 EnvmapRange   : ENVMAPANGE;
float  SpecularPower : SPECULARPOWER;
float  EnvmapPower   : ENVMAPPOWER;

texture EnvMapTex  : EnvMapTexture;
texture diffusemap : DiffuseMap;

sampler samp = sampler_state
{
    Texture   = <diffusemap>;
    AddressU  = WRAP;
    AddressV  = WRAP;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
    MIPFILTER = LINEAR;
};

samplerCUBE envmap_sampler = sampler_state
{
    Texture   = <EnvMapTex>;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
    MIPFILTER = LINEAR;
};
struct VS_INPUT
{
    float4 position : POSITION;
    float3 normal   : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 position       : POSITION;
    float4 diffuse_color  : COLOR0;
    float4 specular_color : COLOR1;
    float4 t0             : TEXCOORD0;
    float4 t1             : TEXCOORD1;
};
VS_OUTPUT vs_main(VS_INPUT IN)
{
    VS_OUTPUT OUT;

    OUT.position = mul(IN.position, WorldViewProj);
    OUT.t1 = IN.texcoord;

    float3 view_vector = normalize(LocalEyePos.xyz - IN.position.xyz);
    float vdotn = max(0.01, dot(view_vector, IN.normal));

    float specvdotn = pow(vdotn, SpecularPower * 1.3);
    float envvdotn  = pow(vdotn, EnvmapPower);

    float4 diffuse_scale  = DiffuseMin  + vdotn     * DiffuseRange;
    float4 specular_scale = SpecularMin + specvdotn * SpecularRange;

    float3 N = IN.normal;
    float4 normal_square = float4(N.x*N.x, N.y*N.y, N.z*N.z, 0);
    float3 normal_cross  = float3(N.x*N.y, N.z*N.x, N.y*N.z);

    float4 LightSum =
        HarmonicCoeff[0] +
        HarmonicCoeff[1] * normal_square.x +
        HarmonicCoeff[2] * normal_square.y +
        HarmonicCoeff[3] * normal_square.z +
        HarmonicCoeff[4] * normal_cross.x +
        HarmonicCoeff[5] * normal_cross.y +
        HarmonicCoeff[6] * normal_cross.z +
        HarmonicCoeff[7] * N.x +
        HarmonicCoeff[8] * N.y +
        HarmonicCoeff[9] * N.z;

    LightSum = max(LightSum, AmbientFloor);

    OUT.diffuse_color = LightSum * diffuse_scale;
    OUT.diffuse_color.w = diffuse_scale.w;

    float3 refl_vector = (2.0 * vdotn * N) - view_vector;
    OUT.t0.xyz = mul(float4(refl_vector, 0), WorldView).xyz;
    OUT.t0.w   = 1.0;

    float4 SpecSum =
        HarmonicCoeff[0] +
        HarmonicCoeff[1] * (refl_vector.x * refl_vector.x) +
        HarmonicCoeff[2] * (refl_vector.y * refl_vector.y) +
        HarmonicCoeff[3] * (refl_vector.z * refl_vector.z) +
        HarmonicCoeff[4] * (refl_vector.x * refl_vector.y) +
        HarmonicCoeff[5] * (refl_vector.z * refl_vector.x) +
        HarmonicCoeff[6] * (refl_vector.y * refl_vector.z) +
        HarmonicCoeff[7] * refl_vector.x +
        HarmonicCoeff[8] * refl_vector.y +
        HarmonicCoeff[9] * refl_vector.z;

    float specular_lum = pow(saturate(SpecSum.w), SpecularPower);

    OUT.specular_color.xyz = SpecSum.xyz * specular_lum * specular_scale.xyz * 0.5;
    OUT.specular_color.w   = envvdotn;

    return OUT;
}
float4 ps_main(VS_OUTPUT IN) : COLOR0
{
    float4 diffuse_tex = tex2D(samp, IN.t1);
    float4 envmap_tex  = texCUBE(envmap_sampler, IN.t0);

    float4 diffuse_final = diffuse_tex * IN.diffuse_color;

    float4 env_scale = EnvmapMin + IN.specular_color.w * EnvmapRange;

    float3 env_contrast = envmap_tex.rgb * envmap_tex.rgb;
    float3 envmap_final =
        lerp(envmap_tex.rgb, env_contrast, 0.3) *
        env_scale.rgb * ReflectionIntensity;

    float3 output_rgb =
        GlobalBrightness * diffuse_final.xyz +
        GlobalBrightness * diffuse_final.w *
        (IN.specular_color.xyz + GlobalBrightness * envmap_final);

    // Saturation (kept, but sane)
    float3 gray = dot(output_rgb, float3(0.3, 0.59, 0.11));
    output_rgb = lerp(gray, output_rgb, CarSaturation);

    return float4(output_rgb, diffuse_final.w);
}
technique car <int shader = 1;>
{
    pass p0
    {
        AlphaTestEnable  = <BlendState[0]>;
        AlphaRef         = <BlendState[1]>;
        AlphaBlendEnable = <BlendState[2]>;
        SrcBlend         = <BlendState[3]>;
        DestBlend        = <BlendState[4]>;
        ZFunc            = 4;
        ColorWriteEnable = 15;
        FogEnable        = 0;

        VertexShader = compile vs_2_0 vs_main();
        PixelShader  = compile ps_2_0 ps_main();
    }
}
