/* cie.c */

#include "cie.h"
#define EPSILON 1e-6

/* this code was taken from the MGF documentation */

#ifdef  NTSC
#define  CIE_x_r                0.670           /* standard NTSC primaries */
#define  CIE_y_r                0.330
#define  CIE_x_g                0.210
#define  CIE_y_g                0.710
#define  CIE_x_b                0.140
#define  CIE_y_b                0.080
#define  CIE_x_w                0.3333333333          /* monitor white point */
#define  CIE_y_w                0.3333333333
#else
#define  CIE_x_r                0.640           /* nominal CRT primaries */
#define  CIE_y_r                0.330
#define  CIE_x_g                0.290
#define  CIE_y_g                0.600
#define  CIE_x_b                0.150
#define  CIE_y_b                0.060
#define  CIE_x_w                0.3333333333          /* monitor white point */
#define  CIE_y_w                0.3333333333
#endif

#define CIE_D           (       CIE_x_r*(CIE_y_g - CIE_y_b) + \
                                CIE_x_g*(CIE_y_b - CIE_y_r) + \
                                CIE_x_b*(CIE_y_r - CIE_y_g)     )
#define CIE_C_rD        ( (1./CIE_y_w) * \
                                ( CIE_x_w*(CIE_y_g - CIE_y_b) - \
                                  CIE_y_w*(CIE_x_g - CIE_x_b) + \
                                  CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g     ) )
#define CIE_C_gD        ( (1./CIE_y_w) * \
                                ( CIE_x_w*(CIE_y_b - CIE_y_r) - \
                                  CIE_y_w*(CIE_x_b - CIE_x_r) - \
                                  CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r     ) )
#define CIE_C_bD        ( (1./CIE_y_w) * \
                                ( CIE_x_w*(CIE_y_r - CIE_y_g) - \
                                  CIE_y_w*(CIE_x_r - CIE_x_g) + \
                                  CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r     ) )

#define CIE_rf          (CIE_y_r*CIE_C_rD/CIE_D)
#define CIE_gf          (CIE_y_g*CIE_C_gD/CIE_D)
#define CIE_bf          (CIE_y_b*CIE_C_bD/CIE_D)

static float  xyz2rgbmat[3][3] = {     /* XYZ to RGB */
        {(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g)/CIE_C_rD,
         (CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b)/CIE_C_rD,
         (CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g)/CIE_C_rD},
        {(CIE_y_b - CIE_y_r - CIE_y_b*CIE_x_r + CIE_y_r*CIE_x_b)/CIE_C_gD,
         (CIE_x_r - CIE_x_b - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r)/CIE_C_gD,
         (CIE_x_b*CIE_y_r - CIE_x_r*CIE_y_b)/CIE_C_gD},
        {(CIE_y_r - CIE_y_g - CIE_y_r*CIE_x_g + CIE_y_g*CIE_x_r)/CIE_C_bD,
         (CIE_x_g - CIE_x_r - CIE_x_g*CIE_y_r + CIE_x_r*CIE_y_g)/CIE_C_bD,
         (CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r)/CIE_C_bD}
};

float  rgb2xyzmat[3][3] = {     /* RGB to XYZ */
        {CIE_x_r*CIE_C_rD/CIE_D,CIE_x_g*CIE_C_gD/CIE_D,CIE_x_b*CIE_C_bD/CIE_D},
        {CIE_y_r*CIE_C_rD/CIE_D,CIE_y_g*CIE_C_gD/CIE_D,CIE_y_b*CIE_C_bD/CIE_D},
        {(1.-CIE_x_r-CIE_y_r)*CIE_C_rD/CIE_D,
         (1.-CIE_x_g-CIE_y_g)*CIE_C_gD/CIE_D,
         (1.-CIE_x_b-CIE_y_b)*CIE_C_bD/CIE_D}
};


void colortrans(float *col, float mat[3][3], float *res)
{
  res[0] = mat[0][0] * col[0] + mat[0][1] * col[1] + mat[0][2] * col[2];
  res[1] = mat[1][0] * col[0] + mat[1][1] * col[1] + mat[1][2] * col[2];
  res[2] = mat[2][0] * col[0] + mat[2][1] * col[1] + mat[2][2] * col[2];
}

void rgb_xyz(float *rgb, float *xyz)
{
  colortrans(rgb, rgb2xyzmat, xyz);
}

void RGBtoMGF(float r, float g, float b, float *x, float *y, float *intensity)
{
  float s, rgb[3], xyz[3];

  rgb[0] = r;
  rgb[1] = g;
  rgb[2] = b;
  rgb_xyz(rgb, xyz);

  *intensity = xyz[1];
  s = xyz[0] + xyz[1] + xyz[2];
  if (s > EPSILON) {
    *x = xyz[0] / s;
    *y = xyz[1] / s;
  } else {
    *x = *y = 0.3333333333;
  }
}
