//  // // # # ### # # -= Nuclex Library =-  // // ## # # # ## ## Blit.h - Software blitting routines  // // ### # # ###  // // # ### # ### Blitting routines for copying or alpha-blending surfaces  // // # ## # # ## ## onto other surface  // // # # ### # # R1 (C)2002-2004 Markus Ewald -> License.txt  // //  // #ifndef NUCLEX_VIDEO_BLIT_H #define NUCLEX_VIDEO_BLIT_H #include "Nuclex/Video/PixelFormat.h" #include "Nuclex/Math/Point2.h" namespace Nuclex { namespace Video { //  // //  Nuclex::Video::Blit  // //  // /// Blit memory block /** Performs a blit, optionally including color conversion, alpha blending from alpha value and/or alpha channel. The best blitting solution is statically chosen by a compile-time solvable call graph of template method. */ template< typename DestinationPixelFormatDescription, typename SourcePixelFormatDescription, bool bAlphaBlend > struct Blit { /// Blit source to destination with optional alpha blending /** With alpha blending: Blends source onto dest by source alpha Without alpha blending: Copies source to dest */ inline void operator ()(void *pDestination, long nDestinationPitch, const void *pSource, long nSourcePitch, const Point2 &Size) { blit( reinterpret_cast(pDestination), nDestinationPitch, reinterpret_cast(pSource), nSourcePitch, Size ); } /// Alpha blit source to destination with optional alpha blending /** With alpha blending: Blends source onto dest by (source alpha x cAlpha) Without alpha blending: Copies source to dest, sets dest alpha to cAlpha */ inline void operator ()(void *pDestination, long nDestinationPitch, const void *pSource, long nSourcePitch, const Point2 &Size, unsigned char cAlpha) { blit( reinterpret_cast(pDestination), nDestinationPitch, reinterpret_cast(pSource), nSourcePitch, Size, cAlpha ); } private: static inline typename DestinationPixelFormatDescription::PixelType convertAdjustAlpha( typename SourcePixelFormatDescription::PixelType Pixel ) { return convertAdjustAlpha( Pixel, Bool2Type< (sizeof(SourcePixelFormatDescription::PixelType) > sizeof(DestinationPixelFormatDescription::PixelType)) >() ); } // Required to let the ColorChannelConverter use the larger of two pixel types static inline typename DestinationPixelFormatDescription::PixelType convertAdjustAlpha( typename SourcePixelFormatDescription::PixelType Pixel, Bool2Type ) { return static_cast( ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel) ); } static inline typename DestinationPixelFormatDescription::PixelType convertAdjustAlpha( typename SourcePixelFormatDescription::PixelType Pixel, Bool2Type ) { return ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel) | ColorChannelConverter()(Pixel); } template inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size); /// Alpha blended blit with optional pixel format conversion template<> inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size) { // dest = source + (dest - source) * source.a // Uses non-alpha blit() if no alpha channel in source blend( pDestination, nDestinationPitch, pSource, nSourcePitch, Size, Bool2Type() ); } /// Blit with optional pixel format conversion template<> inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size) { // dest = source // Uses memcpy() if both pixel formats are identical copy( pDestination, nDestinationPitch, pSource, nSourcePitch, Size, DestinationPixelFormatDescription(), SourcePixelFormatDescription() ); } template inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, unsigned char cAlpha); /// Alpha blended alpha blit with optional pixel format conversion template<> inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, unsigned char cAlpha) { // dest = source + (dest - source) * (cAlpha * source.a) long nSourceLineAdd = nSourcePitch - (Size.X * SourcePixelFormatDescription::BytesPerPixel); long nDestinationLineAdd = nDestinationPitch - (Size.X * DestinationPixelFormatDescription::BytesPerPixel); for(unsigned long nY = 0; nY < Size.Y; ++nY) { for(unsigned long nX = 0; nX < Size.X; ++nX) { WritePixel()( pDestination, AlphaBlend< DestinationPixelFormatDescription, SourcePixelFormatDescription, SourcePixelFormatDescription::Alpha::Bits::Count, 8 >(ReadPixel()(pSource))( ReadPixel()(pDestination), static_cast( (ReadPixel()(pSource) & SourcePixelFormatDescription::Alpha::Bits::Mask) >> SourcePixelFormatDescription::Alpha::Bits::First ), cAlpha ) ); pSource += SourcePixelFormatDescription::BytesPerPixel; pDestination += DestinationPixelFormatDescription::BytesPerPixel; } pSource += nSourceLineAdd; pDestination += nDestinationLineAdd; } } /// Alpha blit with optional pixel format conversion template<> inline void blit(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, unsigned char cAlpha) { // dest = source; dest.a = source.a * cAlpha long nSourceLineAdd = nSourcePitch - (Size.X * SourcePixelFormatDescription::BytesPerPixel); long nDestinationLineAdd = nDestinationPitch - (Size.X * DestinationPixelFormatDescription::BytesPerPixel); for(unsigned long nY = 0; nY < Size.Y; ++nY) { for(unsigned long nX = 0; nX < Size.X; ++nX) { DestinationPixelFormatDescription::PixelType Pixel = DestinationPixelFormatDescription::convertFrom( ReadPixel()(pSource) ); NativeType Alpha = (Pixel & DestinationPixelFormatDescription::Alpha::Bits::Mask) >> DestinationPixelFormatDescription::Alpha::Bits::First; Pixel = static_cast( (Pixel & ~DestinationPixelFormatDescription::Alpha::Bits::Mask) | (Shift< NativeType, 8 - DestinationPixelFormatDescription::Alpha::Bits::First >()(Alpha * cAlpha) & DestinationPixelFormatDescription::Alpha::Bits::Mask) ); WritePixel()( pDestination, Pixel ); pSource += SourcePixelFormatDescription::BytesPerPixel; pDestination += DestinationPixelFormatDescription::BytesPerPixel; } pSource += nSourceLineAdd; pDestination += nDestinationLineAdd; } } /// Alpha blended blit inline void blend(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, Bool2Type) { long nSourceLineAdd = nSourcePitch - (Size.X * SourcePixelFormatDescription::BytesPerPixel); long nDestinationLineAdd = nDestinationPitch - (Size.X * DestinationPixelFormatDescription::BytesPerPixel); for(unsigned long nY = 0; nY < Size.Y; ++nY) { for(unsigned long nX = 0; nX < Size.X; ++nX) { WritePixel()( pDestination, AlphaBlend< DestinationPixelFormatDescription, SourcePixelFormatDescription, SourcePixelFormatDescription::Alpha::Bits::Count >(ReadPixel()(pSource))( ReadPixel()(pDestination), static_cast( (ReadPixel()(pSource) & SourcePixelFormatDescription::Alpha::Bits::Mask) >> SourcePixelFormatDescription::Alpha::Bits::First ) ) ); pSource += SourcePixelFormatDescription::BytesPerPixel; pDestination += DestinationPixelFormatDescription::BytesPerPixel; } pSource += nSourceLineAdd; pDestination += nDestinationLineAdd; } } /// Alpha blended blit inline void blend(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, Bool2Type) { blit( pDestination, nDestinationPitch, pSource, nSourcePitch, Size ); } /// Blit with color conversion template inline void copy(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, A, B) { long nSourceLineAdd = nSourcePitch - (Size.X * SourcePixelFormatDescription::BytesPerPixel); long nDestinationLineAdd = nDestinationPitch - (Size.X * DestinationPixelFormatDescription::BytesPerPixel); for(unsigned long nY = 0; nY < Size.Y; ++nY) { for(unsigned long nX = 0; nX < Size.X; ++nX) { WritePixel()( pDestination, DestinationPixelFormatDescription::convertFrom( ReadPixel()(pSource) ) ); pSource += SourcePixelFormatDescription::BytesPerPixel; pDestination += DestinationPixelFormatDescription::BytesPerPixel; } pSource += nSourceLineAdd; pDestination += nDestinationLineAdd; } } /// Blit without color conversion template inline void copy(unsigned char *pDestination, long nDestinationPitch, const unsigned char *pSource, long nSourcePitch, const Point2 &Size, A, A) { for(unsigned long nY = 0; nY < Size.Y; ++nY) { memcpy(pDestination, pSource, DestinationPixelFormatDescription::BytesPerPixel * Size.X); pSource += nSourcePitch; pDestination += nDestinationPitch; } } }; }} // namespace Nuclex::Video #endif // NUCLEX_VIDEO_BLIT_H