// LumaSharpen
// Based on: https://github.com/CeeJayDK/SweetFX/blob/master/Shaders/LumaSharpen.fx
//
// LumaSharpen version 1.5.0
// by Christian Cann Schuldt Jensen ~ CeeJay.dk
//
// Blurs the original pixel with surrounding pixels and subtracts this blur
// to sharpen the image. Works in luma space to avoid color artifacts.
// Similar to Unsharp Mask in Photoshop.

//!BGFX EFFECT
//!VERSION 1
//!NAME Luma Sharpen
//!CATEGORY Sharpening
//!DESCRIPTION Unsharp mask style sharpening that works in luminance space to avoid color artifacts. Multiple sampling patterns available.


//!PARAMETER
//!LABEL Sharpening Strength
//!DESC Controls the intensity of the sharpening effect.
//!DEFAULT 0.65
//!MIN 0
//!MAX 3
//!STEP 0.01
float sharpStrength;

//!PARAMETER
//!LABEL Sharpening Limit
//!DESC Maximum sharpening amount per pixel. Helps prevent halo artifacts at high strength values.
//!DEFAULT 0.035
//!MIN 0
//!MAX 1
//!STEP 0.005
float sharpClamp;

//!PARAMETER
//!LABEL Sample Pattern
//!DESC Blur kernel shape: 0=Fast (7-tap), 1=Normal (9-tap), 2=Wider (17-tap), 3=Pyramid
//!DEFAULT 1
//!MIN 0
//!MAX 3
//!STEP 1
int pattern;

//!PARAMETER
//!LABEL Offset Bias
//!DESC Adjusts the sampling radius. Default is 1.0, experiment for different effects.
//!DEFAULT 1
//!MIN 0
//!MAX 6
//!STEP 0.01
float offsetBias;

//!TEXTURE
Texture2D INPUT;

//!TEXTURE
//!WIDTH INPUT_WIDTH
//!HEIGHT INPUT_HEIGHT
Texture2D OUTPUT;

//!SAMPLER
//!FILTER LINEAR
SamplerState sam;


//!PASS 1
//!STYLE PS
//!IN INPUT
//!OUT OUTPUT

// Luma coefficients for BT.709 & sRGB (monitors and HD television)
#define CoefLuma float3(0.2126, 0.7152, 0.0722)

float4 Pass1(float2 pos) {
	float2 BUFFER_PIXEL_SIZE = GetInputPt();

	// Get the original pixel
	float3 ori = INPUT.SampleLevel(sam, pos, 0).rgb;

	// Combine strength with luma multipliers
	float3 sharp_strength_luma = (CoefLuma * sharpStrength);

	// Initialize blur accumulator
	float3 blur_ori = { 0, 0, 0 };

	// Pattern 0: Fast 7-tap Gaussian using 2+1 texture fetches
	if (pattern == 0) {
		// Gaussian kernel:
		//   [ 1/9, 2/9,    ]     [ 1 , 2 ,   ]
		//   [ 2/9, 8/9, 2/9]  =  [ 2 , 8 , 2 ]
		//   [    , 2/9, 1/9]     [   , 2 , 1 ]

		blur_ori = INPUT.SampleLevel(sam, pos + (BUFFER_PIXEL_SIZE / 3.0) * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + (-BUFFER_PIXEL_SIZE / 3.0) * offsetBias, 0).rgb;
		blur_ori /= 2;

		sharp_strength_luma *= 1.5;  // Adjust to match pattern 1 strength
	}

	// Pattern 1: Normal 9-tap Gaussian using 4+1 texture fetches
	if (pattern == 1) {
		// Gaussian kernel:
		//   [ .25, .50, .25]     [ 1 , 2 , 1 ]
		//   [ .50,   1, .50]  =  [ 2 , 4 , 2 ]
		//   [ .25, .50, .25]     [ 1 , 2 , 1 ]

		blur_ori = INPUT.SampleLevel(sam, pos + float2(BUFFER_PIXEL_SIZE.x, -BUFFER_PIXEL_SIZE.y) * 0.5 * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos - BUFFER_PIXEL_SIZE * 0.5 * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + BUFFER_PIXEL_SIZE * 0.5 * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos - float2(BUFFER_PIXEL_SIZE.x, -BUFFER_PIXEL_SIZE.y) * 0.5 * offsetBias, 0).rgb;
		blur_ori *= 0.25;
	}

	// Pattern 2: Wider 17-tap Gaussian using 4+1 texture fetches
	if (pattern == 2) {
		// Extended Gaussian for wider blur effect

		blur_ori = INPUT.SampleLevel(sam, pos + BUFFER_PIXEL_SIZE * float2(0.4, -1.2) * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos - BUFFER_PIXEL_SIZE * float2(1.2, 0.4) * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + BUFFER_PIXEL_SIZE * float2(1.2, 0.4) * offsetBias, 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos - BUFFER_PIXEL_SIZE * float2(0.4, -1.2) * offsetBias, 0).rgb;
		blur_ori *= 0.25;

		sharp_strength_luma *= 0.51;
	}

	// Pattern 3: 9-tap high-pass pyramid filter using 4+1 texture fetches
	if (pattern == 3) {
		// Pyramid kernel:
		//   [ .50, .50, .50]     [ 1 , 1 , 1 ]
		//   [ .50,    , .50]  =  [ 1 ,   , 1 ]
		//   [ .50, .50, .50]     [ 1 , 1 , 1 ]

		blur_ori = INPUT.SampleLevel(sam, pos + float2(0.5 * BUFFER_PIXEL_SIZE.x, -BUFFER_PIXEL_SIZE.y * offsetBias), 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + float2(offsetBias * -BUFFER_PIXEL_SIZE.x, 0.5 * -BUFFER_PIXEL_SIZE.y), 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + float2(offsetBias * BUFFER_PIXEL_SIZE.x, 0.5 * BUFFER_PIXEL_SIZE.y), 0).rgb;
		blur_ori += INPUT.SampleLevel(sam, pos + float2(0.5 * -BUFFER_PIXEL_SIZE.x, BUFFER_PIXEL_SIZE.y * offsetBias), 0).rgb;
		blur_ori /= 4.0;

		sharp_strength_luma *= 0.666;  // Adjust to match pattern 1 strength
	}

	// Calculate sharpening by subtracting blurred image from original
	float3 sharp = ori - blur_ori;

	// Calculate luma-weighted sharpening with clamping
	// Roll part of the clamp into the dot product for efficiency
	float4 sharp_strength_luma_clamp = float4(sharp_strength_luma * (0.5 / sharpClamp), 0.5);

	// Scale, adjust strength, and clamp
	float sharp_luma = saturate(dot(float4(sharp, 1.0), sharp_strength_luma_clamp));
	sharp_luma = (sharpClamp * 2.0) * sharp_luma - sharpClamp;

	// Add sharpening to the original pixel
	float3 outputcolor = ori + sharp_luma;

	return float4(saturate(outputcolor), 1);
}
