[Scummvm-git-logs] scummvm master -> 325674ace7774333b191327cba40bd3878d37374
sev-
noreply at scummvm.org
Sun Feb 19 22:51:17 UTC 2023
This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3db67a33ac GRAPHICS: Add support for pixels with masks and inverted pixels
866e459992 TESTBED: Add tests for masked and inverted cursors.
76d84718e2 GRAPHICS: Corrected semantics for MacOS cursors
0a32f23bd6 BACKENDS: ANDROID: Update log message for setMouseCursor
607e49756c BACKENDS: IOS7: Enable log message for unsupported cursor masks
774066714a BACKENDS: N64: Fix wrong error message
6af0bd2a95 COMMON: Correct cursor mask comments.
d7303bd006 GRAPHICS: Delete duplicated (and incorrect) parameter description.
325674ace7 GRAPHICS: Add masked cursor support to SurfaceSdl, fix tests
Commit: 3db67a33aca701bae81d2b68da6c2455656bccc8
https://github.com/scummvm/scummvm/commit/3db67a33aca701bae81d2b68da6c2455656bccc8
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
GRAPHICS: Add support for pixels with masks and inverted pixels
Changed paths:
backends/graphics/graphics.h
backends/graphics/null/null-graphics.h
backends/graphics/opengl/framebuffer.cpp
backends/graphics/opengl/framebuffer.h
backends/graphics/opengl/opengl-graphics.cpp
backends/graphics/opengl/opengl-graphics.h
backends/graphics/opengl/texture.cpp
backends/graphics/opengl/texture.h
backends/graphics/surfacesdl/surfacesdl-graphics.cpp
backends/graphics/surfacesdl/surfacesdl-graphics.h
backends/graphics3d/android/android-graphics3d.cpp
backends/graphics3d/android/android-graphics3d.h
backends/graphics3d/openglsdl/openglsdl-graphics3d.h
backends/modular-backend.cpp
backends/modular-backend.h
backends/platform/3ds/osystem-graphics.cpp
backends/platform/3ds/osystem.h
backends/platform/dc/dc.h
backends/platform/dc/display.cpp
backends/platform/ds/ds-graphics.cpp
backends/platform/ds/osystem_ds.h
backends/platform/ios7/ios7_osys_main.h
backends/platform/ios7/ios7_osys_video.mm
backends/platform/iphone/osys_main.h
backends/platform/iphone/osys_video.mm
backends/platform/n64/osys_n64.h
backends/platform/n64/osys_n64_base.cpp
backends/platform/psp/osys_psp.cpp
backends/platform/psp/osys_psp.h
backends/platform/wii/osystem.h
backends/platform/wii/osystem_gfx.cpp
common/system.h
graphics/cursor.h
graphics/cursorman.cpp
graphics/cursorman.h
graphics/wincursor.cpp
diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h
index 417ac7d192c..553bc26effc 100644
--- a/backends/graphics/graphics.h
+++ b/backends/graphics/graphics.h
@@ -99,7 +99,7 @@ public:
virtual bool showMouse(bool visible) = 0;
virtual void warpMouse(int x, int y) = 0;
- virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) = 0;
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = nullptr, const byte *mask = nullptr) = 0;
virtual void setCursorPalette(const byte *colors, uint start, uint num) = 0;
virtual void displayMessageOnOSD(const Common::U32String &msg) {}
diff --git a/backends/graphics/null/null-graphics.h b/backends/graphics/null/null-graphics.h
index ef6fc4227bd..60437e23238 100644
--- a/backends/graphics/null/null-graphics.h
+++ b/backends/graphics/null/null-graphics.h
@@ -83,7 +83,7 @@ public:
bool showMouse(bool visible) override { return !visible; }
void warpMouse(int x, int y) override {}
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override {}
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override {}
void setCursorPalette(const byte *colors, uint start, uint num) override {}
private:
diff --git a/backends/graphics/opengl/framebuffer.cpp b/backends/graphics/opengl/framebuffer.cpp
index 59096fffd97..e3be0ed990b 100644
--- a/backends/graphics/opengl/framebuffer.cpp
+++ b/backends/graphics/opengl/framebuffer.cpp
@@ -119,6 +119,14 @@ void Framebuffer::applyBlendState() {
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
break;
+ case kBlendModeAdditive:
+ GL_CALL(glEnable(GL_BLEND));
+ GL_CALL(glBlendFunc(GL_ONE, GL_ONE));
+ break;
+ case kBlendModeMaskAlphaAndInvertByColor:
+ GL_CALL(glEnable(GL_BLEND));
+ GL_CALL(glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA));
+ break;
default:
break;
}
diff --git a/backends/graphics/opengl/framebuffer.h b/backends/graphics/opengl/framebuffer.h
index 8e7f57013be..3d3b7909bf8 100644
--- a/backends/graphics/opengl/framebuffer.h
+++ b/backends/graphics/opengl/framebuffer.h
@@ -59,7 +59,18 @@ public:
* Requires the image data being drawn to have its color values pre-multipled
* with the alpha value.
*/
- kBlendModePremultipliedTransparency
+ kBlendModePremultipliedTransparency,
+
+ /**
+ * Newly drawn pixels add to the destination value.
+ */
+ kBlendModeAdditive,
+
+ /**
+ * Newly drawn pixels mask out existing pixels based on the alpha value and
+ * add inversions of the pixels based on the color.
+ */
+ kBlendModeMaskAlphaAndInvertByColor,
};
/**
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 3128b18644c..82ed23fa41a 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -73,10 +73,10 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
_pipeline(nullptr), _stretchMode(STRETCH_FIT),
_defaultFormat(), _defaultFormatAlpha(),
_gameScreen(nullptr), _overlay(nullptr),
- _cursor(nullptr),
+ _cursor(nullptr), _cursorMask(nullptr),
_cursorHotspotX(0), _cursorHotspotY(0),
_cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0),
- _cursorKeyColor(0), _cursorDontScale(false), _cursorPaletteEnabled(false), _shakeOffsetScaled()
+ _cursorKeyColor(0), _cursorUseKey(true), _cursorDontScale(false), _cursorPaletteEnabled(false), _shakeOffsetScaled()
#if !USE_FORCED_GLES
, _libretroPipeline(nullptr)
#endif
@@ -96,6 +96,7 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
delete _gameScreen;
delete _overlay;
delete _cursor;
+ delete _cursorMask;
#ifdef USE_OSD
delete _osdMessageSurface;
delete _osdIconSurface;
@@ -112,6 +113,8 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
case OSystem::kFeatureCursorPalette:
case OSystem::kFeatureFilteringMode:
case OSystem::kFeatureStretchMode:
+ case OSystem::kFeatureCursorMask:
+ case OSystem::kFeatureCursorMaskInvert:
#ifdef USE_SCALERS
case OSystem::kFeatureScalers:
#endif
@@ -588,6 +591,41 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) {
_gameScreen->fill(col);
}
+void OpenGLGraphicsManager::renderCursor() {
+ /*
+ Windows and Mac cursor XOR works by drawing the cursor to the screen with the formula (Destination AND Mask XOR Color)
+
+ OpenGL does not have an XOR blend mode though. Full inversions can be accomplished by using blend modes with
+ ONE_MINUS_DST_COLOR but the problem is how to do that in a way that handles linear filtering properly.
+
+ To avoid color fringing, we need to produce an output of 3 separately-modulated inputs: The framebuffer modulated by
+ (1 - inversion)*(1 - alpha), the inverted framebuffer modulated by inversion*(1 - alpha), and the cursor colors modulated by alpha.
+ The last part is additive and not framebuffer dependent so it can just be a separate draw call. The first two are the problem
+ because we can't use the unmodified framebuffer value twice if we do it in two separate draw calls, and if we do it in a single
+ draw call, we can only supply one RGB input even though the inversion mask should be RGB.
+
+ If we only allow grayscale inversions though, then we can put inversion*(1 - alpha) in the RGB channel and
+ (1 - inversion)*(1 - alpha) in the alpha channel and use and use ((1-dstColor)*src+(1-srcAlpha)*dest) blend formula to do
+ the inversion and opacity mask at once. We use 1-srcAlpha instead of srcAlpha so zero-fill is transparent.
+ */
+ if (_cursorMask) {
+ _backBuffer.enableBlend(Framebuffer::kBlendModeMaskAlphaAndInvertByColor);
+
+ _pipeline->drawTexture(_cursorMask->getGLTexture(),
+ _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x,
+ _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y,
+ _cursorWidthScaled, _cursorHeightScaled);
+
+ _backBuffer.enableBlend(Framebuffer::kBlendModeAdditive);
+ } else
+ _backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
+
+ _pipeline->drawTexture(_cursor->getGLTexture(),
+ _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x,
+ _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y,
+ _cursorWidthScaled, _cursorHeightScaled);
+}
+
void OpenGLGraphicsManager::updateScreen() {
if (!_gameScreen) {
return;
@@ -616,7 +654,7 @@ void OpenGLGraphicsManager::updateScreen() {
&& !(_libretroPipeline && _libretroPipeline->isAnimated())
#endif
&& !(_overlayVisible && _overlay->isDirty())
- && !(_cursorVisible && _cursor && _cursor->isDirty())
+ && !(_cursorVisible && ((_cursor && _cursor->isDirty()) || (_cursorMask && _cursorMask->isDirty())))
#ifdef USE_OSD
&& !_osdMessageSurface && !_osdIconSurface
#endif
@@ -629,6 +667,9 @@ void OpenGLGraphicsManager::updateScreen() {
if (_cursorVisible && _cursor) {
_cursor->updateGLTexture();
}
+ if (_cursorVisible && _cursorMask) {
+ _cursorMask->updateGLTexture();
+ }
_overlay->updateGLTexture();
#if !USE_FORCED_GLES
@@ -665,12 +706,7 @@ void OpenGLGraphicsManager::updateScreen() {
// This has the disadvantage of having overlay (subtitles) drawn above it
// but the cursor will look nicer
if (!_overlayInGUI && drawCursor) {
- _backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
-
- _pipeline->drawTexture(_cursor->getGLTexture(),
- _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x,
- _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y,
- _cursorWidthScaled, _cursorHeightScaled);
+ renderCursor();
drawCursor = false;
// Everything we need to clip has been clipped
@@ -691,14 +727,8 @@ void OpenGLGraphicsManager::updateScreen() {
}
// Fourth step: Draw the cursor if we didn't before.
- if (drawCursor) {
- _backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
-
- _pipeline->drawTexture(_cursor->getGLTexture(),
- _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x,
- _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y,
- _cursorWidthScaled, _cursorHeightScaled);
- }
+ if (drawCursor)
+ renderCursor();
if (!_overlayVisible) {
_backBuffer.enableScissorTest(false);
@@ -819,12 +849,12 @@ namespace {
template<typename SrcColor, typename DstColor>
void multiplyColorWithAlpha(const byte *src, byte *dst, const uint w, const uint h,
const Graphics::PixelFormat &srcFmt, const Graphics::PixelFormat &dstFmt,
- const uint srcPitch, const uint dstPitch, const SrcColor keyColor) {
+ const uint srcPitch, const uint dstPitch, const SrcColor keyColor, bool useKeyColor) {
for (uint y = 0; y < h; ++y) {
for (uint x = 0; x < w; ++x) {
const uint32 color = *(const SrcColor *)src;
- if (color == keyColor) {
+ if (useKeyColor && color == keyColor) {
*(DstColor *)dst = 0;
} else {
byte a, r, g, b;
@@ -849,9 +879,12 @@ void multiplyColorWithAlpha(const byte *src, byte *dst, const uint w, const uint
}
} // End of anonymous namespace
-void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
- _cursorKeyColor = keycolor;
+void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ _cursorUseKey = (mask == nullptr);
+ if (_cursorUseKey)
+ _cursorKeyColor = keycolor;
+
_cursorHotspotX = hotspotX;
_cursorHotspotY = hotspotY;
_cursorDontScale = dontScale;
@@ -859,10 +892,13 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
if (!w || !h) {
delete _cursor;
_cursor = nullptr;
+ delete _cursorMask;
+ _cursorMask = nullptr;
return;
}
Graphics::PixelFormat inputFormat;
+ Graphics::PixelFormat maskFormat;
#ifdef USE_RGB_COLOR
if (format) {
inputFormat = *format;
@@ -873,18 +909,20 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
inputFormat = Graphics::PixelFormat::createFormatCLUT8();
#endif
- // In case the color format has changed we will need to create the texture.
- if (!_cursor || _cursor->getFormat() != inputFormat) {
- delete _cursor;
- _cursor = nullptr;
-
#ifdef USE_SCALERS
- bool wantScaler = (_currentState.scaleFactor > 1) && !dontScale
- && _scalerPlugins[_currentState.scalerIndex]->get<ScalerPluginObject>().canDrawCursor();
+ bool wantScaler = (_currentState.scaleFactor > 1) && !dontScale && _scalerPlugins[_currentState.scalerIndex]->get<ScalerPluginObject>().canDrawCursor();
#else
- bool wantScaler = false;
+ bool wantScaler = false;
#endif
+ bool wantMask = (mask != nullptr);
+ bool haveMask = (_cursorMask != nullptr);
+
+ // In case the color format has changed we will need to create the texture.
+ if (!_cursor || _cursor->getFormat() != inputFormat || haveMask != wantMask) {
+ delete _cursor;
+ _cursor = nullptr;
+
GLenum glIntFormat, glFormat, glType;
Graphics::PixelFormat textureFormat;
@@ -899,9 +937,11 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
} else {
textureFormat = _defaultFormatAlpha;
}
- _cursor = createSurface(textureFormat, true, wantScaler);
+ _cursor = createSurface(textureFormat, true, wantScaler, wantMask);
assert(_cursor);
+
updateLinearFiltering();
+
#ifdef USE_SCALERS
if (wantScaler) {
_cursor->setScaler(_currentState.scalerIndex, _currentState.scaleFactor);
@@ -909,18 +949,40 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
#endif
}
+ if (mask) {
+ if (!_cursorMask) {
+ maskFormat = _defaultFormatAlpha;
+ _cursorMask = createSurface(maskFormat, true, wantScaler);
+ assert(_cursorMask);
+
+ updateLinearFiltering();
+
+#ifdef USE_SCALERS
+ if (wantScaler) {
+ _cursorMask->setScaler(_currentState.scalerIndex, _currentState.scaleFactor);
+ }
+#endif
+ }
+ } else {
+ delete _cursorMask;
+ _cursorMask = nullptr;
+ }
+
Common::Point topLeftCoord(0, 0);
+ Common::Point cursorSurfaceSize(w, h);
// If the cursor is scalable, add a 1-texel transparent border.
// This ensures that linear filtering falloff from the edge pixels has room to completely fade out instead of
// being cut off at half-way. Could use border clamp too, but GLES2 doesn't support that.
if (!_cursorDontScale) {
topLeftCoord = Common::Point(1, 1);
- _cursor->allocate(w + 2, h + 2);
- } else {
- _cursor->allocate(w, h);
+ cursorSurfaceSize += Common::Point(2, 2);
}
+ _cursor->allocate(cursorSurfaceSize.x, cursorSurfaceSize.y);
+ if (_cursorMask)
+ _cursorMask->allocate(cursorSurfaceSize.x, cursorSurfaceSize.y);
+
_cursorHotspotX += topLeftCoord.x;
_cursorHotspotY += topLeftCoord.y;
@@ -930,6 +992,24 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
if (!_cursorDontScale)
_cursor->fill(keycolor);
_cursor->copyRectToTexture(topLeftCoord.x, topLeftCoord.y, w, h, buf, w * inputFormat.bytesPerPixel);
+
+ if (mask) {
+ // Construct a mask of opaque pixels
+ Common::Array<byte> maskBytes;
+ maskBytes.resize(cursorSurfaceSize.x * cursorSurfaceSize.y, 0);
+
+ for (uint y = 0; y < h; y++) {
+ for (uint x = 0; x < w; x++) {
+ // The cursor pixels must be masked out for anything except opaque
+ if (mask[y * w + x] == kCursorMaskOpaque)
+ maskBytes[(y + topLeftCoord.y) * cursorSurfaceSize.x + topLeftCoord.x + x] = 1;
+ }
+ }
+
+ _cursor->setMask(&maskBytes[0]);
+ } else {
+ _cursor->setMask(nullptr);
+ }
} else {
// Otherwise it is a bit more ugly because we have to handle a key
// color properly.
@@ -952,18 +1032,32 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
if (dst->format.bytesPerPixel == 2) {
if (inputFormat.bytesPerPixel == 2) {
multiplyColorWithAlpha<uint16, uint16>((const byte *)buf, topLeftPixelPtr, w, h,
- inputFormat, dst->format, srcPitch, dst->pitch, keycolor);
+ inputFormat, dst->format, srcPitch, dst->pitch, keycolor, _cursorUseKey);
} else if (inputFormat.bytesPerPixel == 4) {
multiplyColorWithAlpha<uint32, uint16>((const byte *)buf, topLeftPixelPtr, w, h,
- inputFormat, dst->format, srcPitch, dst->pitch, keycolor);
+ inputFormat, dst->format, srcPitch, dst->pitch, keycolor, _cursorUseKey);
}
- } else {
+ } else if (dst->format.bytesPerPixel == 4) {
if (inputFormat.bytesPerPixel == 2) {
multiplyColorWithAlpha<uint16, uint32>((const byte *)buf, topLeftPixelPtr, w, h,
- inputFormat, dst->format, srcPitch, dst->pitch, keycolor);
+ inputFormat, dst->format, srcPitch, dst->pitch, keycolor, _cursorUseKey);
} else if (inputFormat.bytesPerPixel == 4) {
multiplyColorWithAlpha<uint32, uint32>((const byte *)buf, topLeftPixelPtr, w, h,
- inputFormat, dst->format, srcPitch, dst->pitch, keycolor);
+ inputFormat, dst->format, srcPitch, dst->pitch, keycolor, _cursorUseKey);
+ }
+ }
+
+ // Replace all non-opaque pixels with black pixels
+ if (mask) {
+ Graphics::Surface *cursorSurface = _cursor->getSurface();
+
+ for (uint x = 0; x < w; x++) {
+ for (uint y = 0; y < h; y++) {
+ uint8 maskByte = mask[y * w + x];
+
+ if (maskByte != kCursorMaskOpaque)
+ cursorSurface->setPixel(x + topLeftCoord.x, y + topLeftCoord.y, 0);
+ }
}
}
@@ -971,6 +1065,54 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
_cursor->flagDirty();
}
+ if (_cursorMask && mask) {
+ // Generate the multiply+invert texture.
+ // We're generating this for a blend mode where source factor is ONE_MINUS_DST_COLOR and dest factor is ONE_MINUS_SRC_ALPHA
+ // In other words, positive RGB channel values will add inverted destination pixels, positive alpha values will modulate
+ // RGB+Alpha = Inverted Alpha Only = Black 0 = No change
+
+ Graphics::Surface *cursorSurface = _cursor->getSurface();
+ Graphics::Surface *maskSurface = _cursorMask->getSurface();
+ maskFormat = _cursorMask->getFormat();
+
+ const Graphics::PixelFormat cursorFormat = cursorSurface->format;
+
+ bool haveXorPixels = false;
+
+ _cursorMask->fill(0);
+ for (uint x = 0; x < w; x++) {
+ for (uint y = 0; y < h; y++) {
+ // See the description of renderCursor for an explanation of why this works the way it does.
+
+ uint8 maskOpacity = 0xff;
+
+ if (inputFormat.bytesPerPixel != 1) {
+ uint32 cursorPixel = cursorSurface->getPixel(x + topLeftCoord.x, y + topLeftCoord.y);
+
+ uint8 r, g, b;
+ cursorFormat.colorToARGB(cursorPixel, maskOpacity, r, g, b);
+ }
+
+ uint8 maskInversionAdd = 0;
+
+ uint8 maskByte = mask[y * w + x];
+ if (maskByte == kCursorMaskTransparent)
+ maskOpacity = 0;
+
+ if (maskByte == kCursorMaskInvert) {
+ maskOpacity = 0xff;
+ maskInversionAdd = 0xff;
+ haveXorPixels = true;
+ }
+
+ uint32 encodedMaskPixel = maskFormat.ARGBToColor(maskOpacity, maskInversionAdd, maskInversionAdd, maskInversionAdd);
+ maskSurface->setPixel(x + topLeftCoord.x, y + topLeftCoord.y, encodedMaskPixel);
+ }
+ }
+
+ _cursorMask->flagDirty();
+ }
+
// In case we actually use a palette set that up properly.
if (inputFormat.bytesPerPixel == 1) {
updateCursorPalette();
@@ -1307,7 +1449,7 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
OpenGLContext.reset();
}
-Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &format, bool wantAlpha, bool wantScaler) {
+Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &format, bool wantAlpha, bool wantScaler, bool wantMask) {
GLenum glIntFormat, glFormat, glType;
#ifdef USE_SCALERS
@@ -1327,7 +1469,7 @@ Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &forma
if (format.bytesPerPixel == 1) {
#if !USE_FORCED_GLES
- if (TextureCLUT8GPU::isSupportedByContext()) {
+ if (TextureCLUT8GPU::isSupportedByContext() && !wantMask) {
return new TextureCLUT8GPU();
}
#endif
@@ -1511,7 +1653,8 @@ void OpenGLGraphicsManager::updateCursorPalette() {
_cursor->setPalette(0, 256, _gamePalette);
}
- _cursor->setColorKey(_cursorKeyColor);
+ if (_cursorUseKey)
+ _cursor->setColorKey(_cursorKeyColor);
}
void OpenGLGraphicsManager::recalculateCursorScaling() {
@@ -1557,6 +1700,10 @@ void OpenGLGraphicsManager::updateLinearFiltering() {
_cursor->enableLinearFiltering(_currentState.filtering);
}
+ if (_cursorMask) {
+ _cursorMask->enableLinearFiltering(_currentState.filtering);
+ }
+
// The overlay UI should also obey the filtering choice (managed via the Filter Graphics checkbox in Graphics Tab).
// Thus, when overlay filtering is disabled, scaling in OPENGL is done with GL_NEAREST (nearest neighbor scaling).
// It may look crude, but it should be crispier and it's left to user choice to enable filtering.
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 4cd3c1f45f7..47b6c6a62df 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -119,7 +119,7 @@ public:
void clearOverlay() override;
void grabOverlay(Graphics::Surface &surface) const override;
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) override;
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) override;
void setCursorPalette(const byte *colors, uint start, uint num) override;
void displayMessageOnOSD(const Common::U32String &msg) override;
@@ -130,6 +130,8 @@ public:
void grabPalette(byte *colors, uint start, uint num) const override;
protected:
+ void renderCursor();
+
/**
* Whether an GLES or GLES2 context is active.
*/
@@ -168,7 +170,7 @@ protected:
* @param wantScaler Whether or not a software scaler should be used.
* @return A pointer to the surface or nullptr on failure.
*/
- Surface *createSurface(const Graphics::PixelFormat &format, bool wantAlpha = false, bool wantScaler = false);
+ Surface *createSurface(const Graphics::PixelFormat &format, bool wantAlpha = false, bool wantScaler = false, bool wantMask = false);
//
// Transaction support
@@ -374,6 +376,11 @@ protected:
*/
Surface *_cursor;
+ /**
+ * The rendering surface for the opacity and inversion mask (if any)
+ */
+ Surface *_cursorMask;
+
/**
* The X offset for the cursor hotspot in unscaled game coordinates.
*/
@@ -417,6 +424,11 @@ protected:
*/
uint32 _cursorKeyColor;
+ /**
+ * If true, use key color.
+ */
+ bool _cursorUseKey;
+
/**
* Whether no cursor scaling should be applied.
*/
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index 8a267ef47ea..f1adfa9079f 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -377,7 +377,8 @@ FakeTexture::FakeTexture(GLenum glIntFormat, GLenum glFormat, GLenum glType, con
: Texture(glIntFormat, glFormat, glType, format),
_fakeFormat(fakeFormat),
_rgbData(),
- _palette(nullptr) {
+ _palette(nullptr),
+ _mask(nullptr) {
if (_fakeFormat.isCLUT8()) {
_palette = new uint32[256];
memset(_palette, 0, sizeof(uint32));
@@ -386,6 +387,7 @@ FakeTexture::FakeTexture(GLenum glIntFormat, GLenum glFormat, GLenum glType, con
FakeTexture::~FakeTexture() {
delete[] _palette;
+ delete[] _mask;
_palette = nullptr;
_rgbData.free();
}
@@ -402,6 +404,22 @@ void FakeTexture::allocate(uint width, uint height) {
_rgbData.create(width, height, getFormat());
}
+void FakeTexture::setMask(const byte *mask) {
+ if (mask) {
+ const uint numPixels = _rgbData.w * _rgbData.h;
+
+ if (!_mask)
+ _mask = new byte[numPixels];
+
+ memcpy(_mask, mask, numPixels);
+ } else {
+ delete[] _mask;
+ _mask = nullptr;
+ }
+
+ flagDirty();
+}
+
void FakeTexture::setColorKey(uint colorKey) {
if (!_palette)
return;
@@ -446,6 +464,32 @@ void FakeTexture::updateGLTexture() {
Graphics::crossBlit(dst, src, outSurf->pitch, _rgbData.pitch, dirtyArea.width(), dirtyArea.height(), outSurf->format, _rgbData.format);
}
+ if (_mask) {
+ uint maskPitch = _rgbData.w;
+ uint dirtyWidth = dirtyArea.width();
+ byte destBPP = outSurf->format.bytesPerPixel;
+
+ const byte *maskRowStart = (_mask + dirtyArea.top * maskPitch + dirtyArea.left);
+ byte *dstRowStart = dst;
+
+ for (uint y = dirtyArea.top; y < static_cast<uint>(dirtyArea.bottom); y++) {
+ if (destBPP == 2) {
+ for (uint x = 0; x < dirtyWidth; x++) {
+ if (!maskRowStart[x])
+ reinterpret_cast<uint16 *>(dstRowStart)[x] = 0;
+ }
+ } else if (destBPP == 4) {
+ for (uint x = 0; x < dirtyWidth; x++) {
+ if (!maskRowStart[x])
+ reinterpret_cast<uint32 *>(dstRowStart)[x] = 0;
+ }
+ }
+
+ dstRowStart += outSurf->pitch;
+ maskRowStart += maskPitch;
+ }
+ }
+
// Do generic handling of updating the texture.
Texture::updateGLTexture();
}
diff --git a/backends/graphics/opengl/texture.h b/backends/graphics/opengl/texture.h
index 3ba19d0c1fd..815f9515220 100644
--- a/backends/graphics/opengl/texture.h
+++ b/backends/graphics/opengl/texture.h
@@ -193,6 +193,13 @@ public:
*/
virtual void allocate(uint width, uint height) = 0;
+ /**
+ * Assign a mask to the surface, where a byte value of 0 is black with 0 alpha and 1 is the normal color.
+ *
+ * @param mask The mask data.
+ */
+ virtual void setMask(const byte *mask) {}
+
/**
* Copy image data to the surface.
*
@@ -320,6 +327,7 @@ public:
~FakeTexture() override;
void allocate(uint width, uint height) override;
+ void setMask(const byte *mask) override;
Graphics::PixelFormat getFormat() const override { return _fakeFormat; }
@@ -336,6 +344,7 @@ protected:
Graphics::Surface _rgbData;
Graphics::PixelFormat _fakeFormat;
uint32 *_palette;
+ uint8 *_mask;
};
class TextureRGB555 : public FakeTexture {
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index 8f4d90be67f..a1a8f649786 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -1948,9 +1948,12 @@ void SurfaceSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, in
#pragma mark --- Mouse ---
#pragma mark -
-void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keyColor, bool dontScale, const Graphics::PixelFormat *format) {
+void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keyColor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
bool formatChanged = false;
+ if (mask)
+ warning("SurfaceSdlGraphicsManager::setMouseCursor: Masks are not supported");
+
if (format) {
#ifndef USE_RGB_COLOR
assert(format->bytesPerPixel == 1);
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h
index 5eb1e6c1f75..8078c8eb089 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.h
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h
@@ -124,7 +124,7 @@ public:
int16 getOverlayHeight() const override { return _videoMode.overlayHeight; }
int16 getOverlayWidth() const override { return _videoMode.overlayWidth; }
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override;
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override;
void setCursorPalette(const byte *colors, uint start, uint num) override;
#ifdef USE_OSD
diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 89c2b26cd8e..dd22a908e43 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -759,10 +759,13 @@ void AndroidGraphics3dManager::updateCursorScaling() {
void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
int hotspotX, int hotspotY,
uint32 keycolor, bool dontScale,
- const Graphics::PixelFormat *format) {
+ const Graphics::PixelFormat *format, const byte *mask) {
ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
keycolor, dontScale, format);
+ if (mask)
+ warning("AndroidGraphics3dManager::setMouseCursor: Masks are not supported");
+
GLTHREADCHECK;
#ifdef USE_RGB_COLOR
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 99d30046ff1..37241e1df2a 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -109,7 +109,7 @@ public:
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
int hotspotY, uint32 keycolor,
bool dontScale,
- const Graphics::PixelFormat *format) override;
+ const Graphics::PixelFormat *format, const byte *mask) override;
virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
float getHiDPIScreenFactor() const override;
diff --git a/backends/graphics3d/openglsdl/openglsdl-graphics3d.h b/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
index d8b19cde173..2100d2620f1 100644
--- a/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
+++ b/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
@@ -103,7 +103,7 @@ public:
// GraphicsManager API - Mouse
bool showMouse(bool visible) override;
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override {}
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override {}
void setCursorPalette(const byte *colors, uint start, uint num) override {}
// SdlGraphicsManager API
diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp
index 1e406c8a5ac..dfab11a165c 100644
--- a/backends/modular-backend.cpp
+++ b/backends/modular-backend.cpp
@@ -260,8 +260,8 @@ void ModularGraphicsBackend::warpMouse(int x, int y) {
_graphicsManager->warpMouse(x, y);
}
-void ModularGraphicsBackend::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
- _graphicsManager->setMouseCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
+void ModularGraphicsBackend::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ _graphicsManager->setMouseCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format, mask);
}
void ModularGraphicsBackend::setCursorPalette(const byte *colors, uint start, uint num) {
diff --git a/backends/modular-backend.h b/backends/modular-backend.h
index d22e2cc9ac8..71713a81e2e 100644
--- a/backends/modular-backend.h
+++ b/backends/modular-backend.h
@@ -115,7 +115,7 @@ public:
bool showMouse(bool visible) override final;
void warpMouse(int x, int y) override final;
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override final;
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override final;
void setCursorPalette(const byte *colors, uint start, uint num) override final;
bool lockMouse(bool lock) override final;
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 7a187229248..3094f93ef07 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -767,13 +767,16 @@ void OSystem_3DS::setCursorDelta(float deltaX, float deltaY) {
void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
int hotspotX, int hotspotY,
uint32 keycolor, bool dontScale,
- const Graphics::PixelFormat *format) {
+ const Graphics::PixelFormat *format, const byte *mask) {
_cursorScalable = !dontScale;
_cursorHotspotX = hotspotX;
_cursorHotspotY = hotspotY;
_cursorKeyColor = keycolor;
_pfCursor = !format ? Graphics::PixelFormat::createFormatCLUT8() : *format;
+ if (mask)
+ warning("OSystem_3DS::setMouseCursor: Masks are not supported");
+
if (w != (uint)_cursor.w || h != (uint)_cursor.h || _cursor.format != _pfCursor) {
_cursor.create(w, h, _pfCursor);
_cursorTexture.create(w, h, &DEFAULT_MODE);
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index 6ca25f3cc2c..fac4d88e729 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -170,7 +170,7 @@ public:
void warpMouse(int x, int y);
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
int hotspotY, uint32 keycolor, bool dontScale = false,
- const Graphics::PixelFormat *format = NULL);
+ const Graphics::PixelFormat *format = NULL, const byte *mask = NULL);
void setCursorPalette(const byte *colors, uint start, uint num);
// Transform point from touchscreen coords into gamescreen coords
diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h
index d7f91e3faef..a8b4a0ce3dd 100644
--- a/backends/platform/dc/dc.h
+++ b/backends/platform/dc/dc.h
@@ -126,7 +126,7 @@ public:
void warpMouse(int x, int y);
// Set the bitmap that's used when drawing the cursor.
- void setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask);
// Replace the specified range of cursor the palette with new colors.
void setCursorPalette(const byte *colors, uint start, uint num);
diff --git a/backends/platform/dc/display.cpp b/backends/platform/dc/display.cpp
index 1a18f522e56..e4dfc2b90de 100644
--- a/backends/platform/dc/display.cpp
+++ b/backends/platform/dc/display.cpp
@@ -295,8 +295,10 @@ void OSystem_Dreamcast::warpMouse(int x, int y)
void OSystem_Dreamcast::setMouseCursor(const void *buf, uint w, uint h,
int hotspot_x, int hotspot_y,
- uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format)
-{
+ uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ if (mask)
+ warning("OSystem_Dreamcast::setMouseCursor: Masks are not supported");
+
_ms_cur_w = w;
_ms_cur_h = h;
diff --git a/backends/platform/ds/ds-graphics.cpp b/backends/platform/ds/ds-graphics.cpp
index b875e749538..c2a09944f21 100644
--- a/backends/platform/ds/ds-graphics.cpp
+++ b/backends/platform/ds/ds-graphics.cpp
@@ -549,10 +549,13 @@ void OSystem_DS::warpMouse(int x, int y) {
_cursorPos = _screen->scaledToReal(x, y);
}
-void OSystem_DS::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void OSystem_DS::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
if (!buf || w == 0 || h == 0)
return;
+ if (mask)
+ warning("OSystem_DS::setMouseCursor: Masks are not supported");
+
Graphics::PixelFormat actualFormat = format ? *format : _pfCLUT8;
if (_cursor.w != (int16)w || _cursor.h != (int16)h || _cursor.format != actualFormat)
_cursor.create(w, h, actualFormat);
diff --git a/backends/platform/ds/osystem_ds.h b/backends/platform/ds/osystem_ds.h
index 113d76bb9f4..9430789a72b 100644
--- a/backends/platform/ds/osystem_ds.h
+++ b/backends/platform/ds/osystem_ds.h
@@ -126,7 +126,7 @@ public:
virtual bool showMouse(bool visible);
virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, u32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask);
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority);
diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h
index 55f42a886c7..da284f49be6 100644
--- a/backends/platform/ios7/ios7_osys_main.h
+++ b/backends/platform/ios7/ios7_osys_main.h
@@ -177,7 +177,7 @@ public:
bool showMouse(bool visible) override;
void warpMouse(int x, int y) override;
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override;
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override;
void setCursorPalette(const byte *colors, uint start, uint num) override;
bool pollEvent(Common::Event &event) override;
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index e4a3e5b0ce5..ab0e4d5637e 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -502,9 +502,12 @@ void OSystem_iOS7::dirtyFullOverlayScreen() {
}
}
-void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
//printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format);
+ //if (mask)
+ // printf("OSystem_iOS7::setMouseCursor: Masks are not supported");
+
const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
#if 0
printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel,
diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h
index 3b5a3291492..965baaf4c4c 100644
--- a/backends/platform/iphone/osys_main.h
+++ b/backends/platform/iphone/osys_main.h
@@ -158,7 +158,7 @@ public:
virtual bool showMouse(bool visible);
virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL);
virtual void setCursorPalette(const byte *colors, uint start, uint num);
virtual bool pollEvent(Common::Event &event);
diff --git a/backends/platform/iphone/osys_video.mm b/backends/platform/iphone/osys_video.mm
index 795755453a5..5bb567fc511 100644
--- a/backends/platform/iphone/osys_video.mm
+++ b/backends/platform/iphone/osys_video.mm
@@ -400,7 +400,7 @@ void OSystem_IPHONE::dirtyFullOverlayScreen() {
}
}
-void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
//printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format);
const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
diff --git a/backends/platform/n64/osys_n64.h b/backends/platform/n64/osys_n64.h
index f391f60daec..b05c1cf2135 100644
--- a/backends/platform/n64/osys_n64.h
+++ b/backends/platform/n64/osys_n64.h
@@ -180,7 +180,7 @@ public:
virtual bool showMouse(bool visible);
virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask);
virtual void setCursorPalette(const byte *colors, uint start, uint num);
virtual bool pollEvent(Common::Event &event);
diff --git a/backends/platform/n64/osys_n64_base.cpp b/backends/platform/n64/osys_n64_base.cpp
index 4642edd09c1..f7906f4bb31 100644
--- a/backends/platform/n64/osys_n64_base.cpp
+++ b/backends/platform/n64/osys_n64_base.cpp
@@ -766,9 +766,12 @@ void OSystem_N64::warpMouse(int x, int y) {
_dirtyOffscreen = true;
}
-void OSystem_N64::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void OSystem_N64::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
if (!w || !h) return;
+ if (mask)
+ warning("OSystem_DS::setMouseCursor: Masks are not supported");
+
_mouseHotspotX = hotspotX;
_mouseHotspotY = hotspotY;
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index c4a8103714f..e6324fe063c 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -305,8 +305,12 @@ void OSystem_PSP::warpMouse(int x, int y) {
_cursor.setXY(x, y);
}
-void OSystem_PSP::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void OSystem_PSP::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
DEBUG_ENTER_FUNC();
+
+ if (mask)
+ PSP_DEBUG_PRINT("OSystem_PSP::setMouseCursor: Masks are not supported");
+
_displayManager.waitUntilRenderFinished();
_pendingUpdate = false;
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 6054bf92654..3287420c4bc 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -114,7 +114,7 @@ public:
// Mouse related
bool showMouse(bool visible);
void warpMouse(int x, int y);
- void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask);
// Events and input
bool pollEvent(Common::Event &event);
diff --git a/backends/platform/wii/osystem.h b/backends/platform/wii/osystem.h
index d28c20f45b4..def660562b2 100644
--- a/backends/platform/wii/osystem.h
+++ b/backends/platform/wii/osystem.h
@@ -191,7 +191,7 @@ public:
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
int hotspotY, uint32 keycolor,
bool dontScale,
- const Graphics::PixelFormat *format) override;
+ const Graphics::PixelFormat *format, const byte *mask) override;
bool pollEvent(Common::Event &event) override;
uint32 getMillis(bool skipRecord = false) override;
diff --git a/backends/platform/wii/osystem_gfx.cpp b/backends/platform/wii/osystem_gfx.cpp
index dab644218ca..490bc8a0c03 100644
--- a/backends/platform/wii/osystem_gfx.cpp
+++ b/backends/platform/wii/osystem_gfx.cpp
@@ -657,7 +657,11 @@ void OSystem_Wii::warpMouse(int x, int y) {
void OSystem_Wii::setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
int hotspotY, uint32 keycolor,
bool dontScale,
- const Graphics::PixelFormat *format) {
+ const Graphics::PixelFormat *format, const byte *mask) {
+
+ if (mask)
+ printf("OSystem_Wii::setMouseCursor: Masks are not supported\n");
+
gfx_tex_format_t tex_format = GFX_TF_PALETTE_RGB5A3;
uint tw, th;
uint32 oldKeycolor = _mouseKeyColor;
diff --git a/common/system.h b/common/system.h
index 1d99f746c2b..2c39d9d1dc1 100644
--- a/common/system.h
+++ b/common/system.h
@@ -120,6 +120,25 @@ enum Type {
} // End of namespace LogMessageType
+/**
+* Pixel mask modes for cursor graphics.
+*/
+enum CursorMaskValue {
+ // Overlapped pixel is unchanged
+ kCursorMaskTransparent = 0,
+
+ // Overlapped pixel is replaced with the cursor pixel.
+ kCursorMaskOpaque = 1,
+
+ /** Fully inverts the overlapped pixel regardless of the cursor color data.
+ * Backend must support kFeatureCursorMaskInvert for this mode. */
+ kCursorMaskInvert = 2,
+
+ /** Inverts the overlapped pixel based on the cursor's color value.
+ * Backend must support kFeatureCursorMaskInvertUsingColor for this mode. */
+ kCursorMaskInvertUsingColor = 3,
+};
+
/**
* Interface for ScummVM backends.
*
@@ -386,6 +405,24 @@ public:
*/
kFeatureCursorPalette,
+ /**
+ * Backends supporting this feature allow specifying a mask for a
+ * cursor instead of a key color.
+ */
+ kFeatureCursorMask,
+
+ /**
+ * Backends supporting this feature allow cursor masks to use mode kCursorMaskInvert in mask values,
+ * which inverts the destination pixel.
+ */
+ kFeatureCursorMaskInvert,
+
+ /**
+ * Backends supporting this feature allow cursor masks to use mode kCursorMaskInvertUsingColor in the mask values,
+ * which inverts the destination pixel based on the color value of the cursor.
+ */
+ kFeatureCursorMaskInvertUsingColor,
+
/**
* A backend has this feature if its overlay pixel format has an alpha
* channel which offers at least 3-4 bits of accuracy (as opposed to
@@ -1312,11 +1349,13 @@ public:
* @param keycolor Transparency color value. This should not exceed the maximum color value of the specified format.
* In case it does, the behavior is undefined. The backend might just error out or simply ignore the
* value. (The SDL backend will just assert to prevent abuse of this).
+ * This parameter does nothing if a mask is provided.
* @param dontScale Whether the cursor should never be scaled. An exception is high ppi displays, where the cursor
* might be too small to notice otherwise, these are allowed to scale the cursor anyway.
* @param format Pointer to the pixel format that the cursor graphic uses (0 means CLUT8).
+ * @param mask A mask containing values from the CursorMaskValue enum for each cursor pixel.
*/
- virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = nullptr) = 0;
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = nullptr, const byte *mask = nullptr) = 0;
/**
* Replace the specified range of cursor palette with new colors.
diff --git a/graphics/cursor.h b/graphics/cursor.h
index 5686d0539ab..e2911c774d1 100644
--- a/graphics/cursor.h
+++ b/graphics/cursor.h
@@ -58,6 +58,9 @@ public:
/** Return the cursor's surface. */
virtual const byte *getSurface() const = 0;
+ /** Return the cursor's mask, if it has one. */
+ virtual const byte *getMask() const { return nullptr; }
+
/** Return the cursor's palette in RGB format. */
virtual const byte *getPalette() const = 0;
/** Return the starting index of the palette. */
diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp
index d9eff1bf4fc..3853132595c 100644
--- a/graphics/cursorman.cpp
+++ b/graphics/cursorman.cpp
@@ -58,13 +58,16 @@ bool CursorManager::showMouse(bool visible) {
return g_system->showMouse(visible);
}
-void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
- Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
+void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ if (!g_system->hasFeature(OSystem::kFeatureCursorMask))
+ mask = nullptr;
+
+ Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format, mask);
cur->_visible = isVisible();
_cursorStack.push(cur);
- g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
+ g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format, mask);
}
void CursorManager::popCursor() {
@@ -76,7 +79,7 @@ void CursorManager::popCursor() {
if (!_cursorStack.empty()) {
cur = _cursorStack.top();
- g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format);
+ g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format, cur->_mask);
} else {
g_system->setMouseCursor(nullptr, 0, 0, 0, 0, 0);
}
@@ -102,10 +105,12 @@ void CursorManager::popAllCursors() {
g_system->showMouse(isVisible());
}
-void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ if (!g_system->hasFeature(OSystem::kFeatureCursorMask))
+ mask = nullptr;
if (_cursorStack.empty()) {
- pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
+ pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format, mask);
return;
}
@@ -130,6 +135,14 @@ void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX,
if (buf && cur->_data)
memcpy(cur->_data, buf, size);
+ delete[] cur->_mask;
+ cur->_mask = nullptr;
+
+ if (mask) {
+ cur->_mask = new byte[w * h];
+ memcpy(cur->_mask, mask, w * h);
+ }
+
cur->_width = w;
cur->_height = h;
cur->_hotspotX = hotspotX;
@@ -143,12 +156,12 @@ void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX,
cur->_format = Graphics::PixelFormat::createFormatCLUT8();
#endif
- g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
+ g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format, mask);
}
void CursorManager::replaceCursor(const Graphics::Cursor *cursor) {
replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
- cursor->getHotspotY(), cursor->getKeyColor());
+ cursor->getHotspotY(), cursor->getKeyColor(), false, nullptr, cursor->getMask());
if (cursor->getPalette())
replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
@@ -241,7 +254,7 @@ void CursorManager::lock(bool locked) {
_locked = locked;
}
-CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
#ifdef USE_RGB_COLOR
if (!format)
_format = Graphics::PixelFormat::createFormatCLUT8();
@@ -258,6 +271,12 @@ CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, in
_data = new byte[_size];
if (data && _data)
memcpy(_data, data, _size);
+ if (mask) {
+ _mask = new byte[w * h];
+ if (_mask)
+ memcpy(_mask, mask, w * h);
+ } else
+ _mask = nullptr;
_width = w;
_height = h;
_hotspotX = hotspotX;
@@ -268,6 +287,7 @@ CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, in
CursorManager::Cursor::~Cursor() {
delete[] _data;
+ delete[] _mask;
}
CursorManager::Palette::Palette(const byte *colors, uint start, uint num) {
diff --git a/graphics/cursorman.h b/graphics/cursorman.h
index de0fe2fbeb8..988c79dac64 100644
--- a/graphics/cursorman.h
+++ b/graphics/cursorman.h
@@ -68,22 +68,25 @@ public:
* can be safely freed afterwards.
*
* @param buf New cursor data.
+ * @param mask New cursor data.
* @param w Width.
* @param h Height.
* @param hotspotX Hotspot X coordinate.
* @param hotspotY Hotspot Y coordinate.
* @param keycolor Color value for the transparent color. This cannot exceed
* the maximum color value as defined by format.
+ * Does nothing if mask is set.
* @param dontScale Whether the cursor should never be scaled. An exception are high PPI displays, where the cursor
* would be too small to notice otherwise. These are allowed to scale the cursor anyway.
* @param format Pointer to the pixel format that the cursor graphic uses.
* CLUT8 will be used if this is null or not specified.
+ * @param mask Optional pointer to cursor mask containing values from the CursorMaskValue enum.
*
* @note It is acceptable for the buffer to be a null pointer. It is sometimes
* useful to push a "dummy" cursor and modify it later. The
* cursor will be added to the stack, but not to the backend.
*/
- void pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
+ void pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL);
/**
* Pop a cursor from the stack, and restore the previous one to the
@@ -100,18 +103,21 @@ public:
* more optimized way of popping the old cursor before pushing the new one.
*
* @param buf New cursor data.
+ * @param mask New cursor mask data.
* @param w Width.
* @param h Height.
* @param hotspotX Hotspot X coordinate.
* @param hotspotY Hotspot Y coordinate.
* @param keycolor Color value for the transparent color. This cannot exceed
* the maximum color value as defined by format.
+ * Does nothing if mask is set.
* @param dontScale Whether the cursor should never be scaled. An exception are high PPI displays, where the cursor
* would be too small to notice otherwise. These are allowed to scale the cursor anyway.
* @param format Pointer to the pixel format that the cursor graphic uses,
* CLUT8 will be used if this is null or not specified.
+ * @param mask Optional pointer to cursor mask containing values from the CursorMaskValue enum.
*/
- void replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
+ void replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = nullptr, const byte *mask = nullptr);
/**
* Replace the current cursor on the stack.
@@ -211,6 +217,7 @@ private:
struct Cursor {
byte *_data;
+ byte *_mask;
bool _visible;
uint _width;
uint _height;
@@ -223,9 +230,9 @@ private:
uint _size;
// _format set to default by Graphics::PixelFormat default constructor
- Cursor() : _data(0), _visible(false), _width(0), _height(0), _hotspotX(0), _hotspotY(0), _keycolor(0), _dontScale(false), _size(0) {}
+ Cursor() : _data(0), _mask(0), _visible(false), _width(0), _height(0), _hotspotX(0), _hotspotY(0), _keycolor(0), _dontScale(false), _size(0) {}
- Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
+ Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask);
~Cursor();
};
diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp
index 677ecf2a650..30ab3e67544 100644
--- a/graphics/wincursor.cpp
+++ b/graphics/wincursor.cpp
@@ -21,6 +21,7 @@
#include "common/ptr.h"
#include "common/stream.h"
+#include "common/system.h"
#include "common/textconsole.h"
#include "graphics/wincursor.h"
@@ -45,6 +46,7 @@ public:
byte getKeyColor() const override;
const byte *getSurface() const override { return _surface; }
+ const byte *getMask() const override { return _mask; }
const byte *getPalette() const override { return _palette; }
byte getPaletteStartIndex() const override { return 0; }
@@ -55,6 +57,7 @@ public:
private:
byte *_surface;
+ byte *_mask;
byte _palette[256 * 3];
uint16 _width; ///< The cursor's width.
@@ -72,7 +75,8 @@ WinCursor::WinCursor() {
_height = 0;
_hotspotX = 0;
_hotspotY = 0;
- _surface = 0;
+ _surface = nullptr;
+ _mask = nullptr;
_keyColor = 0;
memset(_palette, 0, 256 * 3);
}
@@ -104,6 +108,9 @@ byte WinCursor::getKeyColor() const {
bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
clear();
+ const bool supportOpacity = g_system->hasFeature(OSystem::kFeatureCursorMask);
+ const bool supportInvert = g_system->hasFeature(OSystem::kFeatureCursorMaskInvert);
+
_hotspotX = stream.readUint16LE();
_hotspotY = stream.readUint16LE();
@@ -161,6 +168,8 @@ bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
// Parse the XOR map
const byte *src = initialSource;
_surface = new byte[_width * _height];
+ if (supportOpacity)
+ _mask = new byte[_width * _height];
byte *dest = _surface + _width * (_height - 1);
uint32 imagePitch = _width * bitsPerPixel / 8;
@@ -223,9 +232,29 @@ bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
src += andWidth * (_height - 1);
for (uint32 y = 0; y < _height; y++) {
- for (uint32 x = 0; x < _width; x++)
- if (src[x / 8] & (1 << (7 - x % 8)))
- _surface[y * _width + x] = _keyColor;
+ for (uint32 x = 0; x < _width; x++) {
+ byte &surfaceByte = _surface[y * _width + x];
+ if (src[x / 8] & (1 << (7 - x % 8))) {
+ if (_mask) {
+ byte &maskByte = _mask[y * _width + x];
+ if (surfaceByte == 0) {
+ // Transparent
+ maskByte = 0;
+ } else {
+ // Inverted, if the backend supports invert then emit an inverted pixel, otherwise opaque
+ maskByte = supportInvert ? 2 : 1;
+ }
+ } else {
+ // Don't support mask or invert, leave this as opaque if it's XOR so it's visible
+ if (surfaceByte == 0)
+ surfaceByte = _keyColor;
+ }
+ } else {
+ // Opaque pixel
+ if (_mask)
+ _mask[y * _width + x] = 1;
+ }
+ }
src -= andWidth;
}
@@ -235,7 +264,8 @@ bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
}
void WinCursor::clear() {
- delete[] _surface; _surface = 0;
+ delete[] _surface; _surface = nullptr;
+ delete[] _mask; _mask = nullptr;
}
WinCursorGroup::WinCursorGroup() {
Commit: 866e459992006d19b049666a616a447d1a46f4e3
https://github.com/scummvm/scummvm/commit/866e459992006d19b049666a616a447d1a46f4e3
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
TESTBED: Add tests for masked and inverted cursors.
Changed paths:
engines/testbed/graphics.cpp
engines/testbed/graphics.h
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index 83aa2915cea..b66b3103a68 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -56,6 +56,7 @@ GFXTestSuite::GFXTestSuite() {
// Mouse Layer tests (Palettes and movements)
addTest("PalettizedCursors", &GFXtests::palettizedCursors);
+ addTest("MaskedCursors", &GFXtests::maskedCursors);
addTest("MouseMovements", &GFXtests::mouseMovements);
// FIXME: Scaled cursor crash with odd dimmensions
addTest("ScaledCursors", &GFXtests::scaledCursors);
@@ -721,6 +722,223 @@ TestExitStatus GFXtests::palettizedCursors() {
return passed;
}
+/**
+ * Tests Masked cursors.
+ * Method: Create a cursor with a transparent, mask, inverted, and color-inverted areas, it should behave properly over colored areas. Once you click test terminates
+ */
+TestExitStatus GFXtests::maskedCursors() {
+
+ Testsuite::clearScreen();
+ Common::String info = "Masked cursors test. If masked cursors are enabled, you should see a cursor with 4 sections:\n"
+ "T for transparent, O for opaque, I for inverted, C for colorized inverted.\n"
+ "If the I or C letters are absent, then that type of masking is unsupported";
+
+ if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) {
+ Testsuite::logPrintf("Info! Skipping test : Masked Cursors\n");
+ return kTestSkipped;
+ }
+
+ TestExitStatus passed = kTestPassed;
+ bool isFeaturePresent = g_system->hasFeature(OSystem::kFeatureCursorMask);
+
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ const byte cursorLeftColData[] = {
+ 1, 1, 1,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 0, 0,
+
+ 0, 1, 0,
+ 1, 0, 1,
+ 0, 1, 0,
+ 0, 0, 0,
+
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 0, 0,
+
+ 0, 1, 1,
+ 1, 0, 0,
+ 0, 1, 1,
+ 0, 0, 0,
+ };
+
+ byte cursorData[16 * 16];
+ byte maskData[16 * 16];
+
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 16; x++) {
+ // Fill cursor and mask with white transparent
+ cursorData[y * 16 + x] = 3;
+ maskData[y * 16 + x] = kCursorMaskTransparent;
+ }
+ }
+
+ for (int y = 12; y < 16; y++) {
+ for (int x = 5; x < 16; x++) {
+ // Fill color mask part with red
+ cursorData[y * 16 + x] = 2;
+ }
+ }
+
+ // Fill T O I C graphic
+ for (int y = 0; y < 16; y++)
+ for (int x = 0; x < 3; x++)
+ if (cursorLeftColData[y * 3 + x])
+ maskData[y * 16 + x + 1] = kCursorMaskOpaque;
+
+ // Fill middle column
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 5; x++) {
+ maskData[y * 16 + x + 5] = kCursorMaskOpaque;
+ }
+ }
+
+ bool haveInverted = g_system->hasFeature(OSystem::kFeatureCursorMaskInvert);
+ bool haveInvertedColor = g_system->hasFeature(OSystem::kFeatureCursorMaskInvertUsingColor);
+
+ // Fill middle column
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 4; x++) {
+ maskData[y * 16 + x + 5] = kCursorMaskOpaque;
+ }
+ }
+
+ for (int x = 0; x < 5; x++) {
+ for (int y = 0; y < 4; y++) {
+ maskData[(y + 0) * 16 + x + 11] = kCursorMaskTransparent;
+ maskData[(y + 4) * 16 + x + 11] = kCursorMaskOpaque;
+ maskData[(y + 8) * 16 + x + 11] = kCursorMaskInvert;
+ maskData[(y + 12) * 16 + x + 11] = kCursorMaskInvertUsingColor;
+ }
+ }
+
+ // Mask out unsupported types
+ if (!haveInverted) {
+ for (int y = 8; y < 12; y++)
+ for (int x = 0; x < 16; x++)
+ maskData[y * 16 + x] = kCursorMaskTransparent;
+ }
+
+ if (!haveInvertedColor) {
+ for (int y = 12; y < 16; y++)
+ for (int x = 0; x < 16; x++)
+ maskData[y * 16 + x] = kCursorMaskTransparent;
+ }
+
+ byte oldPalette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(oldPalette, 0, 256);
+
+ byte newPalette[] = {0, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255};
+
+ g_system->getPaletteManager()->setPalette(newPalette, 0, 4);
+
+ CursorMan.replaceCursor(cursorData, 16, 16, 1, 1, 0, false, nullptr, maskData);
+ CursorMan.showMouse(true);
+
+ bool waitingForClick = true;
+ while (waitingForClick) {
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN) {
+ waitingForClick = false;
+ }
+ }
+
+ g_system->delayMillis(10);
+ g_system->updateScreen();
+ }
+
+ g_system->getPaletteManager()->setPalette(oldPalette, 0, 256);
+
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'T' transparent?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'O' opaque?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+
+ if (!haveInverted) {
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'I' inverted?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+ }
+
+ if (!haveInvertedColor) {
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+ }
+
+#ifdef USE_RGB_COLOR
+ Common::String rgbInfo = "Try again with a cursor using RGB data?";
+
+ if (!Testsuite::handleInteractiveInput(rgbInfo, "OK", "Skip", kOptionRight)) {
+ g_system->delayMillis(500);
+
+ Graphics::PixelFormat rgbaFormat = Graphics::createPixelFormat<8888>();
+
+ uint32 rgbaCursorData[16 * 16];
+ for (uint i = 0; i < 16 * 16; i++) {
+ byte colorByte = cursorData[i];
+ byte r = newPalette[colorByte * 3 + 0];
+ byte g = newPalette[colorByte * 3 + 1];
+ byte b = newPalette[colorByte * 3 + 2];
+
+ rgbaCursorData[i] = rgbaFormat.ARGBToColor(255, r, g, b);
+ }
+
+ CursorMan.replaceCursor(rgbaCursorData, 16, 16, 1, 1, 0, false, &rgbaFormat, maskData);
+
+ waitingForClick = true;
+ while (waitingForClick) {
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN) {
+ waitingForClick = false;
+ }
+ }
+
+ g_system->delayMillis(10);
+ g_system->updateScreen();
+ }
+
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'T' transparent?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'O' opaque?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+
+ if (!haveInverted) {
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'I' inverted?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+ }
+
+ if (!haveInvertedColor) {
+ if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
+ return kTestFailed;
+ }
+ }
+ }
+#endif
+
+ CursorMan.showMouse(false);
+ } else {
+ Testsuite::displayMessage("feature not supported");
+ }
+
+ g_system->delayMillis(500);
+
+ return passed;
+}
+
/**
* Tests automated mouse movements. "Warp" functionality provided by the backend.
*/
diff --git a/engines/testbed/graphics.h b/engines/testbed/graphics.h
index e46873f4ea6..d7b2525c589 100644
--- a/engines/testbed/graphics.h
+++ b/engines/testbed/graphics.h
@@ -45,6 +45,7 @@ TestExitStatus fullScreenMode();
TestExitStatus filteringMode();
TestExitStatus aspectRatio();
TestExitStatus palettizedCursors();
+TestExitStatus maskedCursors();
TestExitStatus mouseMovements();
TestExitStatus copyRectToScreen();
TestExitStatus iconifyWindow();
Commit: 76d84718e264a83d6b632b27d1908a42b94d7e5c
https://github.com/scummvm/scummvm/commit/76d84718e264a83d6b632b27d1908a42b94d7e5c
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
GRAPHICS: Corrected semantics for MacOS cursors
Changed paths:
common/system.h
engines/testbed/graphics.cpp
diff --git a/common/system.h b/common/system.h
index 2c39d9d1dc1..76736c53236 100644
--- a/common/system.h
+++ b/common/system.h
@@ -134,9 +134,8 @@ enum CursorMaskValue {
* Backend must support kFeatureCursorMaskInvert for this mode. */
kCursorMaskInvert = 2,
- /** Inverts the overlapped pixel based on the cursor's color value.
- * Backend must support kFeatureCursorMaskInvertUsingColor for this mode. */
- kCursorMaskInvertUsingColor = 3,
+ /** kFeatureCursorMaskInvertUsingColor for this mode. */
+ kCursorMaskPaletteXorColorXnor = 3,
};
/**
@@ -418,10 +417,11 @@ public:
kFeatureCursorMaskInvert,
/**
- * Backends supporting this feature allow cursor masks to use mode kCursorMaskInvertUsingColor in the mask values,
- * which inverts the destination pixel based on the color value of the cursor.
+ * Backends supporting this feature allow cursor masks to use mode kCursorMaskPaletteXorColorXnor in the mask values,
+ * which uses (Color XOR Destination) for CLUT8 blending and (Color XNOR Destination) for RGB blending. This is
+ * equivalent to Classic MacOS behavior for pixel colors other than black and white.
*/
- kFeatureCursorMaskInvertUsingColor,
+ kFeatureCursorMaskPaletteXorColorXnor,
/**
* A backend has this feature if its overlay pixel format has an alpha
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index b66b3103a68..5c633fe688f 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -798,7 +798,7 @@ TestExitStatus GFXtests::maskedCursors() {
}
bool haveInverted = g_system->hasFeature(OSystem::kFeatureCursorMaskInvert);
- bool haveInvertedColor = g_system->hasFeature(OSystem::kFeatureCursorMaskInvertUsingColor);
+ bool haveColorXorBlend = g_system->hasFeature(OSystem::kFeatureCursorMaskPaletteXorColorXnor);
// Fill middle column
for (int y = 0; y < 16; y++) {
@@ -812,7 +812,7 @@ TestExitStatus GFXtests::maskedCursors() {
maskData[(y + 0) * 16 + x + 11] = kCursorMaskTransparent;
maskData[(y + 4) * 16 + x + 11] = kCursorMaskOpaque;
maskData[(y + 8) * 16 + x + 11] = kCursorMaskInvert;
- maskData[(y + 12) * 16 + x + 11] = kCursorMaskInvertUsingColor;
+ maskData[(y + 12) * 16 + x + 11] = kCursorMaskPaletteXorColorXnor;
}
}
@@ -823,7 +823,7 @@ TestExitStatus GFXtests::maskedCursors() {
maskData[y * 16 + x] = kCursorMaskTransparent;
}
- if (!haveInvertedColor) {
+ if (!haveColorXorBlend) {
for (int y = 12; y < 16; y++)
for (int x = 0; x < 16; x++)
maskData[y * 16 + x] = kCursorMaskTransparent;
@@ -868,7 +868,7 @@ TestExitStatus GFXtests::maskedCursors() {
}
}
- if (!haveInvertedColor) {
+ if (!haveColorXorBlend) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
@@ -921,7 +921,7 @@ TestExitStatus GFXtests::maskedCursors() {
}
}
- if (!haveInvertedColor) {
+ if (!haveColorXorBlend) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
Commit: 0a32f23bd6b80d8bf7c74fd629160a55c954cbbe
https://github.com/scummvm/scummvm/commit/0a32f23bd6b80d8bf7c74fd629160a55c954cbbe
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
BACKENDS: ANDROID: Update log message for setMouseCursor
Changed paths:
backends/graphics3d/android/android-graphics3d.cpp
diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index dd22a908e43..3648fa9acc4 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -760,8 +760,8 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
int hotspotX, int hotspotY,
uint32 keycolor, bool dontScale,
const Graphics::PixelFormat *format, const byte *mask) {
- ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
- keycolor, dontScale, format);
+ ENTER("%p, %u, %u, %d, %d, %u, %d, %p, %p", buf, w, h, hotspotX, hotspotY,
+ keycolor, dontScale, format, mask);
if (mask)
warning("AndroidGraphics3dManager::setMouseCursor: Masks are not supported");
Commit: 607e49756c12e120d0c73d6aa8b4db4b6e06e287
https://github.com/scummvm/scummvm/commit/607e49756c12e120d0c73d6aa8b4db4b6e06e287
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
BACKENDS: IOS7: Enable log message for unsupported cursor masks
Changed paths:
backends/platform/ios7/ios7_osys_video.mm
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index ab0e4d5637e..4e4d452b50d 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -505,8 +505,8 @@ void OSystem_iOS7::dirtyFullOverlayScreen() {
void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
//printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format);
- //if (mask)
- // printf("OSystem_iOS7::setMouseCursor: Masks are not supported");
+ if (mask)
+ printf("OSystem_iOS7::setMouseCursor: Masks are not supported");
const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
#if 0
Commit: 774066714ac885ef881b67118405d82d55615c0f
https://github.com/scummvm/scummvm/commit/774066714ac885ef881b67118405d82d55615c0f
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
BACKENDS: N64: Fix wrong error message
Changed paths:
backends/platform/n64/osys_n64_base.cpp
diff --git a/backends/platform/n64/osys_n64_base.cpp b/backends/platform/n64/osys_n64_base.cpp
index f7906f4bb31..8cbf7cae9e3 100644
--- a/backends/platform/n64/osys_n64_base.cpp
+++ b/backends/platform/n64/osys_n64_base.cpp
@@ -770,7 +770,7 @@ void OSystem_N64::setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
if (!w || !h) return;
if (mask)
- warning("OSystem_DS::setMouseCursor: Masks are not supported");
+ warning("OSystem_N64::setMouseCursor: Masks are not supported");
_mouseHotspotX = hotspotX;
_mouseHotspotY = hotspotY;
Commit: 6af0bd2a95ea3d2fd5dee84c3549d73a01e5d6fb
https://github.com/scummvm/scummvm/commit/6af0bd2a95ea3d2fd5dee84c3549d73a01e5d6fb
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
COMMON: Correct cursor mask comments.
Changed paths:
common/system.h
diff --git a/common/system.h b/common/system.h
index 76736c53236..79abf853c81 100644
--- a/common/system.h
+++ b/common/system.h
@@ -124,17 +124,20 @@ enum Type {
* Pixel mask modes for cursor graphics.
*/
enum CursorMaskValue {
- // Overlapped pixel is unchanged
+ /** Overlapped pixel is unchanged */
kCursorMaskTransparent = 0,
- // Overlapped pixel is replaced with the cursor pixel.
+ /** Overlapped pixel is replaced with the cursor pixel. */
kCursorMaskOpaque = 1,
/** Fully inverts the overlapped pixel regardless of the cursor color data.
* Backend must support kFeatureCursorMaskInvert for this mode. */
kCursorMaskInvert = 2,
- /** kFeatureCursorMaskInvertUsingColor for this mode. */
+ /** Blends with mode (Destination AND Mask) XOR Color in palette modes, or
+ * (Destination AND Mask) XOR (NOT Color) in RGB modes, which is equivalent to
+ * Classic MacOS behavior for pixel colors other than black and white.
+ * Backend must support kFeatureCursorMaskPaletteXorColorXnor for this mode. */
kCursorMaskPaletteXorColorXnor = 3,
};
Commit: d7303bd0065aaa94439c9dc1338d1932937f5294
https://github.com/scummvm/scummvm/commit/d7303bd0065aaa94439c9dc1338d1932937f5294
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
GRAPHICS: Delete duplicated (and incorrect) parameter description.
Changed paths:
graphics/cursorman.h
diff --git a/graphics/cursorman.h b/graphics/cursorman.h
index 988c79dac64..806ff61d3fe 100644
--- a/graphics/cursorman.h
+++ b/graphics/cursorman.h
@@ -68,7 +68,6 @@ public:
* can be safely freed afterwards.
*
* @param buf New cursor data.
- * @param mask New cursor data.
* @param w Width.
* @param h Height.
* @param hotspotX Hotspot X coordinate.
Commit: 325674ace7774333b191327cba40bd3878d37374
https://github.com/scummvm/scummvm/commit/325674ace7774333b191327cba40bd3878d37374
Author: elasota (ejlasota at gmail.com)
Date: 2023-02-19T23:51:09+01:00
Commit Message:
GRAPHICS: Add masked cursor support to SurfaceSdl, fix tests
Changed paths:
backends/graphics/surfacesdl/surfacesdl-graphics.cpp
engines/testbed/graphics.cpp
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index a1a8f649786..fdb9076177e 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -137,8 +137,8 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
_transactionMode(kTransactionNone),
_scalerPlugins(ScalerMan.getPlugins()), _scalerPlugin(nullptr), _scaler(nullptr),
_needRestoreAfterOverlay(false), _isInOverlayPalette(false), _isDoubleBuf(false), _prevForceRedraw(false), _numPrevDirtyRects(0),
- _prevCursorNeedsRedraw(false)
-{
+ _prevCursorNeedsRedraw(false),
+ _mouseKeyColor(0) {
// allocate palette storage
_currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
@@ -220,7 +220,8 @@ bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
(f == OSystem::kFeatureVSync) ||
#endif
(f == OSystem::kFeatureCursorPalette) ||
- (f == OSystem::kFeatureIconifyWindow);
+ (f == OSystem::kFeatureIconifyWindow) ||
+ (f == OSystem::kFeatureCursorMask);
}
void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
@@ -1949,10 +1950,102 @@ void SurfaceSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, in
#pragma mark -
void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keyColor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
- bool formatChanged = false;
- if (mask)
- warning("SurfaceSdlGraphicsManager::setMouseCursor: Masks are not supported");
+ if (mask && (!format || format->bytesPerPixel == 1)) {
+ // 8-bit masked cursor, SurfaceSdl has no alpha mask support so we must convert this to color key
+ const byte *bufBytes = static_cast<const byte *>(buf);
+
+ uint numPixelUsingColor[256];
+ for (uint i = 0; i < 256; i++)
+ numPixelUsingColor[i] = 0;
+
+ uint numPixels = w * h;
+
+ for (uint i = 0; i < numPixels; i++) {
+ if (mask[i] == kCursorMaskOpaque)
+ numPixelUsingColor[bufBytes[i]]++;
+ }
+
+ uint bestColorNumPixels = 0xffffffffu;
+ uint bestKey = 0;
+ for (uint i = 0; i < 256; i++) {
+ if (numPixelUsingColor[i] < bestColorNumPixels) {
+ bestColorNumPixels = numPixelUsingColor[i];
+ bestKey = i;
+ if (bestColorNumPixels == 0)
+ break;
+ }
+ }
+
+ if (bestColorNumPixels != 0)
+ warning("SurfaceSdlGraphicsManager::setMouseCursor: A mask was specified for an 8-bit cursor but the cursor couldn't be converted to color key");
+
+ Common::Array<byte> maskedImage;
+ maskedImage.resize(w * h);
+ for (uint i = 0; i < numPixels; i++) {
+ if (mask[i] == kCursorMaskOpaque)
+ maskedImage[i] = bufBytes[i];
+ else
+ maskedImage[i] = static_cast<byte>(bestKey);
+ }
+
+ setMouseCursor(&maskedImage[0], w, h, hotspotX, hotspotY, bestKey, dontScale, format, nullptr);
+ return;
+ }
+
+#ifdef USE_RGB_COLOR
+ if (mask && format && format->bytesPerPixel > 1) {
+ const uint numPixels = w * h;
+ const uint inBPP = format->bytesPerPixel;
+
+ Graphics::PixelFormat formatWithAlpha = Graphics::createPixelFormat<8888>();
+
+ // Use the existing format if it already has alpha
+ if (format->aBits() > 0)
+ formatWithAlpha = *format;
+
+ const uint outBPP = format->bytesPerPixel;
+
+ Common::Array<byte> maskedImage;
+ maskedImage.resize(numPixels * outBPP);
+
+ uint32 inColor = 0;
+ byte *inColorPtr = reinterpret_cast<byte *>(&inColor);
+#ifdef SCUMM_BIG_ENDIAN
+ inColorPtr += 4 - inBPP;
+#endif
+
+ uint32 outColor = 0;
+ byte *outColorPtr = reinterpret_cast<byte *>(&outColor);
+#ifdef SCUMM_BIG_ENDIAN
+ outColorPtr += 4 - inBPP;
+#endif
+
+ for (uint i = 0; i < numPixels; i++) {
+ if (mask[i] != kCursorMaskOpaque)
+ outColor = 0;
+ else {
+ memcpy(inColorPtr, static_cast<const byte *>(buf) + i * inBPP, inBPP);
+
+ uint8 r = 0;
+ uint8 g = 0;
+ uint8 b = 0;
+ uint8 a = 0;
+ format->colorToARGB(inColor, a, r, g, b);
+ if (a == 0)
+ outColor = 0;
+ else
+ outColor = formatWithAlpha.ARGBToColor(a, r, g, b);
+ }
+ memcpy(&maskedImage[i * outBPP], outColorPtr, outBPP);
+ }
+
+ setMouseCursor(&maskedImage[0], w, h, hotspotX, hotspotY, 0, dontScale, &formatWithAlpha, nullptr);
+ return;
+ }
+#endif
+
+ bool formatChanged = false;
if (format) {
#ifndef USE_RGB_COLOR
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index 5c633fe688f..d163c59a62d 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -740,6 +740,7 @@ TestExitStatus GFXtests::maskedCursors() {
TestExitStatus passed = kTestPassed;
bool isFeaturePresent = g_system->hasFeature(OSystem::kFeatureCursorMask);
+ bool haveCursorPalettes = g_system->hasFeature(OSystem::kFeatureCursorPalette);
g_system->delayMillis(1000);
@@ -836,6 +837,9 @@ TestExitStatus GFXtests::maskedCursors() {
g_system->getPaletteManager()->setPalette(newPalette, 0, 4);
+ if (haveCursorPalettes)
+ g_system->setCursorPalette(newPalette, 0, 4);
+
CursorMan.replaceCursor(cursorData, 16, 16, 1, 1, 0, false, nullptr, maskData);
CursorMan.showMouse(true);
@@ -862,13 +866,13 @@ TestExitStatus GFXtests::maskedCursors() {
return kTestFailed;
}
- if (!haveInverted) {
+ if (haveInverted) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'I' inverted?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
}
- if (!haveColorXorBlend) {
+ if (haveColorXorBlend) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
@@ -915,13 +919,13 @@ TestExitStatus GFXtests::maskedCursors() {
return kTestFailed;
}
- if (!haveInverted) {
+ if (haveInverted) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'I' inverted?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
}
- if (!haveColorXorBlend) {
+ if (haveColorXorBlend) {
if (!Testsuite::handleInteractiveInput("Was the part of the cursor to the right of the 'C' inverted according to the color to the left of it?", "Yes", "No", kOptionLeft)) {
return kTestFailed;
}
More information about the Scummvm-git-logs
mailing list