/* Copyright (c) 1990 Regents of the University of California */

#ifndef lint
static char SCCSid[] = "@(#)spec_rgb.c 2.1 11/12/91 LBL";
#endif

/*
 * Convert colors and spectral ranges.
 */

#include "color.h"

/*
 *	The following table contains the CIE tristimulus integrals
 *  for X, Y, and Z.  The table is cumulative, so that
 *  each color coordinate integrates to 1.
 */

#define  STARTWL	380		/* starting wavelength (nanometers) */
#define  INCWL		10		/* wavelength increment */
#define  NINC		40		/* # of values */

static BYTE  chroma[3][NINC] = {
	{							/* X */
		0,   0,   0,   2,   6,   13,  22,  30,  36,  41,
		42,  43,  43,  44,  46,  52,  60,  71,  87,  106,
		128, 153, 178, 200, 219, 233, 243, 249, 252, 254,
		255, 255, 255, 255, 255, 255, 255, 255, 255, 255
	}, {							/* Y */
		0,   0,   0,   0,   0,   1,   2,   4,   7,   11,
		17,  24,  34,  48,  64,  84,  105, 127, 148, 169,
		188, 205, 220, 232, 240, 246, 250, 253, 254, 255,
		255, 255, 255, 255, 255, 255, 255, 255, 255, 255
	}, {							/* Z */
		0,   0,   2,   10,  32,  66,  118, 153, 191, 220,
		237, 246, 251, 253, 254, 255, 255, 255, 255, 255,
		255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
		255, 255, 255, 255, 255, 255, 255, 255, 255, 255
	}
};

#ifdef  NTSC
static float  xyz2rgbmat[3][3] = {	/* XYZ to RGB (NTSC) */
	1.73, -.48, -.26,
	-.81, 1.65, -.02,
	 .08, -.17, 1.28,
};
#else
static float xyz2rgbmat[3][3] = {	/* XYZ to RGB (color monitor) */
	 2.739, -1.145, -.424,
	-1.119,  2.029,  .033,
	  .138,  -.333, 1.105,
};
#endif



spec_rgb(col, s, e)		/* compute RGB color from spectral range */
COLOR  col;
int  s, e;
{
	COLOR  ciecolor;

	spec_cie(ciecolor, s, e);
	cie_rgb(col, ciecolor);
}


spec_cie(col, s, e)		/* compute a color from a spectral range */
COLOR  col;		/* returned color */
int  s, e;		/* starting and ending wavelengths */
{
	register int  i, d, r;
	
	s -= STARTWL;
	if (s < 0)
		s = 0;

	e -= STARTWL;
	if (e <= s) {
		col[RED] = col[GRN] = col[BLU] = 0.0;
		return;
	}
	if (e >= INCWL*(NINC - 1))
		e = INCWL*(NINC - 1) - 1;

	d = e / INCWL;			/* interpolate values */
	r = e % INCWL;
	for (i = 0; i < 3; i++)
		col[i] = chroma[i][d]*(INCWL - r) + chroma[i][d + 1]*r;

	d = s / INCWL;
	r = s % INCWL;
	for (i = 0; i < 3; i++)
		col[i] -= chroma[i][d]*(INCWL - r) - chroma[i][d + 1]*r;

	col[RED] = (col[RED] + 0.5) / (256*INCWL);
	col[GRN] = (col[GRN] + 0.5) / (256*INCWL);
	col[BLU] = (col[BLU] + 0.5) / (256*INCWL);
}


cie_rgb(rgbcolor, ciecolor)		/* convert CIE to RGB */
register COLOR  rgbcolor, ciecolor;
{
	register 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)
			rgbcolor[i] = 0.0;
	}
}
