/**********************************************************************************************

		MCColor16.h


		Copyright: (c) 2001 Eovia Corp. All rights reserved.


		Author:	Nicolas
		Date:	07/02/98

		This file contains the tools for using fixed
	
		Revision History

		when		who			what & why
		==========	==========	======================================================
		07/07/99	Nba			Removed InitGlobals
		06/29/99	Nba			Added FastDivide
		6/10/99		Ian			Array API changes.
		05/17/99	del			Added TGray32::FormInt32 & TGray32::ToInt32 and some operators
		04/28/99	del			Fixed bug in TGray32 operator /=
		04/06/99	del			Added operator / by int32 for TGray32
		03/21/99	Frh			added TGray16::k3o4
		03/05/99	del			added TGray16::kTiny
		02/10/99	del			Made TGray32 constructor from fixed1814 explicit
		02/04/99	Nba			Added ClampZeroToOne to TGray32
		02/04/99	Nba			Added FixedMultiply and FixedDivide
		02/04/99	del			Changed ClampToTGray16
		02/02/99	del			Added TGray16::kMax & TGray32::kTiny
		01/29/99	cph			added k1o4, kFour, kEight, kSixteen
		01/26/99	Mathieu		TGray32 : constructor from real
		01/22/99	Nba			added TArrayRGB stuff
		12/11/98	Mathieu		added conversion TGray16 <-> TGray32 calls
		11/30/98	Nba			added some operators to TGray32 ; Added Blend
		12/01/98	Mathieu		added some more constants (-2, 3, 6) and the != operator 
		11/23/98	Del			added constants for TGray32
		11/23/99	Del			added Fixed1814 and TGray32
		10/12/98	Nba			added some operators
		9/4/98		tsh			use multiply, not divide to convert to real
		08/18/98	Mathieu		Added constructor from uint16, optimized ClampZeroToOne
		08/06/98	Del			Added unary -, <<, >>, ClampZeroToOne, IsPositive and some constants
		07/22/98	Nba			Added FromFixed214/ToFixed214 and RtoI, restored Load16 and Store16
		07/22/98	Mathieu		Fixed minor bugs, added comparison with const value
		07/15/98	Nba			Wrote conversion 8 <-> 2_14
		07/14/98	Nba			Changed to TGray16, and added some conversion methods

**********************************************************************************************/

#ifndef __MCColor16__
#define __MCColor16__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"
#include "MCOSConfig.h"
#include "MCFixedSizeArray.h"

typedef int16 TFixed214;

class TGray32;

/// Fixed precision monochrome class
///
class TGray16
{
//	friend class TGray16;
	friend class TGray32;

public:


	// constants
	static const TGray16 kZero;
	static const TGray16 kTiny;
	static const TGray16 k1o12;
	static const TGray16 k1o6;
	static const TGray16 k1o4;
	static const TGray16 k1o3;
	static const TGray16 k1o2;
	static const TGray16 k2o3;
	static const TGray16 k3o4;
	static const TGray16 kOne;
	static const TGray16 kMinusTwo;
	static const TGray16 kMax;

	//
	TGray16() {}
	explicit TGray16(uint8 value)					{ From8(value); }
	explicit TGray16(real32 value)					{ FromReal(value); }
	explicit TGray16(TFixed214 value)				{ FromFixed214(value); }
	explicit TGray16(uint16 value)					{ Store16(value); }


	// NBA-TODO : Write faster conversions
	void   From8		(uint8 value)				{ fValue = (value << 6) + (value >> 2) + (value >> 7); } // (value << 14) / 255
	void   FromReal		(real32 value)				{ fValue = RtoI(value*16384.0f); }
	void   FromFixed214	(TFixed214 value)			{ fValue = value; }
	uint8  To8			() const					{ return (fValue >> 6) - (fValue >> 14); } // (fValue * 255) >> 14
	real32 ToReal		() const					{ return real32(fValue) * k1o16384; }
	TFixed214 ToFixed214() const					{ return fValue; }

	// members used when storing data
	uint16 Load16		() const					{ return (uint16)fValue; }
	void   Store16		(const uint16 value)		{ fValue = (uint16)value; }


	TGray16 operator+	(const TGray16& c2) const	{ return TGray16(TFixed214(fValue+c2.fValue)); }
	TGray16 operator-	(const TGray16& c2) const	{ return TGray16(TFixed214(fValue-c2.fValue)); }
	TGray16 operator-	() const					{ return TGray16(TFixed214(-fValue)); }
	TGray16 operator*	(const TGray16& c2) const	{ return TGray16(TFixed214((fValue*c2.fValue) >> 14)); }
	TGray16 operator/	(const TGray16& c2) const	{ return TGray16(TFixed214((int32(fValue) << 14)/c2.fValue)); }
	TGray16 operator>>	(uint8 i)			const	{ return TGray16(TFixed214(fValue>>i)); }
	TGray16 operator<<	(uint8 i)			const	{ return TGray16(TFixed214(fValue<<i)); }
	TGray16& operator>>=(uint8 i)					{ fValue>>=i; return *this; }
	TGray16& operator<<=(uint8 i)					{ fValue<<=i; return *this; }

	// other operations
	inline TGray16& FastDivide(TGray16& c2);

	TGray16 ClampZeroToOne() const
	{
		return (fValue<0?kZero:(fValue>0x4000?kOne:*this));
	}

	// keep the fractional part
	TGray16 Fractional() const { return TGray16(TFixed214(uint16(fValue) & 0x3FFF)); }

	boolean operator==	(const TGray16& c2) const	{ return fValue == c2.fValue; }
	boolean operator!=	(const TGray16& c2) const	{ return fValue != c2.fValue; }
	boolean operator<=	(const TGray16& c2) const	{ return fValue <= c2.fValue; }
	boolean operator>=	(const TGray16& c2) const	{ return fValue >= c2.fValue; }
	boolean operator<	(const TGray16& c2) const	{ return fValue < c2.fValue; }
	boolean operator>	(const TGray16& c2) const	{ return fValue > c2.fValue; }

	boolean IsPositive	() const					{ return fValue > 0; }
	boolean IsZero		() const					{ return fValue == 0; }

	TGray16& operator=	(const TGray16& s)			{ fValue = s.fValue; return *this; }
	TGray16& operator+=	(const TGray16& c2)			{ fValue += c2.fValue; return *this; }
	TGray16& operator-=	(const TGray16& c2)			{ fValue -= c2.fValue; return *this; }
	TGray16& operator*=	(const TGray16& c2)			{ fValue = (fValue*c2.fValue) >> 14; return *this; }
	TGray16& operator/=	(const TGray16& c2)			{ fValue = (int32(fValue) << 14)/c2.fValue; return *this; }
	TGray16& operator*=	(const int16 i)				{ fValue *= i; return *this; }
	TGray16& operator/=	(const int16 i)				{ fValue /= i; return *this; }



	// operations with other types

	TGray16 operator*	(const int16 c2) const		{ return TGray16(TFixed214(fValue*c2)); }

	boolean operator==	(const TFixed214 c2) const	{ return fValue == c2; }
	boolean operator<=	(const TFixed214 c2) const	{ return fValue <= c2; }
	boolean operator>=	(const TFixed214 c2) const	{ return fValue >= c2; }
	boolean operator<	(const TFixed214 c2) const	{ return fValue < c2; }
	boolean operator>	(const TFixed214 c2) const	{ return fValue > c2; }

	TGray16 &Blend		(const TGray16& val, const TGray16 &alpha) { *this += alpha*(val-*this); return *this; }
	

	static uint32* fFastDivideTable;
private:
	static const real32 k1o16384;
	int16 RtoI(real32 value);
	TFixed214 fValue;
};

inline int16 TGray16::RtoI(real32 value)
{
#if defined(ARCH_X86) && defined(_MSC_VER)
	int32 res;
	int32* milou=&res;
	__asm {
		fld value
		mov eax,milou
		fistp DWORD PTR [eax]
		}
	return (int16)res;
#else
	return (int16)value;
#endif
}

inline TGray16& TGray16::FastDivide(TGray16& c2)
{
	fValue = (long(fValue) * fFastDivideTable[c2.fValue]) >> 16;
	return *this;
}


typedef int32 TFixed1814;

/// Fixed precision monochrome class
///
class TGray32
{

//friend class TGray32;

public:

	// constants
	static const TGray32 kZero;
	static const TGray32 kTiny;
	static const TGray32 k1o12;
	static const TGray32 k1o6;
	static const TGray32 k1o4;
	static const TGray32 k1o3;
	static const TGray32 k1o2;
	static const TGray32 k2o3;
	static const TGray32 k3o4;
	static const TGray32 kOne;
	static const TGray32 kTwo;
	static const TGray32 kFour;
	static const TGray32 kMinusTwo;
	static const TGray32 kThree;
	static const TGray32 kSix;
	static const TGray32 kEight;
	static const TGray32 kSixteen;

	TGray32() {}
	TGray32(const TGray16 t16)				{ FromTGray16(t16); }
	explicit TGray32(const TFixed1814 f)	{ fValue = f;}
	explicit TGray32(const real32 r)		{ FromReal(r); }

	void FromInt32		(const int32 i32)	{ fValue = i32<<14; }
	void FromTGray16	(const TGray16 t16)	{ fValue = t16.fValue; }
	void FromFixed1814	(const TFixed1814 f){ fValue = f; }
	void FromReal		(const real32 r)	{ fValue = (TFixed1814)(r*16384.0f); }

	TGray16	ToTGray16() const { return TGray16((TFixed214)fValue); }
	inline TGray16 ClampToTGray16(boolean &outClamped) const;
	TFixed1814 ToFixed1814() const { return fValue; }
	real32 ToReal() const { return real32(fValue) * TGray16::k1o16384; }
	int32 ToInt32() const { return fValue>>14; }

	TGray16 ClampZeroToOne() const
	{
		return (fValue<0?TGray16::kZero:(fValue>0x04000?TGray16::kOne:this->ToTGray16()));
	}

		
	TGray32 operator+	(const TGray32& c2) const	{ return TGray32(TFixed1814(fValue+c2.fValue)); }
	TGray32 operator-	(const TGray32& c2) const	{ return TGray32(TFixed1814(fValue-c2.fValue)); }
	TGray32 operator-	()					const	{ return TGray32(TFixed1814(-fValue)); }
	TGray32 operator*	(const TGray32& c2) const	{ return TGray32(FixedMultiply(fValue, c2.fValue)); }
	TGray32 operator/	(const TGray32& c2) const	{ return TGray32(FixedDivide(fValue, c2.fValue)); }
	TGray32	operator/	(const int32 i)		const	{ return TGray32(TFixed1814(fValue/i)); }
	TGray32 operator>>	(const uint8 i)		const	{ return TGray32(TFixed1814(fValue>>i)); }
	TGray32 operator<<	(const uint8 i)		const	{ return TGray32(TFixed1814(fValue<<i)); }
	TGray32 operator&	(const uint32 i)	const	{ return TGray32(TFixed1814(fValue&i)); }
	TGray32 operator|	(const uint32 i)	const	{ return TGray32(TFixed1814(fValue|i)); }

	TGray32& operator+=	(const TGray32& c2)			{ fValue += c2.fValue; return *this; }
	TGray32& operator-=	(const TGray32& c2)			{ fValue -= c2.fValue; return *this; }
	TGray32& operator*=	(const TGray32& c2)			{ fValue = FixedMultiply(fValue, c2.fValue); return *this; }
	TGray32& operator/=	(const TGray32& c2)			{ fValue = FixedDivide(fValue, c2.fValue); return *this; }
	TGray32& operator*=	(const int32 i)				{ fValue *= i; return *this; }
	TGray32& operator/=	(const int32 i)				{ fValue /= i; return *this; }
	TGray32& operator&=	(const uint32 i)			{ fValue &= i; return *this; }
	TGray32& operator|=	(const uint32 i)			{ fValue |= i; return *this; }

	TGray32& operator>>=(uint8 i)					{ fValue>>=i; return *this; }
	TGray32& operator<<=(uint8 i)					{ fValue<<=i; return *this; }


	boolean operator==	(const TGray32& c2) const	{ return fValue == c2.fValue; }
	boolean operator!=	(const TGray32& c2) const	{ return fValue != c2.fValue; }
	boolean operator<=	(const TGray32& c2) const	{ return fValue <= c2.fValue; }
	boolean operator>=	(const TGray32& c2) const	{ return fValue >= c2.fValue; }
	boolean operator<	(const TGray32& c2) const	{ return fValue < c2.fValue; }
	boolean operator>	(const TGray32& c2) const	{ return fValue > c2.fValue; }

	TGray32 Fractional	()					const	{ return TGray32(TFixed1814(uint32(fValue) & 0x3FFF)); }

	TGray32&Blend		(const TGray32& val, const TGray32& alpha) { *this += alpha*(val-*this); return *this; }

private:
	inline TFixed1814 FixedMultiply(TFixed1814 x, TFixed1814 y) const;
	inline TFixed1814 FixedDivide(TFixed1814 x, TFixed1814 y) const;
	TFixed1814 fValue;
};

inline TFixed1814 TGray32::FixedMultiply(TFixed1814 x, TFixed1814 y) const
{
	TFixed1814 result;
#if defined(ARCH_X86) && defined(_MSC_VER)
	__asm
	{
		mov eax, x
		mov ebx, y
		imul ebx
		shl edx, 18
		shr eax, 14
		xor eax, edx
		mov result, eax
	}
#else
	result = (int64(x)*int64(y)) >> 14;
#endif
	return result;
}

inline TFixed1814 TGray32::FixedDivide(TFixed1814 x, TFixed1814 y) const
{
	return (int64(x) << 14) / int32(y);
}

inline TGray16 TGray32::ClampToTGray16(boolean &outClamped) const
{
	if(operator >(TGray32(TGray16::kMax)))
	{
		outClamped=true;
		return TGray16::kMax;
	}
	if(operator <(TGray32::kMinusTwo))
	{
		outClamped=true;
		return TGray16::kMinusTwo;
	}
	outClamped=false;
	return ToTGray16();
}

typedef TMCFixedSizeArray<TGray16, 3> TArrayRGB;
typedef TMCFixedSizeArray<TGray16, 4> TArrayRGBA;
typedef TMCFixedSizeArray<TGray16, 4> TArrayCMYK;
typedef TMCFixedSizeArray<TGray16, 5> TArrayCMYKA;


#endif // __MCColor16__