// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2019-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END

#include "common.effect"

// # Linear Optimization
// While the normal way is to sample every texel in the pSize, linear optimization
//  takes advantage of the fact that most people, especially after compression,
//  will not be able to tell the difference between a linear approximation and
//  the actual thing.
//
// Instead of sampling every texel like this:
//
//   |Tx|Tx|Tx|Tx|Tx|
// Tx|-2|-1| 0|+1|+2|
//
// Linear optimization will sample like this:
//
//   |Tx|Tx|Tx|Tx|Tx|
// Tx| -1  | 0|  +1 |
//
// This effectively removes half the necessary samples and looks identical when
//  when used with box blur. However there is an edge case when the blur width
//  is not a multiple of two, where two additional samples have to be spent on
//  reading the outer edge:
//
//   |Tx|Tx|Tx|Tx|Tx|Tx|Tx|
// Tx|-2| -1  | 0|  +1 |+2|
//
// or this alternative pattern that uses two less samples:
//
//   |Tx|Tx|Tx|Tx|Tx|Tx|Tx|
// Tx|  0  |  +1 |  +2 |+3|
//
// With careful planning this can even be used for other types of Blur, such as
//  Gaussian Blur, which suffers a larger hit - however there are better and
//  faster alternatives than linear sampling with Gaussian Blur, such as
//  Dual Filtering ("Dual Kawase").

//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
#define MAX_BLUR_SIZE 128u

//------------------------------------------------------------------------------
// Technique: Directional / Area
//------------------------------------------------------------------------------
float4 PSBlur1D(VertexInformation vtx) : TARGET {
	// y = yes, s = skip, b = break
	// Size-> | 1| 2| 3| 4| 5| 6| 7|
	// -------+--+--+--+--+--+--+--+
	//  n=1   | b| y| y| y| y| y| y|
	//  n=2   |  |bs| s| s| s| s| s|
	//  n=3   |  | b| b| y| y| y| y|
	//  n=4   |  |  |  |bs| s| s| s|
	//  n=5   |  |  |  | b| b| y| y|
	//  n=6   |  |  |  |  |  |bs| s|
	//  n=7   |  |  |  |  |  | b| b|
	//  n=8   |  |  |  |  |  |  |  |

	float4 final = pImage.Sample(LinearClampSampler, vtx.uv);
	for (uint n = 1u; (n < uint(pSize)) && (n < MAX_BLUR_SIZE); n += 2u) {
		float2 nstep = (pImageTexel * pStepScale) * (float(n) + 0.5);
		final += pImage.Sample(LinearClampSampler, vtx.uv + nstep) * 2.;
		final += pImage.Sample(LinearClampSampler, vtx.uv - nstep) * 2.;
	}

	if ((uint(pSize) % 2u) == 1u) {
		float2 nstep = (pImageTexel * pStepScale) * pSize;
		final += pImage.Sample(LinearClampSampler, vtx.uv + nstep);
		final += pImage.Sample(LinearClampSampler, vtx.uv - nstep);
	}

	final *= pSizeInverseMul;
	return final;
}

technique Draw {
	pass {
		vertex_shader = VSDefault(vtx);
		pixel_shader  = PSBlur1D(vtx);
	}
}
