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

#include "shared.effect"

//------------------------------------------------------------------------------
// Uniforms
//------------------------------------------------------------------------------

// Texture to which the effect is applied to.
uniform texture2d image;

// Lift: (rgb + lift.rgb) + lift.a
uniform float4 pLift;

// Gamma: pow(pow(rgb, gamma.rgb), gamma.a)
uniform float4 pGamma;

// Gain: mul(rgb, gain.rgb) * gain.a
uniform float4 pGain;

// Offset: (rgb + offset.rgb) + offset.a
uniform float4 pOffset;

// Tinting
uniform int pTintDetection; // 0 = HSV, 1 = HSL, 2 = YUV HD SDR
uniform int pTintMode; // 0 = Linear, 1 = Exp, 2 = Exp2, 3 = Log, 4 = Log10
uniform float pTintExponent;
uniform float3 pTintLow;
uniform float3 pTintMid;
uniform float3 pTintHig;

// Color Correction
uniform float4 pCorrection;

//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
#define TINT_DETECTION_HSV				0
#define TINT_DETECTION_HSL				1
#define TINT_DETECTION_YUV_SDR			2

#define TINT_MODE_LINEAR				0
#define TINT_MODE_EXP					1
#define TINT_MODE_EXP2					2
#define TINT_MODE_LOG					3
#define TINT_MODE_LOG10					4

#define C_e 2,7182818284590452353602874713527
#define C_log2_e 1.4426950408889634073599246810019 // Windows calculator: log(e(1)) / log(2)

//------------------------------------------------------------------------------
// Functionality
//------------------------------------------------------------------------------

float3 grade_lift(float3 v) {
	float3 multiplier1 = float3(1., 1., 1.) - pLift.rgb;
	float3 multiplier2 = float3(1., 1., 1.) - pLift.aaa;
	return float3(1., 1., 1.) - ((float3(1., 1., 1.) - v) * multiplier1 * multiplier2);
};

float3 grade_gamma(float3 v) {
	return pow(abs(v), pGamma.rgb * pGamma.a) * sign(v);
};

float3 grade_gain(float3 v) {
	return (v.rgb * pGain.rgb) * pGain.a;
};

float3 grade_offset(float3 v) {
	return (v.rgb + pOffset.rgb) + pOffset.a;
};

float3 grade_tint(float3 v) {
	float value = 0.;
	if (pTintDetection == TINT_DETECTION_HSV) { // HSV
		value = RGBtoHSV(v).z;
	} else if (pTintDetection == TINT_DETECTION_HSL) { // HSL
		value = RGBtoHSL(v).z;
	} else if (pTintDetection == TINT_DETECTION_YUV_SDR) { // YUV HD SDR
		const float3x3 mYUV709n = float3x3( // Normalized
			0.2126, 0.7152, 0.0722,
			-0.1145721060573399, -0.3854278939426601, 0.5,
			0.5, -0.4541529083058166, -0.0458470916941834
		);
		value = RGBtoYUV(v, mYUV709n).r;
	}

	if (pTintMode == TINT_MODE_LINEAR) { // Linear
	} else if (pTintMode == TINT_MODE_EXP) { // Exp
		value = 1.0 - exp2(value * pTintExponent * -C_log2_e);
	} else if (pTintMode == TINT_MODE_EXP2) { // Exp2
		value = 1.0 - exp2(value * value * pTintExponent * pTintExponent * -C_log2_e);
	} else if (pTintMode == TINT_MODE_LOG) { // Log
		value = (log2(value) + 2.) / 2.333333;
	} else if (pTintMode == TINT_MODE_LOG10) { // Log10
		value = (m_log10(value) + 1.) / 2.;
	}

	float3 tint = float3(0,0,0);
	if (value > 0.5) {
		tint = lerp(pTintMid, pTintHig, value * 2.0 - 1.0);
	} else {
		tint = lerp(pTintLow, pTintMid, value * 2.0);
	}
	v.rgb *= tint;
	return v;
};

float3 grade_colorcorrection(float3 v) {
	float3 v1 = RGBtoHSV(v);
	v1.r += pCorrection.r; // Hue Shift
	v1.g *= pCorrection.g; // Saturation Multiplier
	v1.b *= pCorrection.b; // Lightness Multiplier
	float3 v2 = HSVtoRGB(v1);
	return v2;
};

float3 grade_contrast(float3 v) {
	v -= .5;
	v *= pCorrection.a;
	v += .5;
	return v;
}

float4 PSDraw(VertexData vtx) : TARGET {
	float4 vo = image.Sample(PointClampSampler, vtx.uv);
	float3 v = vo.rgb;

	v = grade_lift(v);
	v = grade_gamma(v);
	v = grade_gain(v);
	v = grade_offset(v);
	v = grade_tint(v);
	v = grade_colorcorrection(v);
	v = grade_contrast(v);

	return float4(v, vo.a);
};

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