// O-Log REC2020 to ACES AP0 DCTL

typedef struct
{
	float3 r0, r1, r2;
} mat3;

__DEVICE__ mat3 make_mat3(float3 A, float3 B, float3 C);
__DEVICE__ float3 mult_f3_f33 (float3 In, mat3 A);
__DEVICE__ mat3 mult_f33_f33(mat3 A, mat3 B);
__DEVICE__ float mlog_to_lin(float in);
__DEVICE__ float3 mlog_to_lin3(float3 in);

__DEVICE__ mat3 make_mat3(float3 A, float3 B, float3 C)
{
	mat3 out;
    out.r0 = A;
    out.r1 = B;
    out.r2 = C;
    return out;
}

__DEVICE__ float3 mult_f3_f33 (float3 In, mat3 A)
{
    float out[3];
    float in[3] = {In.x, In.y, In.z};
    float a[3][3] = {{A.r0.x, A.r0.y, A.r0.z},
	  {A.r1.x, A.r1.y, A.r1.z},
	  {A.r2.x, A.r2.y, A.r2.z}};
    for( int i = 0; i < 3; ++i)
	{
        out[i] = 0.0f;
        for( int j = 0; j < 3; ++j)
        {
            out[i] = out[i] + in[j] * a[i][j];
        }
    }
    return make_float3(out[0], out[1], out[2]);
}

__DEVICE__ mat3 mult_f33_f33(mat3 A, mat3 B)
{
    float m[3][3];
    float a[3][3] = {{A.r0.x, A.r0.y, A.r0.z},
                    {A.r1.x, A.r1.y, A.r1.z},
                    {A.r2.x, A.r2.y, A.r2.z}};
    float b[3][3] = {{B.r0.x, B.r0.y, B.r0.z},
                    {B.r1.x, B.r1.y, B.r1.z},
                    {B.r2.x, B.r2.y, B.r2.z}};

    for( int i = 0; i < 3; ++i)
    {
        for( int j = 0; j < 3; ++j)
        {
            m[i][j] = 0.0f;
            for( int k = 0; k < 3; ++k)
            {
                m[i][j] = m[i][j] + a[i][k] * b[k][j];
            }
        }
    }
    mat3 M = make_mat3(make_float3(m[0][0], m[0][1], m[0][2]),
    make_float3(m[1][0], m[1][1], m[1][2]), make_float3(m[2][0], m[2][1], m[2][2]));
    return M;
}

#define rec2020_to_xyz make_mat3(make_float3(0.6370f, 0.1446f, 0.1689f), make_float3(0.2627f, 0.6780f, 0.0593f), make_float3(0.0f, 0.0281f, 1.0610f))

#define d65_to_d60_cat02 make_mat3(make_float3(1.01174414f, 0.00770577991f, -0.0157216747f), make_float3(0.00555788933f, 1.00153586f,-0.00626219941f), make_float3(-0.000334059457f,-0.00104828776f, 0.927569778f))

#define xyz_to_acesAP0 make_mat3(make_float3(1.0498110175f, 0.0f, -0.0001f), make_float3(-0.4959030231f, 1.3733130458f, 0.0982400361f), make_float3(0.0f, 0.0f, 0.9912520182f))

#define rec2020_to_AP0 mult_f33_f33(xyz_to_acesAP0, mult_f33_f33(d65_to_d60_cat02, rec2020_to_xyz))


__DEVICE__ float olog_to_lin(float x)
{
   return (_expf((x - 0.614f)/0.139f) - 0.019f)/16.0f*7.37235;
}

__DEVICE__ float3 olog_to_lin3(float3 in)
{
    float3 out;
    out.x = olog_to_lin(in.x);
    out.y = olog_to_lin(in.y);
    out.z = olog_to_lin(in.z);
    return out;
}

__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
{
    float3 rgb = make_float3(p_R, p_G, p_B);
    rgb = olog_to_lin3(rgb);
    rgb = mult_f3_f33(rgb, rec2020_to_AP0);
    return rgb;
}