From a92a509ac844fdad796748848d1143b27547173f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 05:35:20 +0200 Subject: GRAPHICS: Allow in-place conversion with any color formats in crossBlit. --- graphics/conversion.cpp | 70 ++++++++++++++++++++++++++++++++++++++----------- graphics/conversion.h | 9 ++++--- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index ece1f759d9..27a44f4ed5 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -30,7 +30,7 @@ namespace Graphics { namespace { -template +template FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h, const PixelFormat &srcFmt, const PixelFormat &dstFmt, const uint srcDelta, const uint dstDelta) { @@ -41,15 +41,27 @@ FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); *(DstColor *)dst = color; - src += sizeof(SrcColor); - dst += sizeof(DstColor); + + if (backward) { + src -= sizeof(SrcColor); + dst -= sizeof(DstColor); + } else { + src += sizeof(SrcColor); + dst += sizeof(DstColor); + } + } + + if (backward) { + src -= srcDelta; + dst -= dstDelta; + } else { + src += srcDelta; + dst += dstDelta; } - src += srcDelta; - dst += dstDelta; } } -template +template FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h, const PixelFormat &srcFmt, const PixelFormat &dstFmt, const uint srcDelta, const uint dstDelta) { @@ -65,11 +77,23 @@ FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); *(DstColor *)dst = color; - src += 3; - dst += sizeof(DstColor); + + if (backward) { + src -= 3; + dst -= sizeof(DstColor); + } else { + src += 3; + dst += sizeof(DstColor); + } + } + + if (backward) { + src -= srcDelta; + dst -= dstDelta; + } else { + src += srcDelta; + dst += dstDelta; } - src += srcDelta; - dst += dstDelta; } } @@ -110,19 +134,33 @@ bool crossBlit(byte *dst, const byte *src, // TODO: optimized cases for dstDelta of 0 if (dstFmt.bytesPerPixel == 2) { if (srcFmt.bytesPerPixel == 2) { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { - crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } } else if (dstFmt.bytesPerPixel == 4) { if (srcFmt.bytesPerPixel == 2) { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + // We need to blit the surface from bottom right to top left here. + // This is neeeded, because when we convert to the same memory + // buffer copying the surface from top left to bottom right would + // overwrite the source, since we have more bits per destination + // color than per source color. + dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel; + src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel; + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { - crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + // We need to blit the surface from bottom right to top left here. + // This is neeeded, because when we convert to the same memory + // buffer copying the surface from top left to bottom right would + // overwrite the source, since we have more bits per destination + // color than per source color. + dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel; + src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel; + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } } else { return false; diff --git a/graphics/conversion.h b/graphics/conversion.h index 0dce3cf279..28e64a94fb 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -60,9 +60,12 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { * false if there is an error. * * @note Blitting to a 3Bpp destination is not supported - * @note This can convert a rectangle in place, if the source and - * destination format have the same bytedepth. - * + * @note This can convert a surface in place, regardless of the + * source and destination format, as long as there is enough + * space for the destination. The dstPitch / srcPitch ratio + * must at least equal the dstBpp / srcBpp ratio for + * dstPitch >= srcPitch and at most dstBpp / srcBpp for + * dstPitch < srcPitch though. */ bool crossBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, -- cgit v1.2.3