aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2004-04-08 23:43:30 +0000
committerMax Horn2004-04-08 23:43:30 +0000
commit333a2aaea8010317fb4588dcf5e5b172f0c4dc23 (patch)
tree723a771cdc013f8c8aed12286a556c3768534207
parent3dcd7bbfa8de79869a94ce1344fdb7ca141c0bf4 (diff)
downloadscummvm-rg350-333a2aaea8010317fb4588dcf5e5b172f0c4dc23.tar.gz
scummvm-rg350-333a2aaea8010317fb4588dcf5e5b172f0c4dc23.tar.bz2
scummvm-rg350-333a2aaea8010317fb4588dcf5e5b172f0c4dc23.zip
Fix for bugs #929722 (MI2: Difficulty selection screen regression) and #930385 (Subtitles are not shown correctly) by changing restoreCharsetBg() to only restore the screen area which is actually masked by text
svn-id: r13508
-rw-r--r--scumm/gfx.cpp180
1 files changed, 107 insertions, 73 deletions
diff --git a/scumm/gfx.cpp b/scumm/gfx.cpp
index a08c021aa7..f02bdfc9aa 100644
--- a/scumm/gfx.cpp
+++ b/scumm/gfx.cpp
@@ -156,6 +156,44 @@ static const TransitionEffect transitionEffects[5] = {
};
#endif
+static inline void copy8PixelsWithMasking(byte *dst, const byte *src, byte maskbits) {
+ if (!(maskbits & 0x80))
+ dst[0] = src[0];
+ if (!(maskbits & 0x40))
+ dst[1] = src[1];
+ if (!(maskbits & 0x20))
+ dst[2] = src[2];
+ if (!(maskbits & 0x10))
+ dst[3] = src[3];
+ if (!(maskbits & 0x08))
+ dst[4] = src[4];
+ if (!(maskbits & 0x04))
+ dst[5] = src[5];
+ if (!(maskbits & 0x02))
+ dst[6] = src[6];
+ if (!(maskbits & 0x01))
+ dst[7] = src[7];
+}
+
+static inline void clear8PixelsWithMasking(byte *dst, const byte color, byte maskbits) {
+ if (!(maskbits & 0x80))
+ dst[0] = color;
+ if (!(maskbits & 0x40))
+ dst[1] = color;
+ if (!(maskbits & 0x20))
+ dst[2] = color;
+ if (!(maskbits & 0x10))
+ dst[3] = color;
+ if (!(maskbits & 0x08))
+ dst[4] = color;
+ if (!(maskbits & 0x04))
+ dst[5] = color;
+ if (!(maskbits & 0x02))
+ dst[6] = color;
+ if (!(maskbits & 0x01))
+ dst[7] = color;
+}
+
#pragma mark -
#pragma mark --- Virtual Screens ---
#pragma mark -
@@ -544,7 +582,7 @@ void ScummEngine::redrawBGStrip(int start, int num) {
void ScummEngine::restoreBG(Common::Rect rect, byte backColor) {
VirtScreen *vs;
- byte *backbuff;
+ byte *screenBuf;
if (rect.top < 0)
rect.top = 0;
@@ -557,41 +595,33 @@ void ScummEngine::restoreBG(Common::Rect rect, byte backColor) {
if (rect.left > vs->width)
return;
- const int topline = vs->topline;
-
- // Move rect up
- rect.top -= topline;
- rect.bottom -= topline;
+ // Convert 'rect' to local (virtual screen) coordinates
+ rect.top -= vs->topline;
+ rect.bottom -= vs->topline;
rect.clip(vs->width, vs->height);
markRectAsDirty(vs->number, rect, USAGE_BIT_RESTORED);
- int offset = rect.top * vs->width + vs->xstart + rect.left;
- backbuff = vs->screenPtr + offset;
+ const int offset = rect.top * vs->width + vs->xstart + rect.left;
+ screenBuf = vs->screenPtr + offset;
int height = rect.height();
int width = rect.width();
+
+ if (!height)
+ return;
if (vs->hasTwoBuffers && _currentRoom != 0 && isLightOn()) {
- blit(backbuff, vs->backBuf + offset, width, height);
- if (vs->number == kMainVirtScreen && _charset->_hasMask && height) {
- byte *mask;
-
- // Move rect back
- rect.top += topline;
- rect.bottom += topline;
-
+ blit(screenBuf, vs->backBuf + offset, width, height);
+ if (vs->number == kMainVirtScreen && _charset->_hasMask) {
// Note: At first sight it may look as if this could
// be optimized to (rect.right - rect.left) / 8 and
// thus to width / 8, but that's not the case since
// we are dealing with integer math here.
- int mask_width = (rect.right / 8) - (rect.left / 8);
-
- if (rect.right & 0x07)
- mask_width++;
+ const int mask_width = ((rect.right + 7) / 8) - (rect.left / 8);
- mask = getMaskBuffer(rect.left, rect.top + topline, 0);
+ byte *mask = getMaskBuffer(rect.left, rect.top, 0);
do {
memset(mask, 0, mask_width);
@@ -600,34 +630,69 @@ void ScummEngine::restoreBG(Common::Rect rect, byte backColor) {
}
} else {
while (height--) {
- memset(backbuff, backColor, width);
- backbuff += vs->width;
+ memset(screenBuf, backColor, width);
+ screenBuf += vs->width;
}
}
}
void CharsetRenderer::restoreCharsetBg() {
+ _nextLeft = _vm->_string[0].xpos;
+ _nextTop = _vm->_string[0].ypos;
+
if (_hasMask) {
- // Restore background on the whole text area. To do this, we simply
- // pass a large rect to restoreBG, and then rely on it clipping that
- // rect. Also, restoreBG() will use findVirtScreen(rect.top) to
- // determine the virtual screen on which to operate. This is fine
- // for us, since we pass in rect.top, so in older games, the text
- // display area is used; in newer games, the main virtscreen gets
- // restored. That's exactly what we need.
- //
- // Of course this will break down if one of the older games (with
- // multiple virtual screens in use) draw text outside the text virtual
- // screen (verbs are excluded, they are handled in a special fashion).
- // But I have no indication that this does ever happen.
- _vm->restoreBG(Common::Rect(5000, 5000));
_hasMask = false;
_str.left = -1;
_left = -1;
- }
- _nextLeft = _vm->_string[0].xpos;
- _nextTop = _vm->_string[0].ypos;
+ // Restore background on the whole text area. This code is based on
+ // restoreBG(), but was changed to only restore those parts which are
+ // currently covered by the charset mask.
+
+ // Loop over first three virtual screens
+ VirtScreen *vs = &_vm->virtscr[_textScreenID];
+
+ if (!vs->height)
+ return;
+
+ _vm->markRectAsDirty(vs->number, Common::Rect(vs->width, vs->height), USAGE_BIT_RESTORED);
+
+ byte *screenBuf = vs->screenPtr + vs->xstart;
+
+ if (vs->hasTwoBuffers && _vm->_currentRoom != 0 && _vm->isLightOn()) {
+ const byte *backBuf = vs->backBuf + vs->xstart;
+
+ if (vs->number == kMainVirtScreen) {
+ // Restore from back buffer, but only those parts which are
+ // currently covered by the charset mask. In addition, we
+ // clean out the charset mask
+
+ const int mask_width = _vm->gdi._numStrips;
+ byte *mask = _vm->getMaskBuffer(0, vs->topline, 0);
+ assert(vs->width == 8 * _vm->gdi._numStrips);
+
+ int height = vs->height;
+ while (height--) {
+ for (int w = 0; w < mask_width; ++w) {
+ const byte maskbits = mask[w];
+ if (maskbits) {
+ copy8PixelsWithMasking(screenBuf + w*8, backBuf + w*8, ~maskbits);
+ mask[w] = 0;
+ }
+ }
+ screenBuf += vs->width;
+ backBuf += vs->width;
+ mask += _vm->gdi._numStrips;
+ }
+ } else {
+ // Restore from back buffer
+ _vm->blit(screenBuf, backBuf, vs->width, vs->height);
+ }
+ } else {
+ // Clear area
+ memset(screenBuf, 0, vs->height * vs->width);
+ }
+ }
}
void CharsetRenderer::clearCharsetMask() {
@@ -639,8 +704,7 @@ bool CharsetRenderer::hasCharsetMask(int left, int top, int right, int bottom) {
}
byte *ScummEngine::getMaskBuffer(int x, int y, int z) {
- return getResourceAddress(rtBuffer, 9)
- + _screenStartStrip + (x / 8) + y * gdi._numStrips + gdi._imgBufOffs[z];
+ return gdi.getMaskBuffer(x / 8, y, z) + _screenStartStrip;
}
byte *Gdi::getMaskBuffer(int x, int y, int z) {
@@ -1581,22 +1645,7 @@ void Gdi::draw8ColWithMasking(byte *dst, const byte *src, int height, byte *mask
do {
maskbits = *mask;
if (maskbits) {
- if (!(maskbits & 0x80))
- dst[0] = src[0];
- if (!(maskbits & 0x40))
- dst[1] = src[1];
- if (!(maskbits & 0x20))
- dst[2] = src[2];
- if (!(maskbits & 0x10))
- dst[3] = src[3];
- if (!(maskbits & 0x08))
- dst[4] = src[4];
- if (!(maskbits & 0x04))
- dst[5] = src[5];
- if (!(maskbits & 0x02))
- dst[6] = src[6];
- if (!(maskbits & 0x01))
- dst[7] = src[7];
+ copy8PixelsWithMasking(dst, src, maskbits);
} else {
#if defined(SCUMM_NEED_ALIGNMENT)
memcpy(dst, src, 8);
@@ -1617,22 +1666,7 @@ void Gdi::clear8ColWithMasking(byte *dst, int height, byte *mask) {
do {
maskbits = *mask;
if (maskbits) {
- if (!(maskbits & 0x80))
- dst[0] = 0;
- if (!(maskbits & 0x40))
- dst[1] = 0;
- if (!(maskbits & 0x20))
- dst[2] = 0;
- if (!(maskbits & 0x10))
- dst[3] = 0;
- if (!(maskbits & 0x08))
- dst[4] = 0;
- if (!(maskbits & 0x04))
- dst[5] = 0;
- if (!(maskbits & 0x02))
- dst[6] = 0;
- if (!(maskbits & 0x01))
- dst[7] = 0;
+ clear8PixelsWithMasking(dst, 0, maskbits);
} else {
#if defined(SCUMM_NEED_ALIGNMENT)
memset(dst, 0, 8);