// Layered clear-coat reflection for wheel materials.
// This pass deliberately does not supply a base colour: rimpaint/rimpaintsec
// remain visible underneath, including true black and custom wheel colours.

#include "mta-helper.fx"

texture sReflectionTexture;

float sReflectionStrength = 1.65;
float sReflectionOpacity = 0.42;
float sRoughness = 0.035;
float sEnvironmentExposure = 1.15;
float sEnvironmentSaturation = 0.16;
float sEnvironmentWarmth = 0.32;
float sSpecularStrength = 0.12;

samplerCUBE ReflectionSampler = sampler_state
{
    Texture = (sReflectionTexture);
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

struct VSInput
{
    float3 Position : POSITION0;
    float3 Normal : NORMAL0;
    float4 Diffuse : COLOR0;
    float2 TexCoord : TEXCOORD0;
};

struct PSInput
{
    float4 Position : POSITION0;
    float3 WorldNormal : TEXCOORD0;
    float3 ViewDirection : TEXCOORD1;
    float3 Lighting : COLOR0;
};

PSInput WheelVS(VSInput input)
{
    PSInput output = (PSInput)0;
    output.Position = mul(float4(input.Position, 1.0), gWorldViewProjection);

    float3 worldPosition = MTACalcWorldPosition(input.Position);
    output.WorldNormal = normalize(mul(input.Normal, (float3x3)gWorld));
    output.ViewDirection = normalize(gCameraPosition - worldPosition);

    float directLight = saturate(dot(output.WorldNormal, normalize(-gLightDirection)));
    output.Lighting = saturate(gLightAmbient.rgb + gGlobalAmbient.rgb
        + gLightDiffuse.rgb * directLight);
    return output;
}

float3 sampleWheelEnvironment(float3 direction)
{
    float3 helper = abs(direction.y) < 0.92
        ? float3(0.0, 1.0, 0.0)
        : float3(1.0, 0.0, 0.0);
    float3 tangent = normalize(cross(direction, helper));
    float3 bitangent = normalize(cross(direction, tangent));
    float spread = sRoughness * sRoughness * 0.20;

    float3 sharp = texCUBE(ReflectionSampler, direction).rgb;
    float3 blurred = texCUBE(ReflectionSampler, normalize(direction + tangent * spread)).rgb;
    blurred += texCUBE(ReflectionSampler, normalize(direction - tangent * spread)).rgb;
    blurred += texCUBE(ReflectionSampler, normalize(direction + bitangent * spread)).rgb;
    blurred += texCUBE(ReflectionSampler, normalize(direction - bitangent * spread)).rgb;
    blurred *= 0.25;

    float3 environment = lerp(sharp, blurred, saturate(sRoughness * 1.4));
    float environmentLuma = dot(environment, float3(0.299, 0.587, 0.114));
    environment = lerp(environmentLuma.xxx, environment, sEnvironmentSaturation);
    float3 warmNeutral = float3(1.06, 1.01, 0.90);
    environment *= lerp(float3(1.0, 1.0, 1.0), warmNeutral, sEnvironmentWarmth);
    return environment * sEnvironmentExposure;
}

float4 WheelPS(PSInput input) : COLOR0
{
    float3 normal = normalize(input.WorldNormal);
    float3 viewDirection = normalize(input.ViewDirection);
    float nDotV = saturate(dot(normal, viewDirection));
    float edge = 1.0 - nDotV;

    // The bundled cubemap uses GTA's Y/Z orientation.
    float3 reflectionDirection = reflect(-viewDirection, normal).xzy;
    float3 environment = sampleWheelEnvironment(reflectionDirection);

    // Match the old wheel material: its cubemap covered the whole surface
    // instead of appearing only at Fresnel angles. Cubing retains deep black
    // areas while bright cubemap shapes stay sharp and clearly readable.
    float3 shapedEnvironment = environment * environment * environment;
    float surfaceReflection = 0.72 + 0.28 * edge;
    float3 reflection = shapedEnvironment * surfaceReflection * sReflectionStrength;

    float3 lightDirection = normalize(-gLightDirection);
    float3 halfDirection = normalize(lightDirection + viewDirection);
    float highlight = pow(saturate(dot(normal, halfDirection)), 44.0);
    highlight *= saturate(dot(normal, lightDirection)) * sSpecularStrength;

    // Blend the reflected image over rimpaint like the legacy shader did. The
    // underlying primary/secondary colour remains the material's base layer.
    return float4(saturate(reflection + highlight.xxx), sReflectionOpacity);
}

technique neucalion_wheel_clearcoat
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        ZWriteEnable = false;
        VertexShader = compile vs_3_0 WheelVS();
        PixelShader = compile ps_3_0 WheelPS();
    }
}

technique fallback
{
    pass P0
    {
        // Keep the original wheel material on hardware without Shader Model 3.
    }
}
