diff options
-rw-r--r-- | engines/mohawk/cursors.cpp | 14 | ||||
-rw-r--r-- | engines/mohawk/cursors.h | 2 | ||||
-rw-r--r-- | engines/mohawk/graphics.h | 8 | ||||
-rw-r--r-- | engines/mohawk/myst_graphics.cpp | 81 | ||||
-rw-r--r-- | engines/mohawk/myst_graphics.h | 4 |
5 files changed, 81 insertions, 28 deletions
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 4b66829e6a..72eebca917 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -34,8 +34,8 @@ #include "graphics/wincursor.h" #ifdef ENABLE_MYST -#include "mohawk/bitmap.h" #include "mohawk/myst.h" +#include "mohawk/myst_graphics.h" #endif namespace Mohawk { @@ -86,11 +86,9 @@ void DefaultCursorManager::setCursor(uint16 id) { #ifdef ENABLE_MYST MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) { - _bmpDecoder = new MystBitmap(); } MystCursorManager::~MystCursorManager() { - delete _bmpDecoder; } void MystCursorManager::showCursor() { @@ -111,17 +109,18 @@ void MystCursorManager::setCursor(uint16 id) { return; } - // Both Myst and Myst ME use the "MystBitmap" format for cursor images. - MohawkSurface *mhkSurface = _bmpDecoder->decodeImage(_vm->getResource(ID_WDIB, id)); - Graphics::Surface *surface = mhkSurface->getSurface(); Common::SeekableReadStream *clrcStream = _vm->getResource(ID_CLRC, id); uint16 hotspotX = clrcStream->readUint16LE(); uint16 hotspotY = clrcStream->readUint16LE(); delete clrcStream; + // Both Myst and Myst ME use the "MystBitmap" format for cursor images. + MohawkSurface *mhkSurface = _vm->_gfx->findImage(id); + Graphics::Surface *surface = mhkSurface->getSurface(); + // Myst ME stores some cursors as 24bpp images instead of 8bpp if (surface->format.bytesPerPixel == 1) { - CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 0); + CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 255); // We're using the screen palette for the original game, but we need // to use this for any 8bpp cursor in ME. @@ -133,7 +132,6 @@ void MystCursorManager::setCursor(uint16 id) { } _vm->_needsUpdate = true; - delete mhkSurface; } void MystCursorManager::setDefaultCursor() { diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h index c41b5c273e..742ae30107 100644 --- a/engines/mohawk/cursors.h +++ b/engines/mohawk/cursors.h @@ -102,7 +102,6 @@ enum { }; class MohawkEngine_Myst; -class MystBitmap; // The cursor manager for Myst // Uses WDIB + CLRC resources @@ -119,7 +118,6 @@ public: private: MohawkEngine_Myst *_vm; - MystBitmap *_bmpDecoder; }; #endif // ENABLE_MYST diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 5f9b523e9a..f9fdeea15f 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -74,6 +74,10 @@ public: // Free all surfaces in the cache void clearCache(); + // findImage will search the cache to find the image. + // If not found, it will call decodeImage to get a new one. + MohawkSurface *findImage(uint16 id); + void preloadImage(uint16 image); virtual void setPalette(uint16 id); void copyAnimImageToScreen(uint16 image, int left = 0, int top = 0); @@ -85,10 +89,6 @@ public: protected: void copyAnimImageSectionToScreen(MohawkSurface *image, Common::Rect src, Common::Rect dest); - // findImage will search the cache to find the image. - // If not found, it will call decodeImage to get a new one. - MohawkSurface *findImage(uint16 id); - // decodeImage will always return a new image. virtual MohawkSurface *decodeImage(uint16 id) = 0; virtual Common::Array<MohawkSurface *> decodeImages(uint16 id); diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp index 5db9697a78..427fba4d22 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -47,8 +47,7 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { } else { // Paletted initGraphics(_viewport.width(), _viewport.height(), true); - setBasePalette(); - setPaletteToScreen(); + clearScreenPalette(); } _pixelFormat = _vm->_system->getScreenFormat(); @@ -86,7 +85,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { bool isPict = false; - if (_vm->getFeatures() & GF_ME) { + if ((_vm->getFeatures() & GF_ME) && dataStream->size() > 512 + 10 + 4) { // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap // would be compressed, there's no way to detect for the BM without a hack. // So, we search for the PICT version opcode for detection. @@ -109,8 +108,11 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { } else { mhkSurface = _bmpDecoder->decodeImage(dataStream); - if (_vm->getFeatures() & GF_ME) + if (_vm->getFeatures() & GF_ME) { mhkSurface->convertToTrueColor(); + } else { + remapSurfaceToSystemPalette(mhkSurface); + } } assert(mhkSurface); @@ -204,7 +206,7 @@ void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, if (!(_vm->getFeatures() & GF_ME)) { // Make sure the palette is set assert(mhkSurface->getPalette()); - memcpy(_palette + 10 * 3, mhkSurface->getPalette() + 10 * 3, (256 - 10 * 2) * 3); + memcpy(_palette, mhkSurface->getPalette(), 256 * 3); setPaletteToScreen(); } } @@ -703,10 +705,10 @@ void MystGraphics::clearScreenPalette() { _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); } -void MystGraphics::setBasePalette() { +void MystGraphics::remapSurfaceToSystemPalette(MohawkSurface *mhkSurface) { // Entries [0, 9] of the palette static const byte lowPalette[] = { - 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, @@ -729,15 +731,68 @@ void MystGraphics::setBasePalette() { 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00 + 0xFF, 0xFF, 0xFF }; - // Note that 0 and 255 are different from normal Windows. - // Myst seems to hack that to white, resp. black (probably for Mac compat). + byte *originalPalette = mhkSurface->getPalette(); + + // The target palette is made of the Windows reserved palette, and colors 10 to 245 + // of the bitmap palette. Entries 0 to 9 and 246 to 255 of the bitmap palette are + // discarded. + byte targetPalette[256 * 3]; + memcpy(targetPalette, lowPalette, sizeof(lowPalette)); + memcpy(targetPalette + sizeof(lowPalette), originalPalette + sizeof(lowPalette), sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette)); + memcpy(targetPalette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette)); + + // Remap the discarded entries from the bitmap palette using the target palette. + byte lowColorMap[ARRAYSIZE(lowPalette) / 3]; + byte highColorMap[ARRAYSIZE(highPalette) / 3]; + + for (uint i = 0; i < ARRAYSIZE(lowColorMap); i++) { + uint colorIndex = 3 * i; + byte red = originalPalette[colorIndex + 0]; + byte green = originalPalette[colorIndex + 1]; + byte blue = originalPalette[colorIndex + 2]; + + lowColorMap[i] = getColorIndex(targetPalette, red, green, blue); + } + + for (uint i = 0; i < ARRAYSIZE(highColorMap); i++) { + uint colorIndex = 3 * (i + 246); + byte red = originalPalette[colorIndex + 0]; + byte green = originalPalette[colorIndex + 1]; + byte blue = originalPalette[colorIndex + 2]; + + highColorMap[i] = getColorIndex(targetPalette, red, green, blue); + } + + // Replace the original palette with the target palette + memcpy(originalPalette, targetPalette, sizeof(targetPalette)); + + // Remap the pixel data to the target palette + Graphics::Surface *surface = mhkSurface->getSurface(); + byte *pixels = (byte *) surface->getPixels(); + + for (int i = 0; i < surface->w * surface->h; i++) { + if (pixels[i] < ARRAYSIZE(lowColorMap)) { + pixels[i] = lowColorMap[pixels[i]]; + } else if (pixels[i] >= 246) { + pixels[i] = highColorMap[pixels[i] - 246]; + } + } +} + +byte MystGraphics::getColorIndex(const byte *palette, byte red, byte green, byte blue) { + for (uint i = 0; i < 256; i++) { + if (palette[(3 * i) + 0] == red && palette[(3 * i) + 1] == green && palette[(3 * i) + 2] == blue) { + return i; + } + } - memcpy(_palette, lowPalette, sizeof(lowPalette)); - memset(_palette + sizeof(lowPalette), 0, sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette)); - memcpy(_palette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette)); + // GDI actually chooses the nearest color if no exact match is found, + // but this should not happen in Myst + debug(1, "Color (%d, %d, %d) not in target palette", red, green, blue); + return 0; } void MystGraphics::setPaletteToScreen() { diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index 93e388cb83..cd09a53a3a 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -56,7 +56,6 @@ public: void fadeFromBlack(); void clearScreenPalette(); - void setBasePalette(); void setPaletteToScreen(); const byte *getPalette() const { return _palette; } @@ -86,6 +85,9 @@ private: void transitionSlideToBottom(Common::Rect rect, uint16 steps, uint16 delay); void transitionPartialToRight(Common::Rect rect, uint32 width, uint32 steps); void transitionPartialToLeft(Common::Rect rect, uint32 width, uint32 steps); + + void remapSurfaceToSystemPalette(MohawkSurface *mhkSurface); + byte getColorIndex(const byte *palette, byte red, byte green, byte blue); }; } // End of namespace Mohawk |