// Aqsis
// Copyright © 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


/** \file
		\brief Declares the CqColor class for handling generic 3 element colors.
		\author Paul C. Gregory (pgregory@aqsis.com)
*/

//? Is color.h included already?
#ifndef COLOR_H_INCLUDED 
//{
#define COLOR_H_INCLUDED 1

#include	"aqsis.h"

#include	"vector3d.h"

#define		_qShareName	CORE
#include	"share.h"

#include <iostream>

START_NAMESPACE( Aqsis )


//-----------------------------------------------------------------------
/** \class CqColor
 * Class to store and manipulate three component color information.
 */

class _qShareC	CqColor
{
	public:
		/// Default constructor.
		_qShareM	CqColor()
		{}
		/** Component constructor
		 * \param fRed red component 0.0-1.0
		 * \param fGreen green component 0.0-1.0
		 * \param fBlue blue component 0.0-1.0
		 */
		_qShareM	CqColor( TqFloat fRed, TqFloat fGreen, TqFloat fBlue ) :
				m_fRed( fRed ),
				m_fGreen( fGreen ),
				m_fBlue( fBlue )
		{}
		/** 3D vector constructor.
		 * \param From the vector to copy the component values from.
		 */
		_qShareM	CqColor( const CqVector3D& From )
		{
			*this = From;
		}
		/** Array component constructor.
		 * \param From array of floats to use as the components.
		 */
		_qShareM	CqColor( const TqFloat From[ 3 ] ) :
				m_fRed( From[ 0 ] ),
				m_fGreen( From[ 1 ] ),
				m_fBlue( From[ 2 ] )
		{}
		_qShareM	~CqColor()
		{}

		/** Get the red component.
		 * \return float red component 0.0-1.0.
		 */
		_qShareM	TqFloat	fRed() const
		{
			return ( m_fRed );
		}
		/** Set the red component.
		 * \param fValue the new value for the red component 0.0-1.0.
		 */
		_qShareM	void	SetfRed( const TqFloat fValue )
		{
			m_fRed = fValue;
		}
		/** Get the freen component.
		 * \return float green component 0.0-1.0.
		 */
		_qShareM	TqFloat	fGreen() const
		{
			return ( m_fGreen );
		}
		/** Set the green component.
		 * \param fValue the new value for the green component 0.0-1.0.
		 */
		_qShareM	void	SetfGreen( const TqFloat fValue )
		{
			m_fGreen = fValue;
		}
		/** Get the blue component.
		 * \return float blue component 0.0-1.0.
		 */
		_qShareM	TqFloat	fBlue() const
		{
			return ( m_fBlue );
		}
		/** Set the blue component.
		 * \param fValue the new value for the blue component 0.0-1.0.
		 */
		_qShareM	void	SetfBlue( const TqFloat fValue )
		{
			m_fBlue = fValue;
		}
		/** Get the color as indiviual components.
		 * \param pfRed pointer to the area to store the red component.
		 * \param pfGreen pointer to the area to store the green component.
		 * \param pfBlue pointer to the area to store the blue component.
		 */
		_qShareM	void	GetColorRGB( TqFloat* pfRed, TqFloat* pfGreen, TqFloat* pfBlue )
		{
			*pfRed = m_fRed;
			*pfGreen = m_fGreen;
			*pfBlue = m_fBlue;
		}
		/** Set the color as individual components.
		 * \param fRed the new value for the red component 0.0-1.0.
		 * \param fGreen the new value for the green component 0.0-1.0.
		 * \param fBlue the new value for the blue component 0.0-1.0.
		 */
		_qShareM	void	SetColorRGB( TqFloat fRed, TqFloat fGreen, TqFloat fBlue )
		{
			m_fRed = fRed;
			m_fGreen = fGreen;
			m_fBlue = fBlue;
		}

		_qShareM	CqColor	rgbtohsv() const;
		_qShareM	CqColor	rgbtohsl() const;
		_qShareM	CqColor	rgbtoXYZ() const;
		_qShareM	CqColor	rgbtoxyY() const;
		_qShareM	CqColor	rgbtoYIQ() const;
		_qShareM	CqColor	hsvtorgb() const;
		_qShareM	CqColor	hsltorgb() const;
		_qShareM	CqColor	XYZtorgb() const;
		_qShareM	CqColor	xyYtorgb() const;
		_qShareM	CqColor	YIQtorgb() const;

		/// Clamp the components to the range 0.0-1.0.
		_qShareM	void	Clamp()
		{
			if ( m_fRed > 1.0 ) m_fRed = 1.0;
			if ( m_fGreen > 1.0 ) m_fGreen = 1.0;
			if ( m_fBlue > 1.0 ) m_fBlue = 1.0;

			if ( m_fRed < 0.0 ) m_fRed = 0.0;
			if ( m_fGreen < 0.0 ) m_fGreen = 0.0;
			if ( m_fBlue < 0.0 ) m_fBlue = 0.0;
		}

		/** Array based component access.
		 * \param i integer component index, 0-2.
		 * \return a reference to the float value of the appropriate component, returns blue if index is invalid.
		 */
		_qShareM	TqFloat&	operator[] ( TqInt i )
		{
			if ( i==0 ) return ( m_fRed );
			else if ( i == 1 ) return ( m_fGreen );
			else	return ( m_fBlue );
		}
		/** Array based read only component access.
		 * \param i integer component index, 0-2.
		 * \return a constant reference the float value of the appropriate component, returns blue if index is invalid.
		 */
		_qShareM	const TqFloat&	operator[] ( TqInt i ) const
		{
			if ( i==0 ) return ( m_fRed );
			else if ( i == 1 ) return ( m_fGreen );
			else	return ( m_fBlue );
		}
		/** Copy value from a 3D vector.
		 * \param From the vector to get the color cmoponents from.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator=( const CqVector3D& From )
		{
			m_fRed = From.x();
			m_fGreen = From.y();
			m_fBlue = From.z();

			return ( *this );
		}
		/** Additive assign operator.
		 * \param colFrom the color to add to this.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator+=( const CqColor &colFrom )
		{
			m_fRed += colFrom.m_fRed;	m_fGreen += colFrom.m_fGreen;	m_fBlue += colFrom.m_fBlue;
			return ( *this );
		}
		/** Subtractive assign operator.
		 * \param colFrom the color to subtract from this.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator-=( const CqColor &colFrom )
		{
			m_fRed -= colFrom.m_fRed;	m_fGreen -= colFrom.m_fGreen;	m_fBlue -= colFrom.m_fBlue;
			return ( *this );
		}
		/** Component wise multiplicative assign operator.
		 * \param colFrom the color to multiply this with.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator*=( const CqColor& colFrom )
		{
			m_fRed *= colFrom.m_fRed;	m_fGreen *= colFrom.m_fGreen;	m_fBlue *= colFrom.m_fBlue;
			return ( *this );
		}
		/** Component wise multiplicative assign operator.
		 * \param fScale the float to multiply each component with.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator*=( TqFloat fScale )
		{
			m_fRed *= fScale;	m_fGreen *= fScale;	m_fBlue *= fScale;
			return ( *this );
		}
		/** Component wise divisive assign operator.
		 * \param fScale the float to divide each component by.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator/=( const TqFloat fScale )
		{
			m_fRed /= fScale;	m_fGreen /= fScale;	m_fBlue /= fScale;
			return ( *this );
		}
		/** Component wise divisive assign operator.
		 * \param colFrom the color to divide this by.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator/=( const CqColor& colFrom )
		{
			m_fRed /= colFrom.m_fRed;	m_fGreen /= colFrom.m_fGreen;	m_fBlue /= colFrom.m_fBlue;
			return ( *this );
		}
		/** Component wise additive assign operator.
		 * \param Add the float to add to each component.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator+=( const TqFloat Add )
		{
			m_fRed += Add;	m_fGreen += Add;	m_fBlue += Add;
			return ( *this );
		}
		/** Component wise subtractive assign operator.
		 * \param Sub the float to subtract from each component.
		 * \return a reference to this color.
		 */
		_qShareM	CqColor&	operator-=( const TqFloat Sub )
		{
			m_fRed -= Sub;	m_fGreen -= Sub;	m_fBlue -= Sub;
			return ( *this );
		}
		/** Component wise equality operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating equality.
		 */
		_qShareM	TqBool	operator==( const CqColor &colCmp ) const
		{
			return ( ( m_fRed == colCmp.m_fRed ) && ( m_fGreen == colCmp.m_fGreen ) && ( m_fBlue == colCmp.m_fBlue ) );
		}
		/** Component wise inequality operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating inequality.
		 */
		_qShareM	TqBool	operator!=( const CqColor &colCmp ) const
		{
			return ( !( *this == colCmp ) );
		}
		/** Component wise greater than or equal to operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating each component is greater than or equal to its counterpart in the argument.
		 */
		_qShareM	TqBool	operator>=( const CqColor &colCmp ) const
		{
			return ( ( m_fRed >= colCmp.m_fRed ) && ( m_fGreen >= colCmp.m_fGreen ) && ( m_fBlue >= colCmp.m_fBlue ) );
		}
		/** Component wise less than or equal to operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating each component is less than or equal to its counterpart in the argument.
		 */
		_qShareM	TqBool	operator<=( const CqColor &colCmp ) const
		{
			return ( ( m_fRed <= colCmp.m_fRed ) && ( m_fGreen <= colCmp.m_fGreen ) && ( m_fBlue <= colCmp.m_fBlue ) );
		}
		/** Component wise greater than to operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating each component is greater than its counterpart in the argument.
		 */
		_qShareM	TqBool	operator>( const CqColor &colCmp ) const
		{
			return ( ( m_fRed > colCmp.m_fRed ) && ( m_fGreen > colCmp.m_fGreen ) && ( m_fBlue > colCmp.m_fBlue ) );
		}
		/** Component wise less than to operator.
		 * \param colCmp the color to compare this with.
		 * \return boolean indicating each component is less than its counterpart in the argument.
		 */
		_qShareM	TqBool	operator<( const CqColor &colCmp ) const
		{
			return ( ( m_fRed < colCmp.m_fRed ) && ( m_fGreen < colCmp.m_fGreen ) && ( m_fBlue < colCmp.m_fBlue ) );
		}

		/** Component wise friend addition operator.
		 * \param f float to add to each component.
		 * \param c color to add to.
		 * \return new color representing addition. 
		 */
		_qShareM	friend CqColor	operator+( const TqFloat f, const CqColor& c )
		{
			CqColor r( c ); return ( r += f );
		}
		/** Component wise friend addition operator.
		 * \param c color to add to.
		 * \param f float to add to each component.
		 * \return new color representing addition. 
		 */
		_qShareM	friend CqColor	operator+( const CqColor& c, const TqFloat f )
		{
			CqColor r( c ); return ( r += f );
		}
		/** Component wise friend subtraction operator.
		 * \param f float to subtract from each component.
		 * \param c color to subtract from.
		 * \return new color representing subtraction. 
		 */
		_qShareM	friend CqColor	operator-( const TqFloat f, const CqColor& c )
		{
			CqColor r( f, f, f ); return ( r -= c );
		}
		/** Component wise friend subtraction operator.
		 * \param c color to subtract from.
		 * \param f float to subtract from each component.
		 * \return new color representing subtraction. 
		 */
		_qShareM	friend CqColor	operator-( const CqColor& c, const TqFloat f )
		{
			CqColor r( c ); return ( r -= f );
		}
		/** Component wise friend multiplication operator.
		 * \param f float to multiply each component with.
		 * \param c color to multiply with.
		 * \return new color representing multiplication. 
		 */
		_qShareM	friend CqColor	operator*( const TqFloat f, const CqColor& c )
		{
			CqColor r( f, f, f ); return ( r *= c );
		}
		/** Component wise friend multiplication operator.
		 * \param c color to multiply with.
		 * \param f float to multiply each component with.
		 * \return new color representing multiplication. 
		 */
		_qShareM	friend CqColor	operator*( const CqColor& c, const TqFloat f )
		{
			CqColor r( c ); return ( r *= f );
		}
		/** Component wise friend division operator.
		 * \param f float to divide each component by.
		 * \param c color to divide.
		 * \return new color representing division. 
		 */
		_qShareM	friend CqColor	operator/( const TqFloat f, const CqColor& c )
		{
			CqColor r( f, f, f ); return ( r /= c );
		}
		/** Component wise friend division operator.
		 * \param c color to divide.
		 * \param f float to divide each component by.
		 * \return new color representing division. 
		 */
		_qShareM	friend CqColor	operator/( const CqColor& c, const TqFloat f )
		{
			CqColor r( c ); return ( r /= f );
		}

		/** Component wise friend addition operator.
		 * \param a color to add to.
		 * \param b color to add.
		 * \return new color representing addition. 
		 */
		_qShareM	friend CqColor	operator+( const CqColor& a, const CqColor& b )
		{
			CqColor r( a ); return ( r += b );
		}
		/** Component wise friend subtraction operator.
		 * \param a color to subtract from.
		 * \param b color to subtract.
		 * \return new color representing subtraction. 
		 */
		_qShareM	friend CqColor	operator-( const CqColor& a, const CqColor& b )
		{
			CqColor r( a ); return ( r -= b );
		}
		/** Component wise friend multiplication operator.
		 * \param a color to multiply.
		 * \param b color to multiply by.
		 * \return new color representing multiplication. 
		 */
		_qShareM	friend CqColor	operator*( const CqColor& a, const CqColor& b )
		{
			CqColor r( a ); return ( r *= b );
		}
		/** Component wise friend division operator.
		 * \param a color to divide.
		 * \param b color to divide by.
		 * \return new color representing division. 
		 */
		_qShareM	friend CqColor	operator/( const CqColor& a, const CqColor& b )
		{
			CqColor r( a ); return ( r /= b );
		}
		/** Component wise friend negation operator.
		 * \param a color to negate.
		 * \return new color representing negation. 
		 */
		_qShareM	friend CqColor	operator-( const CqColor& a )
		{
			return ( CqColor( -a.m_fRed, -a.m_fGreen, -a.m_fBlue ) );
		} // Negation
		/** Component wide stream output operator.
		 *\param Stream output stream.
		 *\param a color to serialize.
		 *\return input stream.
		 */
		_qShareM	friend std::ostream& operator<<( std::ostream& Stream, const CqColor& a )
		{
			Stream << a.m_fRed << " " << a.m_fGreen << " " << a.m_fBlue;
			return Stream;
		}

	private:
		TqFloat	m_fRed,  				///< the red component 0.0-1.0
		m_fGreen,  			///< the green component 0.0-1.0
		m_fBlue;			///< the blue component 0.0-1.0
}
;


/// Static white color
extern CqColor	gColWhite;
/// Static black color
extern CqColor	gColBlack;
/// Static red color
extern CqColor	gColRed;
/// Static green color
extern CqColor	gColGreen;
/// Static blue color
extern CqColor	gColBlue;

//-----------------------------------------------------------------------

END_NAMESPACE( Aqsis )


//}  // End of #ifdef _H_INCLUDED
#endif
