// $Id: PixelOperations.hh 5893 2006-11-20 20:06:49Z m9710797 $ #ifndef PIXELOPERATIONS_HH #define PIXELOPERATIONS_HH #include namespace openmsx { // TODO: Needed for the "friend" declarations later. template class Scanline; template class SimpleScaler; template class Blur_1on3; template class PixelOperations { public: explicit PixelOperations(const SDL_PixelFormat* format); /** Extract RGB componts */ inline unsigned red(Pixel p) const; inline unsigned green(Pixel p) const; inline unsigned blue(Pixel p) const; /** Same as above, but result is scaled to [0..255] */ inline unsigned red256(Pixel p) const; inline unsigned green256(Pixel p) const; inline unsigned blue256(Pixel p) const; /** Combine RGB components to a pixel */ inline Pixel combine(unsigned r, unsigned g, unsigned b) const; inline Pixel combine256(unsigned r, unsigned g, unsigned b) const; /** Get maximum component value */ inline unsigned getMaxRed() const; inline unsigned getMaxGreen() const; inline unsigned getMaxBlue() const; /** Blend the given colors into a single color. * The special case for blending between two colors with * an equal blend weight has an optimized implementation. */ template inline Pixel blend(Pixel p1, Pixel p2) const; template inline Pixel blend(Pixel p1, Pixel p2, Pixel p3) const; template inline Pixel blend(Pixel p1, Pixel p2, Pixel p3, Pixel p4) const; template inline Pixel blend(Pixel p1, Pixel p2, Pixel p3, Pixel p4, Pixel p5, Pixel p6) const; template inline Pixel blend2(const Pixel* p) const; template inline Pixel blend3(const Pixel* p) const; template inline Pixel blend4(const Pixel* p) const; template inline Pixel blend6(const Pixel* p) const; inline Pixel getBlendMask() const; private: /** Mask used for blending. * The least significant bit of R,G,B must be 1, * all other bits must be 0. * 0000BBBBGGGGRRRR * --> 0000000100010001 */ const SDL_PixelFormat* format; Pixel blendMask; // TODO: These are workarounds for utility classes that should be // centralized somehow. friend class Scanline; friend class SimpleScaler; friend class Blur_1on3; }; template PixelOperations::PixelOperations(const SDL_PixelFormat* format_) : format(format_) { int rBit = ~(format->Rmask << 1) & format->Rmask; int gBit = ~(format->Gmask << 1) & format->Gmask; int bBit = ~(format->Bmask << 1) & format->Bmask; blendMask = rBit | gBit | bBit; } template inline unsigned PixelOperations::red(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Rshift) & 0xFF; } else { return (p & format->Rmask) >> format->Rshift; } } template inline unsigned PixelOperations::green(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Gshift) & 0xFF; } else { return (p & format->Gmask) >> format->Gshift; } } template inline unsigned PixelOperations::blue(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Bshift) & 0xFF; } else { return (p & format->Bmask) >> format->Bshift; } } template inline unsigned PixelOperations::red256(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Rshift) & 0xFF; } else { return ((p >> format->Rshift) << format->Rloss) & 0xFF; } } template inline unsigned PixelOperations::green256(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Gshift) & 0xFF; } else { return ((p >> format->Gshift) << format->Gloss) & 0xFF; } } template inline unsigned PixelOperations::blue256(Pixel p) const { if (sizeof(Pixel) == 4) { return (p >> format->Bshift) & 0xFF; } else { return ((p >> format->Bshift) << format->Bloss) & 0xFF; } } template inline Pixel PixelOperations::combine( unsigned r, unsigned g, unsigned b) const { return (Pixel)((r << format->Rshift) | (g << format->Gshift) | (b << format->Bshift)); } template inline Pixel PixelOperations::combine256( unsigned r, unsigned g, unsigned b) const { if (sizeof(Pixel) == 4) { return (Pixel)((r << format->Rshift) | (g << format->Gshift) | (b << format->Bshift)); } else { return (Pixel)(((r >> format->Rloss) << format->Rshift) | ((g >> format->Gloss) << format->Gshift) | ((b >> format->Bloss) << format->Bshift)); } } template inline unsigned PixelOperations::getMaxRed() const { if (sizeof(Pixel) == 4) { return 255; } else { return 255 >> format->Rloss; } } template inline unsigned PixelOperations::getMaxGreen() const { if (sizeof(Pixel) == 4) { return 255; } else { return 255 >> format->Gloss; } } template inline unsigned PixelOperations::getMaxBlue() const { if (sizeof(Pixel) == 4) { return 255; } else { return 255 >> format->Bloss; } } template struct IsPow2 { static const bool result = ((N & 1) == 0) && IsPow2::result; static const unsigned log2 = 1 + IsPow2::log2; }; template<> struct IsPow2<1> { static const bool result = true; static const unsigned log2 = 0; }; template template inline Pixel PixelOperations::blend(Pixel p1, Pixel p2) const { if (w1 == w2) { return ((p1 & ~blendMask) >> 1) + ((p2 & ~blendMask) >> 1) + (p1 & blendMask); } else { static const unsigned total = w1 + w2; if ((sizeof(Pixel) == 4) && IsPow2::result) { unsigned l2 = IsPow2::log2; unsigned rb = ((p1 & 0xFF00FF) * w1 + (p2 & 0xFF00FF) * w2) & (0xFF00FF << l2); unsigned g = ((p1 & 0x00FF00) * w1 + (p2 & 0x00FF00) * w2) & (0x00FF00 << l2); return (rb | g) >> l2; } else { unsigned r = (red (p1) * w1 + red (p2) * w2) / total; unsigned g = (green(p1) * w1 + green(p2) * w2) / total; unsigned b = (blue (p1) * w1 + blue (p2) * w2) / total; return combine(r, g, b); } } } template template inline Pixel PixelOperations::blend(Pixel p1, Pixel p2, Pixel p3) const { static const unsigned total = w1 + w2 + w3; if ((sizeof(Pixel) == 4) && IsPow2::result) { unsigned l2 = IsPow2::log2; unsigned rb = ((p1 & 0xFF00FF) * w1 + (p2 & 0xFF00FF) * w2 + (p3 & 0xFF00FF) * w3) & (0xFF00FF << l2); unsigned g = ((p1 & 0x00FF00) * w1 + (p2 & 0x00FF00) * w2 + (p3 & 0x00FF00) * w3) & (0x00FF00 << l2); return (rb | g) >> l2; } else { unsigned r = (red (p1) * w1 + red (p2) * w2 + red (p3) * w3) / total; unsigned g = (green(p1) * w1 + green(p2) * w2 + green(p3) * w3) / total; unsigned b = (blue (p1) * w1 + blue (p2) * w2 + blue (p3) * w3) / total; return combine(r, g, b); } } template template inline Pixel PixelOperations::blend( Pixel p1, Pixel p2, Pixel p3, Pixel p4) const { static const unsigned total = w1 + w2 + w3 + w4; if ((sizeof(Pixel) == 4) && IsPow2::result) { unsigned l2 = IsPow2::log2; unsigned rb = ((p1 & 0xFF00FF) * w1 + (p2 & 0xFF00FF) * w2 + (p3 & 0xFF00FF) * w3 + (p4 & 0xFF00FF) * w4) & (0xFF00FF << l2); unsigned g = ((p1 & 0x00FF00) * w1 + (p2 & 0x00FF00) * w2 + (p3 & 0x00FF00) * w3 + (p4 & 0x00FF00) * w4) & (0x00FF00 << l2); return (rb | g) >> l2; } else { unsigned r = (red (p1) * w1 + red (p2) * w2 + red (p3) * w3 + red (p4) * w4) / total; unsigned g = (green(p1) * w1 + green(p2) * w2 + green(p3) * w3 + green(p4) * w4) / total; unsigned b = (blue (p1) * w1 + blue (p2) * w2 + blue (p3) * w3 + blue (p4) * w4) / total; return combine(r, g, b); } } template template inline Pixel PixelOperations::blend( Pixel p1, Pixel p2, Pixel p3, Pixel p4, Pixel p5, Pixel p6) const { static const unsigned total = w1 + w2 + w3 + w4 + w5 + w6; if ((sizeof(Pixel) == 4) && IsPow2::result) { unsigned l2 = IsPow2::log2; unsigned rb = ((p1 & 0xFF00FF) * w1 + (p2 & 0xFF00FF) * w2 + (p3 & 0xFF00FF) * w3 + (p4 & 0xFF00FF) * w4 + (p5 & 0xFF00FF) * w5 + (p6 & 0xFF00FF) * w6) & (0xFF00FF << l2); unsigned g = ((p1 & 0x00FF00) * w1 + (p2 & 0x00FF00) * w2 + (p3 & 0x00FF00) * w3 + (p4 & 0x00FF00) * w4 + (p5 & 0x00FF00) * w5 + (p6 & 0x00FF00) * w6) & (0x00FF00 << l2); return (rb | g) >> l2; } else { unsigned r = (red (p1) * w1 + red (p2) * w2 + red (p3) * w3 + red (p4) * w4 + red (p5) * w5 + red (p6) * w6) / total; unsigned g = (green(p1) * w1 + green(p2) * w2 + green(p3) * w3 + green(p4) * w4 + green(p5) * w5 + green(p6) * w6) / total; unsigned b = (blue (p1) * w1 + blue (p2) * w2 + blue (p3) * w3 + blue (p4) * w4 + blue (p5) * w5 + blue (p6) * w6) / total; return combine(r, g, b); } } template template inline Pixel PixelOperations::blend2(const Pixel* p) const { return blend(p[0], p[1]); } template template inline Pixel PixelOperations::blend3(const Pixel* p) const { return blend(p[0], p[1], p[2]); } template template inline Pixel PixelOperations::blend4(const Pixel* p) const { return blend(p[0], p[1], p[2], p[3]); } template template inline Pixel PixelOperations::blend6(const Pixel* p) const { return blend(p[0], p[1], p[2], p[3], p[4], p[5]); } template inline Pixel PixelOperations::getBlendMask() const { return blendMask; } } // namespace openmsx #endif