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

sampler_state __LUTSampler {
	Filter = Linear;
	AddressU = Clamp;
	AddressV = Clamp;
};

float4 generate_lut(uint bit_depth, float2 uv) {
	uint size = pow(2, bit_depth);
	uint z_size = pow(2, bit_depth / 2);
	uint container_size = pow(2, bit_depth + (bit_depth / 2));

	uint2 xy = uint2(floor(uv * container_size));
	uint2 rg = xy % size;
	uint2 bb = xy / size;

	return float4(
		rg.xy / float(size - 1),
		((bb.y * z_size) + bb.x) / float(size - 1),
		1.
	);
};

float4 generate_lut2(float2 uv, uint4 params0) {
	uint size = params0.r;
	uint z_size = params0.g;
	uint container_size = params0.b;

	uint2 xy = uint2(floor(uv * container_size));
	uint2 rg = xy % size;
	uint2 bb = xy / size;

	return float4(
		rg.xy / float(size - 1),
		((bb.y * z_size) + bb.x) / float(size - 1),
		1.
	);
};

float3 sample_lut(float3 color, uint bit_depth, texture2d lut_texture) {
	uint size = pow(2, bit_depth);
	uint z_size = pow(2, bit_depth / 2);
	uint container_size = pow(2, bit_depth + (bit_depth / 2));

	float inverse_size = 1. / size;
	float inverse_z_size = 1. / z_size;
	float inverse_container_size = 1. / container_size;
	float half_texel = inverse_container_size / 2.; // Linear sampling is weird.

	// Due to our LUT not actually being a cube but a plane pretending to be a cube,
	// we have to do some conversion into the grid structure in order to be successful.

	// 1. Clamp everything to a reasonable range.
	color = saturate(color);

	// 2. Rescale everything into 0..(size - 1)
	color *= (size - 1);

	// 3. Convert red and green into initial grid cell UVs.
	float2 xy_uv = color.xy * inverse_container_size;

	// 4. Figure out the high and low parts for interpolation.
	uint z_lo = floor(color.z);
	uint z_hi = z_lo + 1;

	// 5. Figure out the X location of the cell in the grid.
	uint z_lo_x = z_lo % z_size;
	uint z_hi_x = z_hi % z_size;

	// 6. Figure out the Y location of the cell in the grid.
	uint z_lo_y = z_lo / z_size;
	uint z_hi_y = z_hi / z_size;

	// 7. Convert the X and Y locations into UV coordinates.
	float2 z_lo_uv = float2(z_lo_x, z_lo_y) * inverse_z_size;
	float2 z_hi_uv = float2(z_hi_x, z_hi_y) * inverse_z_size;

	// 8. Sample both low and high points.
	float3 c_lo = lut_texture.Sample(__LUTSampler, xy_uv + z_lo_uv + half_texel).rgb;
	float3 c_hi = lut_texture.Sample(__LUTSampler, xy_uv + z_hi_uv + half_texel).rgb;

	// 9. Return an interpolated version based on the fraction of Z.
	return lerp(c_lo, c_hi, frac(color.z));
};

float3 sample_lut2(float3 color, texture2d lut_texture, int4 params0, float4 params1) {
	uint size = params0.r;
	uint z_size = params0.g;
	uint container_size = params0.b;

	float inverse_size = params1.r;
	float inverse_z_size = params1.g;
	float inverse_container_size = params1.b;
	float half_texel = params1.a;

	// Due to our LUT not actually being a cube but a plane pretending to be a cube,
	// we have to do some conversion into the grid structure in order to be successful.

	// 1. Clamp everything to a reasonable range.
	color = saturate(color);

	// 2. Rescale everything into 0..(size - 1)
	color *= (size - 1);

	// 3. Convert red and green into initial grid cell UVs.
	float2 xy_uv = color.xy * inverse_container_size;

	// 4. Figure out the high and low parts for interpolation.
	uint z_lo = floor(color.z);
	uint z_hi = z_lo + 1;

	// 5. Figure out the X location of the cell in the grid.
	uint z_lo_x = z_lo % z_size;
	uint z_hi_x = z_hi % z_size;

	// 6. Figure out the Y location of the cell in the grid.
	uint z_lo_y = z_lo / z_size;
	uint z_hi_y = z_hi / z_size;

	// 7. Convert the X and Y locations into UV coordinates.
	float2 z_lo_uv = float2(z_lo_x, z_lo_y) * inverse_z_size;
	float2 z_hi_uv = float2(z_hi_x, z_hi_y) * inverse_z_size;

	// 8. Sample both low and high points.
	float3 c_lo = lut_texture.Sample(__LUTSampler, xy_uv + z_lo_uv + half_texel).rgb;
	float3 c_hi = lut_texture.Sample(__LUTSampler, xy_uv + z_hi_uv + half_texel).rgb;

	// 9. Return an interpolated version based on the fraction of Z.
	return lerp(c_lo, c_hi, frac(color.z));
};
