aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mohawk/cursors.cpp14
-rw-r--r--engines/mohawk/cursors.h2
-rw-r--r--engines/mohawk/graphics.h8
-rw-r--r--engines/mohawk/myst_graphics.cpp81
-rw-r--r--engines/mohawk/myst_graphics.h4
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