[Scummvm-git-logs] scummvm master -> 732a19c1eaece169ba0ddab963fcf9a949675f73
bluegr
noreply at scummvm.org
Mon Nov 17 12:43:00 UTC 2025
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
e810fd9fcf GRAPHICS: Extend Surface::clip to support flipping
1c25b17517 GRAPHICS: Add generic alpha blitting routines
18e4df9a8f GRAPHICS: Ensure that ManagedSurface transparent colours are converted
8ebbcb193a NGI: Replace per-pixel alpha with masks and colour keys
732a19c1ea NGI: Support arbitrary pixel formats
Commit: e810fd9fcfd4368e5630ac2b990935a6850b0919
https://github.com/scummvm/scummvm/commit/e810fd9fcfd4368e5630ac2b990935a6850b0919
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-11-17T14:42:55+02:00
Commit Message:
GRAPHICS: Extend Surface::clip to support flipping
Changed paths:
graphics/managed_surface.h
graphics/surface.cpp
graphics/surface.h
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
index 6694a0597a2..292e4442218 100644
--- a/graphics/managed_surface.h
+++ b/graphics/managed_surface.h
@@ -123,8 +123,8 @@ public:
/**
* Clip the given source bounds so the passed destBounds will be entirely on-screen.
*/
- bool clip(Common::Rect& srcBounds, Common::Rect& destBounds) const {
- return _innerSurface.clip(srcBounds, destBounds);
+ bool clip(Common::Rect& srcBounds, Common::Rect& destBounds, uint src_w = 0, uint src_h = 0, byte flip = FLIP_NONE) const {
+ return _innerSurface.clip(srcBounds, destBounds, src_w, src_h, flip);
}
public:
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 9908d3100c0..e6bd8c04240 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -212,7 +212,7 @@ const Surface Surface::getSubArea(const Common::Rect &area) const {
return subSurface;
}
-bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) const {
+bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds, uint src_w, uint src_h, byte flip) const {
if (destBounds.left >= this->w || destBounds.top >= this->h ||
destBounds.right <= 0 || destBounds.bottom <= 0)
return false;
@@ -238,6 +238,18 @@ bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) const {
destBounds.left = 0;
}
+ if (flip & FLIP_H) {
+ int tmp_w = srcBounds.width();
+ srcBounds.left = src_w - srcBounds.right;
+ srcBounds.right = srcBounds.left + tmp_w;
+ }
+
+ if (flip & FLIP_V) {
+ int tmp_h = srcBounds.height();
+ srcBounds.top = src_h - srcBounds.bottom;
+ srcBounds.bottom = srcBounds.top + tmp_h;
+ }
+
return true;
}
diff --git a/graphics/surface.h b/graphics/surface.h
index 0d9b32d47a7..84ed3a4682b 100644
--- a/graphics/surface.h
+++ b/graphics/surface.h
@@ -291,7 +291,7 @@ public:
/**
* Clip the given source bounds so the passed destBounds will be entirely on-screen.
*/
- bool clip(Common::Rect &srcBounds, Common::Rect &destBounds) const;
+ bool clip(Common::Rect &srcBounds, Common::Rect &destBounds, uint src_w = 0, uint src_h = 0, byte flip = FLIP_NONE) const;
/**
* Copy a bitmap to the internal buffer of the surface.
Commit: 1c25b175171ef2c46c7fa83481e8b2fbcd6d71e4
https://github.com/scummvm/scummvm/commit/1c25b175171ef2c46c7fa83481e8b2fbcd6d71e4
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-11-17T14:42:55+02:00
Commit Message:
GRAPHICS: Add generic alpha blitting routines
Changed paths:
engines/freescape/freescape.cpp
engines/testbed/image.cpp
engines/vcruise/runtime.cpp
graphics/blit.h
graphics/blit/blit-alpha.cpp
graphics/managed_surface.cpp
graphics/managed_surface.h
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 6909f2850d5..920c511f53f 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -1245,7 +1245,7 @@ Graphics::ManagedSurface *FreescapeEngine::loadAndConvertScrImage(Common::Seekab
Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
const Graphics::Surface *decoded = decoder.getSurface();
surface->create(320, 200, _gfx->_texturePixelFormat);
- surface->simpleBlitFrom(*decoded, Common::Point((320 - decoded->w) / 2, (200 - decoded->h) / 2), &decoder.getPalette());
+ surface->simpleBlitFrom(*decoded, Common::Point((320 - decoded->w) / 2, (200 - decoded->h) / 2), Graphics::FLIP_NONE, false, 255, &decoder.getPalette());
return surface;
}
diff --git a/engines/testbed/image.cpp b/engines/testbed/image.cpp
index 848f10bbd6c..05d61cc6add 100644
--- a/engines/testbed/image.cpp
+++ b/engines/testbed/image.cpp
@@ -350,7 +350,7 @@ bool ImageTests::testImageDecoder(Common::Path &filepath, Image::ImageDecoder &d
Graphics::Screen screen;
if (decoder.hasPalette()) {
- screen.simpleBlitFrom(*pSurface, &decoder.getPalette());
+ screen.simpleBlitFrom(*pSurface, Graphics::FLIP_NONE, false, 255, &decoder.getPalette());
} else {
screen.simpleBlitFrom(*pSurface);
}
diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index 1fe6edc135b..f47f8bcb6a4 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -2725,7 +2725,7 @@ void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAn
if (copyRect.isValidRect() || !copyRect.isEmpty()) {
Graphics::Palette p(_animDecoder->getPalette(), 256);
- _gameSection.surf->simpleBlitFrom(*surface, copyRect, copyRect.origin(), &p);
+ _gameSection.surf->simpleBlitFrom(*surface, copyRect, copyRect.origin(), Graphics::FLIP_NONE, false, 255, &p);
drawSectionToScreen(_gameSection, copyRect);
}
diff --git a/graphics/blit.h b/graphics/blit.h
index 147de950a50..a18ed55f858 100644
--- a/graphics/blit.h
+++ b/graphics/blit.h
@@ -210,6 +210,42 @@ bool crossMaskBlitMap(byte *dst, const byte *src, const byte *mask,
const uint w, const uint h,
const uint bytesPerPixel, const uint32 *map);
+bool alphaBlit(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,
+ const byte flip, const byte aMod);
+
+bool alphaKeyBlit(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,
+ const uint32 key, const byte flip, const byte aMod);
+
+bool alphaMaskBlit(byte *dst, const byte *src, const byte *mask,
+ const uint dstPitch, const uint srcPitch, const uint maskPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt,
+ const byte flip, const byte aMod);
+
+bool alphaBlitMap(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const byte flip, const byte aMod);
+
+bool alphaKeyBlitMap(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const uint32 key, const byte flip, const byte aMod);
+
+bool alphaMaskBlitMap(byte *dst, const byte *src, const byte *mask,
+ const uint dstPitch, const uint srcPitch, const uint maskPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const byte flip, const byte aMod);
+
typedef void (*FastBlitFunc)(byte *, const byte *, const uint, const uint, const uint, const uint);
#ifdef SCUMMVM_NEON
diff --git a/graphics/blit/blit-alpha.cpp b/graphics/blit/blit-alpha.cpp
index e399b9da553..8e7c998072b 100644
--- a/graphics/blit/blit-alpha.cpp
+++ b/graphics/blit/blit-alpha.cpp
@@ -27,6 +27,282 @@ namespace Graphics {
namespace {
+template<typename Color, int Size>
+static inline uint32 READ_PIXEL(const byte *src) {
+ if (Size == sizeof(Color)) {
+ return *(const Color *)src;
+ } else {
+ uint32 color;
+ uint8 *col = (uint8 *)&color;
+#ifdef SCUMM_BIG_ENDIAN
+ if (Size == 3)
+ col++;
+#endif
+ memcpy(col, src, Size);
+ return color;
+ }
+}
+
+template<typename Color, int Size>
+static inline void WRITE_PIXEL(byte *dst, const uint32 color) {
+ if (Size == sizeof(Color)) {
+ *(Color *)dst = color;
+ } else {
+ const uint8 *col = (const uint8 *)&color;
+#ifdef SCUMM_BIG_ENDIAN
+ if (Size == 3)
+ col++;
+#endif
+ memcpy(dst, col, Size);
+ }
+}
+
+template<typename SrcColor, int SrcSize, typename DstColor, int DstSize, bool hasKey, bool hasMask, bool hasMap>
+static inline void alphaBlitLogic(byte *dst, const byte *src, const byte *mask, const uint w, const uint h,
+ const PixelFormat &srcFmt, const PixelFormat &dstFmt, const uint32 *map,
+ const int srcDelta, const int dstDelta, const int maskDelta,
+ const int srcInc, const int dstInc, const int maskInc,
+ const uint32 key, const byte flip, const byte aMod) {
+ const uint32 alphaMask = srcFmt.ARGBToColor(255, 0, 0, 0);
+ const bool convert = hasMap ? false : ((SrcSize != DstSize) ? true : srcFmt == dstFmt);
+
+ for (uint y = 0; y < h; ++y) {
+ for (uint x = 0; x < w; ++x) {
+ const uint32 srcColor = hasMap ? map[*src]
+ : READ_PIXEL<SrcColor, SrcSize>(src);
+
+ const bool isOpaque = hasMask ? (*mask == 0xff)
+ : (hasKey ? (READ_PIXEL<SrcColor, SrcSize>(src) != key)
+ : !alphaMask || ((srcColor & alphaMask) == alphaMask));
+ const bool isTransparent = hasMask ? (*mask == 0x00)
+ : (hasKey ? (READ_PIXEL<SrcColor, SrcSize>(src) == key)
+ : alphaMask && ((srcColor & alphaMask) == 0));
+
+ if (isOpaque && aMod == 0xff) {
+ if (convert) {
+ byte sR, sG, sB;
+ srcFmt.colorToRGB(srcColor, sR, sG, sB);
+ WRITE_PIXEL<DstColor, DstSize>(dst, dstFmt.RGBToColor(sR, sG, sB));
+ } else {
+ WRITE_PIXEL<DstColor, DstSize>(dst, srcColor);
+ }
+ } else if (!isTransparent) {
+ // TODO: Optimise for matching formats?
+ const uint32 dstColor = READ_PIXEL<DstColor, DstSize>(dst);
+
+ byte sA, sR, sG, sB;
+ srcFmt.colorToARGB(srcColor, sA, sR, sG, sB);
+
+ byte dR, dG, dB;
+ dstFmt.colorToRGB(dstColor, dR, dG, dB);
+
+ if (hasKey)
+ sA = aMod;
+ else if (hasMask)
+ sA = ((*mask * aMod) >> 8);
+ else
+ sA = ((sA * aMod) >> 8);
+
+ dR = (dR * (255-sA) + sR * sA) >> 8;
+ dG = (dG * (255-sA) + sG * sA) >> 8;
+ dB = (dB * (255-sA) + sB * sA) >> 8;
+
+ const uint32 outColor = dstFmt.RGBToColor(dR, dG, dB);
+ WRITE_PIXEL<DstColor, DstSize>(dst, outColor);
+ }
+
+ src += srcInc;
+ dst += dstInc;
+ if (hasMask)
+ mask += maskInc;
+ }
+
+ src += srcDelta;
+ dst += dstDelta;
+ if (hasMask)
+ mask += maskDelta;
+ }
+}
+
+template<bool hasKey, bool hasMask>
+static inline bool alphaBlitHelper(byte *dst, const byte *src, const byte *mask, const uint w, const uint h,
+ const PixelFormat &srcFmt, const PixelFormat &dstFmt,
+ const uint srcPitch, const uint dstPitch, const uint maskPitch,
+ const uint32 key, const byte flip, const byte aMod) {
+ const bool hasMap = false;
+ const bool flipx = flip & FLIP_H;
+ const bool flipy = flip & FLIP_V;
+
+ // Faster, but larger, to provide optimized handling for each case.
+ int dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
+ const int srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
+ const int maskDelta = hasMask ? (maskPitch - w) : 0;
+
+ const int dstInc = flipx ? -dstFmt.bytesPerPixel : dstFmt.bytesPerPixel;
+ const int srcInc = srcFmt.bytesPerPixel;
+ const int maskInc = 1;
+
+ if (flipx)
+ dst += (w - 1) * dstFmt.bytesPerPixel;
+
+ if (flipy)
+ dst += (h - 1) * dstPitch;
+
+ if (flipy && flipx)
+ dstDelta = -dstDelta;
+ else if (flipy)
+ dstDelta = -((dstPitch * 2) - dstDelta);
+ else if (flipx)
+ dstDelta = (dstPitch * 2) - dstDelta;
+
+ if (aMod == 0)
+ return true;
+
+ // TODO: optimized cases for dstDelta of 0
+ if (dstFmt.bytesPerPixel == 2) {
+ if (srcFmt.bytesPerPixel == 2) {
+ alphaBlitLogic<uint16, 2, uint16, 2, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else if (srcFmt.bytesPerPixel == 3) {
+ alphaBlitLogic<uint8, 3, uint16, 2, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else {
+ alphaBlitLogic<uint32, 4, uint16, 2, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ }
+ } else if (dstFmt.bytesPerPixel == 4) {
+ if (srcFmt.bytesPerPixel == 2) {
+ alphaBlitLogic<uint16, 2, uint32, 4, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else if (srcFmt.bytesPerPixel == 3) {
+ alphaBlitLogic<uint8, 3, uint32, 4, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else {
+ alphaBlitLogic<uint32, 4, uint32, 4, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, nullptr, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+template<bool hasKey, bool hasMask>
+static inline bool alphaBlitMapHelper(byte *dst, const byte *src, const byte *mask, const uint w, const uint h,
+ const PixelFormat &dstFmt, const uint32 *map,
+ const uint srcPitch, const uint dstPitch, const uint maskPitch,
+ const uint32 key, const byte flip, const byte aMod) {
+ const Graphics::PixelFormat &srcFmt = dstFmt;
+ const bool hasMap = true;
+ const bool flipx = flip & FLIP_H;
+ const bool flipy = flip & FLIP_V;
+
+ // Faster, but larger, to provide optimized handling for each case.
+ int dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
+ const int srcDelta = (srcPitch - w);
+ const int maskDelta = hasMask ? (maskPitch - w) : 0;
+
+ const int dstInc = flipx ? -dstFmt.bytesPerPixel : dstFmt.bytesPerPixel;
+ const int srcInc = 1;
+ const int maskInc = 1;
+
+ if (flipx)
+ dst += (w - 1) * dstFmt.bytesPerPixel;
+
+ if (flipy)
+ dst += (h - 1) * dstPitch;
+
+ if (flipy && flipx)
+ dstDelta = -dstDelta;
+ else if (flipy)
+ dstDelta = -((dstPitch * 2) - dstDelta);
+ else if (flipx)
+ dstDelta = (dstPitch * 2) - dstDelta;
+
+ // TODO: optimized cases for dstDelta of 0
+ if (dstFmt.bytesPerPixel == 2) {
+ alphaBlitLogic<uint8, 1, uint16, 2, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, map, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else if (dstFmt.bytesPerPixel == 4) {
+ alphaBlitLogic<uint8, 1, uint32, 4, hasKey, hasMask, hasMap>(dst, src, mask, w, h, srcFmt, dstFmt, map, srcDelta, dstDelta, maskDelta, srcInc, dstInc, maskInc, key, flip, aMod);
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // End of anonymous namespace
+
+bool alphaBlit(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,
+ const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
+ || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitHelper<false, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcPitch, dstPitch, 0, 0, flip, aMod);
+}
+
+bool alphaKeyBlit(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,
+ const uint32 key, const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
+ || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitHelper<true, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcPitch, dstPitch, 0, key, flip, aMod);
+}
+
+bool alphaMaskBlit(byte *dst, const byte *src, const byte *mask,
+ const uint dstPitch, const uint srcPitch, const uint maskPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt,
+ const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
+ || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitHelper<false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcPitch, dstPitch, maskPitch, 0, flip, aMod);
+}
+
+bool alphaBlitMap(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((dstFmt.bytesPerPixel == 1) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitMapHelper<false, false>(dst, src, nullptr, w, h, dstFmt, map, srcPitch, dstPitch, 0, 0, flip, aMod);
+}
+
+bool alphaKeyBlitMap(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const uint32 key, const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((dstFmt.bytesPerPixel == 1) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitMapHelper<true, false>(dst, src, nullptr, w, h, dstFmt, map, srcPitch, dstPitch, 0, key, flip, aMod);
+}
+
+bool alphaMaskBlitMap(byte *dst, const byte *src, const byte *mask,
+ const uint dstPitch, const uint srcPitch, const uint maskPitch,
+ const uint w, const uint h,
+ const Graphics::PixelFormat &dstFmt, const uint32 *map,
+ const byte flip, const byte aMod) {
+ // Error out if conversion is impossible
+ if ((dstFmt.bytesPerPixel == 1) || (!dstFmt.bytesPerPixel))
+ return false;
+
+ return alphaBlitMapHelper<false, true>(dst, src, mask, w, h, dstFmt, map, srcPitch, dstPitch, maskPitch, 0, flip, aMod);
+}
+
+namespace {
+
template<typename Size, bool overwriteAlpha>
inline bool applyColorKeyLogic(byte *dst, const byte *src, const uint w, const uint h,
const uint srcDelta, const uint dstDelta,
diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp
index fb65c46c1ff..f076ca8acb6 100644
--- a/graphics/managed_surface.cpp
+++ b/graphics/managed_surface.cpp
@@ -326,47 +326,60 @@ Graphics::ManagedSurface *ManagedSurface::rotoscale(const TransformStruct &trans
return target;
}
-void ManagedSurface::simpleBlitFrom(const Surface &src, const Palette *srcPalette) {
- simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), srcPalette);
+void ManagedSurface::simpleBlitFrom(const Surface &src,
+ byte flip, bool alpha, byte aMod,
+ const Palette *srcPalette) {
+ simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), flip, alpha, aMod, srcPalette);
}
-void ManagedSurface::simpleBlitFrom(const Surface &src, const Common::Point &destPos, const Palette *srcPalette) {
- simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos, srcPalette);
+void ManagedSurface::simpleBlitFrom(const Surface &src, const Common::Point &destPos,
+ byte flip, bool alpha, byte aMod,
+ const Palette *srcPalette) {
+ simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos, flip, alpha, aMod, srcPalette);
}
void ManagedSurface::simpleBlitFrom(const Surface &src, const Common::Rect &srcRect,
- const Common::Point &destPos, const Palette *srcPalette) {
- simpleBlitFromInner(src, srcRect, destPos, srcPalette, false, 0);
+ const Common::Point &destPos,
+ byte flip, bool alpha, byte aMod,
+ const Palette *srcPalette) {
+ simpleBlitFromInner(src, srcRect, destPos, srcPalette, false, 0, flip, alpha, aMod);
}
-void ManagedSurface::simpleBlitFrom(const ManagedSurface &src) {
- simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0));
+void ManagedSurface::simpleBlitFrom(const ManagedSurface &src,
+ byte flip, bool alpha, byte aMod) {
+ simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), flip, alpha, aMod);
}
-void ManagedSurface::simpleBlitFrom(const ManagedSurface &src, const Common::Point &destPos) {
- simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos);
+void ManagedSurface::simpleBlitFrom(const ManagedSurface &src, const Common::Point &destPos,
+ byte flip, bool alpha, byte aMod) {
+ simpleBlitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos, flip, alpha, aMod);
}
void ManagedSurface::simpleBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect,
- const Common::Point &destPos) {
+ const Common::Point &destPos,
+ byte flip, bool alpha, byte aMod) {
simpleBlitFromInner(src._innerSurface, srcRect, destPos, src._palette,
- src._transparentColorSet, src._transparentColor);
+ src._transparentColorSet, src._transparentColor, flip, alpha, aMod);
}
void ManagedSurface::simpleBlitFromInner(const Surface &src, const Common::Rect &srcRect,
const Common::Point &destPos, const Palette *srcPalette,
- bool transparentColorSet, uint transparentColor) {
+ bool transparentColorSet, uint transparentColor,
+ byte flip, bool alpha, byte aMod) {
+
+ if (aMod == 0)
+ return;
Common::Rect srcRectC = srcRect;
Common::Rect dstRectC = srcRect;
dstRectC.moveTo(destPos.x, destPos.y);
- clip(srcRectC, dstRectC);
+ clip(srcRectC, dstRectC, src.w, src.h, flip);
const byte *srcPtr = (const byte *)src.getBasePtr(srcRectC.left, srcRectC.top);
byte *dstPtr = (byte *)getBasePtr(dstRectC.left, dstRectC.top);
- if (format == src.format) {
+ if (format == src.format && !alpha && aMod == 0xff && flip == 0) {
if (transparentColorSet) {
keyBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
format.bytesPerPixel, transparentColor);
@@ -381,70 +394,93 @@ void ManagedSurface::simpleBlitFromInner(const Surface &src, const Common::Rect
uint32 map[256];
convertPaletteToMap(map, srcPalette->data(), srcPalette->size(), format);
- if (transparentColorSet) {
- crossKeyBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
- format.bytesPerPixel, map, transparentColor);
+ if (alpha || aMod != 0xff || flip != 0) {
+ if (transparentColorSet) {
+ alphaKeyBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, map, transparentColor, flip, aMod);
+ } else {
+ alphaBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, map, flip, aMod);
+ }
} else {
- crossBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
- format.bytesPerPixel, map);
+ if (transparentColorSet) {
+ crossKeyBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format.bytesPerPixel, map, transparentColor);
+ } else {
+ crossBlitMap(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format.bytesPerPixel, map);
+ }
}
} else {
- if (transparentColorSet) {
- crossKeyBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
- format, src.format, transparentColor);
+ if (alpha || aMod != 0xff || flip != 0) {
+ if (transparentColorSet) {
+ alphaKeyBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format, transparentColor, flip, aMod);
+ } else {
+ alphaBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format, flip, aMod);
+ }
} else {
- crossBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
- format, src.format);
+ if (transparentColorSet) {
+ crossKeyBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format, transparentColor);
+ } else {
+ crossBlit(dstPtr, srcPtr, pitch, src.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format);
+ }
}
}
addDirtyRect(dstRectC);
}
-void ManagedSurface::maskBlitFrom(const Surface &src, const Surface &mask, const Palette *srcPalette) {
- maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), srcPalette);
+void ManagedSurface::maskBlitFrom(const Surface &src, const Surface &mask, byte flip, bool alpha, byte aMod, const Palette *srcPalette) {
+ maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), flip, alpha, aMod, srcPalette);
}
-void ManagedSurface::maskBlitFrom(const Surface &src, const Surface &mask, const Common::Point &destPos, const Palette *srcPalette) {
- maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), destPos, srcPalette);
+void ManagedSurface::maskBlitFrom(const Surface &src, const Surface &mask, const Common::Point &destPos, byte flip, bool alpha, byte aMod, const Palette *srcPalette) {
+ maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), destPos, flip, alpha, aMod, srcPalette);
}
void ManagedSurface::maskBlitFrom(const Surface &src, const Surface &mask, const Common::Rect &srcRect,
- const Common::Point &destPos, const Palette *srcPalette) {
- maskBlitFromInner(src, mask, srcRect, destPos, srcPalette);
+ const Common::Point &destPos, byte flip, bool alpha, byte aMod, const Palette *srcPalette) {
+ maskBlitFromInner(src, mask, srcRect, destPos, srcPalette, flip, alpha, aMod);
}
-void ManagedSurface::maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask) {
- maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0));
+void ManagedSurface::maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask, byte flip, bool alpha, byte aMod) {
+ maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0), flip, alpha, aMod);
}
-void ManagedSurface::maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask, const Common::Point &destPos) {
- maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), destPos);
+void ManagedSurface::maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask, const Common::Point &destPos, byte flip, bool alpha, byte aMod) {
+ maskBlitFrom(src, mask, Common::Rect(0, 0, src.w, src.h), destPos, flip, alpha, aMod);
}
void ManagedSurface::maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask,
- const Common::Rect &srcRect, const Common::Point &destPos) {
- maskBlitFromInner(src._innerSurface, mask._innerSurface, srcRect, destPos, src._palette);
+ const Common::Rect &srcRect, const Common::Point &destPos, byte flip, bool alpha, byte aMod) {
+ maskBlitFromInner(src._innerSurface, mask._innerSurface, srcRect, destPos, src._palette, flip, alpha, aMod);
}
void ManagedSurface::maskBlitFromInner(const Surface &src, const Surface &mask,
const Common::Rect &srcRect, const Common::Point &destPos,
- const Palette *srcPalette) {
+ const Palette *srcPalette, byte flip, bool alpha, byte aMod) {
if (mask.w != src.w || mask.h != src.h)
error("Surface::maskBlitFrom: mask dimensions do not match src");
+ if (aMod == 0)
+ return;
+
Common::Rect srcRectC = srcRect;
Common::Rect dstRectC = srcRect;
dstRectC.moveTo(destPos.x, destPos.y);
- clip(srcRectC, dstRectC);
+ clip(srcRectC, dstRectC, src.w, src.h, flip);
const byte *srcPtr = (const byte *)src.getBasePtr(srcRectC.left, srcRectC.top);
const byte *maskPtr = (const byte *)mask.getBasePtr(srcRectC.left, srcRectC.top);
byte *dstPtr = (byte *)getBasePtr(dstRectC.left, dstRectC.top);
- if (format == src.format) {
+ if (format == src.format && !alpha && aMod == 0xff && flip == 0) {
maskBlit(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
format.bytesPerPixel);
} else if (src.format.isCLUT8()) {
@@ -453,11 +489,21 @@ void ManagedSurface::maskBlitFromInner(const Surface &src, const Surface &mask,
uint32 map[256];
convertPaletteToMap(map, srcPalette->data(), srcPalette->size(), format);
- crossMaskBlitMap(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
- format.bytesPerPixel, map);
+ if (alpha || aMod != 0xff || flip != 0) {
+ alphaMaskBlitMap(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
+ format, map, flip, aMod);
+ } else {
+ crossMaskBlitMap(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
+ format.bytesPerPixel, map);
+ }
} else {
- crossMaskBlit(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
- format, src.format);
+ if (alpha || aMod != 0xff || flip != 0) {
+ alphaMaskBlit(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format, flip, aMod);
+ } else {
+ crossMaskBlit(dstPtr, srcPtr, maskPtr, pitch, src.pitch, mask.pitch, srcRectC.width(), srcRectC.height(),
+ format, src.format);
+ }
}
addDirtyRect(dstRectC);
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
index 292e4442218..a741575527c 100644
--- a/graphics/managed_surface.h
+++ b/graphics/managed_surface.h
@@ -90,14 +90,15 @@ protected:
*/
void simpleBlitFromInner(const Surface &src, const Common::Rect &srcRect,
const Common::Point &destPos, const Palette *srcPalette,
- bool transparentColorSet, uint transparentColor);
+ bool transparentColorSet, uint transparentColor,
+ byte flip, bool alpha, byte aMod);
/**
* Inner method for blitting with a transparent mask.
*/
void maskBlitFromInner(const Surface &src, const Surface &mask,
const Common::Rect &srcRect, const Common::Point &destPos,
- const Palette *srcPalette);
+ const Palette *srcPalette, byte flip, bool alpha, byte aMod);
/**
* Inner method for blitting.
@@ -329,66 +330,84 @@ public:
/**
* Copy another surface into this one.
*/
- void simpleBlitFrom(const Surface &src, const Palette *srcPalette = nullptr);
+ void simpleBlitFrom(const Surface &src,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one at a given destination position.
*/
- void simpleBlitFrom(const Surface &src, const Common::Point &destPos, const Palette *srcPalette = nullptr);
+ void simpleBlitFrom(const Surface &src, const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one at a given destination position.
*/
void simpleBlitFrom(const Surface &src, const Common::Rect &srcRect,
- const Common::Point &destPos, const Palette *srcPalette = nullptr);
+ const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one.
*/
- void simpleBlitFrom(const ManagedSurface &src);
+ void simpleBlitFrom(const ManagedSurface &src,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one at a given destination position.
*/
- void simpleBlitFrom(const ManagedSurface &src, const Common::Point &destPos);
+ void simpleBlitFrom(const ManagedSurface &src, const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one at a given destination position.
*/
void simpleBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect,
- const Common::Point &destPos);
+ const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one using a transparency mask.
*/
- void maskBlitFrom(const Surface &src, const Surface &mask, const Palette *srcPalette = nullptr);
+ void maskBlitFrom(const Surface &src, const Surface &mask,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one at a given destination position using a transparency mask.
*/
- void maskBlitFrom(const Surface &src, const Surface &mask, const Common::Point &destPos, const Palette *srcPalette = nullptr);
+ void maskBlitFrom(const Surface &src, const Surface &mask, const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one at a given destination position using a transparency mask.
*/
void maskBlitFrom(const Surface &src, const Surface &mask, const Common::Rect &srcRect,
- const Common::Point &destPos, const Palette *srcPalette = nullptr);
+ const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff,
+ const Palette *srcPalette = nullptr);
/**
* Copy another surface into this one using a transparency mask.
*/
- void maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask);
+ void maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one at a given destination position using a transparency mask.
*/
- void maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask, const Common::Point &destPos);
+ void maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask, const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one at a given destination position using a transparency mask.
*/
void maskBlitFrom(const ManagedSurface &src, const ManagedSurface &mask,
- const Common::Rect &srcRect, const Common::Point &destPos);
+ const Common::Rect &srcRect, const Common::Point &destPos,
+ byte flip = FLIP_NONE, bool alpha = false, byte aMod = 0xff);
/**
* Copy another surface into this one.
Commit: 18e4df9a8fed346020ddccfba725f53bcad3da8d
https://github.com/scummvm/scummvm/commit/18e4df9a8fed346020ddccfba725f53bcad3da8d
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-11-17T14:42:55+02:00
Commit Message:
GRAPHICS: Ensure that ManagedSurface transparent colours are converted
Changed paths:
graphics/managed_surface.cpp
graphics/managed_surface.h
diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp
index f076ca8acb6..467df2ae585 100644
--- a/graphics/managed_surface.cpp
+++ b/graphics/managed_surface.cpp
@@ -245,6 +245,20 @@ void ManagedSurface::copyFrom(const Surface &surf) {
}
}
+uint32 ManagedSurface::convertTransparentColor(const ManagedSurface &surf, const PixelFormat &dstFmt) const {
+ if (surf.format == dstFmt) {
+ return surf._transparentColor;
+ } else if (surf.format.isCLUT8()) {
+ byte r, g, b;
+ surf._palette->get(surf._transparentColor, r, g, b);
+ return dstFmt.RGBToColor(r, g, b);
+ } else {
+ byte a, r, g, b;
+ surf.format.colorToARGB(surf._transparentColor, a, r, g, b);
+ return dstFmt.ARGBToColor(a, r, g, b);
+ }
+}
+
void ManagedSurface::convertFrom(const ManagedSurface &surf, const PixelFormat &fmt) {
// Surface::copyFrom frees pixel pointer so let's free up ManagedSurface to be coherent
free();
@@ -258,7 +272,7 @@ void ManagedSurface::convertFrom(const ManagedSurface &surf, const PixelFormat &
// Copy miscellaneous properties
_transparentColorSet = surf._transparentColorSet;
- _transparentColor = surf._transparentColor;
+ _transparentColor = convertTransparentColor(surf, fmt);
_palette = (fmt.isCLUT8() && surf._palette) ? new Palette(*surf._palette) : nullptr;
}
@@ -282,6 +296,16 @@ void ManagedSurface::convertFrom(const Surface &surf, const PixelFormat &fmt) {
}
}
+void ManagedSurface::convertToInPlace(const PixelFormat &dstFormat) {
+ // Convert miscellaneous properties
+ _transparentColor = convertTransparentColor(*this, dstFormat);
+
+ if (_palette)
+ _innerSurface.convertToInPlace(dstFormat, _palette->data(), _palette->size());
+ else
+ _innerSurface.convertToInPlace(dstFormat);
+}
+
Graphics::ManagedSurface *ManagedSurface::scale(int16 newWidth, int16 newHeight, bool filtering) const {
Graphics::ManagedSurface *target = new Graphics::ManagedSurface();
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
index a741575527c..96e3c8a839c 100644
--- a/graphics/managed_surface.h
+++ b/graphics/managed_surface.h
@@ -120,6 +120,8 @@ protected:
const Common::Rect &destRect, const int flipping, const uint colorMod,
const TSpriteBlendMode blend, const AlphaType alphaType);
+ uint32 convertTransparentColor(const ManagedSurface &surf, const PixelFormat &dstFmt) const;
+
public:
/**
* Clip the given source bounds so the passed destBounds will be entirely on-screen.
@@ -994,9 +996,7 @@ public:
*
* @param dstFormat The desired format.
*/
- void convertToInPlace(const PixelFormat &dstFormat) {
- _innerSurface.convertToInPlace(dstFormat);
- }
+ void convertToInPlace(const PixelFormat &dstFormat);
/**
* Convert the data to another pixel format.
Commit: 8ebbcb193a77b1900edb04d067de031d687ee733
https://github.com/scummvm/scummvm/commit/8ebbcb193a77b1900edb04d067de031d687ee733
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-11-17T14:42:55+02:00
Commit Message:
NGI: Replace per-pixel alpha with masks and colour keys
Changed paths:
engines/ngi/gfx.cpp
engines/ngi/gfx.h
engines/ngi/ngi.cpp
engines/ngi/ngi.h
diff --git a/engines/ngi/gfx.cpp b/engines/ngi/gfx.cpp
index 1fd6d50c5fa..d5079116ab7 100644
--- a/engines/ngi/gfx.cpp
+++ b/engines/ngi/gfx.cpp
@@ -703,6 +703,7 @@ Bitmap::Bitmap() {
_flags = 0;
_flipping = Graphics::FLIP_NONE;
_surface = nullptr;
+ _mask = nullptr;
}
Bitmap::Bitmap(const Bitmap &src) {
@@ -714,14 +715,27 @@ Bitmap::Bitmap(const Bitmap &src) {
_width = src._width;
_height = src._height;
_flipping = src._flipping;
- _surface = new Graphics::ManagedSurface();
- _surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
- _surface->copyFrom(*src._surface);
+ _surface = nullptr;
+ _mask = nullptr;
+ if (src._surface) {
+ _surface = new Graphics::ManagedSurface();
+ _surface->copyFrom(*src._surface);
+ }
+ if (src._mask) {
+ _mask = new Graphics::ManagedSurface();
+ _mask->copyFrom(*src._mask);
+ }
}
Bitmap::~Bitmap() {
- _surface->free();
- delete _surface;
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+ if (_mask) {
+ _mask->free();
+ delete _mask;
+ }
}
void Bitmap::load(Common::ReadStream *s) {
@@ -747,13 +761,16 @@ bool Bitmap::isPixelHitAtPos(int x, int y) {
if (!_surface)
return false;
- return ((*((int32 *)_surface->getBasePtr(x - _x, y - _y)) & 0xff) != 0);
+ if (_mask)
+ return (*((uint8 *)_mask->getBasePtr(x - _x, y - _y)) != 0);
+
+ if (_surface->hasTransparentColor())
+ return _surface->getPixel(x - _x, y - _y) != _surface->getTransparentColor();
+
+ return true;
}
void Bitmap::decode(byte *pixels, const Palette &palette) {
- _surface = new Graphics::ManagedSurface();
- _surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
-
if (_type == MKTAG('R', 'B', '\0', '\0'))
putDibRB(pixels, palette);
else
@@ -783,14 +800,14 @@ void Bitmap::putDib(int x, int y, const Palette &palette, byte alpha) {
if (y1 < 0)
y1 = 0;
- uint32 alphac = MS_ARGB(alpha, 0xff, 0xff, 0xff);
-
- g_nmi->_backgroundSurface.blendBlitFrom(*_surface, sub, Common::Point(x1, y1), _flipping, alphac);
+ if (_mask)
+ g_nmi->_backgroundSurface.maskBlitFrom(*_surface, *_mask, sub, Common::Point(x1, y1), _flipping, false, alpha);
+ else
+ g_nmi->_backgroundSurface.simpleBlitFrom(*_surface, sub, Common::Point(x1, y1), _flipping, false, alpha);
g_nmi->_system->copyRectToScreen(g_nmi->_backgroundSurface.getBasePtr(x1, y1), g_nmi->_backgroundSurface.pitch, x1, y1, sub.width(), sub.height());
}
-bool Bitmap::putDibRB(byte *pixels, const Palette &palette) {
- uint32 *curDestPtr;
+void Bitmap::putDibRB(byte *pixels, const Palette &palette) {
int endy;
int x;
int start1;
@@ -802,9 +819,16 @@ bool Bitmap::putDibRB(byte *pixels, const Palette &palette) {
if (!palette.size) {
debugC(2, kDebugDrawing, "Bitmap::putDibRB(): Both global and local palettes are empty");
- return false;
+ return;
}
+ _surface = new Graphics::ManagedSurface();
+ _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+ _mask = new Graphics::ManagedSurface();
+ _mask->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+
+ convertPalette(palette);
+
debugC(8, kDebugDrawing, "Bitmap::putDibRB()");
endy = _height - 1;
@@ -854,10 +878,10 @@ bool Bitmap::putDibRB(byte *pixels, const Palette &palette) {
if (fillLen > 0 || start1 >= 0) {
if (x <= _width + 1 || (fillLen += _width - x + 1, fillLen > 0)) {
if (y <= endy) {
- int bgcolor = palette.pal[(pixel >> 8) & 0xff];
- curDestPtr = (uint32 *)_surface->getBasePtr(start1, y);
+ uint8 *curDestPtr = (uint8 *)_surface->getBasePtr(start1, y);
+ uint8 *curMaskPtr = (uint8 *)_mask->getBasePtr(start1, y);
fillLen = MIN(_width - start1, fillLen);
- colorFill(curDestPtr, fillLen, bgcolor);
+ colorFill(curDestPtr, curMaskPtr, (pixel >> 8) & 0xff, fillLen);
}
}
}
@@ -882,19 +906,17 @@ bool Bitmap::putDibRB(byte *pixels, const Palette &palette) {
}
if (y <= endy) {
- curDestPtr = (uint32 *)_surface->getBasePtr(start1, y);
+ uint8 *curDestPtr = (uint8 *)_surface->getBasePtr(start1, y);
+ uint8 *curMaskPtr = (uint8 *)_mask->getBasePtr(start1, y);
fillLen = MIN(_width - start1, fillLen);
- paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, palette);
+ paletteFill(curDestPtr, curMaskPtr, (byte *)srcPtr2, fillLen);
}
}
}
}
-
- return false;
}
void Bitmap::putDibCB(byte *pixels, const Palette &palette) {
- uint32 *curDestPtr;
int endx;
int endy;
int bpp;
@@ -920,20 +942,47 @@ void Bitmap::putDibCB(byte *pixels, const Palette &palette) {
int starty = 0;
int startx = 0;
- if (_flags & 0x1000000) {
+ if (cb05_format) {
+ _surface = new Graphics::ManagedSurface();
+ _surface->create(_width, _height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+
+ if (_flags & 0x1000000)
+ _surface->setTransparentColor(0);
+
for (int y = starty; y <= endy; srcPtr -= pitch, y++) {
- curDestPtr = (uint32 *)_surface->getBasePtr(startx, y);
- copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, palette, cb05_format);
+ uint16 *curDestPtr = (uint16 *)_surface->getBasePtr(startx, y);
+ copier16(curDestPtr, srcPtr, endx - startx + 1);
}
+
+ // Converting from true colour is slow compared to converting
+ // from paletted surfaces, so we do this up-front.
+ _surface->convertToInPlace(g_system->getScreenFormat());
} else {
+ _surface = new Graphics::ManagedSurface();
+ _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+
+ if (_flags & 0x1000000)
+ _surface->setTransparentColor(_flags & 0xff);
+ convertPalette(palette);
+
for (int y = starty; y <= endy; srcPtr -= pitch, y++) {
- curDestPtr = (uint32 *)_surface->getBasePtr(startx, y);
- copier(curDestPtr, srcPtr, endx - startx + 1, palette, cb05_format);
+ uint8 *curDestPtr = (uint8 *)_surface->getBasePtr(startx, y);
+ copier8(curDestPtr, srcPtr, endx - startx + 1);
}
}
}
-void Bitmap::colorFill(uint32 *dest, int len, int32 color) {
+void Bitmap::convertPalette(const Palette &palette) {
+ constexpr Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
+
+ for (uint i = 0; i < palette.size; i++) {
+ byte col[3];
+ format.colorToRGB(palette.pal[i] & 0xffff, col[0], col[1], col[2]);
+ _surface->setPalette(col, i, 1);
+ }
+}
+
+void Bitmap::colorFill(uint8 *dest, uint8 *mask, byte color, int len) {
#if 0
if (blendMode) {
if (blendMode != 1)
@@ -944,17 +993,13 @@ void Bitmap::colorFill(uint32 *dest, int len, int32 color) {
colorFill = ptrfillColor16bit;
}
#endif
- byte r, g, b;
-
- g_nmi->_origFormat.colorToRGB(color, r, g, b);
-
- uint32 c = MS_ARGB(0xff, r, g, b);
-
- for (int i = 0; i < len; i++)
- *dest++ = c;
+ for (int i = 0; i < len; i++) {
+ *dest++ = color;
+ *mask++ = 0xff;
+ }
}
-void Bitmap::paletteFill(uint32 *dest, byte *src, int len, const Palette &palette) {
+void Bitmap::paletteFill(uint8 *dest, uint8 *mask, byte *src, int len) {
#if 0
if (blendMode) {
if (blendMode != 1)
@@ -966,93 +1011,47 @@ void Bitmap::paletteFill(uint32 *dest, byte *src, int len, const Palette &palett
}
#endif
- byte r, g, b;
-
for (int i = 0; i < len; i++) {
- g_nmi->_origFormat.colorToRGB(palette.pal[*src++] & 0xffff, r, g, b);
-
- *dest++ = MS_ARGB(0xff, r, g, b);
+ *dest++ = *src++;
+ *mask++ = 0xff;
}
}
-void Bitmap::copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, const Palette &palette, bool cb05_format) {
+void Bitmap::copier8(uint8 *dest, byte *src, int len) {
#if 0
if (blendMode) {
if (blendMode == 1) {
- if (cb05_format)
- copierKeyColor = ptrcopier16bitKeycolorAlpha;
- else
- copierKeyColor = ptrcopierKeycolorAlpha;
+ copier = ptrcopierWithPaletteAlpha;
} else {
copier = 0;
}
- } else if (cb05_format) {
- copierKeyColor = ptrcopier16bitKeycolor;
} else {
- copierKeyColor = ptrkeyColor16bit;
+ copier = ptrcopierWithPalette;
}
#endif
- byte r, g, b;
-
- if (!cb05_format) {
- for (int i = 0; i < len; i++) {
- if (*src != keyColor) {
- g_nmi->_origFormat.colorToRGB(palette.pal[*src] & 0xffff, r, g, b);
- *dest = MS_ARGB(0xff, r, g, b);
- }
-
- dest++;
- src++;
- }
- } else {
- int16 *src16 = (int16 *)src;
-
- for (int i = 0; i < len; i++) {
- if (*src16 != 0) {
- g_nmi->_origFormat.colorToRGB(READ_LE_UINT16(src16), r, g, b);
- *dest = MS_ARGB(0xff, r, g, b);
- }
-
- dest++;
- src16++;
- }
+ for (int i = 0; i < len; i++) {
+ *dest++ = *src++;
}
}
-void Bitmap::copier(uint32 *dest, byte *src, int len, const Palette &palette, bool cb05_format) {
+void Bitmap::copier16(uint16 *dest, byte *src, int len) {
#if 0
if (blendMode) {
if (blendMode == 1) {
- if (cb05_format)
- copier = ptrcopier16bitAlpha;
- else
- copier = ptrcopierWithPaletteAlpha;
+ copier = ptrcopier16bitAlpha;
} else {
copier = 0;
}
- } else if (cb05_format) {
- copier = ptrcopier16bit;
} else {
- copier = ptrcopierWithPalette;
+ copier = ptrcopier16bit;
}
#endif
- byte r, g, b;
-
- if (!cb05_format) {
- for (int i = 0; i < len; i++) {
- g_nmi->_origFormat.colorToRGB(palette.pal[*src++] & 0xffff, r, g, b);
+ int16 *src16 = (int16 *)src;
- *dest++ = MS_ARGB(0xff, r, g, b);
- }
- } else {
- int16 *src16 = (int16 *)src;
-
- for (int i = 0; i < len; i++) {
- g_nmi->_origFormat.colorToRGB(READ_LE_UINT16(src16++), r, g, b);
- *dest++ = MS_ARGB(0xff, r, g, b);
- }
+ for (int i = 0; i < len; i++) {
+ *dest++ = READ_LE_UINT16(src16++);
}
}
diff --git a/engines/ngi/gfx.h b/engines/ngi/gfx.h
index 522b2b08e24..cd8723e0b6e 100644
--- a/engines/ngi/gfx.h
+++ b/engines/ngi/gfx.h
@@ -47,6 +47,7 @@ struct Bitmap {
int _flags;
int _flipping;
Graphics::ManagedSurface *_surface;
+ Graphics::ManagedSurface *_mask;
Bitmap();
Bitmap(const Bitmap &src);
@@ -55,13 +56,15 @@ struct Bitmap {
void load(Common::ReadStream *s);
void decode(byte *pixels, const Palette &palette);
void putDib(int x, int y, const Palette &palette, byte alpha);
- bool putDibRB(byte *pixels, const Palette &palette);
+ void putDibRB(byte *pixels, const Palette &palette);
void putDibCB(byte *pixels, const Palette &palette);
- void colorFill(uint32 *dest, int len, int32 color);
- void paletteFill(uint32 *dest, byte *src, int len, const Palette &palette);
- void copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, const Palette &palette, bool cb05_format);
- void copier(uint32 *dest, byte *src, int len, const Palette &palette, bool cb05_format);
+ void convertPalette(const Palette &palette);
+
+ void colorFill(uint8 *dest, uint8 *mask, byte color, int len);
+ void paletteFill(uint8 *dest, uint8 *mask, byte *src, int len);
+ void copier8(uint8 *dest, byte *src, int len);
+ void copier16(uint16 *dest, byte *src, int len);
/** ownership of returned object is transferred to caller */
Bitmap *reverseImage(bool flip = true) const;
diff --git a/engines/ngi/ngi.cpp b/engines/ngi/ngi.cpp
index 3c9d89a991c..02034c82df7 100644
--- a/engines/ngi/ngi.cpp
+++ b/engines/ngi/ngi.cpp
@@ -245,7 +245,6 @@ Common::Error NGIEngine::run() {
initGraphics(800, 600, &format);
_backgroundSurface.create(800, 600, format);
- _origFormat = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
_globalMessageQueueList.reset(new GlobalMessageQueueList);
_behaviorManager.reset(new BehaviorManager);
diff --git a/engines/ngi/ngi.h b/engines/ngi/ngi.h
index 2092835887c..6522fb1aa04 100644
--- a/engines/ngi/ngi.h
+++ b/engines/ngi/ngi.h
@@ -155,7 +155,6 @@ public:
void updateEvents();
Graphics::ManagedSurface _backgroundSurface;
- Graphics::PixelFormat _origFormat;
Common::ScopedPtr<GameLoader> _gameLoader;
GameProject *_gameProject;
Commit: 732a19c1eaece169ba0ddab963fcf9a949675f73
https://github.com/scummvm/scummvm/commit/732a19c1eaece169ba0ddab963fcf9a949675f73
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-11-17T14:42:55+02:00
Commit Message:
NGI: Support arbitrary pixel formats
Changed paths:
engines/ngi/gfx.cpp
engines/ngi/ngi.cpp
diff --git a/engines/ngi/gfx.cpp b/engines/ngi/gfx.cpp
index d5079116ab7..f7ba1a66fea 100644
--- a/engines/ngi/gfx.cpp
+++ b/engines/ngi/gfx.cpp
@@ -1180,17 +1180,21 @@ DynamicPhase *Shadows::findSize(int width, int height) {
}
void NGIEngine::drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha) {
- for (int y = y1; y < y2; y++) {
- uint32 *ptr = (uint32 *)g_nmi->_backgroundSurface.getBasePtr(x1, y);
+ // TODO: Let the backend handle this?
+ const Graphics::PixelFormat &format = g_nmi->_backgroundSurface.format;
+ for (int y = y1; y < y2; y++) {
for (int x = x1; x < x2; x++) {
- uint32 color = *ptr;
- color = (((color >> 24) & 0xff) * alpha / 0xff) << 24 |
- (((color >> 16) & 0xff) * alpha / 0xff) << 16 |
- (((color >> 8) & 0xff) * alpha / 0xff) << 8 |
- (color & 0xff);
- *ptr = color;
- ptr++;
+ uint32 color = g_nmi->_backgroundSurface.getPixel(x, y);
+
+ uint8 a, r, g, b;
+ format.colorToARGB(color, a, r, g, b);
+ r = (r * alpha) / 0xff;
+ g = (g * alpha) / 0xff;
+ b = (b * alpha) / 0xff;
+ color = format.ARGBToColor(a, r, g, b);
+
+ g_nmi->_backgroundSurface.setPixel(x, y, color);
}
}
}
diff --git a/engines/ngi/ngi.cpp b/engines/ngi/ngi.cpp
index 02034c82df7..adb6d5adef7 100644
--- a/engines/ngi/ngi.cpp
+++ b/engines/ngi/ngi.cpp
@@ -240,9 +240,12 @@ Common::String NGIEngine::getSaveStateName(int slot) const {
}
Common::Error NGIEngine::run() {
- const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
// Initialize backend
- initGraphics(800, 600, &format);
+ initGraphics(800, 600, nullptr);
+
+ const Graphics::PixelFormat format = g_system->getScreenFormat();
+ if (format.isCLUT8())
+ return Common::kUnsupportedColorMode;
_backgroundSurface.create(800, 600, format);
More information about the Scummvm-git-logs
mailing list