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