// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RGBA_H #define NL_RGBA_H #include #include "types_nl.h" #include "common.h" namespace NLMISC { class IStream; /** * Class pixel RGBA * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CRGBA { public: /// Default constructor. do nothing CRGBA() {} /** * Constructor. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ CRGBA(uint8 r, uint8 g, uint8 b, uint8 a=255) : R(r), G(g), B(b), A(a) {} /** * setup as a packed pixel */ void setPacked(uint packed) { R= (packed>>24)&255; G= (packed>>16)&255; B= (packed>>8)&255; A= packed & 255; } /** * Return a packed pixel */ uint getPacked() const {return ((uint)R<<24) + ((uint)G<<16) + ((uint)B<<8) + A;} /** * Comparison operator. */ bool operator<(CRGBA c) const {return getPacked()>8); G = uint8((c0.G*a2 + c1.G*a1) >>8); B = uint8((c0.B*a2 + c1.B*a1) >>8); A = uint8((c0.A*a2 + c1.A*a1) >>8); } /** * Modulate colors with a constant. * \param c0 Color 0. * \param a E [0,256]. c0*a returned into this. */ void modulateFromui (CRGBA c0, uint a) { R = uint8((c0.R*a) >>8); G = uint8((c0.G*a) >>8); B = uint8((c0.B*a) >>8); A = uint8((c0.A*a) >>8); } /** * Modulate colors with another color. * \param c0 Color 0. * \param c1 Color 1. c0*c1 returned into this. */ void modulateFromColor (CRGBA c0, CRGBA c1) { R = (c0.R*c1.R) >>8; G = (c0.G*c1.G) >>8; B = (c0.B*c1.B) >>8; A = (c0.A*c1.A) >>8; } /** * Set colors. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ void set (uint8 r, uint8 g, uint8 b, uint8 a=255); /** * Convert to gray value */ uint8 toGray() const; /** * Get a 16 bits 565 pixel. */ uint16 get565 () const { return ((uint16)(R&0xf8)<<8) | ((uint16)(G&0xfc)<<3) | (uint16)(B>>3); } /** * Set the RGB fields with a 16 bits 565 pixel. */ void set565(uint16 col) { // unpack. R= col>>11; G= (col>>5)&0x3F; B= (col)&0x1F; // to 8 bits. R= (R<<3) + (R>>2); G= (G<<2) + (G>>4); B= (B<<3) + (B>>2); } /** * Compute in this the average of 2 RGBA. */ void avg2(CRGBA a, CRGBA b) { R= ((uint)a.R+(uint)b.R)>>1; G= ((uint)a.G+(uint)b.G)>>1; B= ((uint)a.B+(uint)b.B)>>1; A= ((uint)a.A+(uint)b.A)>>1; } /** * Compute in this the average of 4 RGBA. * The average is "correct": +1 is added to the four color, to make a "round" like average. */ void avg4(CRGBA a, CRGBA b, CRGBA c, CRGBA d) { R= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2; G= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2; B= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2; A= ((uint)a.A+(uint)b.A+(uint)c.A+(uint)d.A+ 1)>>2; } /** * Do the sum of 2 rgba, clamp, and store in this */ void add(CRGBA c0, CRGBA c1) { uint r,g,b,a; r= c0.R + c1.R; r= std::min(r, 255U); R= (uint8)r; g= c0.G + c1.G; g= std::min(g, 255U); G= (uint8)g; b= c0.B + c1.B; b= std::min(b, 255U); B= (uint8)b; a= c0.A + c1.A; a= std::min(a, 255U); A= (uint8)a; } /** * Compute c0 - c1, and store in this */ void sub(CRGBA c0, CRGBA c1) { sint r,g,b,a; r= c0.R - c1.R; r= std::max(r, 0); R= (uint8)r; g= c0.G - c1.G; g= std::max(g, 0); G= (uint8)g; b= c0.B - c1.B; b= std::max(b, 0); B= (uint8)b; a= c0.A - c1.A; a= std::max(a, 0); A= (uint8)a; } /// \name RGBOnly methods. Same f() as their homonym, but don't modify A component. // @{ /// see blendFromui() void blendFromuiRGBOnly(CRGBA c0, CRGBA c1, uint coef) // coef must be in [0,256] { uint a1 = coef; uint a2 = 256-a1; R = uint8((c0.R*a2 + c1.R*a1) >>8); G = uint8((c0.G*a2 + c1.G*a1) >>8); B = uint8((c0.B*a2 + c1.B*a1) >>8); } /// see modulateFromui() void modulateFromuiRGBOnly(CRGBA c0, uint a) { R = uint8((c0.R*a) >>8); G = uint8((c0.G*a) >>8); B = uint8((c0.B*a) >>8); } /// see modulateFromColor() void modulateFromColorRGBOnly(CRGBA c0, CRGBA c1) { R = (c0.R*c1.R) >>8; G = (c0.G*c1.G) >>8; B = (c0.B*c1.B) >>8; } /// see avg2() void avg2RGBOnly(CRGBA a, CRGBA b) { R= ((uint)a.R+(uint)b.R)>>1; G= ((uint)a.G+(uint)b.G)>>1; B= ((uint)a.B+(uint)b.B)>>1; } /// see avg4() void avg4RGBOnly(CRGBA a, CRGBA b, CRGBA c, CRGBA d) { R= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2; G= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2; B= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2; } /// see add() void addRGBOnly(CRGBA c0, CRGBA c1) { uint r,g,b; r= c0.R + c1.R; r= std::min(r, 255U); R= (uint8)r; g= c0.G + c1.G; g= std::min(g, 255U); G= (uint8)g; b= c0.B + c1.B; b= std::min(b, 255U); B= (uint8)b; } /// see sub() void subRGBOnly(CRGBA c0, CRGBA c1) { sint r,g,b; r= c0.R - c1.R; r= std::max(r, 0); R= (uint8)r; g= c0.G - c1.G; g= std::max(g, 0); G= (uint8)g; b= c0.B - c1.B; b= std::max(b, 0); B= (uint8)b; } // @} ///\name Color group manipulation //@{ /** Add a group of colors with saturation, using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each source color. * \param Stride between each destination color. * \param Dup the number of time the result must be duplicated in the destination. */ static void addColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); /** Modulate a group of colors with saturation, using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each color. It is the same for sources and destination. */ static void modulateColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); /** Subtract a group of colors with saturation (src1 - src2), using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each color. It is the same for sources and destination. */ static void subtractColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); //@} /// \name Color space conversions RGB only //@{ /** Convert to HLS color space. * Lightness and satuation ranges from 0 to 1 * There's no range for hue, (all hues colors range from 0 to 360, from 360 to 720 and so on) * \return true if the color is achromatic */ bool convertToHLS(float &h, float &l, float &S) const; /** Build from HLS valued * Each component ranges from 0 to 1.f */ void buildFromHLS(float h, float l, float s); //@} static CRGBA stringToRGBA( const char *ptr ); /// Swap the B and R components, to simulate a CBRGA void swapBR() { std::swap(R,B); } /// Red componant. uint8 R; /// Green componant. uint8 G; /// Blue componant. uint8 B; /// Alpha componant. uint8 A; /// some colors static const CRGBA Black ; static const CRGBA Red ; static const CRGBA Green ; static const CRGBA Yellow ; static const CRGBA Blue ; static const CRGBA Magenta ; static const CRGBA Cyan ; static const CRGBA White ; }; /** * Class pixel BGRA, Windows style pixel. * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CBGRA { public: /// Default constructor. do nothing CBGRA() {} /** * Constructor from a CRGBA * \param c CRGBA color. */ CBGRA(CRGBA c) { R=c.R; G=c.G; B=c.B; A=c.A; }; /** * Constructor. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ CBGRA(uint8 r, uint8 g, uint8 b, uint8 a=255) : B(b), G(g), R(r), A(a) {} /** * Cast operator to CRGBA. */ operator CRGBA() { return CRGBA (R, G, B, A); } /** * Return a packed pixel */ uint getPacked() const { return ((uint)B<<24) + ((uint)G<<16) + ((uint)R<<8) + A; } /** * Comparison operator. */ bool operator<(const CBGRA &c) const { return getPacked() inline CRGBA blend(CRGBA c0, CRGBA c1, U blendFactor) { CRGBA result; result.blendFromui(c0, c1, (uint) ((float) blendFactor * 256.f)); return result; } /** * Class pixel float RGBA * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CRGBAF { public: /// Default constructor. do nothing CRGBAF () {} /** * Constructor. * \param _r Red componant. * \param _g Green componant. * \param _b Blue componant. * \param _a Alpha componant. */ CRGBAF (float _r, float _g, float _b, float _a=1.f) { R=_r; G=_g; B=_b; A=_a; } /** * Constructor with a CRGBA. * \param c CRGBA color. */ CRGBAF (CRGBA c) { R=(float)c.R/255.f; G=(float)c.G/255.f; B=(float)c.B/255.f; A=(float)c.A/255.f; } /** * Cast operator to CRGBA. */ operator CRGBA() const { uint8 _r=(uint8)(R*255.f); uint8 _g=(uint8)(G*255.f); uint8 _b=(uint8)(B*255.f); uint8 _a=(uint8)(A*255.f); return CRGBA (_r, _g, _b, _a); } /** * Normalize component between [0.f,1.f] */ void normalize () { R= (R>1.f) ? 1.f : (R<0.f) ? 0.f : R; G= (G>1.f) ? 1.f : (G<0.f) ? 0.f : G; B= (B>1.f) ? 1.f : (B<0.f) ? 0.f : B; A= (A>1.f) ? 1.f : (A<0.f) ? 0.f : A; } /** * Add operator. Sum components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator+ (const CRGBAF& c) const { return CRGBAF (R+c.R, G+c.G, B+c.B, A+c.A); } /** * Sub operator. Substract components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator- (const CRGBAF& c) const { return CRGBAF (R-c.R, G-c.G, B-c.B, A-c.A); } /** * Mul operator. Mul components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator* (const CRGBAF& c) const { return CRGBAF (R*c.R, G*c.G, B*c.B, A*c.A); } /** * Mul float operator. Mul each component by f. * \param f Float factor. * \return Return the result of the opertor */ CRGBAF operator* (float f) const { return CRGBAF (R*f, G*f, B*f, A*f); } /** * Div float operator. Div each component by f. * \param f Float factor. * \return Return the result of the opertor */ CRGBAF operator/ (float f) const { return CRGBAF (R/f, G/f, B/f, A/f); } /** * Add operator. Add each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator+= (const CRGBAF& c) { R+=c.R; G+=c.G; B+=c.B; A+=c.A; return *this; } /** * Sub operator. Substract each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator-= (const CRGBAF& c) { R-=c.R; G-=c.G; B-=c.B; A-=c.A; return *this; } /** * Mul operator. Multiplate each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator*= (const CRGBAF& c) { R*=c.R; G*=c.G; B*=c.B; A*=c.A; return *this; } /** * Mul float operator. Multiplate each component by f. * \param f Float factor. * \return Return a reference on the caller object */ CRGBAF& operator*= (float f) { R*=f; G*=f; B*=f; A*=f; return *this; } /** * Div float operator. Divide each component by f. * \param f Float factor. * \return Return a reference on the caller object */ CRGBAF& operator/= (float f) { R/=f; G/=f; B/=f; A/=f; return *this; } /** * Serialisation. * \param f Stream used for serialisation. */ void serial(class NLMISC::IStream &f); /** * Set colors. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ void set(float r, float g, float b, float a); /// Red componant. float R; /// Green componant. float G; /// Blue componant. float B; /// Alpha componant. float A; }; /** * Mul float operator. Multiplate each component by f. * \param f Float factor. * \return Return the result */ inline CRGBAF operator* (float f, const CRGBAF& c) { return CRGBAF (c.R*f, c.G*f, c.B*f, c.A*f); } #ifdef NL_LITTLE_ENDIAN #define NL_RGBA_R_DWORD_MASK (0x000000ff) #define NL_RGBA_G_DWORD_MASK (0x0000ff00) #define NL_RGBA_B_DWORD_MASK (0x00ff0000) #define NL_RGBA_A_DWORD_MASK (0xff000000) #else // NL_LITTLE_ENDIAN #define NL_RGBA_R_DWORD_MASK (0xff0000) #define NL_RGBA_G_DWORD_MASK (0x00ff0000) #define NL_RGBA_B_DWORD_MASK (0x0000ff00) #define NL_RGBA_A_DWORD_MASK (0x000000ff) #endif // NL_LITTLE_ENDIAN } // NLMISC #endif // NL_RGBA_H /* End of rgba.h */