/* color.h */

#ifndef _COLOR_H_
#define _COLOR_H_

#include "Float.h"
#include "mymath.h"

#ifdef __cplusplus
extern "C" {
#endif

/* color model used for representing radiance during the computations: can
 * be something else than RGB, e.g. a number of spectral samples. */
typedef struct COLOR {
  float r, g, b;
} COLOR;

/* macro's to manipulate colors: if you want another color model, all you should have
 * to do is change the macros below and of course the struct COLOR above */

#define ColorPrint(fp, color) 	fprintf(fp, "%g %g %g", (color).r, (color).g, (color).b);

#define COLORCLEAR(color)	((color).r = (color).g = (color).b = 0.)

#define COLORSET(color, R, G, B)  ((color).r = (R), (color).g = (G), (color).b = (B))

#define COLORSETMONOCHROME(color, x) ((color).r = (color).g = (color).b = x)

#define COLORCLEAR(color)	((color).r = (color).g = (color).b = 0.)

#define COLORNULL(color)	((color).r < EPSILON && (color).r > -EPSILON &&	\
			 (color).g < EPSILON && (color).g > -EPSILON &&	\
			 (color).b < EPSILON && (color).b > -EPSILON)

#define COLORSCALE(a, color, d)    ((d).r = (a)*(color).r , \
				    (d).g = (a)*(color).g , \
				    (d).b = (a)*(color).b)

#define COLORPROD(color1, color2, d) ((d).r = (color1).r * (color2).r ,	\
				(d).g = (color1).g * (color2).g ,	\
				(d).b = (color1).b * (color2).b )

#define COLORPRODSCALED(color1, a, color2, d) ((d).r = (color1).r * (a) * (color2).r ,	\
				(d).g = (color1).g * (a) * (color2).g ,	\
				(d).b = (color1).b * (a) * (color2).b )

#define COLORSCALARPRODUCT(color1, color2) ((color1).r * (color2).r +	\
				(color1).g * (color2).g +	\
				(color1).b * (color2).b )

#define COLORADD(color1, color2, d)  ((d).r = (color1).r + (color2).r ,	\
				(d).g = (color1).g + (color2).g ,	\
				(d).b = (color1).b + (color2).b )

#define COLORADDSCALED(color1, a, color2, d)  ((d).r = (color1).r + (a)*(color2).r ,	\
				(d).g = (color1).g + (a)*(color2).g ,	\
				(d).b = (color1).b + (a)*(color2).b )

#define COLORADDCONSTANT(color1, a,  d)  ((d).r = (color1).r + (a),	\
				(d).g = (color1).g + (a),	\
				(d).b = (color1).b + (a) )

#define COLORSUBTRACT(color1, color2, d)  ((d).r = (color1).r - (color2).r ,	\
				(d).g = (color1).g - (color2).g ,	\
				(d).b = (color1).b - (color2).b )

#define COLORSUBTRACTSCALED(color1, a, color2, d)  ((d).r = (color1).r - (a)*(color2).r , \
				(d).g = (color1).g - (a)*(color2).g ,	\
				(d).b = (color1).b - (a)*(color2).b )

#define COLORDIV(color1, color2, d)   ((d).r = (color2).r == 0.0 ? (color1).r : (color1).r / (color2).r ,	\
				(d).g = (color2).g == 0.0 ? (color1).g : (color1).g / (color2).g ,	\
				(d).b = (color2).b == 0.0 ? (color1).b : (color1).b / (color2).b)

#define COLORSCALEINVERSE(a, color, d)    ((d).r = (color).r/(a) , \
				(d).g = (color).g/(a) , \
				(d).b = (color).b/(a))

#define COLORMAXCOMPONENT(color)	(\
			(color).g > (color).r ? ((color).b > (color).g ? (color).b : (color).g) : (\
					((color).b > (color).r ? (color).b : (color).r)))

#define COLORSUMABSCOMPONENTS(color)	(fabs((color).r) + fabs((color).b) + fabs((color).g))

#define COLORABS(color, abs)	{(abs).r = fabs((color).r); \
				 (abs).g = fabs((color).g); \
				 (abs).b = fabs((color).b);}

#define COLORMAX(A, B, max)	{(max).r = ((A).r > (B).r) ? (A).r : (B).r; \
				 (max).g = ((A).g > (B).g) ? (A).g : (B).g; \
				 (max).b = ((A).b > (B).b) ? (A).b : (B).b;}

#define COLORMIN(A, B, min)	{(min).r = ((A).r < (B).r) ? (A).r : (B).r; \
				 (min).g = ((A).g < (B).g) ? (A).g : (B).g; \
				 (min).b = ((A).b < (B).b) ? (A).b : (B).b;}

#define COLORAVERAGE(A)         (((A).r + (A).g + (A).b) / 3.0)

/* computes the relative (to the old) difference of the two colors new and 
 * old */
#define COLORRELATIVEDIFFERENCE(new, old, del)	{			\
		del.r = old.r < EPSILON ? 0.0 : (new.r-old.r)/old.r;	\
		del.g = old.g < EPSILON ? 0.0 : (new.g-old.g)/old.g;	\
		del.b = old.b < EPSILON ? 0.0 : (new.b-old.b)/old.b;	\
					 }

/* Y = lm/cd INT y(lambda) L(lambda) dlambda */
#define COLORLUMINANCE(color)	(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b)

/* barycentric color interpolation */
#define COLORINTERPOLATEBARYCENTRIC(c0, c1, c2, u, v, c)     {			\
        double _u = (u), _v = (v); 						\
	(c).r = (c0).r + _u * ((c1).r - (c0).r) + _v * ((c2).r - (c0).r);	\
	(c).g = (c0).g + _u * ((c1).g - (c0).g) + _v * ((c2).g - (c0).g);	\
	(c).b = (c0).b + _u * ((c1).b - (c0).b) + _v * ((c2).b - (c0).b);	\
				      }

/* bilinear color interpolation */
#define COLORINTERPOLATEBILINEAR(c0, c1 ,c2 ,c3, u, v, c)	{	\
        double _c=(u)*(v), _b=(u)-_c, _d=(v)-_c;	\
	(c).r = (c0).r + (_b) * ((c1).r - (c0).r) + (_c) * ((c2).r - (c0).r)+ (_d) * ((c3).r - (c0).r);	\
	(c).g = (c0).g + (_b) * ((c1).g - (c0).g) + (_c) * ((c2).g - (c0).g)+ (_d) * ((c3).g - (c0).g);	\
	(c).b = (c0).b + (_b) * ((c1).b - (c0).b) + (_c) * ((c2).b - (c0).b)+ (_d) * ((c3).b - (c0).b);	\
					};


/********************************************************************************/
/* colors in RGB, the colormodel used by the rendering subsystem, here assumed
 * to be a display screen. The display hardware wants RGB triplets:
 * 3 floats between 0. and 1., determining how intense the red, green
 * and blue phosphor on the screen will shine. */
typedef struct RGB {
	float r, g, b;
} RGB;

/* some RGB colors for e.g. debugging purposes */
extern RGB Black, White, Green, Yellow, Red, Magenta, Blue, Turquoise;

/* macro to convert a COLOR to an RGB triplet (very easy since COLOR
 * is as yet actually also an RGB triplet). */
#define ColorToRGB(color, rgb) 	{(rgb).r = (color).r; \
                                 (rgb).g = (color).g; \
		                 (rgb).b = (color).b;}

/* macro to print an RGB triplet */
#define RGBPrint(fp, color) 	fprintf(fp, "%g %g %g", (color).r, (color).g, (color).b);

/* macro to fill in an RGB structure with given red,green and blue components */
#define RGBSET(color, R, G, B)  ((color).r = (R), (color).g = (G), (color).b = (B))

/* clips RGB intensities to the interval [0,1] */
#define RGBCLIP(color)		(\
			(color).r = ((color).r < 0. ? 0. : ((color).r > 1. ? 1. : (color).r)), \
			(color).g = ((color).g < 0. ? 0. : ((color).g > 1. ? 1. : (color).g)), \
			(color).b = ((color).b < 0. ? 0. : ((color).b > 1. ? 1. : (color).b)))

/* gamma correction */
#define RGBGAMMACORRECT(color, gamma)  (\
			(color).r = (gamma==1. ? (color).r : pow((color).r, 1./gamma)), \
			(color).g = (gamma==1. ? (color).g : pow((color).g, 1./gamma)), \
			(color).b = (gamma==1. ? (color).b : pow((color).b, 1./gamma)))

#define RED	{1., 0., 0.}
#define YELLOW	{1., 1., 0.}
#define GREEN	{0., 1., 0.}
#define TURQUOISE {0., 1., 1.}
#define BLUE	{0., 0., 1.}
#define MAGENTA	{1., 0., 1.}
#define WHITE	{1., 1., 1.}
#define BLACK	{0., 0., 0.}

#ifdef __cplusplus
}
#endif

#endif /*_COLOR_H_*/



