/// tip:"Requires MSAA off for best results"

/*****************************************
 * FXAA 3.11 Implementation - effendiian
 * -------------------------------------
 * FXAA implementation based off of the 
 * work by Timothy Lottes in the Nvidia white paper:
 * https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
 *
 * Also used these resources:
 * - https://catlikecoding.com/unity/tutorials/advanced-rendering/fxaa/
 * - https://blog.codinghorror.com/fast-approximate-anti-aliasing-fxaa/
 *****************************************/

// Turn off FXAA.
// #define FXAA 0

// Turn on FXAA.
#define FXAA 1

// Turn on split screen between no-FXAA and FXAA.
// #define FXAA 2

/*
/   FXAA setting, defined via preprocessor variables
*/
#ifndef FXAA_PRESET
    #define FXAA_PRESET 5
    #define FXAA_DEBUG_SKIPPED 0
    #define FXAA_DEBUG_PASSTHROUGH 0
    #define FXAA_DEBUG_HORZVERT 0
    #define FXAA_DEBUG_PAIR 0
    #define FXAA_DEBUG_NEGPOS 0
    #define FXAA_DEBUG_OFFSET 0
    #define FXAA_DEBUG_HIGHLIGHT 0
    #define FXAA_LUMINANCE 1
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 0)
    #define FXAA_EDGE_THRESHOLD      (1.0/4.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/12.0)
    #define FXAA_SEARCH_STEPS        2
    #define FXAA_SEARCH_ACCELERATION 4
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       1
    #define FXAA_SUBPIX_CAP          (2.0/3.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 1)
    #define FXAA_EDGE_THRESHOLD      (1.0/8.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/16.0)
    #define FXAA_SEARCH_STEPS        4
    #define FXAA_SEARCH_ACCELERATION 3
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       0
    #define FXAA_SUBPIX_CAP          (3.0/4.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 2)
    #define FXAA_EDGE_THRESHOLD      (1.0/8.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/24.0)
    #define FXAA_SEARCH_STEPS        8
    #define FXAA_SEARCH_ACCELERATION 2
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       0
    #define FXAA_SUBPIX_CAP          (3.0/4.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 3)
    #define FXAA_EDGE_THRESHOLD      (1.0/8.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/24.0)
    #define FXAA_SEARCH_STEPS        16
    #define FXAA_SEARCH_ACCELERATION 1
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       0
    #define FXAA_SUBPIX_CAP          (3.0/4.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 4)
    #define FXAA_EDGE_THRESHOLD      (1.0/8.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/24.0)
    #define FXAA_SEARCH_STEPS        24
    #define FXAA_SEARCH_ACCELERATION 1
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       0
    #define FXAA_SUBPIX_CAP          (3.0/4.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#if (FXAA_PRESET == 5)
    #define FXAA_EDGE_THRESHOLD      (1.0/8.0)
    #define FXAA_EDGE_THRESHOLD_MIN  (1.0/24.0)
    #define FXAA_SEARCH_STEPS        32
    #define FXAA_SEARCH_ACCELERATION 1
    #define FXAA_SEARCH_THRESHOLD    (1.0/4.0)
    #define FXAA_SUBPIX              1
    #define FXAA_SUBPIX_FASTER       0
    #define FXAA_SUBPIX_CAP          (3.0/4.0)
    #define FXAA_SUBPIX_TRIM         (1.0/4.0)
#endif
/*--------------------------------------------------------------------------*/
#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))

// --------------------------------------
// Helper functions.
// --------------------------------------

// ---------------------
// Conversion functions.

// ToVec2
vec2 ToVec2( float value ) { return vec2(value, value); }

// ToVec3
vec3 ToVec3( float value ) { return vec3(value, value, value); }
vec3 ToVec3( vec2 vector, float z ) { return vec3(vector.x, vector.y, z); }
vec3 ToVec3( vec2 vector ) { return ToVec3(vector, 0.0); }

// ToVec4
vec4 ToVec4( vec2 vector, float z, float w ) { return vec4(vector.x, vector.y, z, w); }
vec4 ToVec4( vec2 vector, float z ) { return ToVec4(vector, z, 0.0); }
vec4 ToVec4( vec2 vector ) { return ToVec4(vector, 0.0); }
vec4 ToVec4( vec3 vector, float w ) { return vec4(vector.x, vector.y, vector.z, w); }
vec4 ToVec4( vec3 vector ) { return ToVec4(vector, 0.0); }
vec4 ToVec4( float value, float w ) { return vec4(value, value, value, w); }
vec4 ToVec4( float value ) { return ToVec4(value, 0.0); }

// ---------------------
// Texture sampler functions.

// Return sampled image from a point + offset texel space.
vec4 TextureOffset( sampler2D tex, 
                    vec2 uv, 
                    vec2 offset ) {
    
    // Return color from the specified location.
    return texture(tex, uv + offset); 
        
}

// ---------------------
// Grayscale functions.

// Return grayscaled image based off of the selected color channel.
vec3 Grayscale( vec3 color, int index ) {
    int selectedChannel = clamp(index, 0, 2); // [0]r, [1]g, [2]b.
    return ToVec3(color[selectedChannel]);
}

// Return grayscaled image based off of the selected color channel.
vec4 Grayscale( vec4 color, int index ) {
    int selectedChannel = clamp(index, 0, 3); // [0]r, [1]g, [2]b, [3]a.
    return ToVec4(color[selectedChannel]);
}

// Default to green color channel when no index is supplied.
vec3 Grayscale( vec3 color ) { return Grayscale(color, 1); }
vec4 Grayscale( vec4 color ) { return Grayscale(color, 1); }

// ---------------------
// Luminance functions.

// Map RGB to Luminance linearly.
float LinearRGBLuminance( vec3 color ) {
    
    // Weights for relative luma from here: https://en.wikipedia.org/wiki/Luma_(video)
    vec3 weight = vec3(0.2126729, 0.7151522, 0.0721750);
    
    // Get the dot product:
    // - color.r * weight.r + color.g * weight.g + color.b * weight*b.
    return dot(color, weight);
}

// Luminance based off of the original specification.
float FXAALuminance( vec3 color ) {
    
    #if FXAA_LUMINANCE == 0
    
    return LinearRGBLuminance( color );
    
    #else
    
    return color.g * (0.587/0.299) + color.r;
    
    #endif
}

// ---------------------
// Vertical/Horizontal Edge Test functions.

float FXAAVerticalEdge( float lumaO,
                       float lumaN, 
                       float lumaE, 
                       float lumaS, 
                       float lumaW,
                       float lumaNW,
                       float lumaNE,
                       float lumaSW,
                       float lumaSE ) {
    
    // Slices to calculate.
    float top = (0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE);
    float middle = (0.50 * lumaW ) + (-1.0 * lumaO) + (0.50 * lumaE );
    float bottom = (0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE);
    
    // Return value.
    return abs(top) + abs(middle) + abs(bottom);
}

float FXAAHorizontalEdge( float lumaO,
                       float lumaN, 
                       float lumaE, 
                       float lumaS, 
                       float lumaW,
                       float lumaNW,
                       float lumaNE,
                       float lumaSW,
                       float lumaSE ) {
    
    // Slices to calculate.
    float top = (0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW);
    float middle = (0.50 * lumaN ) + (-1.0 * lumaO) + (0.50 * lumaS );
    float bottom = (0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE);
    
    // Return value.
    return abs(top) + abs(middle) + abs(bottom);
}

// ------------------------
// FXAA specific functions.
// ------------------------

// Entry point for the FXAA process.
vec3 applyFXAA(sampler2D textureSource, 
               vec2 textureDimensions, 
               vec2 pixelPosition,
               vec2 screenResolution) {
    
    // Normalized pixel coordinates (from 0 to 1).
    vec2 uv = pixelPosition / screenResolution;
    
    // Calculate distance between pixels in texture space.
    vec2 texel = vec2(1.0, 1.0) / textureDimensions;
    
    // Caculate the luminance.
    // float luma = FXAALuminance(rgbO.xyz);
    // float luma = LinearRGBLuminance(clamp(rgbO.xyz, 0.0, 1.0));
    
    //-------------------------
    // 1. LOCAL CONTRAST CHECK
    
    // Sample textures from cardinal directions.
    vec3 rgbN = TextureOffset(textureSource, uv, vec2(0, -texel.y)).rgb; // NORTH
    vec3 rgbW = TextureOffset(textureSource, uv, vec2(-texel.x, 0)).rgb; // WEST
    vec3 rgbO = TextureOffset(textureSource, uv, vec2(0, 0)).rgb; // ORIGIN
    vec3 rgbE = TextureOffset(textureSource, uv, vec2(texel.x, 0)).rgb; // EAST
    vec3 rgbS = TextureOffset(textureSource, uv, vec2(0, texel.y)).rgb; // SOUTH
    
    #if FXAA == 0
    return rgbO; // Skip FXAA if it is off.
    #endif    
    
    // Calculate the luminance for each sampled value.
    float lumaN = FXAALuminance(rgbN);
    float lumaW = FXAALuminance(rgbW);
    float lumaO = FXAALuminance(rgbO);
    float lumaE = FXAALuminance(rgbE);
    float lumaS = FXAALuminance(rgbS);
    
    // Calculate the minimum luma range.
    float minLuma = min( lumaO, min( min( lumaN, lumaW ), min( lumaS, lumaE ) ) );
    float maxLuma = max( lumaO, max( max( lumaN, lumaW ), max( lumaS, lumaE ) ) );
    float localContrast = maxLuma - minLuma;    
    
    // Check for early exit.
    if(localContrast < max( FXAA_EDGE_THRESHOLD_MIN, maxLuma * FXAA_EDGE_THRESHOLD )) {
        
        #if FXAA_DEBUG_SKIPPED
                
        return vec3(0);
        
        #else
        
        return rgbO;
        
        #endif
    }
        
    //-------------------------
    // 2. SUB-PIXEL ALIASING TEST
    
    // Calculate the pixel contrast ratio.
    // - Sub-pixel aliasing is detected by taking the ratio of the 
    // pixel contrast over the local contrast. This ratio nears 1.0
    // in the presence of single pixel dots and otherwise falls off
    // towards 0.0 as more pixels contribute to an edge. This ratio
    // is transformed into the amount of lowpass filter to blend in
    // at the end of the algorithm.
    
    #if FXAA_SUBPIX > 0
    
    // Calculate sum of local samples for the lowpass.
    vec3 rgbL = (rgbN + rgbW + rgbO + rgbE + rgbS);
    
        #if FXAA_SUBPIX_FASTER

        // Average the lowpass now since this skips the addition of the diagonal neighbors (NW, NE, SW, SE).
        rgbL *= (1.0/5.0);

        #endif    

    // Calculate the lowpass luma.
    // - Lowpass luma is calculated as the average between the luma of neigboring pixels.
    float lumaL = (lumaN + lumaW + lumaS + lumaE) * 0.25;

    // Calculate the pixel contrast.
    // - Pixel contrast is the abs() difference between origin pixel luma and lowpass luma of neighbors.
    float pixelContrast = abs(lumaL - lumaO);
    
    // Remember: 
    // - pixel contrast is the origin - lowpass(neighbors).
    // - local contrast is the min(origin + neighbors) - max(origin + neighbors) < threshold.
   
    // Calculate the ratio between the pixelContrast and localContrast.
    float contrastRatio = pixelContrast / localContrast;
    float lowpassBlend = 0.0; // Default is zero. Will be changed depending on subpixel level.
    
        #if FXAA_SUBPIX == 1
    
        // Normal subpixel aliasing. Set based on FXAA algorithm for subpixel aliasing.
        lowpassBlend = max( 0.0, contrastRatio - FXAA_SUBPIX_TRIM ) * FXAA_SUBPIX_TRIM_SCALE;
        lowpassBlend = min( FXAA_SUBPIX_CAP, lowpassBlend );
    
        #elif FXAA_SUBPIX == 2
    
        // Full force subpixel aliasing. Set blend to ratio.
        lowpassBlend = contrastRatio;
    
        #endif
    
    #endif
    
    // Show selected pixels if debug mode is active.
    #if FXAA_DEBUG_PASSTHROUGH
    
        #if FXAA_SUBPIX > 0    
    
        return vec3(localContrast, lowpassBlend, 0.0);
    
        #else 
        
        return vec3(localContrast, 0.0, 0.0);   
    
        #endif
    
    #endif
    
    //-------------------------
    // 3. VERTICAL & HORIZONTAL EDGE TEST
    
    // Sample the additional diagonal neighbors.
    vec3 rgbNW = TextureOffset(textureSource, uv, vec2(-texel.x, -texel.y)).rgb; // NORTH-WEST
    vec3 rgbNE = TextureOffset(textureSource, uv, vec2(texel.x, -texel.y)).rgb; // NORTH-EAST
    vec3 rgbSW = TextureOffset(textureSource, uv, vec2(-texel.x, texel.y)).rgb; // SOUTH-WEST
    vec3 rgbSE = TextureOffset(textureSource, uv, vec2(texel.x, texel.y)).rgb; // SOUTH-EAST
    
    // Average additional neighbors when sub-pix aliasing is on and it isn't in 'fast' mode.
    #if FXAA_SUBPIX > 0
        #if FXAA_SUBPIX_FASTER == 0
            // Add missing neighbors and average them.
            rgbL += (rgbNW + rgbNE + rgbSW + rgbSE);  
            rgbL *= (1.0/9.0);
        #endif
    #endif
    
    // Calculate luma for additional neighbors.
    float lumaNW = FXAALuminance(rgbNW);
    float lumaNE = FXAALuminance(rgbNE);
    float lumaSW = FXAALuminance(rgbSW);
    float lumaSE = FXAALuminance(rgbSE);
    
    // Calculate the vertical and horizontal edges. (Uses algorithm from FXAA white paper).
    float edgeVert = FXAAVerticalEdge(lumaO, lumaN, lumaE, lumaS, lumaW, lumaNW, lumaNE, lumaSW, lumaSE);
    float edgeHori = FXAAHorizontalEdge(lumaO, lumaN, lumaE, lumaS, lumaW, lumaNW, lumaNE, lumaSW, lumaSE);
    
    // Check if edge is horizontal.
    bool isHorizontal = edgeHori >= edgeVert;
    
    #if FXAA_DEBUG_HORZVERT
    if(isHorizontal) 
    {
        return vec3(1.0, 0.75, 0.0);
    } 
    else 
    {
        return vec3(0.10, 0.10, 1.0);
    }
    #endif
    
    //-------------------------
    // 4. FIND HIGHEST CONTRAST PAIR 90deg TO EDGE
    
    // Contain the appropriate sign for the top left.
    float edgeSign = isHorizontal ? -texel.y : -texel.x; // Note, if isHorizontal == true, -texel.y is applied (not -texel.x).
    
    // Calculate the gradients. The luma used changes based on the horizontal edge status.
    float gradientNeg = isHorizontal ? abs(lumaN - lumaO) : abs(lumaW - lumaO);
    float gradientPos = isHorizontal ? abs(lumaS - lumaO) : abs(lumaE - lumaO); 
    
    // Calculate the luma based on its direction.
    // It is an average of the origin and the luma in the respective direction.
    float lumaNeg = isHorizontal ? ((lumaN + lumaO) * 0.5) : ((lumaW + lumaO) * 0.5);    
    float lumaPos = isHorizontal ? ((lumaS + lumaO) * 0.5) : ((lumaE + lumaO) * 0.5);
    
    // Select the highest gradient pair.
    bool isNegative = (gradientNeg >= gradientPos);
    float gradientHighest = isNegative ? gradientNeg : gradientPos; // Assign higher pair.
    float lumaHighest = isNegative ? lumaNeg : lumaPos;
    
    // If gradient pair in the negative direction is higher, flip the edge sign.
    if(isNegative) { edgeSign *= -1.0; }
    
    #if FXAA_DEBUG_PAIR
    return isHorizontal ? vec3(0.0, gradientHighest, lumaHighest) : vec3(0.0, lumaHighest, gradientHighest); 
    #endif
    
    //-------------------------
    // 5. END-OF-EDGE SEARCH
    
    // Select starting point.
    vec2 pointN = vec2(0.0, 0.0);
    pointN.x = uv.x + (isHorizontal ? 0.0 : edgeSign * 0.5);
    pointN.y = uv.y + (isHorizontal ? edgeSign * 0.5 : 0.0);
    
    // Assign search limiting values.
    gradientHighest *= FXAA_SEARCH_THRESHOLD;
    
    // Prepare variables for search.
    vec2 pointP = pointN; // Start at the same point.
    vec2 pointOffset = isHorizontal ? vec2(texel.x, 0.0) : vec2(0.0, texel.y);
    float lumaNegEnd = lumaNeg;
    float lumaPosEnd = lumaPos;
    bool searchNeg = false;
    bool searchPos = false;
    
    // Apply values based on FXAA flags.
    if(FXAA_SEARCH_ACCELERATION == 1) {
        
        pointN += pointOffset * vec2(-1.0);
        pointP += pointOffset * vec2(1.0);
        // pointOffset *= vec2(1.0);
        
    } else if(FXAA_SEARCH_ACCELERATION == 2) {    
        
        pointN += pointOffset * vec2(-1.5);
        pointP += pointOffset * vec2(1.5);
        pointOffset *= vec2(2.0);
        
    } else if(FXAA_SEARCH_ACCELERATION == 3) {  
        
        pointN += pointOffset * vec2(-2.0);
        pointP += pointOffset * vec2(2.0);
        pointOffset *= vec2(3.0);
        
    } else if(FXAA_SEARCH_ACCELERATION == 4) { 
        
        pointN += pointOffset * vec2(-2.5);
        pointP += pointOffset * vec2(2.5);
        pointOffset *= vec2(4.0);
        
    }
    
    // Perform the end-of-edge search.
    for(int i = 0; i < FXAA_SEARCH_STEPS; i++) 
    {
        if(FXAA_SEARCH_ACCELERATION == 1) {            
            if(!searchNeg) { lumaNegEnd = FXAALuminance(texture(textureSource, pointN).rgb); }
            if(!searchPos) { lumaPosEnd = FXAALuminance(texture(textureSource, pointP).rgb); } 
        } 
        else
        {
            if(!searchNeg) { lumaNegEnd = FXAALuminance(textureGrad(textureSource, pointN, pointOffset, pointOffset).rgb); }
            if(!searchPos) { lumaPosEnd = FXAALuminance(textureGrad(textureSource, pointP, pointOffset, pointOffset).rgb); } 
        }
        
        // Search for significant change in luma compared to current highest pair.
#if 0 // original
        searchNeg = searchNeg || (abs(lumaNegEnd - lumaNeg) >= gradientNeg);
        searchPos = searchPos || (abs(lumaPosEnd - lumaPos) >= gradientPos);
#else // iradicator's fix
        searchNeg = searchNeg || (abs(lumaNegEnd - lumaHighest) >= gradientHighest);
        searchPos = searchPos || (abs(lumaPosEnd - lumaHighest) >= gradientHighest);
#endif        
        
        // Display debug information regarding edges.
        #if FXAA_DEBUG_NEGPOS
        
        if(searchNeg) { 
            return vec3(abs(lumaNegEnd - gradientNeg), 0.0, 0.0);  
        } else if(searchPos) { 
            return vec3(0.0, 0.0, abs(lumaPosEnd - gradientPos));  
        }

        #endif
        
        // Determine if search is over early.
        if(searchNeg && searchPos) { break; }
        
        // If still searching, increment offset.
        if(!searchNeg) { pointN -= pointOffset; }
        if(!searchPos) { pointP += pointOffset; }
    }
    
    //-------------------------
    // 6. SUB-PIXEL SHIFT
    
    // Determine if sub-pixel center falls on positive or negative side.
    float distanceNeg = isHorizontal ? uv.x - pointN.x : uv.y - pointN.y;
    float distancePos = isHorizontal ? pointP.x - uv.x : pointP.y - uv.y;
    bool isCloserToNegative = distanceNeg < distancePos;
    
    // Assign respective luma.
    float lumaEnd = isCloserToNegative ? lumaNegEnd : lumaPosEnd;
    
    // Check if pixel is in area that receives no filtering.
    if( ((lumaO - lumaNeg) < 0.0) == ((lumaEnd - lumaNeg) < 0.0) ) {
        edgeSign = 0.0;
    }
    
    // Compute sub-pixel offset and filter span.
    float filterSpanLength = (distancePos + distanceNeg);
    float filterDistance = isCloserToNegative ? distanceNeg : distancePos;
    float subpixelOffset = ( 0.5 + ( filterDistance * (-1.0 / filterSpanLength) ) ) * edgeSign;
    
    #if FXAA_DEBUG_OFFSET  
    
    if(subpixelOffset < 0.0) {
        return isHorizontal ? vec3(1.0, 0.0, 0.0) : vec3(1.0, 0.7, 0.1); // neg-horizontal (red) : neg-vertical (gold)
    } 
    
    if(subpixelOffset > 0.0) {
        return isHorizontal ? vec3(0.0, 0.0, 1.0) : vec3(0.1, 0.3, 1.0); // pos-horizontal (blue) : pos-vertical (skyblue)
    }
        
    #endif
    
    // Resample using the subpixel offset.
    vec3 rgbOffset = textureLod(textureSource, vec2( uv.x + (isHorizontal ? 0.0 : subpixelOffset), uv.y + (isHorizontal ? subpixelOffset : 0.0)), 0.0).rgb;
    
    // return vec3((lumaN + lumaS + lumaE + lumaW + lumaNW + lumaNE + lumaSW + lumaSE) * (1.0/9.0));
    
    #if FXAA_DEBUG_HIGHLIGHT
    
    return isHorizontal ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
    
    #endif
    
    // Return the FXAA effect.
    #if FXAA_SUBPIX == 0
    
    return vec3(rgbOffset);
    
    #else
    
    return mix(rgbOffset, rgbL, lowpassBlend);
    
    #endif
}

// ------------------------
// Main function.
// ------------------------

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{ 
    
    #if (FXAA == 2)
    
    vec2 uv = fragCoord/iResolution.xy; // Normalized pixel coordinates (from 0 to 1)
    vec3 resultFXAA = vec3(1.0);
    
    float speed = 0.45;
    vec2 extents = vec2(0.1, 0.8);
    float divisor = ( ((sin(iTime * speed) * 0.5) + 0.5) * extents.y ) + extents.x;
    float increment = 0.005;
    
    float divNeg = divisor - increment;
    float divPos = divisor + increment;
    
    if(uv.x >= divNeg && uv.x <= divPos) { resultFXAA = vec3(0.1); }
    if(uv.x < divNeg) { resultFXAA = mix(texture(iChannel0, vec2(uv.x, uv.y)).xyz, vec3(0.9, 0.9, 0.9), 0.1); }
    if(uv.x > divPos) { resultFXAA = applyFXAA(iChannel0, iChannelResolution[0].xy, fragCoord, iResolution.xy); }   
    
    #else
        
    // Calculuate the FXAA value for the whole screen.
    vec3 resultFXAA = applyFXAA(iChannel0, iChannelResolution[0].xy, fragCoord, iResolution.xy);
    
    #endif
    
    // Return the sampled pixel.
    fragColor = ToVec4(resultFXAA, 1.0);    
}