// Copyright (C) Microsoft Corporation. All rights reserved.
// On update: build, rename & replace ShaderEffect.cso

#define D2D_INPUT_COUNT 1
#define D2D_REQUIRES_SCENE_POSITION
 
#include "d2d1effecthelpers.hlsli"
 
// Uniform
// Color the screen slowly turns as the ripple completes
float4 glimmerColor;
float2 resolution;
float2 clickPos;
float time;
 
// Wavelength of the ripple
static const float wavelength = 0.75;
 
// Height of the wave
static const float amplitude = 0.04;
 
// Duration of the animation in seconds
// NOTE - if the click is in the center of the screen, the animation reaches the edges of the
// screen faster than if the click is at one edge of the screen. This duration is the MAXIMUM
// amount of time the animation will take. It will finish twice as fast if the click is in the
// center of the screen.
static const float duration = 0.7;
 
// Color shift for chromatic aberration, as a multipler of the wave
static const float2 redShift = float2(0.0115, 1.15);
static const float2 greenShift = float2(0.01, 1.0);
static const float2 blueShift = float2(0.0085, 0.85);
 
static const float M_2PI = 6.28318530718;
 
D2D_PS_ENTRY(main)
{
    // Calculate distance of pixel from click position
    float2 fragCoord = D2DGetScenePosition().xy;
    float resolution1D = min(resolution.x, resolution.y);
    float2 offset = fragCoord - clickPos;
    float dist = length(offset) / resolution1D;
 
    // Time passed from 0 to 1
    float t = min(1.0, time / duration);
 
    // Define the ripple radius based on time
    // -(x-1)^2 + 1 is a fast-in/ease-out function
    float rippleRadius = -(t-1)*(t-1)+1;
 
    // Fade the wavelength to widen with time
    // (we will also adjust amplitude down with time, like it is spreading out)
    // Careful to never let it reach 0, since we divide by this later.
    float lambda = wavelength * (1 + t * 0.1); 
    // Calculate how many periods away this fragment is
    float d = max(0, (rippleRadius-dist) / lambda);
    // Height of the sine wave
    float sinFactor = -sin(d * M_2PI);
    // Fade the ripple amplitude the farther away this fragment is from the current radius
    float fade = exp(-d * d * 4);
 
    // Calculate the height of the wave using all those parameters.
    // Multiply by 1-t to make the amplitude fade down linearly over time.
    float h = sinFactor * fade * max(1-t,0);
 
    // Uncomment to see the sine wave
    // return float4(h,h,h,1);
 
    // Multiply by the amplitude
    h *= amplitude;
 
    float2 redChrom = resolution1D / 2 * redShift;
    float2 greenChrom = resolution1D / 2 * greenShift;
    float2 blueChrom = resolution1D / 2 * blueShift;
 
    // Chromatic aberration offsets
    // Alpha is disabled for the moment but can be re-enabled if we want.
    float2 uvRed = (fragCoord + h * redChrom) / resolution;
    float2 uvGreen = (fragCoord + h * greenChrom) / resolution;
    float2 uvBlue = (fragCoord + h * blueChrom) / resolution;
 
    // Clamp to the last pixel
    float2 minBorder = float2(1,1) / resolution;
    float2 maxBorder = (resolution-float2(1,1)) / resolution;
    uvRed = clamp(uvRed, minBorder, maxBorder);
    uvGreen = clamp(uvGreen, minBorder, maxBorder);
    uvBlue = clamp(uvBlue, minBorder, maxBorder);
    float red = D2DSampleInput(0, uvRed).r;
    float green = D2DSampleInput(0, uvGreen).g;
    float blue = D2DSampleInput(0, uvBlue).b;
 
    // Add in some blue haze
    // e^(-t*t*4) is a smooth-in smooth-out easing function from 1 to 0, so subtract from 1
    float glimmerAlpha = glimmerColor.a * (1 - exp(-t * t * 4));
 
    return float4(float3(red,green,blue) * (1 - glimmerAlpha) + glimmerColor.rgb * glimmerAlpha, 1);
}
