/* cie.c */

#include "cie.h"

/* 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}
};

static 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}
};

static void cie_rgb(float *ciecolor, float *rgbcolor)             /* convert CIE to RGB */
{
        int  i;

        for (i = 0; i < 3; i++) {
                rgbcolor[i] =   xyz2rgbmat[i][0]*ciecolor[0] +
                                xyz2rgbmat[i][1]*ciecolor[1] +
                                xyz2rgbmat[i][2]*ciecolor[2] ;
                if (rgbcolor[i] < 0.0)          /* watch for negative values */
                        rgbcolor[i] = 0.0;
        }
}

static void rgb_cie(float *rgbcolor, float *ciecolor)             /* convert RGB to CIE */
{
        int  i;

        for (i = 0; i < 3; i++)
                ciecolor[i] =   rgb2xyzmat[i][0]*rgbcolor[0] +
                                rgb2xyzmat[i][1]*rgbcolor[1] +
                                rgb2xyzmat[i][2]*rgbcolor[2] ;
}

void CIExyToColor(float x, float y, COLOR *color)
{
	Float cie[3], rgb[3];

	cie[0] = x;
	cie[1] = y;
	cie[2] = 1.-x-y;

	cie_rgb(cie, rgb);

	COLORSET(*color, rgb[0]*3., rgb[1]*3., rgb[2]*3.);
}


