diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index d404e560ade..ce2cb4f9682 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -113,9 +113,17 @@ void ScummEngine_v6::setCursorTransparency(int a) { size = _cursor.width * _cursor.height; - for (i = 0; i < size; i++) - if (_grabbedCursor[i] == (byte)a) - _grabbedCursor[i] = 0xFF; + if (_enableEGADithering) { + for (i = 0; i < size; i += 2) { + int st = 1 ^ ((i / (_cursor.width << 1)) & 1); + if (_grabbedCursor[i] == _egaColorMap[st][a] && _grabbedCursor[i + 1] == _egaColorMap[st ^ 1][a]) + _grabbedCursor[i] = _grabbedCursor[i + 1] = 0xFF; + } + } else { + for (i = 0; i < size; i++) + if (_grabbedCursor[i] == (byte)a) + _grabbedCursor[i] = 0xFF; + } updateCursor(); } @@ -153,43 +161,51 @@ void ScummEngine_v6::setDefaultCursor() { setCursorFromBuffer(default_v6_cursor, 16, 13, 16); } -void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) { +void ScummEngine_v6::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) { uint size; byte *dst; - int sclW = _enableEGADithering ? 2 : 1; - int sclH = _enableEGADithering ? 2 : 1; - - size = width * sclW * height * sclH * _bytesPerPixel; + size = width * height * _bytesPerPixel; + if (_enableEGADithering) + size <<= 2; if (size > sizeof(_grabbedCursor)) error("grabCursor: grabbed cursor too big"); - _cursor.width = width * sclW; - _cursor.height = height * sclH; + _cursor.width = width; + _cursor.height = height; _cursor.animate = 0; - dst = _grabbedCursor; + dst = _enableEGADithering ? _compositeBuf : _grabbedCursor; for (; height; height--) { - for (int h2 = sclH; h2; --h2) { - const byte *s1 = ptr; - const byte *s2 = 0; - byte *d = dst; - for (int w = width; w; --w) { - for (int w2 = sclW; w2; --w2) { - s2 = s1; - for (int w3 = _bytesPerPixel; w3; --w3) - *d++ = *s2++; - } - s1 = s2; - } - dst += width * sclW * _bytesPerPixel; - } + memcpy(dst, ptr, width * _bytesPerPixel); + dst += width * _bytesPerPixel; ptr += pitch; } + if (_enableEGADithering) + ditherCursor(); + updateCursor(); } +void ScummEngine_v6::ditherCursor() { + int x = 0; + int y = 0; + int pitch = _cursor.width; + + // We temporarily put the transparency color in the EGA color tables. + uint8 backupEGA0 = _egaColorMap[0][255]; + uint8 backupEGA1 = _egaColorMap[1][255]; + _egaColorMap[0][255] = _egaColorMap[1][255] = 0xFF; + + ditherVGAtoEGA(pitch, x, y, _cursor.width, _cursor.height); + + _egaColorMap[0][255] = backupEGA0; + _egaColorMap[1][255] = backupEGA1; + + memcpy(_grabbedCursor, _hercCGAScaleBuf, _cursor.width * _cursor.height); +} + void ScummEngine_v70he::setCursorFromImg(uint img, uint room, uint imgindex) { _resExtractor->setCursor(img); } @@ -391,6 +407,8 @@ void ScummEngine_v6::useBompCursor(const byte *im, int width, int height) { height *= 8; size = width * height; + if (_enableEGADithering) + size <<= 2; if (size > sizeof(_grabbedCursor)) error("useBompCursor: cursor too big (%d)", size); @@ -404,7 +422,10 @@ void ScummEngine_v6::useBompCursor(const byte *im, int width, int height) { } else { im += 18; } - decompressBomp(_grabbedCursor, im, width, height); + decompressBomp(_enableEGADithering ? _compositeBuf : _grabbedCursor, im, width, height); + + if (_enableEGADithering) + ditherCursor(); updateCursor(); } diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp index 99d8dc6a8bd..76f431ba98c 100644 --- a/engines/scumm/palette.cpp +++ b/engines/scumm/palette.cpp @@ -252,6 +252,12 @@ void ScummEngine::resetPalette() { } else if (_renderMode == Common::kRenderEGA && _supportsEGADithering) { setPaletteFromTable(tableEGAPalette, sizeof(tableEGAPalette) / 3); _enableEGADithering = true; + // Set the color tables to sane values (for games that dither the mouse cursor + // right at the beginning, before these tables get filled normally. + if (_currentRoom == 0) { + for (uint16 i = 0; i < 256; ++i) + _egaColorMap[0][i] = _egaColorMap[1][i] = i & 0x0F; + } #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE } else if (_game.platform == Common::kPlatformFMTowns) { if (_game.id == GID_INDY4 || _game.id == GID_MONKEY2) diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index bce0c2ff4a8..47bd5f5d887 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1172,7 +1172,7 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) { x *= 2; x += (kHercWidth - _screenWidth * 2) / 2; y = y * 7 / 4; - } else if (_macScreen || (_useCJKMode && _textSurfaceMultiplier == 2)) { + } else if (_macScreen || (_useCJKMode && _textSurfaceMultiplier == 2) || _renderMode == Common::kRenderCGA_BW || _enableEGADithering) { x *= 2; y *= 2; } diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 353ed881468..2f0f0444f95 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -243,8 +243,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) // VGA games which support an EGA dithering mode static const byte egaModeIDs[] = { - /*GID_SAMNMAX,*/ // Not supported in the original interpreter. It works, but is too glitchy to have it enabled without further fine tuning... - GID_TENTACLE, // Not supported in the original interpreter. Less glitchy than SAM, so I leave it enabled. I guess, people who actually select this will know what they're doing. + GID_SAMNMAX, // Not supported in the original interpreter. Glitches might occur. + GID_TENTACLE, // Not supported in the original interpreter. Glitches might occur. GID_LOOM, // Supported in the original interpreter. GID_MONKEY, GID_MONKEY_VGA, @@ -2691,13 +2691,13 @@ void ScummEngine_v3::scummLoop_handleSaveLoad() { _townsPlayer->restoreAfterLoad(); } } + void ScummEngine_v5::scummLoop_handleSaveLoad() { bool processIQPoints = (_game.id == GID_INDY4) && (_saveLoadFlag == 2 || _loadFromLauncher); _loadFromLauncher = false; ScummEngine::scummLoop_handleSaveLoad(); - if (_videoModeChanged) { _videoModeChanged = false; warning("Loading savegame with a different render mode setting. Glitches might occur"); @@ -2734,6 +2734,33 @@ void ScummEngine_v5::scummLoop_handleSaveLoad() { runScript(145, 0, 0, nullptr); } +void ScummEngine_v6::scummLoop_handleSaveLoad() { + ScummEngine::scummLoop_handleSaveLoad(); + + if (_videoModeChanged) { + _videoModeChanged = false; + warning("Loading savegame with a different render mode setting. Glitches might occur"); + if (_supportsEGADithering) { + // Reconstruct the screen palette. + setCurrentPalette(_curPalIndex); + // Reconstruct mouse cursor (crosshair for DOTT, verb cursor for SAM). + if (_game.id == GID_SAMNMAX) { + setCursorFromImg(VAR(177), VAR(177) > 890 ? 94 : 93, 1); + if (VAR(177) > 890) { + // The inventory item cursors require some extra treatment... + setCursorTransparency(180); + setCursorTransparency(178); + setCursorTransparency(176); + setCursorTransparency(6); + setCursorTransparency(0); + } + } else { + setDefaultCursor(); + } + } + } +} + #ifdef ENABLE_SCUMM_7_8 void ScummEngine_v8::scummLoop_handleSaveLoad() { ScummEngine::scummLoop_handleSaveLoad(); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 2435580ab5f..671f5a8b217 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -1054,8 +1054,6 @@ protected: void setShadowPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor, int start, int end); virtual void darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor); - void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch); - public: void markRectAsDirty(VirtScreenNumber virt, int left, int right, int top, int bottom, int dirtybit = 0); void markRectAsDirty(VirtScreenNumber virt, const Common::Rect& rect, int dirtybit = 0) { diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h index d1ccd9435ee..f4dd5b811a0 100644 --- a/engines/scumm/scumm_v6.h +++ b/engines/scumm/scumm_v6.h @@ -108,6 +108,7 @@ public: protected: void setupOpcodes() override; + void scummLoop_handleSaveLoad() override; void scummLoop_handleActors() override; void processKeyboard(Common::KeyState lastKeyHit) override; @@ -143,6 +144,8 @@ protected: void useIm01Cursor(const byte *im, int w, int h); void useBompCursor(const byte *im, int w, int h); void grabCursor(int x, int y, int w, int h); + void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch); + void ditherCursor(); virtual void drawBlastTexts() {} virtual void removeBlastTexts() {}