////////////////////////////////////////////////////////////////////////////////////////////////////
// Constant values
////////////////////////////////////////////////////////////////////////////////////////////////////

//RGBXYZFԂւ̕ϊs
static const float3x3 RGB_TO_XYZ =
{
	 0.51413640,  0.32387860, 0.16036376,
	 0.26506800,  0.67023428, 0.06409157,
	 0.02411880,  0.12281780, 0.84442666
};

//XYZRGBFԂւ̕ϊs
static const float3x3 XYZ_TO_RGB =
{
	 2.56510000, -1.16650000, -0.39860000,
	-1.02170000,  1.97770000,  0.04390000,
	 0.07530000, -0.25430000,  1.18920000
};

//u[Vtgւ̕ϊxNg
static const float3 BLUESHIFT_VECTOR = { 1.05, 0.97, 1.27 };

////////////////////////////////////////////////////////////////////////////////////////////////////
// Sub functions
////////////////////////////////////////////////////////////////////////////////////////////////////

//RGBXYZɕϊ
float3 RGBToXYZ( float3 color )
{
	return mul( RGB_TO_XYZ, color );
}

//XYZRGBɕϊ
float3 XYZToRGB( float3 color )
{
	return mul( XYZ_TO_RGB, color );
}

//XYZYxyɕϊ
float3 XYZToYxy( float3 color )
{
	float invRGB;
	float3 Yxy;

	//0Z΍
	invRGB = color.r + color.g + color.b;
	if( any( invRGB ) == true )
	{
		invRGB = 1.0 / invRGB;
	}
	else
	{
		invRGB = 0.0f;
	}

	Yxy.r = color.g;
	Yxy.g = color.r * invRGB;
	Yxy.b = color.g * invRGB;

	return Yxy;
}

//YxyXYZɕϊ
float3 YxyToXYZ( float3 color )
{
	float invB;
	float3 XYZ;

	//0Z΍
	if( any( color.b ) == true )
	{
		invB = 1.0 / color.b;
	}
	else
	{
		invB = 0.0f;
	}

	XYZ.r = color.r * color.g * invB;
	XYZ.g = color.r;
	XYZ.b = color.r * ( 1.0 - color.g - color.b ) * invB;

	return XYZ;
}

//RGBYxyɕϊ
float3 RGBToYxy( float3 color )
{
	float invXYZ;
	float3 XYZ;
	float3 Yxy;

	//RGBXYZ֕ϊ
	XYZ = mul( RGB_TO_XYZ, color );

	//0Z΍
	invXYZ = XYZ.r + XYZ.g + XYZ.b;
	if( any( invXYZ ) == true )
	{
		invXYZ = 1.0 / invXYZ;
	}
	else
	{
		invXYZ = 0.0f;
	}

	//XYZYxy֕ϊ
	Yxy.r = XYZ.g;
	Yxy.g = XYZ.r * invXYZ;
	Yxy.b = XYZ.g * invXYZ;

	return Yxy;
}

//YxyRGBɕϊ
float3 YxyToRGB( float3 color )
{
	float invB;
	float3 XYZ;
	float3 RGB;

	//0Z΍
	if( any( color.b ) == true )
	{
		invB = 1.0 / color.b;
	}
	else
	{
		invB = 0.0f;
	}

	//YxyXYZ֕ϊ
	XYZ.r = color.r * color.g * invB;
	XYZ.g = color.r;
	XYZ.b = color.r * ( 1.0 - color.g - color.b ) * invB;

	//XYZRGB֕ϊ
	RGB = mul( XYZ_TO_RGB, XYZ );

	return RGB;
}

//PxXP[
float LumScaled( float Y, float middleGray, float lumAdapted, float invWhite2 )
{
	float lumScaled = Y * ( middleGray / ( lumAdapted + 0.0001 ) );

	return ( lumScaled * ( 1.0 + lumScaled * invWhite2 ) ) / ( 1.0f + lumScaled );
}

//u[Vtg
float3 BlueShift( float3 XYZ )
{
	float V = XYZ.g * ( 1.33 * ( 1.0 + ( ( XYZ.g + XYZ.b ) / XYZ.r ) ) - 1.68 );

	if( any( XYZ.r ) == true )
	{
		V = XYZ.g * ( 1.33 * ( 1.0 + ( ( XYZ.g + XYZ.b ) / XYZ.r ) ) - 1.68 );
	}
	else
	{
		//XYZ.g * ( 1.33 - 1.68 )
		V = XYZ.g * -0.53;
	}

	return XYZ.rgb * ( V * BLUESHIFT_VECTOR );
}
