1 /*--License:
2 	Kyra Sprite Engine
3 	Copyright Lee Thomason (Grinning Lizard Software) 2001-2005
4 	www.grinninglizard.com/kyra
5 	www.sourceforge.net/projects/kyra
6 
7 	Kyra is provided under the LGPL.
8 
9 	I kindly request you display a splash screen (provided in the HTML documentation)
10 	to promote Kyra and acknowledge the software and everyone who has contributed to it,
11 	but it is not required by the license.
12 
13 --- LGPL License --
14 
15     This library is free software; you can redistribute it and/or
16     modify it under the terms of the GNU Lesser General Public
17     License as published by the Free Software Foundation; either
18     version 2.1 of the License, or (at your option) any later version.
19 
20     This library is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23     Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public
26     License along with this library; if not, write to the Free Software
27     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 
29 	The full text of the license can be found in lgpl.txt
30 */
31 
32 
33 #ifndef COLOR_INCLUDED
34 #define COLOR_INCLUDED
35 
36 #include "SDL.h"
37 #include "../../grinliz/gltypes.h"
38 
39 // This is a guess, on what the byte ordering for 32 bit should be:
40 #if !defined( SDL_BYTEORDER )
41 	#error Need byte order!
42 #endif
43 
44 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
45 	#define KYRA_FLIP_COLORS
46 #endif
47 
48 /** The basic color and pixel structure. This may be the greatest
49 	number of interpretations of the least amount of data.
50 
51 	Color is one byte each of red, green, blue, and alpha. Sometimes
52 	its useful to think of these as bytes (the components), sometimes
53 	as an array, and sometimes as one 32 bit value. This is
54 	accomplisted, of course, with a union.
55 
56 	Nothing is guarenteed about the order of
57 	red, green, blue, and alpha, and #ifdefs may be used
58 	to change this on various systems.
59 
60 	In order to access the color that you want via 'array',
61 	an enumeration is defined.
62 
63 	Addtionally, assuming no system will ever
64 	have the alpha in between the other
65 	colors, you can iterate through 'array'
66 	from START to < END to
67 	get all the colors without alpha.
68 
69 	@note
70 	There is no constructor -- it is oppressive
71 	in debug mode to have the constructor getting called on
72 	huge blocks of memory. Use 'Set' for an initializer.
73 
74 	@note
75 	A constructor will screw up memory pool allocation
76 	in KrRleSegment.
77 */
78 union KrRGBA
79 {
80 	enum
81 	{
82 		KR_TRANSPARENT = 0,
83 		KR_OPAQUE      = 255,
84 	};
85 
86 
87 	enum {
88 
89 // It will work regardless of the endian, or whether the colors
90 // are aligned. But it is much faster if the colors are aligned.
91 #ifndef KYRA_FLIP_COLORS
92 		RED,
93 		GREEN,
94 		BLUE,
95 #else
96 		BLUE,
97 		GREEN,
98 		RED,
99 #endif
100 		ALPHA,
101 
102 		START = 0,
103 		END = 3			// r, g, b...alpha not in this.
104 	};
105 
106 	struct
107 	{
108 #ifndef KYRA_FLIP_COLORS
109 		U8 red;			///< Red component.
110 		U8 green;		///< Green component.
111 		U8 blue;		///< Blue component.
112 #else
113 		U8 blue;
114 		U8 green;
115 		U8 red;
116 #endif
117 		U8 alpha;		///< Alpha component.
118 	} c;
119 
120 	U8		array[4];
121 	U32		all;
122 
123 	/// Color accessor, for OpenGL
Redf()124 	float Redf()	const { return float( c.red )   / 255.0f; }
Greenf()125 	float Greenf()	const { return float( c.green ) / 255.0f; }
Bluef()126 	float Bluef()	const { return float( c.blue )  / 255.0f; }
Alphaf()127 	float Alphaf()	const { return float( c.alpha ) / 255.0f; }
128 
129 	/// Set all the members at once - a convenience method.
130 	void Set( U8 _red, U8 _green, U8 _blue, U8 _alpha = 255 )
131 			{	c.red = _red;
132 				c.green = _green;
133 				c.blue = _blue;
134 				c.alpha = _alpha;
135 			}
136 
137 	bool operator==( KrRGBA rhs )	{ return ( all == rhs.all ); }
138 	bool operator!=( KrRGBA rhs )	{ return ( all != rhs.all ); }
139 
140 	/** Reads a color in the #rrggbbaa or #rrggbb format.
141 		Used for parsing the XML files.
142 	*/
143 	void FromString( const char* str );
144 };
145 
146 
147 
148 /** A class that defines a color transformation. Unlike vectors
149 	and rectangles, it has many invalid states and is better ecapselated.
150 	It does have a constructor, and it's private data can not be
151 	directly accessed.
152 
153 		c' = m * c / 255  +  b / 255
154 
155 	where:
156 		- c is the original color component, either
157 		  the red, green, blue, or alpha component.
158 		- c' is the transformed color component.
159 
160 	c will always be in the range of 0-255. m and b must be
161 	specified so that c' will always be in the range of
162 	0-255 as well. In other words, this is an unbounded transform.
163 	If colors out of range occur, strange things will happen.
164 
165 	Using the "Friendly API" this will never be a problem: values
166 	will be kept in range for you. When using Set* directly, however,
167 	be cautious.
168 */
169 class KrColorTransform
170 {
171   public:
KrColorTransform()172 	KrColorTransform()	: 	identity( true ),
173 					  		hasAlpha( false ),
174 							hasColor( false )
175 						{
176 							m.Set( 255, 255, 255, 0 );
177 							b.Set( 0, 0, 0, 255 );
178 						}
179 	// --------- Friendly API ---------- //
180 	/// Clear all color transformations.
SetIdentity()181 	void SetIdentity()					{ m.Set( 255, 255, 255, 0 );
182 										  b.Set( 0, 0, 0, 255 );
183 										}
SetAlpha(U8 a)184 	void SetAlpha( U8 a )				{ b.c.alpha = a; CalcState(); }		///< Set the alpha. 0 is transparent and 255 is opaque.
185 
TintRed(U8 tint)186  	void TintRed( U8 tint )				{ SetRed( 255 - tint, tint ); }		///< Tint but leave the other channels unchanged.
TintGreen(U8 tint)187  	void TintGreen( U8 tint )			{ SetGreen( 255 - tint, tint ); }	///< Tint but leave the other channels unchanged.
TintBlue(U8 tint)188  	void TintBlue( U8 tint )			{ SetBlue( 255 - tint, tint ); }	///< Tint but leave the other channels unchanged.
TintAlpha(U8 tint)189 	void TintAlpha( U8 tint )			{ SetAlpha( 255 - tint ); }			///< Only sets alpha, but in inverse: 0 is opaque.
190 
191 	/// Approximate brightening -- not symmetric with darken. val==0 is no change.
Brighten(U8 val)192 	void Brighten( U8 val )			{ m.c.red   = 255-val; b.c.red   = val;
193 									  m.c.green = 255-val; b.c.green = val;
194 									  m.c.blue  = 255-val; b.c.blue  = val;
195 									  CalcState();
196 									}
197 
198 	/// Approximate darkening -- not symmetric with brighten. val==0 is no change.
Darken(U8 val)199 	void Darken( U8 val  )			{ m.c.red   = 255-val; b.c.red = 0;
200 									  m.c.green = 255-val; b.c.green = 0;
201 									  m.c.blue  = 255-val; b.c.blue = 0;
202 									  CalcState();
203 									}
204 
205 	// --------- Advanced API ------- //
206 	/**	Arbitrary set of the components. Gives
207 	    lots of control over the color
208 		transformation. The color is transformed
209 		by the equation:
210 
211 			c' = m * c / 255  +  b / 255
212 
213 		where:
214 			- c is the original color component, either
215 			  the red, green, blue, or alpha component.
216 			- c' is the transformed color component.
217 
218 		c will always be in the range of 0-255. m and b must be
219 		specified so that c' will always be in the range of
220 		0-255 as well. In other words, this is an unbounded transform.
221 		If colors out of range occur, strange things will happen.
222 
223 		The "friendly api", above, will always guarentee color
224 		transformations are correctly bounded.
225 	*/
226 	void Set( U8 mRed, U8 bRed, U8 mGreen, U8 bGreen, U8 mBlue, U8 bBlue, U8 alpha );
227 
228 	/// Arbitrary red set (other channel will not be affected.)
SetRed(U8 _m,U8 _b)229 	void SetRed( U8 _m, U8 _b )		{	m.c.red = _m; b.c.red = _b; CalcState(); }
230 	/// Arbitrary green set (other channel will not be affected.)
SetGreen(U8 _m,U8 _b)231 	void SetGreen( U8 _m, U8 _b )	{	m.c.green = _m; b.c.green = _b; CalcState(); }
232 	/// Arbitrary blue set (other channel will not be affected.)
SetBlue(U8 _m,U8 _b)233 	void SetBlue( U8 _m, U8 _b )	{	m.c.blue = _m; b.c.blue = _b; CalcState(); }
234 
IsIdentity()235 	bool IsIdentity() const	{ return identity; }
HasAlpha()236 	bool HasAlpha()	const	{ return hasAlpha; }
HasColor()237 	bool HasColor() const	{ return hasColor; }
238 
Alpha()239 	U8   Alpha() const		{ return b.c.alpha; }
240 
241 	// Apply 'color' to this transformation. Composite assumes 'color' PRE transforms this.
242 	void Composite( const KrColorTransform& color );
243 
244 	// Note this transforms color but not alpha
TransformRed(U8 red)245 	inline U8 TransformRed( U8 red ) const		{ return (( red*m.c.red ) >> 8 ) + b.c.red; }
246 	// Note this transforms color but not alpha
TransformGreen(U8 green)247 	inline U8 TransformGreen( U8 green ) const	{ return (( green*m.c.green ) >> 8 ) + b.c.green; }
248 	// Note this transforms color but not alpha
TransformBlue(U8 blue)249 	inline U8 TransformBlue( U8 blue ) const	{ return (( blue*m.c.blue ) >> 8 ) + b.c.blue; }
250 
251 	// Transform the color (all channels) no alpha is used.
252 	void ApplyTransform( KrRGBA* ) const;
253 
254 	bool operator==( const KrColorTransform& rhs ) const	{ return  ( m.all == rhs.m.all && b.all == rhs.b.all ); }
255 	bool operator!=( const KrColorTransform& rhs ) const	{ return !( m.all == rhs.m.all && b.all == rhs.b.all ); }
256 
257   private:
258 	void CalcState();
259 
260 	bool identity;		// no color transform?
261 	bool hasAlpha;		// alpha transform?
262 	bool hasColor;		// rgb transform?
263 
264   public:
265 	// These are public so the blit macros can get to them without
266 	// showing up when the code is profiled. DO NOT change these
267 	// directly -- use the API above.
268 
269 	// For consistency with loops and types, we use RGBAs here as
270 	// well. Note this results in an extra alpha: alpha is an
271 	// absolute, not slope/intercept like the other components.
272 	// (At least in Kyra...)
273 	// So: m.c.alpha must always be 0.
274 	//     b.c.alpha is the alpha channel used.
275 
276 	KrRGBA	m,	// multiplication of color (255 == 1.0)
277 			b;	// addtion of color (0 == no color change)
278 };
279 
280 
281 
282 #endif
283