// Ambient Edge Background
// Samples colors from game edges to create a dynamic ambient glow effect
// Similar to Philips Ambilight / bias lighting

//!BGFX EFFECT
//!VERSION 1
//!NAME Ambient Edge
//!CATEGORY Background
//!DESCRIPTION Creates an ambient glow effect by sampling colors from the edges of the game content. Similar to Ambilight/bias lighting.
//!USE_DYNAMIC

//!PARAMETER
//!LABEL Glow Intensity
//!DESC Brightness of the ambient glow effect.
//!DEFAULT 0.6
//!MIN 0.1
//!MAX 1.0
//!STEP 0.05
float glowIntensity;

//!PARAMETER
//!LABEL Glow Spread
//!DESC How far the glow extends into the bar area.
//!DEFAULT 0.5
//!MIN 0.1
//!MAX 1.0
//!STEP 0.05
float glowSpread;

//!PARAMETER
//!LABEL Sample Depth
//!DESC How far into the content to sample for edge colors (in pixels).
//!DEFAULT 20
//!MIN 5
//!MAX 50
//!STEP 5
float sampleDepth;

//!PARAMETER
//!LABEL Color Smoothing
//!DESC Smooths the color transitions along edges. Higher = smoother.
//!DEFAULT 0.5
//!MIN 0.0
//!MAX 1.0
//!STEP 0.1
float colorSmoothing;

//!TEXTURE
Texture2D INPUT;

//!TEXTURE
//!WIDTH RENDERER_WIDTH
//!HEIGHT RENDERER_HEIGHT
Texture2D OUTPUT;

//!SAMPLER
//!FILTER LINEAR
SamplerState linearSampler;

//!COMMON

float3 SampleEdgeColor(float2 edgePos, float2 normal, float depth) {
    float2 pt = GetInputPt();
    float3 sum = float3(0, 0, 0);
    float weight = 0;

    // Sample multiple points along the edge
    for (float d = 0; d < depth; d += 2.0) {
        float2 samplePos = edgePos + normal * d * pt;
        samplePos = saturate(samplePos);
        float w = 1.0 / (1.0 + d * 0.1);
        sum += INPUT.SampleLevel(linearSampler, samplePos, 0).rgb * w;
        weight += w;
    }

    return sum / max(weight, 0.001);
}

//!PASS 1
//!DESC Ambient Edge Background
//!STYLE PS
//!IN INPUT
//!OUT OUTPUT

float4 Pass1(float2 pos) {
    float2 inputSize = float2(GetInputSize());
    float2 outputSize = float2(GetOutputSize());

    float inputAspect = inputSize.x / inputSize.y;
    float outputAspect = outputSize.x / outputSize.y;

    float2 contentScale;
    float2 contentOffset;

    if (inputAspect > outputAspect) {
        contentScale = float2(1.0, outputAspect / inputAspect);
        contentOffset = float2(0.0, (1.0 - contentScale.y) * 0.5);
    } else {
        contentScale = float2(inputAspect / outputAspect, 1.0);
        contentOffset = float2((1.0 - contentScale.x) * 0.5, 0.0);
    }

    float2 contentUV = (pos - contentOffset) / contentScale;
    bool insideContent = all(contentUV >= 0.0) && all(contentUV <= 1.0);

    // Initialize result
    float4 result = float4(0, 0, 0, 1);

    if (insideContent) {
        result = INPUT.SampleLevel(linearSampler, contentUV, 0);
    } else {
        // Determine which edge to sample from and calculate glow
        float2 clampedUV = saturate(contentUV);
        float2 distFromEdge = abs(contentUV - clampedUV);

        // Find the closest edge and sample direction
        float3 edgeColor = float3(0, 0, 0);

        if (contentUV.x < 0.0) {
            // Left edge
            edgeColor = SampleEdgeColor(float2(0, clampedUV.y), float2(1, 0), sampleDepth);
        } else if (contentUV.x > 1.0) {
            // Right edge
            edgeColor = SampleEdgeColor(float2(1, clampedUV.y), float2(-1, 0), sampleDepth);
        } else if (contentUV.y < 0.0) {
            // Top edge
            edgeColor = SampleEdgeColor(float2(clampedUV.x, 0), float2(0, 1), sampleDepth);
        } else {
            // Bottom edge
            edgeColor = SampleEdgeColor(float2(clampedUV.x, 1), float2(0, -1), sampleDepth);
        }

        // Apply smoothing by blending with neighbors
        if (colorSmoothing > 0.0) {
            float2 pt = GetInputPt() * 10.0;
            float3 neighbor1 = INPUT.SampleLevel(linearSampler, saturate(clampedUV + float2(pt.x, 0)), 0).rgb;
            float3 neighbor2 = INPUT.SampleLevel(linearSampler, saturate(clampedUV - float2(pt.x, 0)), 0).rgb;
            float3 neighbor3 = INPUT.SampleLevel(linearSampler, saturate(clampedUV + float2(0, pt.y)), 0).rgb;
            float3 neighbor4 = INPUT.SampleLevel(linearSampler, saturate(clampedUV - float2(0, pt.y)), 0).rgb;
            float3 avgNeighbor = (neighbor1 + neighbor2 + neighbor3 + neighbor4) * 0.25;
            edgeColor = lerp(edgeColor, avgNeighbor, colorSmoothing * 0.5);
        }

        // Calculate falloff from content edge
        float dist = length(distFromEdge);
        float maxDist = length(contentOffset) * glowSpread;
        float falloff = 1.0 - saturate(dist / max(maxDist, 0.001));
        falloff = pow(falloff, 1.5); // Smooth falloff curve

        // Apply glow
        float3 color = edgeColor * glowIntensity * falloff;
        result = float4(color, 1.0);
    }

    return result;
}
