// Copyright 2021 Michael Fabian Dirks <info@xaymar.com>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holder nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#define IS_FILTER
#include "../base.effect"

//------------------------------------------------------------------------------
// Uniforms
//------------------------------------------------------------------------------
uniform float _0_Strength<
	string name = "Rollbar Strength";
	string field_type = "slider";
	float minimum = 0.;
	float maximum = 100.;
	float step = 0.01;
	float scale = 0.01;
> = 100.0;

uniform int _1_Scanlines<
	string name = "Scanlines";
	string field_type = "slider";
	int minimum = 128;
	int maximum = 16384;
	int step = 1;
> = 525;

uniform float2 _1_Intensity<
	string name = "Scanline Brightness Min/Max";
	string field_type = "slider";
	float2 minimum = {0., 0.};
	float2 maximum = {200., 200.};
	float2 step = {0.01, 0.01};
	float2 scale = {0.01, 0.01};
> = {95.0, 100.0};

uniform bool _2_EnableBleed<
	string name = "Enable Color Bleeding";
> = true;

uniform float _3_ScanlineSize<
	string name = "Scanline Scaling";
	string field_type = "slider";
	float minimum = 0.01;
	float maximum = 100.;
	float step = 0.01;
	float scale = 0.01;
> = 100.0;

uniform float _4_Speed<
	string name = "Timescale";
	string field_type = "slider";
	float minimum = 0.01;
	float maximum = 100.;
	float step = 0.01;
	float scale = 0.01;
> = 60.0;

//------------------------------------------------------------------------------
// Technique: Version 1.0
//------------------------------------------------------------------------------
float4 Version1_0(VertexInformation vtx) : TARGET {
	float2 uv = vtx.texcoord0.xy;

	// 1. Calculate our current time offset based on the provided speed.
	float time_offset = Time.y * _4_Speed;

	// 2. Sample the original input.
	float4 rgb = InputA.Sample(LinearClampSampler, uv);

	// 3. If the user requested Scan Lines...
	if (!is_float_equal(_1_Intensity.x, _1_Intensity.y)) {
		// 1. Calculate the vertical index of the line.
		uint scanline_index = uint(floor(fmod((uv.y + time_offset), 1.) * _1_Scanlines));

		// 2. Map it back into a useful range.
		uint scanline_intensity = scanline_index % 2;

		// 3. Calculate the multiplier based on the index.
		float slmul = scanline_intensity == 0 ? _1_Intensity.x : _1_Intensity.y;

		// 4. Does the user want naive CRT bleeding?
		if (_2_EnableBleed) {
			// Very naive bleeding, but it gets the effect across.
			float offset = float(scanline_intensity) * 0.0005;
			float colorShift = 0.001;
			float r = InputA.Sample(LinearClampSampler, uv + offset + colorShift).r;
			float g = InputA.Sample(LinearClampSampler, uv + offset - colorShift).g;
			float b = rgb.b;
			rgb.rgb = float3(r, g, b); // g * 0.99?
		}

		// 4. Apply the multiplier.
		rgb.rgb *= slmul;
	} else {
		rgb.rgb *= _1_Intensity.x;
	}

	// 4. Does the user want the rollbar effect?
	if (is_float_equal(_0_Strength, .01) || (_0_Strength > 0.01)) {
		const float rollbar_cycle_length = 5.;
		float rollbar_cycle = Time.y + fmod(Time.z, rollbar_cycle_length);
		float rollbar = sin((uv.y + rollbar_cycle / rollbar_cycle_length) * TAU);
		rgb.rgb = lerp(rgb.rgb, rgb.rgb + (rollbar * 0.1), _0_Strength);
	}

	return rgb;
}

technique Draw {
	pass {
		vertex_shader = DefaultVertexShader(vtx);
		pixel_shader  = Version1_0(vtx);
	}
}

technique V1_0 {
	pass {
		vertex_shader = DefaultVertexShader(vtx);
		pixel_shader  = Version1_0(vtx);
	}
}
