aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/gfx.cpp
diff options
context:
space:
mode:
authorFlorian Kagerer2010-10-01 19:24:52 +0000
committerFlorian Kagerer2010-10-01 19:24:52 +0000
commit0d8f4a22ae51d5943014a4c5f3ba610686039a24 (patch)
tree4f2ba902f2681c10f1f9949efc9424bcc93e14c1 /engines/scumm/gfx.cpp
parentbe1d196da5dbbabaef0bfa835b51e9c82c407645 (diff)
downloadscummvm-rg350-0d8f4a22ae51d5943014a4c5f3ba610686039a24.tar.gz
scummvm-rg350-0d8f4a22ae51d5943014a4c5f3ba610686039a24.tar.bz2
scummvm-rg350-0d8f4a22ae51d5943014a4c5f3ba610686039a24.zip
SCUMM/FM-TOWNS: fix palette and other graphics issues
This commit should fix at least the following bugs/feature requests: #1032859, #1252088, #1055391, #1315968, #1315938, #1742106, #812891. The FM-Towns version of Scumm games use a mixed graphics mode with 2 layers (one with 32767 colors and one with 16 colors). Among other things I have added a screen output class which emulates this dual layer approach which allows specific hardware effects like enabling and disabling layers (e.g. in the voodoo priestess scene in MI1). Old savegames (saved before this update) will load, but you’ll encounter palette glitches in the verb/inventory screen, since the 16 color palette for layer 2 is not contained in your savegame. This will be true at least for version 5 games. Certain scene change actions (which require the verb/inventory part to be redrawn) might correct this (e.g. try looking at the treasure map in MI1 and closing it). Version 3 games should be okay, since they use a static text palette which is never changed and which will be reset after loading a savegame. This update requires a USE_RGB_COLORS setting for proper operation. 8 bit users will get a warning that they’ll have to expect palette glitches . Apart from that the engine in 8 bit mode should not only still work okay, but also benefit from some of the other (non palette related) improvements (e.g. bug #1032859 should be fixed even in 8 bit mode). Japanese font drawing hasn’t been improved much yet. This will be a separate task. svn-id: r52966
Diffstat (limited to 'engines/scumm/gfx.cpp')
-rw-r--r--engines/scumm/gfx.cpp233
1 files changed, 123 insertions, 110 deletions
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 3b8d9c296a..2ee54337b8 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -51,7 +51,6 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8
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);
-static void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h);
struct StripTable {
int offsets[160];
@@ -323,6 +322,16 @@ void ScummEngine::initScreens(int b, int h) {
_res->nukeResource(rtBuffer, i + 5);
}
+ if (_townsScreen) {
+ if (!_townsClearLayerFlag && (h - b != _virtscr[kMainVirtScreen].h))
+ _townsScreen->clearLayer(0);
+
+ if (_game.id == GID_MONKEY2 || _game.id == GID_INDY4) {
+ _textSurface.fillRect(Common::Rect(0, 0, _textSurface.w * _textSurfaceMultiplier, _textSurface.h * _textSurfaceMultiplier), 0);
+ _townsScreen->clearLayer(1);
+ }
+ }
+
if (!getResourceAddress(rtBuffer, 4)) {
// Since the size of screen 3 is fixed, there is no need to reallocate
// it if its size changed.
@@ -611,16 +620,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
int m = _textSurfaceMultiplier;
int vsPitch;
int pitch = vs->pitch;
-
- if (_useCJKMode && _textSurfaceMultiplier == 2) {
- scale2x(_fmtownsBuf, _screenWidth * m, (const byte *)src, vs->pitch, width, height);
- src = _fmtownsBuf;
-
- vsPitch = _screenWidth * m - width * m;
-
- } else {
- vsPitch = vs->pitch - width * vs->bytesPerPixel;
- }
+ vsPitch = vs->pitch - width * vs->bytesPerPixel;
if (_game.version < 7) {
@@ -643,7 +643,10 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
#ifdef USE_ARM_GFX_ASM
asmDrawStripToScreen(height, width, text, src, _compositeBuf, vs->pitch, width, _textSurface.pitch);
#else
- if (_bytesPerPixel == 2) {
+ if (_game.platform == Common::kPlatformFMTowns) {
+ towns_drawStripToScreen(vs, x, y, x, top, width, height);
+ return;
+ } else if (_bytesPerPixelOutput == 2) {
const byte *srcPtr = (const byte *)src;
const byte *textPtr = (byte *)_textSurface.getBasePtr(x * m, y * m);
byte *dstPtr = _compositeBuf;
@@ -824,28 +827,6 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid
*height = dsty - *y;
}
-void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) {
- /* dst and dstPitch should both be even. So the use of (void *) in
- * the following casts to avoid the unnecessary warning is valid. */
- uint16 *dstL1 = (uint16 *)(void *)dst;
- uint16 *dstL2 = (uint16 *)(void *)(dst + dstPitch);
-
- const int dstAdd = dstPitch - w;
- const int srcAdd = srcPitch - w;
-
- while (h--) {
- for (int x = 0; x < w; ++x) {
- uint16 col = *src++;
- col |= col << 8;
- *dstL1++ = col;
- *dstL2++ = col;
- }
- dstL1 += dstAdd; dstL2 += dstAdd;
- src += srcAdd;
- }
-}
-
-
#pragma mark -
#pragma mark --- Background buffers & charset mask ---
#pragma mark -
@@ -1017,7 +998,7 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
VirtScreen *vs;
byte *screenBuf;
- if (rect.top < 0)
+ if (rect.top < 0)
rect.top = 0;
if (rect.left >= rect.right || rect.top >= rect.bottom)
return;
@@ -1028,6 +1009,9 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
if (rect.left > vs->w)
return;
+ if (_game.platform == Common::kPlatformFMTowns && _game.id == GID_MONKEY && vs->number == kVerbVirtScreen && rect.bottom <= 154)
+ rect.right = 320;
+
// Convert 'rect' to local (virtual screen) coordinates
rect.top -= vs->topline;
rect.bottom -= vs->topline;
@@ -1047,10 +1031,21 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
if (vs->hasTwoBuffers && _currentRoom != 0 && isLightOn()) {
blit(screenBuf, vs->pitch, vs->getBackPixels(rect.left, rect.top), vs->pitch, width, height, vs->bytesPerPixel);
if (vs->number == kMainVirtScreen && _charset->_hasMask) {
- byte *mask = (byte *)_textSurface.getBasePtr(rect.left, rect.top - _screenTop);
- fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height, _textSurface.bytesPerPixel);
+ if (_game.platform == Common::kPlatformFMTowns) {
+ byte *mask = (byte *)_textSurface.getBasePtr(rect.left * _textSurfaceMultiplier, (rect.top + vs->topline) * _textSurfaceMultiplier);
+ fill(mask, _textSurface.pitch, 0, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+ } else {
+ byte *mask = (byte *)_textSurface.getBasePtr(rect.left, rect.top - _screenTop);
+ fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+ }
}
} else {
+ if (_game.platform == Common::kPlatformFMTowns) {
+ backColor |= (backColor << 4);
+ byte *mask = (byte *)_textSurface.getBasePtr(rect.left * _textSurfaceMultiplier, (rect.top + vs->topline) * _textSurfaceMultiplier);
+ fill(mask, _textSurface.pitch, backColor, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+ }
+
if (_game.features & GF_16BIT_COLOR)
fill(screenBuf, vs->pitch, _16BitPalette[backColor], width, height, vs->bytesPerPixel);
else
@@ -1102,7 +1097,10 @@ void ScummEngine::clearCharsetMask() {
}
void ScummEngine::clearTextSurface() {
- fill((byte*)_textSurface.pixels, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, _textSurface.w, _textSurface.h, _textSurface.bytesPerPixel);
+ if (_townsScreen)
+ _townsScreen->fillLayerRect(1, 0, 0, _textSurface.w, _textSurface.h, 0);
+
+ fill((byte*)_textSurface.pixels, _textSurface.pitch, _game.platform == Common::kPlatformFMTowns ? 0 : CHARSET_MASK_TRANSPARENCY, _textSurface.w, _textSurface.h, _textSurface.bytesPerPixel);
}
byte *ScummEngine::getMaskBuffer(int x, int y, int z) {
@@ -1256,13 +1254,25 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
backbuff = vs->getPixels(x, y);
bgbuff = vs->getBackPixels(x, y);
- if (color == -1) {
- if (vs->number != kMainVirtScreen)
- error("can only copy bg to main window");
- blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel);
- if (_charset->_hasMask) {
- byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop) * _textSurfaceMultiplier);
- fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+ // A check for -1 might be wrong in all cases since o5_drawBox() in its current form
+ // is definitely not capable of passing a parameter of -1 (color range is 0 - 255).
+ // Just to make sure I don't break anything I restrict the code change to FM-Towns
+ // version 5 games where this change is necessary to fix certain long standing bugs.
+ if (color == -1 || (color >= 254 && _game.platform == Common::kPlatformFMTowns && (_game.id == GID_MONKEY2 || _game.id == GID_INDY4))) {
+ if (_game.platform == Common::kPlatformFMTowns) {
+ if (color == 254) {
+ color = color;
+ towns_setupPalCycleField(x, y, x2, y2);
+ }
+ } else {
+ if (vs->number != kMainVirtScreen)
+ error("can only copy bg to main window");
+
+ blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel);
+ if (_charset->_hasMask) {
+ byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop) * _textSurfaceMultiplier);
+ fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+ }
}
} else if (_game.heversion >= 72) {
// Flags are used for different methods in HE games
@@ -1293,10 +1303,20 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel);
}
} else {
- if (_game.features & GF_16BIT_COLOR)
+ if (_game.features & GF_16BIT_COLOR) {
fill(backbuff, vs->pitch, _16BitPalette[color], width, height, vs->bytesPerPixel);
- else
+ } else {
+ if (_game.platform == Common::kPlatformFMTowns) {
+ color = ((color & 0x0f) << 4) | (color & 0x0f);
+ byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop + vs->topline) * _textSurfaceMultiplier);
+ fill(mask, _textSurface.pitch, color, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel);
+
+ if (_game.id == GID_MONKEY2 || _game.id == GID_INDY4)
+ return;
+ }
+
fill(backbuff, vs->pitch, color, width, height, vs->bytesPerPixel);
+ }
}
}
@@ -1703,6 +1723,11 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const
warning("Gdi::drawBitmap, strip drawn to %d below window bottom %d", y + height, vs->h);
}
+ if (_vm->_townsPaletteFlags & 2) {
+ int cx = (x - _vm->_screenStartStrip) << 3;
+ _vm->_textSurface.fillRect(Common::Rect(cx * _vm->_textSurfaceMultiplier, y * _vm->_textSurfaceMultiplier, (cx + width - 1) * _vm->_textSurfaceMultiplier, (y + height - 1) * _vm->_textSurfaceMultiplier), 0);
+ }
+
_vertStripNextInc = height * vs->pitch - 1 * vs->bytesPerPixel;
_objectMode = (flag & dbObjectMode) == dbObjectMode;
@@ -3662,6 +3687,9 @@ void ScummEngine::fadeOut(int effect) {
// Fill screen 0 with black
memset(vs->getPixels(0, 0), 0, vs->pitch * vs->h);
+ if (_game.version == 3 && _game.platform == Common::kPlatformFMTowns)
+ _textSurface.fillRect(Common::Rect(0, vs->topline * _textSurfaceMultiplier, _textSurface.pitch, (vs->topline + vs->h) * _textSurfaceMultiplier), 0);
+
// Fade to black with the specified effect, if any.
switch (effect) {
case 1:
@@ -3856,15 +3884,10 @@ void ScummEngine::dissolveEffect(int width, int height) {
x = offsets[i] % vs->pitch;
y = offsets[i] / vs->pitch;
- if (_useCJKMode && _textSurfaceMultiplier == 2) {
- int m = _textSurfaceMultiplier;
- byte *dst = _fmtownsBuf + x * m + y * m * _screenWidth * m;
- scale2x(dst, _screenWidth * m, vs->getPixels(x, y), vs->pitch, width, height);
-
- _system->copyRectToScreen(dst, _screenWidth * m, x * m, (y + vs->topline) * m, width * m, height * m);
- } else {
+ if (_game.platform == Common::kPlatformFMTowns)
+ towns_drawStripToScreen(vs, x, y + vs->topline, x, y, width, height);
+ else
_system->copyRectToScreen(vs->getPixels(x, y), vs->pitch, x, y + vs->topline, width, height);
- }
if (++blits >= blits_before_refresh) {
@@ -3904,23 +3927,19 @@ void ScummEngine::scrollEffect(int dir) {
y = 1 + step;
while (y < vs->h) {
moveScreen(0, -step, vs->h);
-
- src = vs->getPixels(0, y - step);
- if (_useCJKMode && m == 2) {
- int x1 = 0, y1 = vs->h - step;
- byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m;
- scale2x(dst, _screenWidth * m, src, vs->pitch, vs->w, step);
- src = dst;
- vsPitch = _screenWidth * 2;
+
+ if (_townsScreen) {
+ towns_drawStripToScreen(vs, 0, vs->topline + vs->h - step, 0, y - step, vs->w, step);
+ } else {
+ src = vs->getPixels(0, y - step);
+ _system->copyRectToScreen(src,
+ vsPitch,
+ 0, (vs->h - step) * m,
+ vs->w * m, step * m);
+ _system->updateScreen();
}
-
- _system->copyRectToScreen(src,
- vsPitch,
- 0 * m, (vs->h - step) * m,
- vs->w * m, step * m);
- _system->updateScreen();
+
waitForTimer(delay);
-
y += step;
}
break;
@@ -3929,21 +3948,19 @@ void ScummEngine::scrollEffect(int dir) {
y = 1 + step;
while (y < vs->h) {
moveScreen(0, step, vs->h);
- src = vs->getPixels(0, vs->h - y);
- if (_useCJKMode && m == 2) {
- int x1 = 0, y1 = 0;
- byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m;
- scale2x(dst, _screenWidth * m, src, vs->pitch, vs->w, step);
- src = dst;
- vsPitch = _screenWidth * 2;
+
+ if (_townsScreen) {
+ towns_drawStripToScreen(vs, 0, vs->topline, 0, vs->h - y, vs->w, step);
+ } else {
+ src = vs->getPixels(0, vs->h - y);
+ _system->copyRectToScreen(src,
+ vsPitch,
+ 0, 0,
+ vs->w * m, step * m);
+ _system->updateScreen();
}
- _system->copyRectToScreen(src,
- vsPitch,
- 0, 0,
- vs->w * m, step * m);
- _system->updateScreen();
+
waitForTimer(delay);
-
y += step;
}
break;
@@ -3952,21 +3969,19 @@ void ScummEngine::scrollEffect(int dir) {
x = 1 + step;
while (x < vs->w) {
moveScreen(-step, 0, vs->h);
- src = vs->getPixels(x - step, 0);
- if (_useCJKMode && m == 2) {
- int x1 = vs->w - step, y1 = 0;
- byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m;
- scale2x(dst, _screenWidth * m, src, vs->pitch, step, vs->h);
- src = dst;
- vsPitch = _screenWidth * 2;
+
+ if (_townsScreen) {
+ towns_drawStripToScreen(vs, vs->w - step, vs->topline, x - step, 0, step, vs->h);
+ } else {
+ src = vs->getPixels(x - step, 0);
+ _system->copyRectToScreen(src,
+ vsPitch,
+ (vs->w - step) * m, 0,
+ step * m, vs->h * m);
+ _system->updateScreen();
}
- _system->copyRectToScreen(src,
- vsPitch,
- (vs->w - step) * m, 0,
- step * m, vs->h * m);
- _system->updateScreen();
- waitForTimer(delay);
+ waitForTimer(delay);
x += step;
}
break;
@@ -3975,21 +3990,19 @@ void ScummEngine::scrollEffect(int dir) {
x = 1 + step;
while (x < vs->w) {
moveScreen(step, 0, vs->h);
- src = vs->getPixels(vs->w - x, 0);
- if (_useCJKMode && m == 2) {
- int x1 = 0, y1 = 0;
- byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m;
- scale2x(dst, _screenWidth * m, src, vs->pitch, step, vs->h);
- src = dst;
- vsPitch = _screenWidth * 2;
- }
- _system->copyRectToScreen(src,
- vsPitch,
- 0, 0,
- step, vs->h);
- _system->updateScreen();
- waitForTimer(delay);
+ if (_townsScreen) {
+ towns_drawStripToScreen(vs, 0, vs->topline, vs->w - x, 0, step, vs->h);
+ } else {
+ src = vs->getPixels(vs->w - x, 0);
+ _system->copyRectToScreen(src,
+ vsPitch,
+ 0, 0,
+ step, vs->h);
+ _system->updateScreen();
+ }
+
+ waitForTimer(delay);
x += step;
}
break;