[Scummvm-git-logs] scummvm master -> e993bbc389de3edf540c6fa8a8ff46bdad7e7608
athrxx
noreply at scummvm.org
Sat Jul 23 21:18:11 UTC 2022
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
660512ac4d SCUMM: (V3/4 - CGA) - fix CGA mode for MI1EGA + cleanup
af2ce28786 SCUMM: (V4 - Hercules) - fix Hercules mode for MI1EGA
4230a882b0 SCUMM: (V4/EGA/CGA) - improve post-load fixes
e993bbc389 SCUMM: (V4 - Hercules) - fix typo
Commit: 660512ac4d88dd21f8f8e4c9c563929475066e7e
https://github.com/scummvm/scummvm/commit/660512ac4d88dd21f8f8e4c9c563929475066e7e
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:45+02:00
Commit Message:
SCUMM: (V3/4 - CGA) - fix CGA mode for MI1EGA + cleanup
In the end, once fully understood, the CGA rendering is very similar for all versions. So I did manage to clean out some code. Hercules mode for MI1EGA is broken here, I will have another commit for that, once I understand how it works.
Changed paths:
engines/scumm/actor.cpp
engines/scumm/gfx.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index ec37dc69144..a798221e079 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -3159,16 +3159,16 @@ void Actor::setActorCostume(int c) {
} else if (_vm->_game.features & GF_OLD_BUNDLE) {
for (i = 0; i < 16; i++)
_palette[i] = i;
-
- // Make stuff more visible on CGA. Based on disassembly
- if (_vm->_renderMode == Common::kRenderCGA && _vm->_game.version > 2) {
- _palette[6] = 5;
- _palette[7] = 15;
- }
} else {
for (i = 0; i < 32; i++)
_palette[i] = 0xFF;
}
+
+ // Make stuff more visible on CGA. Based on disassembly. It is exactly the same in INDY3, LOOM and MI1 EGA.
+ if (_vm->_renderMode == Common::kRenderCGA && _vm->_game.version > 2 && _vm->_game.version < 5) {
+ _palette[6] = 5;
+ _palette[7] = 15;
+ }
}
static const char *const v0ActorNames_English[25] = {
@@ -3827,6 +3827,24 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
_cost.frame[i] = (_cost.frame[i] << 2) | newDirToOldDir(_facing);
}
}
+
+ // Post-load actor palette fixes for games that were saved with a different video mode (concerns INDY3, LOOM and MI1EGA).
+ if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.version == 4) && _vm->_game.platform == Common::kPlatformDOS) {
+ // Loom is not really much of a problem here, since it has extensive scripted post-load
+ // treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
+ // where it won't be triggered (basically savegames from places where the original does
+ // not allow saving). Indy3 is more dependant on this than Loom, since it does have much
+ // less scripted post-load magic of its own. Monkey Island always needs this, since V4+
+ // games don't do scripted loading of savegames (scripted post-load things) at all.
+ bool cga = (_vm->_renderMode == Common::kRenderCGA);
+ if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
+ _palette[6] ^= 3;
+ _palette[7] ^= 8;
+ }
+ // Extra fix for Bobbin in his normal costume.
+ if (_vm->_game.id == GID_LOOM && _number == 1 && ((cga && _palette[8] == 8) || (!cga && _palette[8] == 0)))
+ _palette[8] ^= 8;
+ }
}
void Actor_v3::saveLoadWithSerializer(Common::Serializer &s) {
@@ -3861,23 +3879,6 @@ void Actor_v3::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint16LE(_stepX, VER(rev));
s.syncAsUint16LE(_stepThreshold, VER(rev));
}
-
- // Post-load actor palette fixes for games that were saved with a different video mode.
- if (s.isLoading() && _vm->_game.version == 3 && _vm->_game.platform == Common::kPlatformDOS) {
- // Loom is not really much of a problem here, since it has extensive scripted post-load
- // treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
- // where it won't be triggered (basically savegames from places where the original does
- // not allow saving). Indy3 is more dependant on this than Loom, since it does have much
- // less scripted post-load magic of its own.
- bool cga = (_vm->_renderMode == Common::kRenderCGA);
- if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
- _palette[6] ^= 3;
- _palette[7] ^= 8;
- }
- // Extra fix for Bobbin in his normal costume.
- if (_vm->_game.id == GID_LOOM && _number == 1 && ((cga && _palette[8] == 8) || (!cga && _palette[8] == 0)))
- _palette[8] ^= 8;
- }
}
} // End of namespace Scumm
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 19e1980b913..2343a8527b5 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -54,8 +54,6 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8
#endif
static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth);
-static void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height);
-
struct StripTable {
int offsets[160];
int run[160];
@@ -767,27 +765,15 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
_system->copyRectToScreen(blackbuf, 16, 0, 0, 16, 240); // Fix left strip
}
}
- } else if (_game.version == 1 || _game.version == 2) {
- // MM/ZAK v1/v2
- src = postProcessV2Graphics(vs, pitch, x, y, width, height);
- } else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) {
- // MI1
- ditherHerc(_compositeBuf, _hercCGAScaleBuf, width, &x, &y, &width, &height);
-
- src = _hercCGAScaleBuf + x + y * kHercWidth;
- pitch = kHercWidth;
-
- // center image on the screen
- x += (kHercWidth - _screenWidth * 2) / 2; // (720 - 320*2)/2 = 40
} else if (_useCJKMode && m == 2) {
pitch *= m;
x *= m;
y *= m;
width *= m;
height *= m;
- } else if (_renderMode == Common::kRenderCGA) {
- // LOOM, MI1
- ditherCGA(_compositeBuf, width, x, y, width, height);
+ } else if (_game.platform == Common::kPlatformDOS && _game.version < 5) {
+ // CGA and Hercules modes for MM/ZAK v1/v2, INDY3, LOOM, MI1EGA
+ src = postProcessDOSGraphics(vs, pitch, x, y, width, height);
}
}
@@ -795,11 +781,24 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
_system->copyRectToScreen(src, pitch, x, y, width, height);
}
-const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
- static const byte v2VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
- static const byte v2TxtColMap[] = { 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
- static const byte mmv1VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
- static const byte v2MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
+const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
+ static const byte v2VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
+ static const byte v2TxtColMap[] = { 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
+ static const byte mmv1VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
+ static const byte v2MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
+ static const byte v3MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF,
+ 0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF };
+ static const byte v4MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
+ 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
+ 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
+ 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF };
+
+ static const byte hrcTableV4[32] = { 0x00, 0x00, 0x08, 0x80, 0xaa, 0xaa, 0xbb, 0xdd, 0x55, 0x00, 0x66, 0x99, 0x99, 0x66, 0x7f, 0xf7,
+ 0x11, 0x44, 0x55, 0xaa, 0x77, 0xdd, 0xee, 0x77, 0xaa, 0xff, 0xee, 0xbb, 0xff, 0xbb, 0xff, 0xff };
+
+ static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
+
+ assert(_game.version < 5);
byte tmpTxtColMap[16];
for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
@@ -809,17 +808,26 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
byte *dst = _compositeBuf;
const byte *src = res;
bool renderHerc = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG);
+ bool renderV1 = (_game.version == 1);
+ bool renderV3 = _game.version > 2;
const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
+ const byte *colMap2 = mainColMap[_game.version];
+
+ // For v3 CGA is dithered as 4x4 squares, for v4 as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+ uint8 lnMod = (_game.version > 3) ? 0x40 : 0x20;
+ uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderCGAComp) {
- if (vs->number == kMainVirtScreen) {
+ if (renderV3 || vs->number == kMainVirtScreen) {
for (int h = height; h; --h) {
for (int w = width >> 1; w; --w) {
- byte c = (_game.version == 1) ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+ byte c = renderV1 ? *src : (colMap2[src[0] + lnIdx] & 0x0C) | (colMap2[src[1] + lnIdx] & 0x03);
*dst++ = (c >> 2) & 3;
*dst++ = c & 3;
src += 2;
}
+ if (renderV3)
+ lnIdx = (lnIdx + 0x10) % lnMod;
}
} else {
for (int h = height; h; --h) {
@@ -856,7 +864,7 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
for (int h = height2; h; --h) {
for (int w = width >> 1; w; --w) {
const uint32 *s = (const uint32*)dst;
- byte c = (_game.version == 1) ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+ byte c = renderV1 ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
*dst++ = (c >> 3) & 1;
*dst++ = (c >> 2) & 1;
*dst++ = (c >> 1) & 1;
@@ -905,7 +913,7 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
height <<= 1;
}
- } else if (_game.version == 1 && vs->number == kTextVirtScreen) {
+ } else if (renderV1 && vs->number == kTextVirtScreen) {
// For EGA, the only colors that need remapping are for the kTextVirtScreen.
for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
tmpTxtColMap[i] = _gdi->remapColorToRenderMode(i);
@@ -918,39 +926,6 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
return res;
}
-// CGA
-// indy3 loom maniac monkey1 zak
-//
-// Herc (720x350)
-// maniac monkey1 zak
-//
-// EGA
-// monkey2 loom maniac monkey1 atlantis indy3 zak loomcd
-
-static const byte cgaDither[2][2][16] = {
- {{0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 3, 1, 3, 2, 1, 3},
- {0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3}},
- {{0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3},
- {0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 1, 1, 3, 2, 1, 3}}};
-
-void ScummEngine::ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const {
- byte *ptr;
- int idx1, idx2;
- // CGA dithers 4x4 square with direct substitutes
- // Odd lines have colors swapped, so there will be checkered patterns.
- // But apparently there is a mistake for 10th color.
- for (int y1 = 0; y1 < height; y1++) {
- ptr = dst + y1 * dstPitch;
- idx1 = (y + y1) % 2;
-
- for (int x1 = 0; x1 < width; x1++) {
- idx2 = (x + x1) % 2;
- *ptr = cgaDither[idx1][idx2][*ptr & 0xF];
- ptr++;
- }
- }
-}
-
// Hercules dithering. It uses same dithering tables but output is 1bpp and
// it stretches in this way:
// aaaa0
@@ -960,8 +935,8 @@ void ScummEngine::ditherCGA(byte *dst, int dstPitch, int x, int y, int width, in
// dd cccc0
// cccc1
// dddd0
-void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) {
- byte *srcptr, *dstptr;
+//void ScummEngine::ditherV4herc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) const {
+ /*byte *srcptr, *dstptr;
const int xo = *x, yo = *y, widtho = *width, heighto = *height;
int dsty = yo*2 - yo/4;
@@ -974,21 +949,21 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid
const int idx1 = (dsty % 7) % 2;
for (int x1 = 0; x1 < widtho; x1++) {
const int idx2 = (xo + x1) % 2;
- const byte tmp = cgaDither[idx1][idx2][*srcptr & 0xF];
- *dstptr++ = tmp >> 1;
- *dstptr++ = tmp & 0x1;
+ //const byte tmp = _ditheringTable[idx1][idx2][*srcptr & 0xF];
+ //*dstptr++ = tmp >> 1;
+ //*dstptr++ = tmp & 0x1;
srcptr++;
}
if (idx1 || dsty % 7 == 6)
y1++;
dsty++;
- }
+ }*/
- *x *= 2;
- *y = yo*2 - yo/4;
- *width *= 2;
- *height = dsty - *y;
-}
+ //*x *= 2;
+ //*y = yo*2 - yo/4;
+ //*width *= 2;
+ //*height = dsty - *y;
+//}
#pragma mark -
#pragma mark --- Background buffers & charset mask ---
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 16f36a5932b..5db3ea79d45 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1072,8 +1072,7 @@ protected:
void mac_undrawIndy3TextBox();
void mac_undrawIndy3CreditsText();
- const byte *postProcessV2Graphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const;
- void ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const;
+ const byte *postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const;
public:
VirtScreen *findVirtScreen(int y);
@@ -1082,7 +1081,6 @@ public:
protected:
void fadeIn(int effect);
void fadeOut(int effect);
- void setScrollBuffer();
void dissolveEffectSelector();
void transitionEffect(int a);
Commit: af2ce287863efd343a9d1baa8f76cc2d84afc938
https://github.com/scummvm/scummvm/commit/af2ce287863efd343a9d1baa8f76cc2d84afc938
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:45+02:00
Commit Message:
SCUMM: (V4 - Hercules) - fix Hercules mode for MI1EGA
Changed paths:
engines/scumm/cursor.cpp
engines/scumm/gfx.cpp
diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index ff8f6531ffc..c3d31560fc3 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -692,32 +692,36 @@ void ScummEngine_v5::setBuiltinCursor(int idx) {
252, 252, 253, 254
};
color = indy4AmigaColors[idx];
+ } else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) {
+ color = idx & 1;
} else {
color = default_cursor_colors[idx];
}
memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
}
- _cursor.hotspotX = _cursorHotspots[2 * _currentCursor] * _textSurfaceMultiplier;
- _cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1] * _textSurfaceMultiplier;
- _cursor.width = 16 * _textSurfaceMultiplier;
- _cursor.height = 16 * _textSurfaceMultiplier;
-
- int scl = _outputPixelFormat.bytesPerPixel * _textSurfaceMultiplier;
+ int sclW = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) ? 2 : _textSurfaceMultiplier;
+ int sclH = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) ? 1 : _textSurfaceMultiplier;
+ int sclW2 = _outputPixelFormat.bytesPerPixel * sclW;
+ _cursor.hotspotX = _cursorHotspots[2 * _currentCursor] * sclW;
+ _cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1] * sclH;
+ _cursor.width = 16 * sclW;
+ _cursor.height = 16 * sclH;
+
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
if (src[i] & (1 << j)) {
- byte *dst1 = _grabbedCursor + 16 * scl * i * _textSurfaceMultiplier + (15 - j) * scl;
- byte *dst2 = (_textSurfaceMultiplier == 2) ? dst1 + 16 * scl : dst1;
+ byte *dst1 = _grabbedCursor + 16 * sclW2 * i * sclH + (15 - j) * sclW2;
+ byte *dst2 = (sclH == 2) ? dst1 + 16 * sclW2 : dst1;
if (_outputPixelFormat.bytesPerPixel == 2) {
- for (int b = 0; b < scl; b += 2) {
+ for (int b = 0; b < sclW; b++) {
*((uint16 *)dst1) = *((uint16 *)dst2) = color;
dst1 += 2;
dst2 += 2;
}
} else {
- for (int b = 0; b < scl; b++)
+ for (int b = 0; b < sclW; b++)
*dst1++ = *dst2++ = color;
}
}
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 2343a8527b5..d0580d78d32 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -628,6 +628,15 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
assert(x >= 0 && width <= vs->pitch);
assert(_textSurface.getPixels());
+ // Some extra clipping/alignment for certain render modes. This is from the MI1EGA interpreter where it actually matters.
+ // The dithering patterns require the alignment, otherwise there will be visible glitches. For V3, the original interpreter
+ // actually does this for all graphics modes...
+ if (_game.version > 2 && (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderHercG || _renderMode == Common::kRenderHercA)) {
+ top &= ~3;
+ if (bottom & 3)
+ bottom = (bottom + 4) & ~3;
+ }
+
// Perform some clipping
if (width > vs->w - x)
width = vs->w - x;
@@ -782,23 +791,26 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
}
const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
- static const byte v2VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
- static const byte v2TxtColMap[] = { 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
- static const byte mmv1VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
- static const byte v2MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
- static const byte v3MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF,
- 0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF };
- static const byte v4MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
- 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
- 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
- 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF };
-
- static const byte hrcTableV4[32] = { 0x00, 0x00, 0x08, 0x80, 0xaa, 0xaa, 0xbb, 0xdd, 0x55, 0x00, 0x66, 0x99, 0x99, 0x66, 0x7f, 0xf7,
- 0x11, 0x44, 0x55, 0xaa, 0x77, 0xdd, 0xee, 0x77, 0xaa, 0xff, 0xee, 0xbb, 0xff, 0xbb, 0xff, 0xff };
+ static const byte v2VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
+ static const byte v2TxtColMap[] = { 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
+ static const byte mmv1VrbColMap[] = { 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
+ static const byte v2MainColMap[] = { 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
- static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
+ static const byte v3MainColMap[] = {
+ 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF
+ };
+
+ static const byte v4MainColMap[] = {
+ 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
+ 0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF
+ };
- assert(_game.version < 5);
+ static const byte hrcTableV4[32] = {
+ 0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x77, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
+ 0x00, 0x80, 0xAA, 0xDD, 0x00, 0x99, 0x66, 0xF7, 0x44, 0xAA, 0xDD, 0x77, 0xFF, 0xBB, 0xBB, 0xFF
+ };
+
+ static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
byte tmpTxtColMap[16];
for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
@@ -810,11 +822,15 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
bool renderHerc = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG);
bool renderV1 = (_game.version == 1);
bool renderV3 = _game.version > 2;
+
+ if (!renderV1 && !renderHerc && _renderMode != Common::kRenderCGA)
+ return res;
+
const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
const byte *colMap2 = mainColMap[_game.version];
- // For v3 CGA is dithered as 4x4 squares, for v4 as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
- uint8 lnMod = (_game.version > 3) ? 0x40 : 0x20;
+ // For LOOM and INDY3, CGA gets dithered as 4x4 squares, for MI1EGA as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+ uint8 lnMod = (_game.version > 3 && !renderHerc) ? 0x40 : 0x20;
uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderCGAComp) {
@@ -839,18 +855,37 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
}
} else if (renderHerc || _renderMode == Common::kRenderCGA_BW) {
- // The monochrome rendering is very similiar for Hercules and CGA b/w.
- // For Hercules we have to do some corrections to fit into the 350 pixels
- // height. The text and verb vs are rendered in normal height, only the
- // main vs gets scaled by leaving out every other line. And we center the
- // image horizontally within the 720 pixels width.
- // For CGA b/w the origial resolution is 640x200, so we just scale that
- // to our 640x400 by repeating each line.
+ // The monochrome rendering is very similiar for Hercules and CGA b/w. For Hercules we have to do some corrections to fit into the 350 pixels height.
+ // For Hercules V1/2, the text and verb vs are rendered in normal height, only the main vs gets scaled by leaving out every other line. Hercules V4
+ // instead scales everything in a 4-to-7 lines ratio. And for all versions, we center the image horizontally within the 720 pixels width.
+ // For CGA b/w the origial resolution is 640x200, so we just scale that to our 640x400 by repeating each line.
pitch = renderHerc ? kHercWidth : (_screenWidth << 1);
dst = res = _hercCGAScaleBuf;
int pitch1 = (pitch - width) << 1;
- if (vs->number == kMainVirtScreen) {
+ if (renderV3) {
+ pitch1 = pitch - (width << 1);
+ int height2 = height >> 2;
+ height = height2 * 7;
+ y = (y << 1) - (y >> 2);
+
+ for (int h1 = height2; h1; --h1) {
+ lnIdx = 0; // The 7-lines pattern always starts from the beginning. Which works fine, since the strips get vertically aligned for Hercules and CGA.
+ for (int h2 = 7; h2; --h2) {
+ for (int w = width >> 2; w; --w) {
+ byte c = (hrcTableV4[src[0] + lnIdx] & 0xC0) | (hrcTableV4[src[1] + lnIdx] & 0x30) | (hrcTableV4[src[2] + lnIdx] & 0x0C) | (hrcTableV4[src[3] + lnIdx] & 0x03);
+ for (int i = 7; i >= 0; --i)
+ *dst++ = (c >> i) & 1;
+ src += 4;
+ }
+ dst += pitch1;
+ if (lnIdx ^= 0x10)
+ src -= width;
+ }
+ src += width;
+ }
+
+ } else if (vs->number == kMainVirtScreen) {
uint32 *dst2 = (uint32*)(dst + pitch);
int pitch2 = pitch1 >> 2;
int height2 = height;
@@ -864,7 +899,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
for (int h = height2; h; --h) {
for (int w = width >> 1; w; --w) {
const uint32 *s = (const uint32*)dst;
- byte c = renderV1 ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+ byte c = renderV1 ? *src : (colMap2[src[0]] & 0x0C) | (colMap2[src[1]] & 0x03);
*dst++ = (c >> 3) & 1;
*dst++ = (c >> 2) & 1;
*dst++ = (c >> 1) & 1;
@@ -926,45 +961,6 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
return res;
}
-// Hercules dithering. It uses same dithering tables but output is 1bpp and
-// it stretches in this way:
-// aaaa0
-// aa aaaa1
-// bb bbbb0 Here 0 and 1 mean dithering table row number
-// cc --> bbbb1
-// dd cccc0
-// cccc1
-// dddd0
-//void ScummEngine::ditherV4herc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) const {
- /*byte *srcptr, *dstptr;
- const int xo = *x, yo = *y, widtho = *width, heighto = *height;
- int dsty = yo*2 - yo/4;
-
- for (int y1 = 0; y1 < heighto;) {
- assert(dsty < kHercHeight);
-
- srcptr = src + y1 * srcPitch;
- dstptr = hercbuf + dsty * kHercWidth + xo * 2;
-
- const int idx1 = (dsty % 7) % 2;
- for (int x1 = 0; x1 < widtho; x1++) {
- const int idx2 = (xo + x1) % 2;
- //const byte tmp = _ditheringTable[idx1][idx2][*srcptr & 0xF];
- //*dstptr++ = tmp >> 1;
- //*dstptr++ = tmp & 0x1;
- srcptr++;
- }
- if (idx1 || dsty % 7 == 6)
- y1++;
- dsty++;
- }*/
-
- //*x *= 2;
- //*y = yo*2 - yo/4;
- //*width *= 2;
- //*height = dsty - *y;
-//}
-
#pragma mark -
#pragma mark --- Background buffers & charset mask ---
#pragma mark -
Commit: 4230a882b06d64b53081192faf868baeb8fedc0a
https://github.com/scummvm/scummvm/commit/4230a882b06d64b53081192faf868baeb8fedc0a
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:46+02:00
Commit Message:
SCUMM: (V4/EGA/CGA) - improve post-load fixes
Also include room palette fixes for games that were saved with a different video mode. Unfortunately the scripts make changes to the room palette based on VAR_VIDEOMODE. The original interpreter does not fix that.
Changed paths:
engines/scumm/actor.cpp
engines/scumm/saveload.cpp
engines/scumm/script_v5.cpp
engines/scumm/scumm.cpp
engines/scumm/scumm.h
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index a798221e079..eae8e2ae26f 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -3828,8 +3828,10 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
}
}
- // Post-load actor palette fixes for games that were saved with a different video mode (concerns INDY3, LOOM and MI1EGA).
- if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.version == 4) && _vm->_game.platform == Common::kPlatformDOS) {
+ // WORKAROUND: Post-load actor palette fixes for games that were saved with a different render mode
+ // (concerns INDY3, LOOM and MI1EGA). The original interpreter does not fix this, savegames from
+ // different videomodes will cause glitches there.
+ if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.id == GID_MONKEY_EGA) && _vm->_game.platform == Common::kPlatformDOS) {
// Loom is not really much of a problem here, since it has extensive scripted post-load
// treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
// where it won't be triggered (basically savegames from places where the original does
@@ -3837,7 +3839,10 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
// less scripted post-load magic of its own. Monkey Island always needs this, since V4+
// games don't do scripted loading of savegames (scripted post-load things) at all.
bool cga = (_vm->_renderMode == Common::kRenderCGA);
- if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
+ if (cga && _vm->_game.id == GID_MONKEY_EGA && _palette[6] == 0xFF && _palette[7] == 0xFF) {
+ _palette[6] = 5;
+ _palette[7] = 15;
+ } else if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
_palette[6] ^= 3;
_palette[7] ^= 8;
}
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 6dd2dbeddcd..bce0c2ff4a8 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1446,7 +1446,13 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
// Set video mode var to the current actual mode, not the one that was enabled when the game was saved.
// At least for Loom this fixes glitches, since the game actually reads the var and makes actor palette
// adjustments based on that. This is a bug that happens in the original interpreter, too.
- setVideoModeVarToCurrentConfig();
+ if (s.isLoading() && VAR_VIDEOMODE != 0xFF) {
+ int videoModeSaved = VAR(VAR_VIDEOMODE);
+ setVideoModeVarToCurrentConfig();
+ // For MI1EGA we need to know if the savegame is from a different render mode, so we can apply some
+ // post-load fixes if necessary.
+ _videoModeChanged = (videoModeSaved != VAR(VAR_VIDEOMODE));
+ }
// WORKAROUND: FM-TOWNS Zak used the extra 40 pixels at the bottom to increase the inventory to 10 items
// if we trim to 200 pixels, we can show only 6 items
@@ -1466,7 +1472,6 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
runInventoryScript(0);
}
-
//
// Save/load a list of the locked objects
//
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 9031d456317..68260ee988b 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -540,7 +540,7 @@ void ScummEngine_v5::o5_actorOps() {
// WORKAROUND for original bug. The original interpreter has a color fix for CGA mode which can be seen
// in Actor::setActorCostume(). Sometimes (e. g. when Bobbin walks out of the darkened tent) the actor
- // colors are changed via script without taking into the account the need to repeat the color fix.
+ // colors are changed via script without taking into account the need to repeat the color fix.
if (_game.id == GID_LOOM && _renderMode == Common::kRenderCGA && act == 1) {
if (i == 6 && j == 6)
j = 5;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 0cd105a6454..f632b919862 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2681,6 +2681,27 @@ void ScummEngine_v5::scummLoop_handleSaveLoad() {
ScummEngine::scummLoop_handleSaveLoad();
+ // WORKAROUND: MI1 post-load room palette fixes for games that were saved with a different
+ // render mode. The entry scripts apply custom fixes here, based on the VAR_VIDEOMODE
+ // var. Saving this state and then loading the savegame with a different render mode setting,
+ // will mess up the room palette. The original interpreter does not fix this, savegames
+ // from different videomodes are basically incompatible, at least until a scene comes up
+ // where the script might again apply the necessary fixes. Unfortunately, this workaround
+ // will also only work if the current room has a script with the correct fixes...
+ if (_game.id == GID_MONKEY_EGA && _videoModeChanged) {
+ _videoModeChanged = false;
+ // Reset everything that the former entry script might have
+ // done (based on the former VAR_VIDEOMODE).
+ for (int i = 0; i < ARRAYSIZE(_roomPalette); ++i)
+ _roomPalette[i] = i;
+ // We want just the ENCD script...
+ int entryScript = VAR_ENTRY_SCRIPT;
+ VAR_ENTRY_SCRIPT = 0xFF;
+ runEntryScript();
+ VAR_ENTRY_SCRIPT = entryScript;
+ warning("Loading savegame with a different render mode setting. Glitches might occur");
+ }
+
// update IQ points after loading
if (processIQPoints)
runScript(145, 0, 0, nullptr);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 5db3ea79d45..848bdd3a8b8 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -606,6 +606,7 @@ protected:
uint32 _lastSaveTime = 0;
bool _saveTemporaryState = false;
bool _loadFromLauncher = false;
+ bool _videoModeChanged = false;
Common::String _saveLoadFileName;
Common::String _saveLoadDescription;
Commit: e993bbc389de3edf540c6fa8a8ff46bdad7e7608
https://github.com/scummvm/scummvm/commit/e993bbc389de3edf540c6fa8a8ff46bdad7e7608
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:46+02:00
Commit Message:
SCUMM: (V4 - Hercules) - fix typo
Changed paths:
engines/scumm/gfx.cpp
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index d0580d78d32..742ab8e4878 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -806,7 +806,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
};
static const byte hrcTableV4[32] = {
- 0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x77, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
+ 0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x7F, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
0x00, 0x80, 0xAA, 0xDD, 0x00, 0x99, 0x66, 0xF7, 0x44, 0xAA, 0xDD, 0x77, 0xFF, 0xBB, 0xBB, 0xFF
};
@@ -829,7 +829,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
const byte *colMap2 = mainColMap[_game.version];
- // For LOOM and INDY3, CGA gets dithered as 4x4 squares, for MI1EGA as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+ // For LOOM and INDY3, CGA gets dithered as 2x2 squares, for MI1EGA as 2x4 squares. Odd lines have the colors swapped, so there will be checkered patterns.
uint8 lnMod = (_game.version > 3 && !renderHerc) ? 0x40 : 0x20;
uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
@@ -864,6 +864,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
int pitch1 = (pitch - width) << 1;
if (renderV3) {
+ // This is for MI1EGA Hercules only
pitch1 = pitch - (width << 1);
int height2 = height >> 2;
height = height2 * 7;
@@ -886,6 +887,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
}
} else if (vs->number == kMainVirtScreen) {
+ // V1/2 Hercules and CGA b/w mode
uint32 *dst2 = (uint32*)(dst + pitch);
int pitch2 = pitch1 >> 2;
int height2 = height;
@@ -912,6 +914,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
}
} else {
+ // V1/2 Hercules and CGA b/w mode
if (renderHerc) {
pitch1 = kHercWidth - (width << 1);
y -= vs->topline;
More information about the Scummvm-git-logs
mailing list