aboutsummaryrefslogtreecommitdiff
path: root/graphics/conversion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/conversion.cpp')
-rw-r--r--graphics/conversion.cpp202
1 files changed, 111 insertions, 91 deletions
diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp
index 713a06ea74..fec1d240e2 100644
--- a/graphics/conversion.cpp
+++ b/graphics/conversion.cpp
@@ -22,123 +22,143 @@
#include "graphics/conversion.h"
#include "graphics/pixelformat.h"
+#include "common/endian.h"
+
namespace Graphics {
// TODO: YUV to RGB conversion function
+namespace {
+
+template<typename SrcColor, typename DstColor, bool backward>
+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) {
+ for (uint y = 0; y < h; ++y) {
+ for (uint x = 0; x < w; ++x) {
+ const uint32 color = *(const SrcColor *)src;
+ byte a, r, g, b;
+ srcFmt.colorToARGB(color, a, r, g, b);
+ *(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
+
+ 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;
+ }
+ }
+}
+
+template<typename DstColor, bool backward>
+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) {
+ uint32 color;
+ byte r, g, b, a;
+ uint8 *col = (uint8 *)&color;
+#ifdef SCUMM_BIG_ENDIAN
+ col++;
+#endif
+ for (uint y = 0; y < h; ++y) {
+ for (uint x = 0; x < w; ++x) {
+ memcpy(col, src, 3);
+ srcFmt.colorToARGB(color, a, r, g, b);
+ *(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
+
+ if (backward) {
+ src -= 3;
+ dst -= sizeof(DstColor);
+ } else {
+ src += 3;
+ dst += sizeof(DstColor);
+ }
+ }
+
+ if (backward) {
+ src -= srcDelta;
+ dst -= dstDelta;
+ } else {
+ src += srcDelta;
+ dst += dstDelta;
+ }
+ }
+}
+
+} // End of anonymous namespace
+
// Function to blit a rect from one color format to another
-bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch,
- int w, int h, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
+bool crossBlit(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
- || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel)
- || (srcFmt.bytesPerPixel > dstFmt.bytesPerPixel))
+ || (dstFmt.bytesPerPixel == 3)
+ || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;
// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
- if (dst == src)
- return true;
- if (dstpitch == srcpitch && ((w * dstFmt.bytesPerPixel) == dstpitch)) {
- memcpy(dst,src,dstpitch * h);
- return true;
- } else {
- for (int i = 0; i < h; i++) {
- memcpy(dst,src,w * dstFmt.bytesPerPixel);
- dst += dstpitch;
- src += srcpitch;
+ if (dst != src) {
+ if (dstPitch == srcPitch && ((w * dstFmt.bytesPerPixel) == dstPitch)) {
+ memcpy(dst, src, dstPitch * h);
+ } else {
+ for (uint i = 0; i < h; ++i) {
+ memcpy(dst, src, w * dstFmt.bytesPerPixel);
+ dst += dstPitch;
+ src += srcPitch;
+ }
}
- return true;
}
+
+ return true;
}
// Faster, but larger, to provide optimized handling for each case.
- int srcDelta, dstDelta;
- srcDelta = (srcpitch - w * srcFmt.bytesPerPixel);
- dstDelta = (dstpitch - w * dstFmt.bytesPerPixel);
+ const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
+ const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
// TODO: optimized cases for dstDelta of 0
- uint8 r, g, b, a;
if (dstFmt.bytesPerPixel == 2) {
- uint16 color;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 2, dst += 2) {
- color = *(const uint16 *)src;
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- *(uint16 *)dst = color;
- }
- src += srcDelta;
- dst += dstDelta;
- }
- } else if (dstFmt.bytesPerPixel == 3) {
- uint32 color;
- uint8 *col = (uint8 *) &color;
-#ifdef SCUMM_BIG_ENDIAN
- col++;
-#endif
if (srcFmt.bytesPerPixel == 2) {
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 2, dst += 3) {
- color = *(const uint16 *)src;
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- memcpy(dst, col, 3);
- }
- src += srcDelta;
- dst += dstDelta;
- }
+ crossBlitLogic<uint16, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
+ } else if (srcFmt.bytesPerPixel == 3) {
+ crossBlitLogic3BppSource<uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
} else {
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 3, dst += 3) {
- memcpy(col, src, 3);
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- memcpy(dst, col, 3);
- }
- src += srcDelta;
- dst += dstDelta;
- }
+ crossBlitLogic<uint32, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
}
} else if (dstFmt.bytesPerPixel == 4) {
- uint32 color;
if (srcFmt.bytesPerPixel == 2) {
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 2, dst += 4) {
- color = *(const uint16 *)src;
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- *(uint32 *)dst = color;
- }
- src += srcDelta;
- dst += 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<uint16, uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
} else if (srcFmt.bytesPerPixel == 3) {
- uint8 *col = (uint8 *)&color;
-#ifdef SCUMM_BIG_ENDIAN
- col++;
-#endif
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 2, dst += 4) {
- memcpy(col, src, 3);
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- *(uint32 *)dst = color;
- }
- src += srcDelta;
- dst += 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<uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
} else {
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++, src += 4, dst += 4) {
- color = *(const uint32 *)src;
- srcFmt.colorToARGB(color, a, r, g, b);
- color = dstFmt.ARGBToColor(a, r, g, b);
- *(uint32 *)dst = color;
- }
- src += srcDelta;
- dst += dstDelta;
- }
+ crossBlitLogic<uint32, uint32, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
}
} else {
return false;