scummvm/engines/mohawk/cursors.cpp
Bastien Bouclet 3391c726cf MOHAWK: Remap bitmaps not to use undefined colors
The Spanish version of Myst has bitmaps that use palette indices in the system
reserved range. Affected pixels previously used colors from the Windows system
palette instead of the bitmap's own palette, resulting in visual glitches.

Bitmaps are now remapped to the screen palette which is made of the Windows
reserved palette and part of the bitmap palette. The original engine used GDI's
StretchDIBits with DIB_RGB_COLORS to achieve the same result.

Fixes #7153.
2016-06-26 08:37:07 +02:00

275 lines
7.5 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "mohawk/cursors.h"
#include "mohawk/mohawk.h"
#include "mohawk/resource.h"
#include "common/macresman.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/winexe_ne.h"
#include "common/winexe_pe.h"
#include "graphics/cursorman.h"
#include "graphics/maccursor.h"
#include "graphics/wincursor.h"
#ifdef ENABLE_MYST
#include "mohawk/myst.h"
#include "mohawk/myst_graphics.h"
#endif
namespace Mohawk {
void CursorManager::showCursor() {
CursorMan.showMouse(true);
}
void CursorManager::hideCursor() {
CursorMan.showMouse(false);
}
void CursorManager::setDefaultCursor() {
Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
delete cursor;
}
void CursorManager::setCursor(uint16 id) {
// For the base class, just use the default cursor always
setDefaultCursor();
}
void CursorManager::setMacCursor(Common::SeekableReadStream *stream) {
assert(stream);
Graphics::MacCursor *macCursor = new Graphics::MacCursor();
if (!macCursor->readFromStream(*stream))
error("Could not parse Mac cursor");
CursorMan.replaceCursor(macCursor->getSurface(), macCursor->getWidth(), macCursor->getHeight(),
macCursor->getHotspotX(), macCursor->getHotspotY(), macCursor->getKeyColor());
CursorMan.replaceCursorPalette(macCursor->getPalette(), 0, 256);
delete macCursor;
delete stream;
}
void DefaultCursorManager::setCursor(uint16 id) {
setMacCursor(_vm->getResource(_tag, id));
}
#ifdef ENABLE_MYST
MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) {
}
MystCursorManager::~MystCursorManager() {
}
void MystCursorManager::showCursor() {
CursorMan.showMouse(true);
_vm->_needsUpdate = true;
}
void MystCursorManager::hideCursor() {
CursorMan.showMouse(false);
_vm->_needsUpdate = true;
}
void MystCursorManager::setCursor(uint16 id) {
// Zero means empty cursor
if (id == 0) {
static const byte emptyCursor[4] = { 0, 0, 0, 0 };
CursorMan.replaceCursor(&emptyCursor, 2, 2, 0, 0, 0);
return;
}
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, 255);
// We're using the screen palette for the original game, but we need
// to use this for any 8bpp cursor in ME.
if (_vm->getFeatures() & GF_ME)
CursorMan.replaceCursorPalette(mhkSurface->getPalette(), 0, 256);
} else {
Graphics::PixelFormat pixelFormat = g_system->getScreenFormat();
CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, pixelFormat.RGBToColor(255, 255, 255), false, &pixelFormat);
}
_vm->_needsUpdate = true;
}
void MystCursorManager::setDefaultCursor() {
setCursor(kDefaultMystCursor);
}
#endif
NECursorManager::NECursorManager(const Common::String &appName) {
_exe = new Common::NEResources();
if (!_exe->loadFromEXE(appName)) {
// Not all have cursors anyway, so this is not a problem
delete _exe;
_exe = 0;
}
}
NECursorManager::~NECursorManager() {
delete _exe;
}
void NECursorManager::setCursor(uint16 id) {
if (_exe) {
Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
if (cursorGroup) {
Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor;
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
delete cursorGroup;
return;
}
}
// Last resort (not all have cursors)
setDefaultCursor();
}
MacCursorManager::MacCursorManager(const Common::String &appName) {
if (!appName.empty()) {
_resFork = new Common::MacResManager();
if (!_resFork->open(appName)) {
// Not all have cursors anyway, so this is not a problem
delete _resFork;
_resFork = 0;
}
} else {
_resFork = 0;
}
}
MacCursorManager::~MacCursorManager() {
delete _resFork;
}
void MacCursorManager::setCursor(uint16 id) {
if (!_resFork) {
setDefaultCursor();
return;
}
// Try a color cursor first
Common::SeekableReadStream *stream = _resFork->getResource(MKTAG('c','r','s','r'), id);
// Fall back to monochrome cursors
if (!stream)
stream = _resFork->getResource(MKTAG('C','U','R','S'), id);
if (stream)
setMacCursor(stream);
else
setDefaultCursor();
}
LivingBooksCursorManager_v2::LivingBooksCursorManager_v2() {
// Try to open the system archive if we have it
_sysArchive = new MohawkArchive();
if (!_sysArchive->openFile("system.mhk")) {
delete _sysArchive;
_sysArchive = 0;
}
}
LivingBooksCursorManager_v2::~LivingBooksCursorManager_v2() {
delete _sysArchive;
}
void LivingBooksCursorManager_v2::setCursor(uint16 id) {
if (_sysArchive && _sysArchive->hasResource(ID_TCUR, id)) {
setMacCursor(_sysArchive->getResource(ID_TCUR, id));
} else {
// TODO: Handle generated cursors
}
}
void LivingBooksCursorManager_v2::setCursor(const Common::String &name) {
if (!_sysArchive)
return;
uint16 id = _sysArchive->findResourceID(ID_TCUR, name);
if (id == 0xffff)
error("Could not find cursor '%s'", name.c_str());
else
setCursor(id);
}
PECursorManager::PECursorManager(const Common::String &appName) {
_exe = new Common::PEResources();
if (!_exe->loadFromEXE(appName)) {
// Not all have cursors anyway, so this is not a problem
delete _exe;
_exe = 0;
}
}
PECursorManager::~PECursorManager() {
delete _exe;
}
void PECursorManager::setCursor(uint16 id) {
if (_exe) {
Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
if (cursorGroup) {
Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor;
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
delete cursorGroup;
return;
}
}
// Last resort (not all have cursors)
setDefaultCursor();
}
} // End of namespace Mohawk