/*
  * Khoros: $Id: colorspace.h,v 1.2 1991/07/15 05:48:19 khoros Exp $
  */

 /*
  * $Log: colorspace.h,v $
 * Revision 1.2  1991/07/15  05:48:19  khoros
 * HellPatch1
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 *
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */
#include "unmcopyright.h"        /* Copyright 1990 by UNM */


#ifndef _colorspace_h_
#define _colorspace_h_

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                          <<<<
   >>>>      file: colorspace.h				         <<<<
   >>>>                                                          <<<<
   >>>>      contains: colorspace definitions.                   <<<<
   >>>>                                                          <<<<
   >>>>      date:  5/24/89					 <<<<
   >>>>                                                          <<<<
   >>>>      written by: Mark Young                              <<<<
   >>>>                                                          <<<<
   >>>>      modifications:                                      <<<<
   >>>>          added YIQ, UVW, XYZ, HLS colorspace conversions <<<<
   >>>>								 <<<<
   >>>>     changed rgb to hls to give a more representative     <<<<
   >>>>     saturation calculation.  Also changed the hls to rgb <<<<
   >>>>     to keep compatible with the rgb to hls.		 <<<<
   >>>> 							 <<<<
   >>>>				Patrick Arnoul  (4/4/91)	 <<<<
   >>>>                                                          <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  */


   
/*
 *
 *	The following algorithms are variations from:
 *		"Computer Graphics"
 *		Donald Hearn / m. Pauline Baker
 *		PRENTICE-HALL
 *		pg 303-306
 *
 *		"Fundamentals of Interactive Computer Graphics"
 *		J.D Foley / A. Van Dam
 *		Addison-Wesley
 *		pg 613-616
 *
 *	The only difference is that the color spaces were
 *	normalized for the X window system.  Both RGB & CMY
 *	are ranged from 0 to 65535 (MAX_INTEN).  The HSV &
 *	HLS space is normalized between 0.0 and 1.0
 *
 */

#include "vipl/lvcltrans.h"


#ifndef MAX_INTEN
#define MAX_INTEN 65535
#endif

/*
 *  Helper routines for the RGB_to_HSV() & HSV_to_RGB()
 *  functions.
 *
 *  NORMALIZE() converts a number from 0 - 65535 to
 *  0 - 1.
 *
 *  NORMALIZE_RGB() converts a number from 0 - 1 to
 *  0 - 65535.
 */
#define NORMALIZE(v)	 (((float) (v)) / MAX_INTEN)
#define NORMALIZE_RGB(v) ((unsigned short) ((v) * MAX_INTEN + 0.5))


#define  RGB_to_CMY(rgb, cmy)						\
{									\
	cmy.red   = MAX_INTEN - rgb.red;				\
	cmy.green = MAX_INTEN - rgb.green;				\
	cmy.blue  = MAX_INTEN - rgb.blue;				\
}

#define  CMY_to_RGB(cmy, rgb)						\
{									\
	rgb.red   = MAX_INTEN - cmy.red;				\
	rgb.green = MAX_INTEN - cmy.green;				\
	rgb.blue  = MAX_INTEN - cmy.blue;				\
}

#define  RGB_to_YIQ(rgb, y, i, q)					\
{									\
	static float	tmp_r, tmp_g, tmp_b;				\
									\
	tmp_r = NORMALIZE(rgb.red);					\
	tmp_g = NORMALIZE(rgb.green);					\
	tmp_b = NORMALIZE(rgb.blue);					\
	y = TRANS1(tmp_r, tmp_g, tmp_b, RGBtoYIQ);			\
	i = TRANS2(tmp_r, tmp_g, tmp_b, RGBtoYIQ);			\
	q = TRANS3(tmp_r, tmp_g, tmp_b, RGBtoYIQ);			\
}

#define  YIQ_to_RGB(y, i, q, rgb)					\
{									\
	rgb.red   = NORMALIZE_RGB(TRANS1(y, i, q, YIQtoRGB));		\
	rgb.green = NORMALIZE_RGB(TRANS2(y, i, q, YIQtoRGB));		\
	rgb.blue  = NORMALIZE_RGB(TRANS3(y, i, q, YIQtoRGB));		\
}

#define  RGB_to_XYZ(rgb, x, y, z)					\
{									\
	static float	tmp_r, tmp_g, tmp_b;				\
									\
	tmp_r = NORMALIZE(rgb.red);						\
	tmp_g = NORMALIZE(rgb.green);					\
	tmp_b = NORMALIZE(rgb.blue);					\
	x = TRANS1(tmp_r, tmp_g, tmp_b, RGBtoXYZ);			\
	y = TRANS2(tmp_r, tmp_g, tmp_b, RGBtoXYZ);			\
	z = TRANS3(tmp_r, tmp_g, tmp_b, RGBtoXYZ);			\
}

#define  XYZ_to_RGB(x, y, z, rgb)					\
{									\
	rgb.red   = NORMALIZE_RGB(TRANS1(x, y, z, XYZtoRGB));		\
	rgb.green = NORMALIZE_RGB(TRANS2(x, y, z, XYZtoRGB));		\
	rgb.blue  = NORMALIZE_RGB(TRANS3(x, y, z, XYZtoRGB));		\
}

#define  RGB_to_UVW(rgb, u, v, w)					\
{									\
	static float	tmp_r, tmp_g, tmp_b;				\
									\
	tmp_r = NORMALIZE(rgb.red);					\
	tmp_g = NORMALIZE(rgb.green);					\
	tmp_b = NORMALIZE(rgb.blue);					\
	u = TRANS1(tmp_r, tmp_g, tmp_b, RGBtoUVW);			\
	v = TRANS2(tmp_r, tmp_g, tmp_b, RGBtoUVW);			\
	w = TRANS3(tmp_r, tmp_g, tmp_b, RGBtoUVW);			\
}

#define  UVW_to_RGB(u, v, w, rgb)					\
{									\
	rgb.red   = NORMALIZE_RGB(TRANS1(u, v, w, UVWtoRGB));		\
	rgb.green = NORMALIZE_RGB(TRANS2(u, v, w, UVWtoRGB));		\
	rgb.blue  = NORMALIZE_RGB(TRANS3(u, v, w, UVWtoRGB));		\
}



/*
 *  Convert  RGB_to_HSV()  - converts a Red, Green, Blue number
 *			     to a Hue, Saturation, Value one.
 */
#define  RGB_to_HSV(rgb, h, s, v)					\
{									\
	static float	tmp_m, tmp_r, tmp_g, tmp_b;			\
									\
	tmp_r = NORMALIZE(rgb.red);					\
	tmp_g = NORMALIZE(rgb.green);					\
	tmp_b = NORMALIZE(rgb.blue);					\
	v = MAX(MAX(tmp_r, tmp_g), tmp_b);				\
	tmp_m = MIN(MIN(tmp_r, tmp_g), tmp_b);				\
									\
	if (v == 0.0)							\
	   s = 0.0;							\
	else s = (v - tmp_m)/v;						\
									\
	if (s == 0.0)							\
	   h = 0.0;							\
	else								\
	{								\
	   if (tmp_r == v)						\
	      h = ((v - tmp_b)/(v - tmp_m)) - ((v - tmp_g)/(v - tmp_m)); \
	   else if (tmp_g == v)						\
	      h = 2 + ((v - tmp_r)/(v - tmp_m)) - ((v - tmp_b)/(v - tmp_m)); \
	   else if (tmp_b == v)						\
	      h = 4 + ((v - tmp_g)/(v - tmp_m)) - ((v - tmp_r)/(v - tmp_m)); \
									\
	   h /= 6.0;							\
	   if (h < 0.0) h += 1.0;					\
	}								\
}


/*
 *  Convert  HSV_to_RGB()  - converts a Hue, Saturation, Value number
 *			     to a Red, Green, Blue one.
 */
#define HSV0(v, s, f)	NORMALIZE_RGB(v)
#define HSV1(v, s, f)	NORMALIZE_RGB(v * (1 - s))
#define HSV2(v, s, f)	NORMALIZE_RGB(v * (1 - (s * f)))
#define HSV3(v, s, f)	NORMALIZE_RGB(v * (1 - (s * (1 - f))))

#define  HSV_to_RGB(h, s, v, rgb)					\
{									\
	static int	tmp_i;						\
	static float	tmp_f;						\
									\
	tmp_i = (int) (h * 6.0);					\
	tmp_f = (h * 6.0) - tmp_i;					\
									\
	switch(tmp_i)							\
	{								\
	     case 0:    rgb.red   = HSV0(v, s, tmp_f);			\
			rgb.green = HSV3(v, s, tmp_f);			\
			rgb.blue  = HSV1(v, s, tmp_f);			\
			break;						\
									\
	     case 1:    rgb.red   = HSV2(v, s, tmp_f);			\
			rgb.green = HSV0(v, s, tmp_f);			\
			rgb.blue  = HSV1(v, s, tmp_f);			\
			break;						\
									\
	     case 2:    rgb.red   = HSV1(v, s, tmp_f);			\
			rgb.green = HSV0(v, s, tmp_f);			\
			rgb.blue  = HSV3(v, s, tmp_f);			\
			break;						\
									\
	     case 3:    rgb.red   = HSV1(v, s, tmp_f);			\
			rgb.green = HSV2(v, s, tmp_f);			\
			rgb.blue  = HSV0(v, s, tmp_f);			\
			break;						\
									\
	     case 4:    rgb.red   = HSV3(v, s, tmp_f);			\
			rgb.green = HSV1(v, s, tmp_f);			\
			rgb.blue  = HSV0(v, s, tmp_f);			\
			break;						\
									\
	     case 5:    rgb.red   = HSV0(v, s, tmp_f);			\
			rgb.green = HSV1(v, s, tmp_f);			\
			rgb.blue  = HSV2(v, s, tmp_f);			\
			break;						\
	}								\
}

/*
 *  Convert  RGB_to_HLS()  - converts a Red, Green, Blue number
 *			     to a Hue, Light, Saturation one.
 */
#define  RGB_to_HLS(rgb, h, l, s)					\
{									\
	static float	maximum, minimum, tmp_r, tmp_g, tmp_b;		\
									\
	tmp_r = NORMALIZE(rgb.red);					\
	tmp_g = NORMALIZE(rgb.green);					\
	tmp_b = NORMALIZE(rgb.blue);					\
	maximum = MAX(MAX(tmp_r, tmp_g), tmp_b);			\
	minimum = MIN(MIN(tmp_r, tmp_g), tmp_b);			\
									\
	l = (maximum + minimum)/2;					\
	if (maximum == minimum)						\
	   s = h = 0.0;							\
	else								\
	{								\
	   s = (maximum - minimum)/(maximum + minimum);			\
									\
	   if (tmp_r == maximum)					\
	      h = (maximum - tmp_b)/(maximum - minimum) -               \
		  (maximum - tmp_g)/(maximum - minimum); 		\
	   else if (tmp_g == maximum)					\
	      h = 2 + (maximum - tmp_r)/(maximum - minimum) - 	 	\
		  (maximum - tmp_b)/(maximum - minimum); 		\
	   else if (tmp_b == maximum)					\
	      h = 4 + (maximum - tmp_g)/(maximum - minimum) - 		\
		  (maximum - tmp_r)/(maximum - minimum); 		\
									\
	   h /= 6.0;							\
	   if (h < 0.0) h += 1.0;					\
	}								\
}


/*
 *  Convert  HLS_to_RGB()  - converts a Hue, Light, Saturation number
 *			     to a Red, Green, Blue one.
 */
#define  HLS_to_RGB(h, l, s, rgb)					\
{									\
	static int	tmp_i;						\
	static float	tmp_v, tmp_f, minimum, vsf;			\
									\
        tmp_v = l * (1.0 + s);						\
	if (s == 0.0)							\
	{								\
	   rgb.red   =							\
	   rgb.green =							\
	   rgb.blue = NORMALIZE_RGB(l);					\
	}								\
	else								\
	{								\
	   if (h < 0.0)							\
	      h += 1.0;							\
									\
	   tmp_i = (int) (h * 6.0);					\
	   tmp_f = (h * 6.0) - tmp_i;					\
									\
	   minimum = l * 2 - tmp_v;					\
	   vsf = (tmp_v - minimum) * tmp_f;				\
									\
	   switch (tmp_i)						\
	   {								\
	      case 0:	rgb.red   = NORMALIZE_RGB(tmp_v);		\
			rgb.green = NORMALIZE_RGB(minimum + vsf);	\
			rgb.blue  = NORMALIZE_RGB(minimum);		\
			break;						\
									\
	      case 1:	rgb.red   = NORMALIZE_RGB(tmp_v - vsf);		\
			rgb.green = NORMALIZE_RGB(tmp_v);		\
			rgb.blue  = NORMALIZE_RGB(minimum);		\
			break;						\
									\
	      case 2:	rgb.red   = NORMALIZE_RGB(minimum);		\
			rgb.green = NORMALIZE_RGB(tmp_v);		\
			rgb.blue  = NORMALIZE_RGB(minimum + vsf);	\
			break;						\
									\
	      case 3:	rgb.red   = NORMALIZE_RGB(minimum);		\
			rgb.green = NORMALIZE_RGB(tmp_v - vsf);		\
			rgb.blue  = NORMALIZE_RGB(tmp_v);		\
			break;						\
									\
	      case 4:	rgb.red   = NORMALIZE_RGB(minimum + vsf);	\
			rgb.green = NORMALIZE_RGB(minimum);		\
			rgb.blue  = NORMALIZE_RGB(tmp_v);		\
			break;						\
									\
	      case 5:	rgb.red   = NORMALIZE_RGB(tmp_v);		\
			rgb.green = NORMALIZE_RGB(minimum);		\
			rgb.blue  = NORMALIZE_RGB(tmp_v - vsf);		\
			break;						\
									\
	   }								\
	}								\
}

#endif /* _colorspace_h_ */
/* Do not add after this line */
