From 5e00b39caec66e1c5626a89f207c26c577fd30d8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 8 Feb 2015 22:07:42 -0500 Subject: MADS: Implementing code for panning screen transitions --- engines/mads/msurface.cpp | 15 +++++- engines/mads/msurface.h | 7 +++ engines/mads/palette.cpp | 26 ++++++++++ engines/mads/palette.h | 3 ++ engines/mads/screen.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++++- engines/mads/screen.h | 13 +++++ 6 files changed, 183 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index 39824bac4b..d8d01f307c 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -485,7 +485,6 @@ void MSurface::scrollY(int yAmount) { delete[] tempData; } - void MSurface::translate(Common::Array &palette) { for (int y = 0; y < this->h; ++y) { byte *pDest = getBasePtr(0, y); @@ -521,6 +520,20 @@ MSurface *MSurface::flipHorizontal() const { return dest; } +void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, + const Common::Point &destPos, const Common::Rect &srcRect) { + // Loop through the lines + for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) { + const byte *srcP = srcSurface.getBasePtr(srcRect.left, srcRect.top + yCtr); + byte *destP = getBasePtr(destPos.x, destPos.y + yCtr); + + // Copy the line over + for (int xCtr = 0; xCtr < srcRect.width(); ++xCtr, ++srcP, ++destP) { + *destP = paletteMap[*srcP]; + } + } +} + /*------------------------------------------------------------------------*/ int DepthSurface::getDepth(const Common::Point &pt) { diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index 650d7fdaee..754e70bf7f 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -220,6 +220,13 @@ public: * Create a new surface which is a flipped horizontal copy of the current one */ MSurface *flipHorizontal() const; + + /** + * Copy an area from one surface to another, translating it using a palette + * map as it's done + */ + void copyRectTranslate(MSurface &srcSurface, const byte *paletteMap, + const Common::Point &destPos, const Common::Rect &srcRect); }; class DepthSurface : public MSurface { diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp index 250eb75955..250c98b074 100644 --- a/engines/mads/palette.cpp +++ b/engines/mads/palette.cpp @@ -885,4 +885,30 @@ void Palette::refreshSceneColors() { setPalette(_mainPalette + (val * 3), val, 256 - val); } +int Palette::closestColor(const byte *matchColor, const byte *refPalette, + int listWrap, int count) { + int bestColor = 0; + int bestDifference = 0x7fff; + + for (int idx = 0; idx < count; ++idx) { + // Figure out hash for color + int hash = 0; + for (int rgbIdx = 0; rgbIdx < 3; ++rgbIdx, ++refPalette) { + byte diff = *refPalette - matchColor[rgbIdx]; + hash += (int)diff * (int)diff; + } + + // If the given color is a closer match to our color, store the index + if (hash < bestDifference) { + bestDifference = hash; + bestColor = idx; + } + + refPalette += listWrap - 3; + } + + return bestColor; +} + + } // End of namespace MADS diff --git a/engines/mads/palette.h b/engines/mads/palette.h index 27d25f266b..1c387b4368 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -318,6 +318,9 @@ public: void unlock(); void refreshSceneColors(); + + static int closestColor(const byte *matchColor, const byte *refPalette, + int listWrap, int count); }; } // End of namespace MADS diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index 8552effd98..f7179877d5 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -607,6 +607,7 @@ void ScreenSurface::updateScreen() { void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag) { Palette &pal = *_vm->_palette; + Scene &scene = _vm->_game->_scene; byte palData[PALETTE_SIZE]; switch (transitionType) { @@ -639,8 +640,9 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag case kTransitionPanLeftToRight: case kTransitionPanRightToLeft: - warning("TODO: pan transition"); - transition(kTransitionFadeIn, surfaceFlag); + panTransition(scene._backgroundSurface, pal._mainPalette, + transitionType - kTransitionPanLeftToRight, + Common::Point(0, 0), scene._posAdjust, THROUGH_BLACK2, true, 1); break; case kTransitionCircleIn1: @@ -674,5 +676,121 @@ void ScreenSurface::resetClipBounds() { setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); } +void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entrySide, + const Common::Point &srcPos, const Common::Point &destPos, + ThroughBlack throughBlack, bool setPalette, int numTicks) { + EventsManager &events = *_vm->_events; + Palette &palette = *_vm->_palette; + Common::Point size; + int y1, y2; + int startX = 0; + int deltaX; + int sizeY; + int xAt; + int loopStart; +// uint32 baseTicks, currentTicks; + byte paletteMap[256]; + + size.x = MIN(newScreen.w, (uint16)MADS_SCREEN_WIDTH); + size.y = newScreen.h; + if (newScreen.h >= MADS_SCREEN_HEIGHT) + size.y = MADS_SCENE_HEIGHT; + + // Set starting position and direction delta for the transition + if (entrySide == 1) + // Right to left + startX = size.x - 1; + deltaX = startX ? -1 : 1; + + if (setPalette & !throughBlack) + palette.setFullPalette(palData); + + // TODO: Original uses a different frequency ticks counter. Need to + // confirm frequency and see whether we need to implement it, or + // if the current frame ticks can substitute for it +// baseTicks = events.getFrameCounter(); + + y1 = 0; + y2 = size.y - 1; + sizeY = y2 - y1 + 1; + + if (throughBlack == THROUGH_BLACK2) + swapForeground(palData, &paletteMap[0]); + + loopStart = throughBlack == THROUGH_BLACK1 ? 0 : 1; + for (int loop = loopStart; loop < 2; ++loop) { + xAt = startX; + for (int xCtr = 0; xCtr < size.x; ++xCtr, xAt += deltaX) { + if (!loop) { + fillRect(Common::Rect(xAt + destPos.x, y1 + destPos.y, + xAt + destPos.x + 1, y2 + destPos.y), 0); + } else if (throughBlack == THROUGH_BLACK2) { + copyRectTranslate(newScreen, paletteMap, + Common::Point(xAt, destPos.y), + Common::Rect(srcPos.x + xAt, srcPos.y, + srcPos.x + xAt + 1, srcPos.y + size.y)); + } else { + newScreen.copyRectToSurface(*this, xAt, destPos.y, + Common::Rect(srcPos.x + xAt, srcPos.y, + srcPos.x + xAt + 1, srcPos.y + size.y)); + } + + copyRectToScreen(Common::Rect(xAt, destPos.y, xAt + 1, destPos.y + size.y)); + + // Slight delay + events.delay(1); + } + + if ((setPalette && !loop) || throughBlack == THROUGH_BLACK2) + palette.setFullPalette(palData); + } + + if (throughBlack == THROUGH_BLACK2) { + Common::Rect r(srcPos.x, srcPos.y, srcPos.x + size.x, srcPos.y + size.y); + copyRectToSurface(newScreen, destPos.x, destPos.y, r); + copyRectToScreen(r); + } +} + +void ScreenSurface::swapForeground(byte palData[PALETTE_SIZE], byte *paletteMap) { + Palette &palette = *_vm->_palette; + byte oldPalette[PALETTE_SIZE]; + byte oldMap[256]; + byte newMap[256]; + + palette.getFullPalette(oldPalette); + swapPalette(oldPalette, oldMap, true); + swapPalette(palData, newMap, false); + + Common::copy(&palData[3], &palData[PALETTE_SIZE], &oldPalette[3]); + + copyRectTranslate(*this, oldMap, Common::Point(0, 0), + Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); + palette.setFullPalette(oldPalette); +} + +void ScreenSurface::swapPalette(byte *palData, byte swapTable[PALETTE_COUNT], + int start) { + byte *dynamicList = &palData[start * 3]; + int staticStart = 1 - start; + byte *staticList = &palData[staticStart * 3]; + const int PALETTE_START = 1; + const int PALETTE_END = 252; + + // Set initial index values + for (int idx = 0; idx < PALETTE_COUNT; ++idx) + swapTable[idx] = idx; + + for (int idx = 0; idx < 128; ++idx) { + if (start >= PALETTE_START && start <= PALETTE_END) { + swapTable[start] = Palette::closestColor(dynamicList, staticList, + 6, 128) * 2 + staticStart; + } + + dynamicList += 6; + start += 2; + } +} + } // End of namespace MADS diff --git a/engines/mads/screen.h b/engines/mads/screen.h index 6800523f92..35042e88d2 100644 --- a/engines/mads/screen.h +++ b/engines/mads/screen.h @@ -56,6 +56,11 @@ enum InputMode { kInputLimitedSentences = 2 // Use only scene hotspots }; +enum ThroughBlack { + THROUGH_BLACK1 = 1, + THROUGH_BLACK2 = 2 +}; + class SpriteSlot; class TextDisplay; class UISlot; @@ -207,6 +212,14 @@ private: uint16 _random; byte *_surfacePixels; Common::Rect _clipBounds; + + void panTransition(MSurface &newScreen, byte *palData, int entrySide, + const Common::Point &srcPos, const Common::Point &destPos, + ThroughBlack throughBlack, bool setPalette, int numTicks); + + void swapForeground(byte *palData, byte *paletteMap); + + void swapPalette(byte palData[PALETTE_SIZE], byte swapTable[PALETTE_COUNT], int start); public: int _shakeCountdown; public: -- cgit v1.2.3