#ifndef _CHROMADISTORT_FXH_
#define _CHROMADISTORT_FXH_
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//                                                                      
//  Multi-layerd Chromatic Distortion by kingeric1992        
//                                              update: Nov.4.2017
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include "enbInternals.fxh"
#include "Utilities.fxh"

static const float ChromaDistort_Taps = 2.0;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  Internals
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//.rgb == color, .a == offset
static const float4 ChromaDistort_Spectrum[7] = {
    float4(1.0, 0.0, 0.0,  1.0),//red
    float4(1.0, 0.5, 0.0,  0.7),//orange
    float4(1.0, 1.0, 0.0,  0.3),//yellow
    float4(0.0, 1.0, 0.0,  0.0),//green  
    float4(0.0, 0.0, 1.0, -0.6),//blue  
    float4(0.3, 0.0, 0.5, -0.8),//indigo  
    float4(0.1, 0.0, 0.2, -1.0) //purple 
};

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  Function
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

struct ChromaDistortStruct {
    bool  State;
    float Weight;
    float Ratio, Curve, Scale, Dispersion;
    Texture2D Tex;
};

float3 ChromaDistort( inout float2 uv, float3 col, ChromaDistortStruct IN) {
    if(!IN.State) return col;
    
           uv     -= 0.5;
    float2 ratio   = max(float2(IN.Ratio * ScreenSize.z, ScreenSize.w/IN.Ratio), 1.0) * ScreenSize.w; 
    float2 offset  = Distort(uv*ratio, IN.Curve, (1.0 + IN.Scale) * IN.Dispersion)/ratio - uv;
           uv      = Distort(uv*ratio, IN.Curve, IN.Scale)/ratio + 0.5;
    col = 0.0;
    [unroll]
    for(int i=0; i< 6 * ChromaDistort_Taps; i++) {
        float  t = i / ChromaDistort_Taps;
        float4 spectrum = lerp(ChromaDistort_Spectrum[t], ChromaDistort_Spectrum[t+1], frac(t));
        col = max(col, IN.Tex.Sample(SamplerLinear, uv + offset * spectrum.a).rgb * spectrum.rgb);
    }
    return max(col, IN.Tex.Sample(SamplerLinear, uv + offset * ChromaDistort_Spectrum[6].a).rgb
                                                             * ChromaDistort_Spectrum[6].rgb);
}

//Optional pass
float3 ChromaDistort_Opt( float3 col, float2 uv, ChromaDistortStruct IN) {
    if(!IN.State) return col;
    
    float  weight[11]= {0.082607, 0.080977, 0.076276, 0.069041, 0.060049, 
                        0.050187, 0.040306, 0.031105, 0.023066, 0.016436, 0.011254};
    float2 ratio   = max(float2(IN.Ratio, 1.0/IN.Ratio), 1.0);    
    float2 offset  = Distort((uv-0.5)*ratio, IN.Curve, IN.Scale)/ratio - (uv - 0.5);
           offset *= IN.Dispersion * 0.05;
           col     = IN.Tex.Sample(SamplerLinear, uv).rgb * weight[0];
    [unroll]
    for(int i=1; i<11; i++) {
        col += IN.Tex.Sample(SamplerLinear, uv + offset * i).rgb * weight[i];
        col += IN.Tex.Sample(SamplerLinear, uv + offset * i).rgb * weight[i];
    }
    return col;
}

#endif //_CHROMADISTORT_FXH_