/*-
 * Copyright (c) 1999,2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of the source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Any redistribution solely in binary form must conspicuously
 *    reproduce the following disclaimer in documentation provided with the
 *    binary redistribution.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'', WITHOUT ANY WARRANTIES, EXPRESS
 * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  LICENSOR SHALL
 * NOT BE LIABLE FOR ANY LOSS OR DAMAGES RESULTING FROM THE USE OF THIS
 * SOFTWARE, EITHER ALONE OR IN COMBINATION WITH ANY OTHER SOFTWARE.
 * 
 * 	$Id: color4b.h,v 1.11 2000/05/26 08:47:18 dfr Exp $
 */

#ifndef __Color4b_h__
#define __Color4b_h__

MATHS_BEGIN

struct EXPORT_QMATHS Color4b
{
			Color4b()
			{
			    value_ = 0;
			}
			Color4b(const Color4b& c)
			{
			    value_ = c.value_;
			}
			Color4b(unsigned int v) { value_ = v; }
			Color4b(unsigned int r,
				unsigned int g,
				unsigned int b)
			{
			    value_ = (255 << 24) | (r << 16) |
				(g << 8) | (b << 0);
			}
			Color4b(unsigned int r,
				unsigned int g,
				unsigned int b,
				unsigned int a) 
			{
			    value_ = (a << 24) | (r << 16) |
				(g << 8) | (b << 0);
			}
			Color4b(const Vec3b& v)
			{
			    value_ = (255 << 24) | (v[0] << 16) |
				(v[1] << 8) | (v[2] << 0);
			}
			Color4b(const Vec4b& v)
			{
			    value_ = (v[3] << 24) | (v[0] << 16) |
				(v[1] << 8) | (v[2] << 0);
			}
			Color4b(const Vec3f& v)
			{
			    value_ = pack(v.x, v.y, v.z, 1.0f);
			}
			Color4b(const Vec4f& v)
			{
			    value_ = pack(v.x, v.y, v.z, v.w);
			}
			Color4b(const Vec4ui& v)
			{
			    value_ = pack(v.x, v.y, v.z, v.w);
			}
    
    unsigned int	alpha() const	{ return (value_ >> 24) & 0xff; }
    unsigned int	red() const	{ return (value_ >> 16) & 0xff; }
    unsigned int	green() const	{ return (value_ >> 8) & 0xff; }
    unsigned int	blue() const	{ return (value_ >> 0) & 0xff; }
    unsigned int	value() const	{ return value_; }

    operator unsigned int() const	{ return value_; }
    operator Vec4b() const		{ return Vec4b(red(), green(),
						       blue(), alpha()); }
    operator Vec4f() const		{ return Vec4f(fixedToFloat(red()),
						       fixedToFloat(green()),
						       fixedToFloat(blue()),
						       fixedToFloat(alpha()));
					}
    operator Vec3f() const		{ return Vec3f(fixedToFloat(red()),
						       fixedToFloat(green()),
						       fixedToFloat(blue())); }

    
    friend EXPORT_QMATHS Color4b operator+(const Color4b& c1, const Color4b& c2);
    friend EXPORT_QMATHS Color4b operator-(const Color4b& c1, const Color4b& c2);
    friend EXPORT_QMATHS Color4b operator-(float m, const Color4b& c1);
    friend EXPORT_QMATHS Color4b operator*(const Color4b& c1, const Color4b& c2);
    friend EXPORT_QMATHS Color4b operator*(const Color4b& c1, float m);
    friend EXPORT_QMATHS Color4b operator*(float m, const Color4b& c1);
    friend int operator==(const Color4b& c1, const Color4b& c2)
	{
	    return c1.value_ == c2.value_;
	}
    
    void		alpha(unsigned int a)
	{
	    value_ = (value_ & 0x00ffffff) | ((a & 0xff) << 24);
	}
    void		red(unsigned int a)
	{
	    value_ = (value_ & 0xff00ffff) | ((a & 0xff) << 16);
	}
    void		green(unsigned int a)
	{
	    value_ = (value_ & 0xffff00ff) | ((a & 0xff) << 8);
	}
    void		blue(unsigned int a)
	{
	    value_ = (value_ & 0xffffff00) | ((a & 0xff) << 0);
	}
    void		value(unsigned int value)
	{
	    value_ = value;
	}

    friend EXPORT_QMATHS Color4b interpolate(float f, const Color4b& c1,
				      const Color4b& c2)
	{
	    Vec4f v1(fixedToFloat(c1.red(), 0),
		     fixedToFloat(c1.green(), 0),
		     fixedToFloat(c1.blue(), 0),
		     fixedToFloat(c1.alpha(), 0));
	    Vec4f v2(fixedToFloat(c2.red(), 0),
		     fixedToFloat(c2.green(), 0),
		     fixedToFloat(c2.blue(), 0),
		     fixedToFloat(c2.alpha(), 0));
	    
	    Vec4f v = (1 - f) * v1 +  f * v2;

	    return Color4b(floatToFixed(v.x, 0),
			   floatToFixed(v.y, 0),
			   floatToFixed(v.z, 0),
			   floatToFixed(v.w, 0));
	}
    
private:
    unsigned int	pack(float r1, float g1, float b1, float a1) const
	{
	    int r = floatToFixed(r1);
	    int g = floatToFixed(g1);
	    int b = floatToFixed(b1);
	    int a = floatToFixed(a1);
	    
	    int mask1 = intToMask(r - 255);
	    int mask2 = intToMask(g - 255);
	    int mask3 = intToMask(b - 255);
	    int mask4 = intToMask(a - 255);
	    
	    return (((a & mask4) | (0xff & ~mask4)) << 24) |
		(((r & mask1) | (0xff & ~mask1)) << 16) |
		(((g & mask2) | (0xff & ~mask2)) << 8) |
		((b & mask3) | (0xff & ~mask3));
	}
    
    unsigned int	pack(unsigned int r, unsigned int g,
			     unsigned int b, unsigned int a) const
	{
	    // Clamp each channel between 0 & 255 
	    
	    int mask1 = intToMask(r - 0xff);
	    int mask2 = intToMask(g - 0xff);
	    int mask3 = intToMask(b - 0xff);
	    int mask4 = intToMask(a - 0xff);
	    
	    return (((a & mask4) | (0xff & ~mask4)) << 24) |
		(((r & mask1) | (0xff & ~mask1)) << 16) |
		(((g & mask2) | (0xff & ~mask2)) << 8) |
		((b & mask3) | (0xff & ~mask3));
	}
    
    unsigned int	value_;
};

MATHS_END

#endif /* __Color4b_h__ */

