summaryrefslogtreecommitdiff
path: root/Runtime/Math/Color.h
blob: 594598b1bb90777ad18625983dfb7a85f90840db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#ifndef COLOR_H
#define COLOR_H

#include "Runtime/Serialize/SerializeUtility.h"
#include "Runtime/Serialize/SerializationMetaFlags.h"
#include <algorithm>
#include "Runtime/Utilities/Utility.h"
#include "FloatConversion.h"
#include "Runtime/Serialize/SwapEndianBytes.h"

class ColorRGBAf
{
	public:
	float	r, g, b, a;

	DEFINE_GET_TYPESTRING_IS_ANIMATION_CHANNEL (ColorRGBA)

	ColorRGBAf () {}
	
	ColorRGBAf (float inR, float inG, float inB, float inA = 1.0F) : r(inR), g(inG), b(inB), a(inA) {}
	explicit ColorRGBAf (const float* c) : r(c[0]), g(c[1]), b(c[2]), a(c[3]) {}

	template<class TransferFunction> 
	void Transfer (TransferFunction& transfer);

	void Set (float inR, float inG, float inB, float inA) {r = inR; g = inG; b = inB; a = inA;}
	
	void SetHex (UInt32 hex)
	{
		Set(float (hex >> 24) / 255.0f, 
			float ((hex >> 16) & 255) / 255.0f, 
			float ((hex >> 8) & 255) / 255.0f, 
			float (hex & 255) / 255.0f);
	}

	UInt32 GetHex () const
	{
		UInt32 hex = (NormalizedToByte(r) << 24) | (NormalizedToByte(g) << 16) | (NormalizedToByte(b) << 8) | NormalizedToByte(a);
		return hex;
	}
	
	float AverageRGB () const {return (r+g+b)*(1.0F / 3.0F);}
	float GreyScaleValue () const { return r * 0.30f + g * 0.59f  + b * 0.11f; }
	
	ColorRGBAf& operator = (const ColorRGBAf& in) { Set (in.r, in.g, in.b, in.a); return *this; }

	bool Equals(const ColorRGBAf& inRGB) const
	{
		return (r == inRGB.r && g == inRGB.g && b == inRGB.b && a == inRGB.a);
	}
	
	bool NotEquals(const ColorRGBAf& inRGB) const
	{
		return (r != inRGB.r || g != inRGB.g || b != inRGB.b || a != inRGB.a);
	}

	float* GetPtr ()				{return &r;}
	const float* GetPtr () const	{return &r;}

	ColorRGBAf& operator += (const ColorRGBAf &inRGBA)
	{
		r += inRGBA.r; g += inRGBA.g; b += inRGBA.b; a += inRGBA.a;
		return *this;
	}

	ColorRGBAf& operator *= (const ColorRGBAf &inRGBA)
	{
		r *= inRGBA.r; g *= inRGBA.g; b *= inRGBA.b; a *= inRGBA.a;
		return *this;
	}

private:
	// intentionally undefined
	bool operator == (const ColorRGBAf& inRGB) const;
	bool operator != (const ColorRGBAf& inRGB) const;
};


inline ColorRGBAf operator + (const ColorRGBAf& inC0, const ColorRGBAf& inC1)
{
	return ColorRGBAf (inC0.r + inC1.r, inC0.g + inC1.g, inC0.b + inC1.b, inC0.a + inC1.a);
}

inline ColorRGBAf operator * (const ColorRGBAf& inC0, const ColorRGBAf& inC1)
{
	return ColorRGBAf (inC0.r * inC1.r, inC0.g * inC1.g, inC0.b * inC1.b, inC0.a * inC1.a);
}

inline ColorRGBAf operator * (float inScale, const ColorRGBAf& inC0)
{
	return ColorRGBAf (inC0.r * inScale, inC0.g * inScale, inC0.b * inScale, inC0.a * inScale);
}

inline ColorRGBAf operator * (const ColorRGBAf& inC0, float inScale)
{
	return ColorRGBAf (inC0.r * inScale, inC0.g * inScale, inC0.b * inScale, inC0.a * inScale);
}

inline ColorRGBAf Lerp (const ColorRGBAf& c0, const ColorRGBAf& c1, float t)
{
	return (1.0f - t) * c0 + t * c1; 
}



class ColorRGBA32
{
	public:

	UInt8	r, g, b, a;

	DEFINE_GET_TYPESTRING_IS_ANIMATION_CHANNEL (ColorRGBA)
	
	ColorRGBA32 ()								{}
	
	ColorRGBA32 (UInt8 inR, UInt8 inG, UInt8 inB, UInt8 inA)		{ r = inR; g = inG; b = inB; a = inA; }
	ColorRGBA32 (UInt32 c)						{ *(UInt32*)this = c; }
	void Set (UInt8 inR, UInt8 inG, UInt8 inB, UInt8 inA)		{ r = inR; g = inG; b = inB; a = inA; }

	ColorRGBA32 operator = (const ColorRGBA32& c)	{ *(UInt32*)this = *((UInt32*)&c); return *this;}
	
	ColorRGBA32 (const ColorRGBAf& c) { Set (c); }
	
	operator ColorRGBAf() const
	{
		return ColorRGBAf (ByteToNormalized(r), ByteToNormalized(g), ByteToNormalized(b), ByteToNormalized(a));
	}
	
	UInt32 AsUInt32 () const { return *(UInt32*)this; }

	void operator = (const ColorRGBAf& c)
	{
		Set (c);
	}
	
	UInt32 GetUInt32 () { return *(UInt32*)this; }

	void Set (const ColorRGBAf& c)
	{
		r = NormalizedToByte(c.r);
		g = NormalizedToByte(c.g);
		b = NormalizedToByte(c.b);
		a = NormalizedToByte(c.a);
	}
	
	template<class TransferFunction> 
	void Transfer (TransferFunction& transfer)
	{
		transfer.SetVersion (2);
		UInt32* c =  reinterpret_cast<UInt32*> (this);
		// When transferring colors we shouldn't swap bytes.
		// UInt32 already convert endianess by default so we convert it two times to keep it the same :)
		if (transfer.ConvertEndianess ())
		{
			if (transfer.IsReading())
			{
				transfer.Transfer (*c, "rgba", kHideInEditorMask);	
				SwapEndianBytes (*c);
			}
			else
			{
				UInt32 temp = *c;
				SwapEndianBytes (temp);
				transfer.Transfer (temp, "rgba", kHideInEditorMask);	
			}
		}
		else
		{
			transfer.Transfer (*c, "rgba", kHideInEditorMask);	
		}
	}
	
	UInt8& operator [] (long i) {return GetPtr () [i];}
	const UInt8& operator [] (long i)const {return GetPtr () [i];}
	
	bool operator == (const ColorRGBA32& inRGB) const
	{
		return (r == inRGB.r && g == inRGB.g && b == inRGB.b && a == inRGB.a) ? true : false;
	}
	
	bool operator != (const ColorRGBA32& inRGB) const
	{
		return (r != inRGB.r || g != inRGB.g || b != inRGB.b || a != inRGB.a) ? true : false;
	}
	
	UInt8* GetPtr ()		{return &r;}
	const UInt8* GetPtr ()const	{return &r;}
	
	inline ColorRGBA32 operator * (int scale) const
	{
		//AssertIf (scale < 0 || scale > 255);
		scale += 1;
		const UInt32& u = reinterpret_cast<const UInt32&> (*this);
		UInt32 lsb = (((u & 0x00ff00ff) * scale) >> 8) & 0x00ff00ff;
		UInt32 msb = (((u & 0xff00ff00) >> 8) * scale) & 0xff00ff00;
		lsb |= msb;
		return ColorRGBA32 (lsb);
	}

	inline void operator *= (const ColorRGBA32& inC1)
	{
#if 0
		r = (r * inC1.r) / 255;
		g = (g * inC1.g) / 255;
		b = (b * inC1.b) / 255;
		a = (a * inC1.a) / 255;
#else // This is much faster, but doesn't guarantee 100% matching result (basically color values van vary 1/255 but not at ends, check out unit test in cpp file).
		UInt32& u = reinterpret_cast<UInt32&> (*this);
		const UInt32& v = reinterpret_cast<const UInt32&> (inC1);
		UInt32 result = (((u & 0x000000ff) * ((v & 0x000000ff) + 1)) >> 8) & 0x000000ff;
		result |= (((u & 0x0000ff00) >> 8) * (((v & 0x0000ff00) >> 8) + 1)) & 0x0000ff00;
		result |= (((u & 0x00ff0000) * (((v & 0x00ff0000) >> 16) + 1)) >> 8) & 0x00ff0000;
		result |= (((u & 0xff000000) >> 8) * (((v & 0xff000000) >> 24) + 1)) & 0xff000000;
		u = result;
#endif
}

	inline ColorRGBA32 SwizzleToBGRA() const { return ColorRGBA32(b, g, r, a); }
	inline ColorRGBA32 SwizzleToBGR() const { return ColorRGBA32(b, g, r, 255); }
	inline ColorRGBA32 SwizzleToARGB() const { return ColorRGBA32(a, r, g, b); }
	inline ColorRGBA32 UnswizzleBGRA() const { return ColorRGBA32(b, g, r, a); }
	inline ColorRGBA32 UnswizzleARGB() const { return ColorRGBA32(g, b, a, r); }
};

#if GFX_OPENGLESxx_ONLY
	inline ColorRGBA32 SwizzleColorForPlatform(const ColorRGBA32& col) { return col; }
	inline ColorRGBA32 UnswizzleColorForPlatform(const ColorRGBA32& col) { return col; }
#elif UNITY_XENON || UNITY_PS3 || UNITY_WII
	inline ColorRGBA32 SwizzleColorForPlatform(const ColorRGBA32& col) { return col.SwizzleToARGB(); }
	inline ColorRGBA32 UnswizzleColorForPlatform(const ColorRGBA32& col) { return col.UnswizzleARGB(); }
#else
	inline ColorRGBA32 SwizzleColorForPlatform(const ColorRGBA32& col) { return col.SwizzleToBGRA(); }
	inline ColorRGBA32 UnswizzleColorForPlatform(const ColorRGBA32& col) { return col.UnswizzleBGRA(); }
#endif

struct OpColorRGBA32ToUInt32
{
	typedef UInt32 result_type;
	UInt32 operator() (ColorRGBA32 const& arg) const { return arg.AsUInt32(); }
};

inline ColorRGBA32 operator + (const ColorRGBA32& inC0, const ColorRGBA32& inC1)
{
	return ColorRGBA32 (std::min<int> (inC0.r + inC1.r, 255), 
		std::min<int> (inC0.g + inC1.g, 255),
		std::min<int> (inC0.b + inC1.b, 255),
		std::min<int> (inC0.a + inC1.a, 255));
}

inline ColorRGBA32 operator * (const ColorRGBA32& inC0, const ColorRGBA32& inC1)
{
#if 0
	return ColorRGBA32 ((inC0.r * inC1.r) / 255, 
		(inC0.g * inC1.g) / 255,
		(inC0.b * inC1.b) / 255,
		(inC0.a * inC1.a) / 255);
#else
	// This is much faster, but doesn't guarantee 100% matching result (basically color values van vary 1/255 but not at ends, check out unit test in cpp file).
	const UInt32& u = reinterpret_cast<const UInt32&> (inC0);
	const UInt32& v = reinterpret_cast<const UInt32&> (inC1);
	UInt32 result = (((u & 0x000000ff) * ((v & 0x000000ff) + 1)) >> 8) & 0x000000ff;
	result |= (((u & 0x0000ff00) >> 8) * (((v & 0x0000ff00) >> 8) + 1)) & 0x0000ff00;
	result |= (((u & 0x00ff0000) * (((v & 0x00ff0000) >> 16) + 1)) >> 8) & 0x00ff0000;
	result |= (((u & 0xff000000) >> 8) * (((v & 0xff000000) >> 24) + 1)) & 0xff000000;
	return ColorRGBA32 (result);
#endif
}

inline ColorRGBA32 Lerp(const ColorRGBA32& c0, const ColorRGBA32& c1, int scale)
{
	//AssertIf (scale < 0 || scale > 255);
	const UInt32& u0 = reinterpret_cast<const UInt32&> (c0);
	const UInt32& u1 = reinterpret_cast<const UInt32&> (c1);
	UInt32 vx = u0 & 0x00ff00ff;
	UInt32 rb = vx + ((((u1 & 0x00ff00ff) - vx) * scale) >> 8) & 0x00ff00ff;
	vx = u0 & 0xff00ff00;
	return ColorRGBA32( rb | (vx + ((((u1 >> 8) & 0x00ff00ff) - (vx >> 8)) * scale) & 0xff00ff00) );
}


template<class TransferFunction> 
void ColorRGBAf::Transfer (TransferFunction& transfer)
{
	transfer.AddMetaFlag (kTransferUsingFlowMappingStyle);
	transfer.Transfer (r, "r", kHideInEditorMask);
	transfer.Transfer (g, "g", kHideInEditorMask);
	transfer.Transfer (b, "b", kHideInEditorMask);
	transfer.Transfer (a, "a", kHideInEditorMask);
}


#endif