1// tColour.h 
2// 
3// Colour and pixel classes. There are classes for: 
4// * A 32 bit colour. 4 unsigned 8-bit integer components (rgb + alpha). 
5// * A 96 bit colour. 3 32-bit float components. 
6// * A 128 bit colour. 4 32-bit float components (rgb + alpha). 
7// 
8// Copyright (c) 2006, 2011, 2017, 2020 Tristan Grimmer. 
9// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
10// granted, provided that the above copyright notice and this permission notice appear in all copies. 
11// 
12// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
13// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
14// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
15// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
16// PERFORMANCE OF THIS SOFTWARE. 
17 
18#pragma once 
19#include <Foundation/tFundamentals.h> 
20#include "Math/tVector3.h" 
21#include "Math/tVector4.h" 
22class tColouri
23class tColourf
24class tColour3f
25 
26 
27namespace tMath 
28
29 // Colour space conversions. The integer versions accept angle modes of Degrees and Norm256 only. The angle mode 
30 // determines the range of the hue. Degrees means angles are in [0, 360). Norm256 means angles are in [0, 256). 
31 // Saturation and value are both in [0, 256) for the integer conversion functions. 
32 void tRGBToHSV(int& h, int& s, int& v, int r, int g, int b, tAngleMode = tMath::tAngleMode::Degrees); 
33 void tHSVToRGB(int& r, int& g, int& b, int h, int s, int v, tMath::tAngleMode = tMath::tAngleMode::Degrees); 
34 
35 // The floating point colour space conversion functions accept any angle mode. Radians mean angles are in [0.0, 2Pi). 
36 // Degrees means angles are in [0.0, 360.0). Norm256 means angles are in [0.0, 256.0). NormOne means angles are 
37 // in [0.0, 1.0]. 
38 void tRGBToHSV(float& h, float& s, float& v, float r, float g, float b, tMath::tAngleMode = tMath::tAngleMode::Radians); 
39 void tHSVToRGB(float& r, float& g, float& b, float h, float s, float v, tMath::tAngleMode = tMath::tAngleMode::Radians); 
40 
41 // Convert a standard web colour name (as may be found in rgb.txt for example) into a 32bit RGBA tColouri. 
42 tColouri tGetColour(const char* colourName); 
43 
44 // Alpha is ignored for these colour difference functions. 
45 float tColourDiffEuclideanSq(const tColouri& a, const tColouri& b); // Returns value E [0.0, 195075.0] 
46 float tColourDiffEuclidean(const tColouri& a, const tColouri& b); // Returns value E [0.0, 441.672956] 
47 float tColourDiffRedmean(const tColouri& a, const tColouri& b); // Returns value E [0.0, 764.8340] 
48 
49 enum ColourChannel 
50
51 ColourChannel_R = 1 << 0
52 ColourChannel_G = 1 << 1
53 ColourChannel_B = 1 << 2
54 ColourChannel_A = 1 << 3
55 ColourChannel_RGB = ColourChannel_R | ColourChannel_G | ColourChannel_B
56 ColourChannel_RGBA = ColourChannel_R | ColourChannel_G | ColourChannel_B | ColourChannel_A
57 ColourChannel_All = ColourChannel_RGBA 
58 }; 
59
60 
61 
62// The tColouri class represents a colour in 32 bits and is made of 4 unsigned byte-size integers in the order RGBA. 
63class tColouri 
64
65public
66 tColouri() /* Does NOT set the colour values. */ { } 
67 tColouri(const tColouri& c) : BP(c.BP) { } 
68 tColouri(int r, int g, int b, int a = 0xFF) { R = tMath::tClamp(r, 0, 0xFF); G = tMath::tClamp(g, 0, 0xFF); B = tMath::tClamp(b, 0, 0xFF); A = tMath::tClamp(a, 0, 0xFF); } 
69 tColouri(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : R(r), G(g), B(b), A(a) { } 
70 tColouri(uint32 bits) : BP(bits) { } 
71 tColouri(const tColourf& c) { Set(c); } 
72 tColouri(float r, float g, float b, float a = 1.0f) { Set(r, g, b, a); } 
73 tColouri(const float* src) { Set(src); } 
74 
75 void Set(const tColouri& c) { BP = c.BP; } 
76 void Set(int r, int g, int b, int a = 255) { R = uint8(r); G = uint8(g); B = uint8(b); A = uint8(a); } 
77 void Set(const tColourf& c); 
78 void Set(const float* src) { SetR(src[0]); SetG(src[1]); SetB(src[2]); SetA(src[3]); } 
79 
80 // The floating point set methods use a range of [0.0, 1.0] for each component. 
81 void Set(float r, float g, float b, float a = 1.0f) { SetR(r); SetG(g); SetB(b); SetA(a); } 
82 void SetR(float r) { R = tMath::tClamp( tMath::tFloatToInt(r*255.0f), 0, 0xFF ); } 
83 void SetG(float g) { G = tMath::tClamp( tMath::tFloatToInt(g*255.0f), 0, 0xFF ); } 
84 void SetB(float b) { B = tMath::tClamp( tMath::tFloatToInt(b*255.0f), 0, 0xFF ); } 
85 void SetA(float a) { A = tMath::tClamp( tMath::tFloatToInt(a*255.0f), 0, 0xFF ); } 
86 
87 // The floating point get methods use a range of [0.0, 1.0] for each component. 
88 float GetR() const { return float(R) / 255.0f; } 
89 float GetG() const { return float(G) / 255.0f; } 
90 float GetB() const { return float(B) / 255.0f; } 
91 float GetA() const { return float(A) / 255.0f; } 
92 void Get(float* dest) const { dest[0] = GetR(); dest[1] = GetG(); dest[2] = GetB(); dest[3] = GetA(); } 
93 void Get(tMath::tVector3& dest) const { dest.x = GetR(); dest.y = GetG(); dest.z = GetB(); } 
94 void Get(tMath::tVector4& dest) const { dest.x = GetR(); dest.y = GetG(); dest.z = GetB(); dest.w = GetA(); } 
95 void Get(float& r, float&g, float& b, float& a) const { r = GetR(); g = GetG(); b = GetB(); a = GetA(); } 
96 
97 // These floating point get methods use a range of [0.0, 255.0] for each component. 
98 float GetDenormR() const { return float(R); } 
99 float GetDenormG() const { return float(G); } 
100 float GetDenormB() const { return float(B); } 
101 float GetDenormA() const { return float(A); } 
102 void GetDenorm(float* dest) const { dest[0] = GetDenormR(); dest[1] = GetDenormG(); dest[2] = GetDenormB(); dest[3] = GetDenormA(); } 
103 void GetDenorm(tMath::tVector3& dest) const { dest.x = GetDenormR(); dest.y = GetDenormG(); dest.z = GetDenormB(); } 
104 void GetDenorm(tMath::tVector4& dest) const { dest.x = GetDenormR(); dest.y = GetDenormG(); dest.z = GetDenormB(); dest.w = GetDenormA(); } 
105 void GetDenorm(float& r, float&g, float& b, float& a) const { r = GetDenormR(); g = GetDenormG(); b = GetDenormB(); a = GetDenormA(); } 
106 
107 void Get(tColouri& c) const { c.BP = BP; } 
108 void MakeZero() { R = 0x00; G = 0x00; B = 0x00; A = 0x00; } 
109 void MakeBlack() { R = 0x00; G = 0x00; B = 0x00; A = 0xFF; } 
110 void MakeWhite() { R = 0xFF; G = 0xFF; B = 0xFF; A = 0xFF; } 
111 void MakePink() { R = 0xFF; G = 0x80; B = 0x80; A = 0xFF; } 
112 
113 void MakeRed() { R = 0xFF; G = 0x00; B = 0x00; A = 0xFF; } 
114 void MakeGreen() { R = 0x00; G = 0xFF; B = 0x00; A = 0xFF; } 
115 void MakeBlue() { R = 0x00; G = 0x00; B = 0xFF; A = 0xFF; } 
116 
117 void MakeGrey() { R = 0x80; G = 0x80; B = 0x80; A = 0xFF; } 
118 void MakeLightGrey() { R = 0xC0; G = 0xC0; B = 0xC0; A = 0xFF; } 
119 void MakeDarkGrey() { R = 0x40; G = 0x40; B = 0x40; A = 0xFF;} 
120 
121 void MakeCyan() { R = 0x00; G = 0xFF; B = 0xFF; A = 0xFF; } 
122 void MakeMagenta() { R = 0xFF; G = 0x00; B = 0xFF; A = 0xFF; } 
123 void MakeYellow() { R = 0xFF; G = 0xFF; B = 0x00; A = 0xFF; } 
124 
125 // These querying calls ignore alpha. 
126 bool IsBlack() const { return ((R == 0x00) && (G == 0x00) && (B == 0x00)) ? true : false; } 
127 bool IsWhite() const { return ((R == 0xFF) && (G == 0xFF) && (B == 0xFF)) ? true : false; } 
128 bool IsRed() const { return ((R == 0xFF) && (G == 0x00) && (B == 0x00)) ? true : false; } 
129 bool IsGreen() const { return ((R == 0x00) && (G == 0xFF) && (B == 0x00)) ? true : false; } 
130 bool IsBlue() const { return ((R == 0x00) && (G == 0x00) && (B == 0xFF)) ? true : false; } 
131 
132 // When using the HSV representation of a tColouri, the hue is in normalized angle units. See tAngleMode::Norm256. 
133 // Since only one byte is used, we divide the circle into 256 equal parts. All 4 values will be E [0, 255]. 
134 // Consider using a tColoutf object when working in HSV space. It can more accurately represent the hue value 
135 // without as much loss in precision. See the tRGBToHSV function for retrieval of hue in different angle units. 
136 // Both of the functions below leave the alpha unchanged. 
137 void RGBToHSV(); // Assumes current values are RGB. 
138 void HSVToRGB(); // Assumes current values are HSV. 
139 
140 bool Equal(const tColouri&, uint32 channels = tMath::ColourChannel_All) const
141 bool operator==(const tColouri& c) const { return (BP == c.BP); } 
142 bool operator!=(const tColouri& c) const { return (BP != c.BP); } 
143 tColouri& operator=(const tColouri& c) { BP = c.BP; return *this; } 
144 
145 tColouri& operator*=(float f) { R = uint8(float(R)*f); G = uint8(float(G)*f); B = uint8(float(B)*f); A = uint8(float(A)*f); return *this; } 
146 const tColouri operator*(float f) const { tColouri res(*this); res *= f; return res; } 
147 tColouri& operator+=(const tColouri& c) { R += c.R; G += c.G; B += c.B; A += c.A; return *this; } 
148 const tColouri operator+(const tColouri& c) const { tColouri res(*this); res += c; return res; } 
149 
150 // Predefined colours. Initialized using the C++11 aggregate initializer syntax. These may be used before main() 
151 // in normally (non-aggregate syntax) constructed objects. 
152 const static tColouri black
153 const static tColouri white
154 const static tColouri pink
155 
156 const static tColouri red
157 const static tColouri green
158 const static tColouri blue
159 
160 const static tColouri grey
161 const static tColouri lightgrey
162 const static tColouri darkgrey
163 
164 const static tColouri cyan
165 const static tColouri magenta
166 const static tColouri yellow
167 
168 const static tColouri transparent
169 
170 union 
171
172 struct { uint8 R, G, B, A; }; 
173 struct { uint8 H, S, V, O; }; // O for opacity. Some compilers don't like a repeated A. 
174 
175 // Bit Pattern member. 
176 // Accessing the colour as a 32 bit value using the BP member means you must take the machine's endianness into 
177 // account. This explains why the member isn't named something like RGBA. For example, in memory it's always in the 
178 // RGBA no matter what endianness, but on a little endian machine you'd access the blue component with something 
179 // like (colour.BP >> 16) % 0xFF 
180 uint32 BP
181 
182 // Individual elements. Makes it easy to submit colours to OpenGL using glColor3ubv. 
183 uint8 E[4]; 
184 }; 
185}; 
186typedef tColouri tPixel
187 
188 
189// The tColourf class represents a colour in 4 floats and is made of 4 floats in the order RGBA. 
190// The values of each float component are E [0.0, 1.0]. 
191class tColourf 
192
193public
194 tColourf() { } 
195 tColourf(const tColourf& src) { Set(src); } 
196 tColourf(float r, float g, float b, float a = 1.0f) { Set(r, g, b, a); } 
197 tColourf(const tMath::tVector3& c, float a = 1.0f) { Set(c, a); } 
198 tColourf(const tMath::tVector4& ca) { Set(ca); } 
199 tColourf(const tColouri& src) { Set(src); } 
200 tColourf(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { Set(r, g, b, a); } 
201 tColourf(int r, int g, int b, int a = 255) { Set(r, g, b, a); } 
202 
203 void Unset() { R = -1.0f; G = -1.0f; B = -1.0f; A = -1.0f; } // An unset colour has value (-1.0f, -1.0f, -1.0f, -1.0f). 
204 bool IsSet() const { if ((R != -1.0f) || (G != -1.0f) || (B != -1.0f) || (A != -1.0f)) return true; return false; } // Any set component means the whole colour is considered set. 
205 void Set(const tColourf& c) { BP0 = c.BP0; BP1 = c.BP1; } 
206 void Set(float r, float g, float b, float a = 1.0f) { R = r; G = g; B = b; A = a; } 
207 void Set(const float* src) { R = src[0]; G = src[1]; B = src[2]; A = src[3]; } 
208 void Set(const tMath::tVector3& c, float a = 1.0f) { R = c.x; G = c.y; B = c.z; A = a; } 
209 void Set(const tMath::tVector4& ca) { R = ca.x; G = ca.y; B = ca.z; A = ca.w; } 
210 void Set(const tColouri& c) { Set(float(c.R)/255.0f, float(c.G)/255.0f, float(c.B)/255.0f, float(c.A)/255.0f); } 
211 void Set(int r, int g, int b, int a = 255) { Set(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, float(a)/255.0f); } 
212 void SetR(int r) { R = float(r)/255.0f; } 
213 void SetG(int g) { G = float(g)/255.0f; } 
214 void SetB(int b) { B = float(b)/255.0f; } 
215 void SetA(int a) { A = float(a)/255.0f; } 
216 
217 // The integer get and set methods use a range of [0, 255] for each component. 
218 int GetR() const { return tMath::tFloatToInt(R * 255.0f); } 
219 int GetG() const { return tMath::tFloatToInt(G * 255.0f); } 
220 int GetB() const { return tMath::tFloatToInt(B * 255.0f); } 
221 int GetA() const { return tMath::tFloatToInt(A * 255.0f); } 
222 void Get(int* dest) const { dest[0] = GetR(); dest[1] = GetG(); dest[2] = GetB(); dest[3] = GetA(); } 
223 void Get(tMath::tVector3& dest) const { dest.x = R; dest.y = G; dest.z = B; } 
224 void Get(tMath::tVector4& dest) const { dest.x = R; dest.y = G; dest.z = B; dest.w = A; } 
225 void Get(float& r, float&g, float& b, float& a) const { r = R; g = G; b = B; a = A; } 
226 void Get(tColourf& c) const { c.BP0 = BP0; c.BP1 = BP1;} 
227 void Saturate() { tMath::tiSaturate(R); tMath::tiSaturate(G); tMath::tiSaturate(B); tMath::tiSaturate(A); } 
228 
229 void MakeBlack() { R = 0.0f; G = 0.0f; B = 0.0f; A = 1.0f; } 
230 void MakeWhite() { R = 1.0f; G = 1.0f; B = 1.0f; A = 1.0f; } 
231 void MakePink() { R = 1.0f; G = 0.5f; B = 0.5f; A = 1.0f; } 
232 
233 void MakeRed() { R = 1.0f; G = 0.0f; B = 0.0f; A = 1.0f; } 
234 void MakeGreen() { R = 0.0f; G = 1.0f; B = 0.0f; A = 1.0f; } 
235 void MakeBlue() { R = 0.0f; G = 0.0f; B = 1.0f; A = 1.0f; } 
236 
237 void MakeGrey() { R = 0.5f; G = 0.5f; B = 0.5f; A = 1.0f; } 
238 void MakeLightGrey() { R = 0.75f; G = 0.75f; B = 0.75f; A = 1.0f; } 
239 void MakeDarkGrey() { R = 0.25f; G = 0.25f; B = 0.25f; A = 1.0f;} 
240 
241 void MakeCyan() { R = 0.0f; G = 1.0f; B = 1.0f; A = 1.0f; } 
242 void MakeMagenta() { R = 1.0f; G = 0.0f; B = 1.0f; A = 1.0f; } 
243 void MakeYellow() { R = 1.0f; G = 1.0f; B = 0.0f; A = 1.0f; } 
244 
245 // These querying calls ignore alpha. 
246 bool IsBlack() const { return ((R == 0.0f) && (G == 0.0f) && (B == 0.0f)) ? true : false; } 
247 bool IsWhite() const { return ((R == 1.0f) && (G == 1.0f) && (B == 1.0f)) ? true : false; } 
248 bool IsRed() const { return ((R == 1.0f) && (G == 0.0f) && (B == 0.0f)) ? true : false; } 
249 bool IsGreen() const { return ((R == 0.0f) && (G == 1.0f) && (B == 0.0f)) ? true : false; } 
250 bool IsBlue() const { return ((R == 0.0f) && (G == 0.0f) && (B == 1.0f)) ? true : false; } 
251 
252 // Colours in textures in files may be in Gamma space and ought to be converted to linear space before 
253 // lighting calculations are made. They should then be converted back to Gamma space before being displayed. 
254 // Gamma-space here should really be sRGB but we're just using an approximation by squaring (gamma=2) when the 
255 // average sRGB gamma should be 2.2. To do the conversion properly, the gamma varies with intensity from 1 to 2.4, 
256 // but, again, we're only approximating here. 
257 void ToLinearSpaceApprox() { R *= R; G *= G; B *= B; } 
258 void ToGammaSpaceApprox() { R = tMath::tSqrt(R); G = tMath::tSqrt(G); B = tMath::tSqrt(B); } 
259 
260 // When using the HSV representation of a tColourf, the hue is in NormOne angle mode. See the tRGBToHSV and 
261 // tHSVToRGB functions if you wish to use different angle units. All the components (h, s, v, r, g, b, a) are in 
262 // [0.0, 1.0]. Both of the functions below leave the alpha unchanged. 
263 void RGBToHSV(); // Assumes current values are RGB. 
264 void HSVToRGB(); // Assumes current values are HSV. 
265 
266 bool operator==(const tColourf& c) const { return ((BP0 == c.BP0) && (BP1 == c.BP1)); } 
267 bool operator!=(const tColourf& c) const { return ((BP0 != c.BP0) || (BP1 != c.BP1)); } 
268 tColourf& operator=(const tColourf& c) { BP0 = c.BP0; BP1 = c.BP1; return *this; } 
269 tColourf& operator*=(float f) { R *= f; G *= f; B *= f; A *= f; return *this; } 
270 const tColourf operator*(float f) const { tColourf res(*this); res *= f; return res; } 
271 tColourf& operator+=(const tColourf& c) { R += c.R; G += c.G; B += c.B; A += c.A; return *this; } 
272 const tColourf operator+(const tColourf& c) const { tColourf res(*this); res += c; return res; } 
273 
274 // Predefined colours. 
275 const static tColourf invalid
276 const static tColourf black
277 const static tColourf white
278 const static tColourf hotpink
279 
280 const static tColourf red
281 const static tColourf green
282 const static tColourf blue
283 
284 const static tColourf grey
285 const static tColourf lightgrey
286 const static tColourf darkgrey
287 
288 const static tColourf cyan
289 const static tColourf magenta
290 const static tColourf yellow
291 
292 const static tColourf transparent
293 
294 union 
295
296 struct { float R, G, B, A; }; 
297 struct { float H, S, V, O; }; 
298 struct { uint64 BP0, BP1; }; // Bit Pattern. 
299 float E[4]; 
300 }; 
301}; 
302typedef tColourf tColour
303 
304 
305// The tColour3f class represents a colour in 3 floats and is made of 3 floats in the order RGB. 
306// The values of each float component are E [0.0, 1.0]. 
307class tColour3f 
308
309public
310 tColour3f() { } 
311 tColour3f(const tColour3f& src) { Set(src); } 
312 tColour3f(float r, float g, float b) { Set(r, g, b); } 
313 tColour3f(const tMath::tVector3& c) { Set(c); } 
314 tColour3f(const tMath::tVector4& c) { Set(c); } 
315 tColour3f(const tColouri& src) { Set(src); } 
316 tColour3f(uint8 r, uint8 g, uint8 b) { Set(r, g, b); } 
317 tColour3f(int r, int g, int b) { Set(r, g, b); } 
318 
319 void Unset() { R = -1.0f; G = -1.0f; B = -1.0f; } // An unset colour has value (-1.0f, -1.0f, -1.0f). 
320 bool IsSet() const { return ((R != -1.0f) || (G != -1.0f) || (B != -1.0f)); } // Any set component means the whole colour is considered set. 
321 void Set(const tColour3f& c) { R = c.R; G = c.G; B = c.B; } 
322 void Set(float r, float g, float b) { R = r; G = g; B = b; } 
323 void Set(const float* src) { R = src[0]; G = src[1]; B = src[2]; } 
324 void Set(const tMath::tVector3& c) { R = c.x; G = c.y; B = c.z; } 
325 void Set(const tMath::tVector4& c) { R = c.x; G = c.y; B = c.z; } 
326 void Set(const tColouri& c) { Set(float(c.R)/255.0f, float(c.G)/255.0f, float(c.B)/255.0f); } 
327 void Set(int r, int g, int b) { Set(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f); } 
328 void SetR(int r) { R = float(r)/255.0f; } 
329 void SetG(int g) { G = float(g)/255.0f; } 
330 void SetB(int b) { B = float(b)/255.0f; } 
331 
332 // The integer get and set methods use a range of [0, 255] for each component. 
333 int GetR() const { return tMath::tFloatToInt(R * 255.0f); } 
334 int GetG() const { return tMath::tFloatToInt(G * 255.0f); } 
335 int GetB() const { return tMath::tFloatToInt(B * 255.0f); } 
336 void Get(int* dest) const { dest[0] = GetR(); dest[1] = GetG(); dest[2] = GetB(); } 
337 void Get(tMath::tVector3& dest) const { dest.x = R; dest.y = G; dest.z = B; } 
338 void Get(tMath::tVector4& dest) const { dest.x = R; dest.y = G; dest.z = B; dest.w = 1.0f; } 
339 void Get(float& r, float&g, float& b) const { r = R; g = G; b = B; } 
340 void Get(tColour3f& c) const { c.R = R; c.G = G; c.B = B; } 
341 
342 void MakeBlack() { R = 0.0f; G = 0.0f; B = 0.0f; } 
343 void MakeWhite() { R = 1.0f; G = 1.0f; B = 1.0f; } 
344 void MakePink() { R = 1.0f; G = 0.5f; B = 0.5f; } 
345 
346 void MakeRed() { R = 1.0f; G = 0.0f; B = 0.0f; } 
347 void MakeGreen() { R = 0.0f; G = 1.0f; B = 0.0f; } 
348 void MakeBlue() { R = 0.0f; G = 0.0f; B = 1.0f; } 
349 
350 void MakeGrey() { R = 0.5f; G = 0.5f; B = 0.5f; } 
351 void MakeLightGrey() { R = 0.75f; G = 0.75f; B = 0.75f; } 
352 void MakeDarkGrey() { R = 0.25f; G = 0.25f; B = 0.25f; } 
353 
354 void MakeCyan() { R = 0.0f; G = 1.0f; B = 1.0f; } 
355 void MakeMagenta() { R = 1.0f; G = 0.0f; B = 1.0f; } 
356 void MakeYellow() { R = 1.0f; G = 1.0f; B = 0.0f; } 
357 
358 // These querying calls ignore alpha. 
359 bool IsBlack() const { return ((R == 0.0f) && (G == 0.0f) && (B == 0.0f)); } 
360 bool IsWhite() const { return ((R == 1.0f) && (G == 1.0f) && (B == 1.0f)); } 
361 bool IsRed() const { return ((R == 1.0f) && (G == 0.0f) && (B == 0.0f)); } 
362 bool IsGreen() const { return ((R == 0.0f) && (G == 1.0f) && (B == 0.0f)); } 
363 bool IsBlue() const { return ((R == 0.0f) && (G == 0.0f) && (B == 1.0f)); } 
364 
365 // Colours in textures in files may be in Gamma space and ought to be converted to linear space before 
366 // lighting calculations are made. They should then be converted back to Gamma space before being displayed. 
367 // Gamma-space here should really be sRGB but we're just using an approximation by squaring (gamma=2) when the 
368 // average sRGB gamma should be 2.2. To do the conversion properly, the gamma varies with intensity from 1 to 2.4, 
369 // but, again, we're only approximating here. 
370 void ToLinearSpaceApprox() { R *= R; G *= G; B *= B; } 
371 void ToGammaSpaceApprox() { R = tMath::tSqrt(R); G = tMath::tSqrt(G); B = tMath::tSqrt(B); } 
372 
373 // When using the HSV representation of a tColourf, the hue is in NormOne angle mode. See the tRGBToHSV and 
374 // tHSVToRGB functions if you wish to use different angle units. All the components (h, s, v, r, g, b, a) are in 
375 // [0.0, 1.0]. Both of the functions below leave the alpha unchanged. 
376 void RGBToHSV(); // Assumes current values are RGB. 
377 void HSVToRGB(); // Assumes current values are HSV. 
378 
379 bool operator==(const tColourf& c) const { return ((R == c.R) && (G == c.G) && (B == c.B)); } 
380 bool operator!=(const tColourf& c) const { return ((R != c.R) || (G != c.G) || (B != c.B)); } 
381 tColour3f& operator=(const tColour3f& c) { R = c.R; G = c.G; B = c.B; return *this; } 
382 
383 // Predefined colours. 
384 const static tColour3f invalid
385 const static tColour3f black
386 const static tColour3f white
387 const static tColour3f hotpink
388 
389 const static tColour3f red
390 const static tColour3f green
391 const static tColour3f blue
392 
393 const static tColour3f grey
394 const static tColour3f lightgrey
395 const static tColour3f darkgrey
396 
397 const static tColour3f cyan
398 const static tColour3f magenta
399 const static tColour3f yellow
400 
401 union 
402
403 struct { float R, G, B; }; 
404 struct { float H, S, V; }; 
405 float E[3]; 
406 }; 
407}; 
408typedef tColour3f tColour3
409 
410 
411// Implementation below this line. 
412 
413 
414inline void tColouri::Set(const tColourf& c
415
416 Set(c.R, c.G, c.B, c.A); 
417
418 
419 
420inline void tColouri::RGBToHSV() 
421
422 int r = R
423 int g = G
424 int b = B
425 int h, s, v
426 tRGBToHSV(h, s, v, r, g, b, tMath::tAngleMode::Norm256); 
427 H = h
428 S = s
429 V = v
430
431 
432 
433inline void tColouri::HSVToRGB() 
434
435 int h = H
436 int s = S
437 int v = V
438 int r, g, b
439 tHSVToRGB(r, g, b, h, s, v, tMath::tAngleMode::Norm256); 
440 R = r
441 G = g
442 B = b
443
444 
445 
446inline bool tColouri::Equal(const tColouri& colour, uint32 channels) const 
447
448 if ((channels & tMath::ColourChannel_R) && (R != colour.R)) 
449 return false
450 
451 if ((channels & tMath::ColourChannel_G) && (R != colour.G)) 
452 return false
453 
454 if ((channels & tMath::ColourChannel_B) && (R != colour.B)) 
455 return false
456 
457 if ((channels & tMath::ColourChannel_A) && (R != colour.A)) 
458 return false
459 
460 return true
461
462 
463 
464inline void tColourf::RGBToHSV() 
465
466 float r = R
467 float g = G
468 float b = B
469 tRGBToHSV(H, S, V, r, g, b, tMath::tAngleMode::NormOne); 
470
471 
472 
473inline void tColourf::HSVToRGB() 
474
475 float h = H
476 float s = S
477 float v = V
478 tHSVToRGB(R, G, B, h, s, v, tMath::tAngleMode::NormOne); 
479
480 
481 
482inline float tMath::tColourDiffEuclideanSq(const tColouri& aa, const tColouri& bb
483
484 tVector3 a; aa.GetDenorm(a); 
485 tVector3 b; bb.GetDenorm(b); 
486 return tDistBetweenSq(a, b); 
487
488 
489 
490inline float tMath::tColourDiffEuclidean(const tColouri& aa, const tColouri& bb
491
492 tVector3 a; aa.GetDenorm(a); 
493 tVector3 b; bb.GetDenorm(b); 
494 return tDistBetween(a, b); 
495
496