diff options
Diffstat (limited to 'engines')
49 files changed, 1461 insertions, 742 deletions
diff --git a/engines/cine/pal.h b/engines/cine/pal.h index 4764d5a474..26513eb5a1 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -36,7 +36,8 @@ namespace Cine { #define kLowPalNumBytes ((kLowPalNumColors) * (kLowPalBytesPerColor)) /*! \brief Low resolution (9-bit) color format used in Cine's 16-color modes. */ -static const Graphics::PixelFormat kLowPalFormat = {kLowPalBytesPerColor, 5, 5, 5, 8, 8, 4, 0, 0}; + static const Graphics::PixelFormat kLowPalFormat(kLowPalBytesPerColor, 5, 5, 5, 8, 8, 4, 0, 0); + // Constants related to kHighPalFormat #define kHighPalBytesPerColor 3 @@ -44,10 +45,10 @@ static const Graphics::PixelFormat kLowPalFormat = {kLowPalBytesPerColor, 5, 5, #define kHighPalNumBytes ((kHighPalNumColors) * (kHighPalBytesPerColor)) /*! \brief High resolution (24-bit) color format used in Cine's 256-color modes. */ -static const Graphics::PixelFormat kHighPalFormat = {kHighPalBytesPerColor, 0, 0, 0, 8, 0, 8, 16, 0}; +static const Graphics::PixelFormat kHighPalFormat(kHighPalBytesPerColor, 0, 0, 0, 8, 0, 8, 16, 0); /*! \brief The color format used by OSystem's setPalette-function. */ -static const Graphics::PixelFormat kSystemPalFormat = {4, 0, 0, 0, 8, 0, 8, 16, 0}; +static const Graphics::PixelFormat kSystemPalFormat(4, 0, 0, 0, 8, 0, 8, 16, 0); /*! \brief Endian types. Used at least by Palette class's load and save functions. * TODO: Move somewhere more general as this is definitely not Cine-engine specific diff --git a/engines/engine.cpp b/engines/engine.cpp index 0847e27246..1fd77eb310 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -125,11 +125,16 @@ void initCommonGFX(bool defaultTo1XScaler) { g_system->setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen")); } -void initGraphics(int width, int height, bool defaultTo1xScaler) { +void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format) { + g_system->beginGFXTransaction(); initCommonGFX(defaultTo1xScaler); +#ifdef ENABLE_RGB_COLOR + g_system->initSize(width, height, format); +#else g_system->initSize(width, height); +#endif OSystem::TransactionError gfxError = g_system->endGFXTransaction(); @@ -150,6 +155,15 @@ void initGraphics(int width, int height, bool defaultTo1xScaler) { } // Just show warnings then these occur: +#ifdef ENABLE_RGB_COLOR + if (gfxError & OSystem::kTransactionFormatNotSupported) { + Common::String message = "Could not initialize color format."; + + GUI::MessageDialog dialog(message); + dialog.runModal(); + } +#endif + if (gfxError & OSystem::kTransactionModeSwitchFailed) { Common::String message = "Could not switch to video mode: '"; message += ConfMan.get("gfx_mode"); diff --git a/engines/engine.h b/engines/engine.h index ff3ce6c326..d570f18073 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -29,6 +29,7 @@ #include "common/error.h" #include "common/fs.h" #include "common/str.h" +#include "graphics/pixelformat.h" class OSystem; @@ -58,8 +59,10 @@ void initCommonGFX(bool defaultTo1XScaler); * * Errors out when backend is not able to switch to the specified * mode. + * + * Defaults to 256 color paletted mode if no graphics format is provided. */ -void initGraphics(int width, int height, bool defaultTo1xScaler); +void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format = NULL); /** * Initializes graphics and shows error message. diff --git a/engines/gob/video_v6.cpp b/engines/gob/video_v6.cpp index 74447f1a84..983eeea8cf 100644 --- a/engines/gob/video_v6.cpp +++ b/engines/gob/video_v6.cpp @@ -25,6 +25,7 @@ #include "common/endian.h" #include "common/savefile.h" +#include "graphics/conversion.h" #include "graphics/dither.h" #include "gob/gob.h" @@ -45,8 +46,8 @@ void Video_v6::setPrePalette() { for (int i = 0; i < 256; i++) { byte r, g, b; - Graphics::PaletteLUT::YUV2RGB(fpal[i * 3 + 0], fpal[i * 3 + 1], fpal[i * 3 + 2], - r, g, b); + Graphics::YUV2RGB(fpal[i * 3 + 0], fpal[i * 3 + 1], fpal[i * 3 + 2], + r, g, b); tpal[i * 3 + 0] = r >> 2; tpal[i * 3 + 1] = g >> 2; diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp index 647eaa913b..1e54f0e79b 100644 --- a/engines/groovie/graphics.cpp +++ b/engines/groovie/graphics.cpp @@ -31,8 +31,8 @@ namespace Groovie { GraphicsMan::GraphicsMan(GroovieEngine *vm) : _vm(vm), _changed(false), _fading(0) { // Create the game surfaces - _foreground.create(640, 320, 1); - _background.create(640, 320, 1); + _foreground.create(640, 320, _vm->_pixelFormat.bytesPerPixel); + _background.create(640, 320, _vm->_pixelFormat.bytesPerPixel); } GraphicsMan::~GraphicsMan() { diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 9381b5b47c..6f985ddad5 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -70,7 +70,21 @@ GroovieEngine::~GroovieEngine() { Common::Error GroovieEngine::run() { // Initialize the graphics - initGraphics(640, 480, true); + switch (_gameDescription->version) { + case kGroovieV2: + // Request the mode with the highest precision available + _pixelFormat = _system->getSupportedFormats().front(); + initGraphics(640, 480, true, &_pixelFormat); + + // Save the enabled mode as it can be both an RGB mode or CLUT8 + _pixelFormat = _system->getScreenFormat(); + _mode8bit = (_pixelFormat == Graphics::PixelFormat::createFormatCLUT8()); + break; + case kGroovieT7G: + initGraphics(640, 480, true); + _pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); + break; + } // Create debugger. It requires GFX to be initialized _debugger = new Debugger(this); @@ -204,13 +218,18 @@ Common::Error GroovieEngine::run() { case Common::EVENT_LBUTTONDOWN: // Send the event to the scripts - _script.setMouseClick(); + _script.setMouseClick(1); // Continue the script execution to handle // the click _waitingForInput = false; break; + case Common::EVENT_RBUTTONDOWN: + // Send the event to the scripts (to skip the video) + _script.setMouseClick(2); + break; + case Common::EVENT_QUIT: quitGame(); break; diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h index a137193adf..bf57ae77de 100644 --- a/engines/groovie/groovie.h +++ b/engines/groovie/groovie.h @@ -85,6 +85,8 @@ protected: public: void waitForInput(); + Graphics::PixelFormat _pixelFormat; + bool _mode8bit; Script _script; ResMan *_resMan; GrvCursorMan *_grvCursorMan; diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index dcb8eafcb8..538b1b7111 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -29,6 +29,12 @@ #include "groovie/groovie.h" #include "groovie/roq.h" +#include "graphics/jpeg.h" + +#ifdef ENABLE_RGB_COLOR +// Required for the YUV to RGB conversion +#include "graphics/conversion.h" +#endif #include "sound/mixer.h" namespace Groovie { @@ -43,50 +49,52 @@ ROQPlayer::ROQPlayer(GroovieEngine *vm) : _currBuf = new Graphics::Surface(); _prevBuf = new Graphics::Surface(); - byte pal[256 * 4]; + if (_vm->_mode8bit) { + byte pal[256 * 4]; #ifdef DITHER - byte pal3[256 * 3]; - // Initialize to a black palette - for (int i = 0; i < 256 * 3; i++) { - pal3[i] = 0; - } - - // Build a basic color palette - for (int r = 0; r < 4; r++) { - for (int g = 0; g < 4; g++) { - for (int b = 0; b < 4; b++) { - byte col = (r << 4) | (g << 2) | (b << 0); - pal3[3 * col + 0] = r << 6; - pal3[3 * col + 1] = g << 6; - pal3[3 * col + 2] = b << 6; + byte pal3[256 * 3]; + // Initialize to a black palette + for (int i = 0; i < 256 * 3; i++) { + pal3[i] = 0; + } + + // Build a basic color palette + for (int r = 0; r < 4; r++) { + for (int g = 0; g < 4; g++) { + for (int b = 0; b < 4; b++) { + byte col = (r << 4) | (g << 2) | (b << 0); + pal3[3 * col + 0] = r << 6; + pal3[3 * col + 1] = g << 6; + pal3[3 * col + 2] = b << 6; + } } } - } - // Initialize the dithering algorithm - _paletteLookup = new Graphics::PaletteLUT(8, Graphics::PaletteLUT::kPaletteYUV); - _paletteLookup->setPalette(pal3, Graphics::PaletteLUT::kPaletteRGB, 8); - for (int i = 0; (i < 64) && !_vm->shouldQuit(); i++) { - debug("Groovie::ROQ: Building palette table: %02d/63", i); - _paletteLookup->buildNext(); - } + // Initialize the dithering algorithm + _paletteLookup = new Graphics::PaletteLUT(8, Graphics::PaletteLUT::kPaletteYUV); + _paletteLookup->setPalette(pal3, Graphics::PaletteLUT::kPaletteRGB, 8); + for (int i = 0; (i < 64) && !_vm->shouldQuit(); i++) { + debug("Groovie::ROQ: Building palette table: %02d/63", i); + _paletteLookup->buildNext(); + } - // Prepare the palette to show - for (int i = 0; i < 256; i++) { - pal[(i * 4) + 0] = pal3[(i * 3) + 0]; - pal[(i * 4) + 1] = pal3[(i * 3) + 1]; - pal[(i * 4) + 2] = pal3[(i * 3) + 2]; - } -#else - // Set a grayscale palette - for (int i = 0; i < 256; i++) { - pal[(i * 4) + 0] = i; - pal[(i * 4) + 1] = i; - pal[(i * 4) + 2] = i; - } -#endif + // Prepare the palette to show + for (int i = 0; i < 256; i++) { + pal[(i * 4) + 0] = pal3[(i * 3) + 0]; + pal[(i * 4) + 1] = pal3[(i * 3) + 1]; + pal[(i * 4) + 2] = pal3[(i * 3) + 2]; + } +#else // !DITHER + // Set a grayscale palette + for (int i = 0; i < 256; i++) { + pal[(i * 4) + 0] = i; + pal[(i * 4) + 1] = i; + pal[(i * 4) + 2] = i; + } +#endif // DITHER - _syst->setPalette(pal, 0, 256); + _syst->setPalette(pal, 0, 256); + } } ROQPlayer::~ROQPlayer() { @@ -152,22 +160,39 @@ void ROQPlayer::buildShowBuf() { for (int line = 0; line < _showBuf.h; line++) { byte *out = (byte *)_showBuf.getBasePtr(0, line); - byte *in = (byte *)_prevBuf->getBasePtr(0, line / _scaleY); + byte *in = (byte *)_currBuf->getBasePtr(0, line / _scaleY); for (int x = 0; x < _showBuf.w; x++) { + if (_vm->_mode8bit) { #ifdef DITHER - *out = _dither->dither(*in, *(in + 1), *(in + 2), x); + *out = _dither->dither(*in, *(in + 1), *(in + 2), x); #else - // Just use the luminancy component - *out = *in; -#endif - out++; + // Just use the luminancy component + *out = *in; +#endif // DITHER +#ifdef ENABLE_RGB_COLOR + } else { + // Do the format conversion (YUV -> RGB -> Screen format) + byte r, g, b; + Graphics::YUV2RGB(*in, *(in + 1), *(in + 2), r, g, b); + // FIXME: this is fixed to 16bit + *(uint16 *)out = (uint16)_vm->_pixelFormat.RGBToColor(r, g, b); +#endif // ENABLE_RGB_COLOR + } + + // Skip to the next pixel + out += _vm->_pixelFormat.bytesPerPixel; if (!(x % _scaleX)) - in += _prevBuf->bytesPerPixel; + in += _currBuf->bytesPerPixel; } #ifdef DITHER _dither->nextLine(); #endif } + + // Swap buffers + Graphics::Surface *tmp = _prevBuf; + _prevBuf = _currBuf; + _currBuf = tmp; } bool ROQPlayer::playFrameInternal() { @@ -180,7 +205,7 @@ bool ROQPlayer::playFrameInternal() { } if (_dirty) { - // Build the show buffer from the previous (back) buffer + // Build the show buffer from the current buffer buildShowBuf(); } @@ -189,7 +214,7 @@ bool ROQPlayer::playFrameInternal() { if (_dirty) { // Update the screen - _syst->copyRectToScreen((byte *)_showBuf.getBasePtr(0, 0), _showBuf.w, 0, (_syst->getHeight() - _showBuf.h) / 2, _showBuf.pitch, _showBuf.h); + _syst->copyRectToScreen((byte *)_showBuf.getBasePtr(0, 0), _showBuf.pitch, 0, (_syst->getHeight() - _showBuf.h) / 2, _showBuf.w, _showBuf.h); _syst->updateScreen(); // Clear the dirty flag @@ -240,19 +265,15 @@ bool ROQPlayer::processBlock() { case 0x1002: // Quad codebook definition ok = processBlockQuadCodebook(blockHeader); break; - case 0x1011: { // Quad vector quantised video frame + case 0x1011: // Quad vector quantised video frame ok = processBlockQuadVector(blockHeader); _dirty = true; endframe = true; - - // Swap buffers - Graphics::Surface *tmp = _prevBuf; - _prevBuf = _currBuf; - _currBuf = tmp; break; - } case 0x1012: // Still image (JPEG) ok = processBlockStill(blockHeader); + _dirty = true; + endframe = true; break; case 0x1013: // Hang assert(blockHeader.size == 0 && blockHeader.param == 0); @@ -317,7 +338,19 @@ bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) { // Allocate new buffers _currBuf->create(width, height, 3); _prevBuf->create(width, height, 3); - _showBuf.create(width * _scaleX, height * _scaleY, 1); + _showBuf.create(width * _scaleX, height * _scaleY, _vm->_pixelFormat.bytesPerPixel); + + // Clear the buffers with black YUV values + byte *ptr1 = (byte *)_currBuf->getBasePtr(0, 0); + byte *ptr2 = (byte *)_prevBuf->getBasePtr(0, 0); + for (int i = 0; i < width * height; i++) { + *ptr1++ = 0; + *ptr1++ = 128; + *ptr1++ = 128; + *ptr2++ = 0; + *ptr2++ = 128; + *ptr2++ = 128; + } #ifdef DITHER // Reset the dithering algorithm with the new width @@ -456,10 +489,23 @@ void ROQPlayer::processBlockQuadVectorBlockSub(int baseX, int baseY, int8 Mx, in bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing still (JPEG) block"); - warning("Groovie::ROQ: JPEG frame (unimplemented)"); - memset(_prevBuf->getBasePtr(0, 0), 0, _prevBuf->w * _prevBuf->h * _prevBuf->bytesPerPixel); + warning("Groovie::ROQ: JPEG frame (unfinshed)"); + + Graphics::JPEG *jpg = new Graphics::JPEG(); + jpg->read(_file); + byte *y = (byte *)jpg->getComponent(1)->getBasePtr(0, 0); + byte *u = (byte *)jpg->getComponent(2)->getBasePtr(0, 0); + byte *v = (byte *)jpg->getComponent(3)->getBasePtr(0, 0); + + byte *ptr = (byte *)_currBuf->getBasePtr(0, 0); + for (int i = 0; i < _currBuf->w * _currBuf->h; i++) { + *ptr++ = *y++; + *ptr++ = *u++; + *ptr++ = *v++; + } + memcpy(_prevBuf->getBasePtr(0, 0), _currBuf->getBasePtr(0, 0), _prevBuf->w * _prevBuf->h * 3); - _file->skip(blockHeader.size); + delete jpg; return true; } diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index eb53842b91..6dd1124fce 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -101,6 +101,7 @@ Script::Script(GroovieEngine *vm, EngineVersion version) : _hotspotSlot = (uint16)-1; _oldInstruction = (uint16)-1; + _videoSkipAddress = 0; } Script::~Script() { @@ -230,8 +231,8 @@ void Script::step() { (this->*op)(); } -void Script::setMouseClick() { - _eventMouseClicked = true; +void Script::setMouseClick(uint8 button) { + _eventMouseClicked = button; } void Script::setKbdChar(uint8 c) { @@ -354,7 +355,7 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { Common::isDebugChannelEnabled(kGroovieDebugAll)) { rect.translate(0, -80); _vm->_graphicsMan->_foreground.frameRect(rect, 250); - _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), 640, 0, 80, 640, 320); + _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); _vm->_system->updateScreen(); } @@ -525,7 +526,6 @@ void Script::o_videofromref() { // 0x09 bool Script::playvideofromref(uint32 fileref) { // It isn't the current video, open it if (fileref != _videoRef) { - // Debug bitflags debugScript(1, false, "Play video 0x%04X (bitflags:", fileref); for (int i = 15; i >= 0; i--) { @@ -554,6 +554,21 @@ bool Script::playvideofromref(uint32 fileref) { } _bitflags = 0; + + // Reset the clicked mouse events + _eventMouseClicked = 0; + } + + // Check if the user wants to skip the video + if ((_eventMouseClicked == 2) && (_videoSkipAddress != 0)) { + // Jump to the given address + _currentInstruction = _videoSkipAddress; + + // Reset the skip address + _videoSkipAddress = 0; + + // End the playback + return true; } // Video available, play one frame @@ -567,7 +582,7 @@ bool Script::playvideofromref(uint32 fileref) { _videoRef = 0; // Clear the input events while playing the video - _eventMouseClicked = false; + _eventMouseClicked = 0; _eventKbdChar = 0; // Newline @@ -598,8 +613,8 @@ void Script::o_inputloopstart() { //0x0B _inputLoopAddress = _currentInstruction - 1; // Save the current mouse state for the whole loop - _mouseClicked = _eventMouseClicked; - _eventMouseClicked = false; + _mouseClicked = (_eventMouseClicked == 1); + _eventMouseClicked = 0; // Save the current pressed character for the whole loop _kbdChar = _eventKbdChar; @@ -1378,7 +1393,7 @@ void Script::o_sub() { void Script::o_cellmove() { uint16 arg = readScript8bits(); byte *scriptBoard = &_variables[0x19]; - byte *board = (byte*) malloc (BOARDSIZE * BOARDSIZE * sizeof(byte)); + byte *board = (byte *) malloc (BOARDSIZE * BOARDSIZE * sizeof(byte)); byte startX, startY, endX, endY; debugScript(1, true, "CELL MOVE var[0x%02X]", arg); @@ -1396,14 +1411,13 @@ void Script::o_cellmove() { debugScript(1, false, "\n"); } - CellGame staufsMove((byte*) board); - staufsMove.calcMove((byte*) board, CELL_GREEN, 2); + CellGame staufsMove((byte *) board); + staufsMove.calcMove((byte *) board, CELL_GREEN, 2); startX = staufsMove.getStartX(); startY = staufsMove.getStartY(); endX = staufsMove.getEndX(); endY = staufsMove.getEndY(); - // Set the movement origin setVariable(0, startY); // y setVariable(1, startX); // x @@ -1411,7 +1425,7 @@ void Script::o_cellmove() { setVariable(2, endY); setVariable(3, endX); - free (board); + free(board); } void Script::o_returnscript() { @@ -1535,20 +1549,19 @@ void Script::o_stub59() { debugScript(1, true, "STUB59: 0x%04X 0x%02X", val1, val2); } -void Script::o2_playsong(){ +void Script::o2_playsong() { uint32 fileref = readScript32bits(); debugScript(1, true, "PlaySong(0x%08X): Play xmidi file", fileref); _vm->_musicPlayer->playSong(fileref); - } -void Script::o2_setbackgroundsong(){ +void Script::o2_setbackgroundsong() { uint32 fileref = readScript32bits(); debugScript(1, true, "SetBackgroundSong(0x%08X)", fileref); _vm->_musicPlayer->setBackgroundSong(fileref); } -void Script::o2_videofromref(){ +void Script::o2_videofromref() { uint32 fileref = readScript32bits(); // Show the debug information just when starting the playback @@ -1556,6 +1569,7 @@ void Script::o2_videofromref(){ debugScript(1, true, "VIDEOFROMREF(0x%08X) (Not fully imp): Play video file from ref", fileref); debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Playing video 0x%08X via 0x09", fileref); } + // Play the video if (!playvideofromref(fileref)) { // Move _currentInstruction back @@ -1563,7 +1577,7 @@ void Script::o2_videofromref(){ } } -void Script::o2_vdxtransition(){ +void Script::o2_vdxtransition() { uint32 fileref = readScript32bits(); // Show the debug information just when starting the playback @@ -1587,11 +1601,21 @@ void Script::o2_vdxtransition(){ } } -void Script::o2_stub52(){ +void Script::o2_setvideoskip() { + _videoSkipAddress = readScript16bits(); + debugScript(1, true, "SetVideoSkip (0x%04X)", _videoSkipAddress); +} + +void Script::o2_stub52() { uint8 arg = readScript8bits(); debugScript(1, true, "STUB52 (0x%02X)", arg); } +void Script::o2_setscriptend() { + uint16 arg = readScript16bits(); + debugScript(1, true, "SetScriptEnd (0x%04X)", arg); +} + Script::OpcodeFunc Script::_opcodesT7G[NUM_OPCODES] = { &Script::o_nop, // 0x00 &Script::o_nop, @@ -1692,11 +1716,11 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = { &Script::o_invalid, // 0x00 &Script::o_nop, &Script::o2_playsong, - &Script::o_bf9on, - &Script::o_palfadeout, // 0x04 - &Script::o_bf8on, - &Script::o_bf6on, - &Script::o_bf7on, + &Script::o_nop, + &Script::o_nop, // 0x04 + &Script::o_nop, + &Script::o_nop, + &Script::o_nop, &Script::o2_setbackgroundsong, // 0x08 &Script::o2_videofromref, &Script::o_bf5on, @@ -1719,7 +1743,7 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = { &Script::o_xor_obfuscate, &Script::o2_vdxtransition, // 0x1C &Script::o_swap, - &Script::o_nop8, + &Script::o_invalid, &Script::o_inc, &Script::o_dec, // 0x20 &Script::o_strcmpnejmp_var, @@ -1729,10 +1753,10 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = { &Script::o_add, &Script::o_videofromstring1, &Script::o_videofromstring2, - &Script::o_nop16, // 0x28 - &Script::o_stopmidi, - &Script::o_endscript, + &Script::o_invalid, // 0x28 &Script::o_nop, + &Script::o_endscript, + &Script::o_invalid, &Script::o_sethotspottop, // 0x2C &Script::o_sethotspotbottom, &Script::o_loadgame, @@ -1759,22 +1783,22 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = { &Script::o_returnscript, &Script::o_sethotspotright, // 0x44 &Script::o_sethotspotleft, - &Script::o_nop, - &Script::o_nop, - &Script::o_nop8, // 0x48 - &Script::o_nop, - &Script::o_nop16, - &Script::o_nop8, - &Script::o_getcd, // 0x4C - &Script::o_playcd, + &Script::o_invalid, + &Script::o_invalid, + &Script::o_invalid, // 0x48 + &Script::o_invalid, &Script::o_nop16, + &Script::o_invalid, + &Script::o_invalid, // 0x4C + &Script::o_invalid, + &Script::o_invalid, &Script::o_nop16, &Script::o_nop16, // 0x50 - &Script::o_nop16, + &Script::o2_setvideoskip, &Script::o2_stub52, &Script::o_hotspot_outrect, - &Script::o_nop, // 0x54 - &Script::o_nop16, + &Script::o_invalid, // 0x54 + &Script::o2_setscriptend, &Script::o_stub56, &Script::o_invalid, &Script::o_invalid, // 0x58 diff --git a/engines/groovie/script.h b/engines/groovie/script.h index 664cac82d8..8a95f093ce 100644 --- a/engines/groovie/script.h +++ b/engines/groovie/script.h @@ -57,7 +57,7 @@ public: void directGameLoad(int slot); void step(); - void setMouseClick(); + void setMouseClick(uint8 button); void setKbdChar(uint8 c); Common::String &getContext(); @@ -95,7 +95,7 @@ private: // Input bool _mouseClicked; - bool _eventMouseClicked; + uint8 _eventMouseClicked; uint8 _kbdChar; uint8 _eventKbdChar; uint16 _inputLoopAddress; @@ -114,6 +114,7 @@ private: Common::SeekableReadStream *_videoFile; uint32 _videoRef; uint16 _bitflags; + uint16 _videoSkipAddress; // Debugging Debugger *_debugger; @@ -224,7 +225,9 @@ private: void o2_setbackgroundsong(); void o2_videofromref(); void o2_vdxtransition(); + void o2_setvideoskip(); void o2_stub52(); + void o2_setscriptend(); }; } // End of Groovie namespace diff --git a/engines/sci/gfx/gfx_driver.cpp b/engines/sci/gfx/gfx_driver.cpp index 0b1387074c..b71152822c 100644 --- a/engines/sci/gfx/gfx_driver.cpp +++ b/engines/sci/gfx/gfx_driver.cpp @@ -27,18 +27,19 @@ #include "common/system.h" #include "graphics/cursorman.h" #include "graphics/primitives.h" +#include "graphics/surface.h" #include "sci/sci.h" #include "sci/gfx/gfx_driver.h" #include "sci/gfx/gfx_tools.h" + namespace Sci { -GfxDriver::GfxDriver(int xfact, int yfact, int bytespp) { +GfxDriver::GfxDriver(int xfact, int yfact, Graphics::PixelFormat format) { int i; - Graphics::PixelFormat format = { bytespp, 0, 0, 0, 0, 0, 0, 0, 0 }; - _mode = gfx_new_mode(xfact, yfact, format, new Palette(256), 0); + _mode = gfx_new_mode(xfact, yfact, format, format.bytesPerPixel == 1 ? new Palette(256) : 0, 0); _mode->xsize = xfact * 320; _mode->ysize = yfact * 200; @@ -51,14 +52,15 @@ GfxDriver::GfxDriver(int xfact, int yfact, int bytespp) { // create the visual buffers for (i = 0; i < 2; i++) { _visual[i] = NULL; - _visual[i] = new byte[_mode->xsize * _mode->ysize]; + _visual[i] = new byte[_mode->xsize * _mode->ysize * _mode->bytespp]; if (!_visual[i]) { error("Out of memory: Could not allocate visual buffers! (%dx%d)\n", _mode->xsize, _mode->ysize); } - memset(_visual[i], 0, _mode->xsize * _mode->ysize); + memset(_visual[i], 0, _mode->xsize * _mode->ysize * _mode->bytespp); } - _mode->palette->name = "global"; + if (_mode->palette) + _mode->palette->name = "global"; } GfxDriver::~GfxDriver() { @@ -77,10 +79,12 @@ GfxDriver::~GfxDriver() { // Drawing operations +template<int COPY_BYTES, typename SIZETYPE, int EXTRA_BYTE_OFFSET> static void drawProc(int x, int y, int c, void *data) { GfxDriver *drv = (GfxDriver *)data; byte *p = drv->getVisual0(); - p[y * 320* drv->getMode()->xfact + x] = c; + SIZETYPE col = c << (EXTRA_BYTE_OFFSET * 8); + memcpy(p + (y * 320* drv->getMode()->xfact + x) * COPY_BYTES, &col, COPY_BYTES); } int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t color, @@ -91,6 +95,28 @@ int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t colo int xsize = _mode->xsize; int ysize = _mode->ysize; + void (*modeDrawProc)(int,int,int,void*); + switch (_mode->bytespp) { + case 1: + modeDrawProc = drawProc<1, uint8, 0>; + break; + case 2: + modeDrawProc = drawProc<2, uint16, 0>; + break; + case 3: +#ifdef SCUMM_BIG_ENDIAN + modeDrawProc = drawProc<3, uint32, 1>; +#else + modeDrawProc = drawProc<3, uint32, 0>; +#endif + break; + case 4: + modeDrawProc = drawProc<4, uint32, 0>; + break; + default: + error("Invalid mode->bytespp=%d", _mode->bytespp); + } + if (color.mask & GFX_MASK_VISUAL) { Common::Point nstart, nend; @@ -102,7 +128,7 @@ int GfxDriver::drawLine(Common::Point start, Common::Point end, gfx_color_t colo nend.x = CLIP<int16>(end.x + xc, 0, xsize - 1); nend.y = CLIP<int16>(end.y + yc, 0, ysize - 1); - Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, scolor, drawProc, this); + Graphics::drawLine(nstart.x, nstart.y, nend.x, nend.y, scolor, modeDrawProc, this); if (color.mask & GFX_MASK_PRIORITY) { gfx_draw_line_pixmap_i(_priority[0], nstart, nend, color.priority); @@ -118,7 +144,8 @@ int GfxDriver::drawFilledRect(rect_t rect, gfx_color_t color1, gfx_color_t color gfx_rectangle_fill_t shade_mode) { if (color1.mask & GFX_MASK_VISUAL) { for (int i = rect.y; i < rect.y + rect.height; i++) { - memset(_visual[0] + i * _mode->xsize + rect.x, color1.visual.parent_index, rect.width); + memset(_visual[0] + (i * _mode->xsize + rect.x) * _mode->bytespp, + color1.visual.parent_index, rect.width * _mode->bytespp); } } @@ -138,8 +165,10 @@ int GfxDriver::drawPixmap(gfx_pixmap_t *pxm, int priority, rect_t src, rect_t de return GFX_ERROR; } - gfx_crossblit_pixmap(_mode, pxm, priority, src, dest, _visual[bufnr], _mode->xsize, - _priority[bufnr]->index_data, _priority[bufnr]->index_width, 1, 0); + gfx_crossblit_pixmap(_mode, pxm, priority, src, dest, _visual[bufnr], + _mode->xsize * _mode->bytespp, + _priority[bufnr]->index_data, + _priority[bufnr]->index_width, 1, 0); return GFX_OK; } @@ -161,7 +190,9 @@ int GfxDriver::grabPixmap(rect_t src, gfx_pixmap_t *pxm, gfx_map_mask_t map) { pxm->width = src.width; pxm->height = src.height; for (int i = 0; i < src.height; i++) { - memcpy(pxm->data + i * src.width, _visual[0] + (i + src.y) * _mode->xsize + src.x, src.width); + memcpy(pxm->data + i * src.width * _mode->bytespp, + _visual[0] + _mode->bytespp * ((i + src.y) * _mode->xsize + src.x), + src.width * _mode->bytespp); } break; @@ -193,17 +224,18 @@ int GfxDriver::update(rect_t src, Common::Point dest, gfx_buffer_t buffer) { switch (buffer) { case GFX_BUFFER_BACK: for (int i = 0; i < src.height; i++) { - memcpy(_visual[0] + (dest.y + i) * _mode->xsize + dest.x, - _visual[1] + (src.y + i) * _mode->xsize + src.x, src.width); + memcpy(_visual[0] + _mode->bytespp * ( (dest.y + i) * _mode->xsize + dest.x), + _visual[1] + _mode->bytespp * ( (src.y + i) * _mode->xsize + src.x), src.width * _mode->bytespp ); } if ((src.x == dest.x) && (src.y == dest.y)) gfx_copy_pixmap_box_i(_priority[0], _priority[1], src); break; - case GFX_BUFFER_FRONT: - g_system->copyRectToScreen(_visual[0] + src.x + src.y * _mode->xsize, _mode->xsize, dest.x, dest.y, src.width, src.height); + case GFX_BUFFER_FRONT: { + g_system->copyRectToScreen(_visual[0] + _mode->bytespp * (src.x + src.y * _mode->xsize), _mode->xsize * _mode->bytespp, dest.x, dest.y, src.width, src.height); g_system->updateScreen(); break; + } default: error("Invalid buffer %d in update", buffer); return GFX_ERROR; @@ -213,7 +245,7 @@ int GfxDriver::update(rect_t src, Common::Point dest, gfx_buffer_t buffer) { } int GfxDriver::setStaticBuffer(gfx_pixmap_t *pic, gfx_pixmap_t *priority) { - memcpy(_visual[1], pic->data, _mode->xsize * _mode->ysize); + memcpy(_visual[1], pic->data, _mode->xsize * _mode->ysize * _mode->bytespp); gfx_copy_pixmap_box_i(_priority[1], priority, gfx_rect(0, 0, _mode->xsize, _mode->ysize)); return GFX_OK; diff --git a/engines/sci/gfx/gfx_driver.h b/engines/sci/gfx/gfx_driver.h index f7cbd0b6c2..cc8a5208d4 100644 --- a/engines/sci/gfx/gfx_driver.h +++ b/engines/sci/gfx/gfx_driver.h @@ -29,6 +29,8 @@ #include "sci/gfx/gfx_system.h" #include "sci/uinput.h" +#include "graphics/pixelformat.h" + namespace Sci { enum gfx_buffer_t { @@ -85,7 +87,7 @@ public: * not be set, or GFX_FATAL if the graphics target * is unuseable. */ - GfxDriver(int xfact, int yfact, int bytespp); + GfxDriver(int xfact, int yfact, Graphics::PixelFormat mode); /** * Uninitializes the current graphics mode. diff --git a/engines/sci/gfx/gfx_pixmap_scale.cpp b/engines/sci/gfx/gfx_pixmap_scale.cpp index 034efafe8d..41e6102cbd 100644 --- a/engines/sci/gfx/gfx_pixmap_scale.cpp +++ b/engines/sci/gfx/gfx_pixmap_scale.cpp @@ -70,14 +70,11 @@ void _gfx_xlate_pixmap_unfiltered(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale // Calculate all colors for (i = 0; i < pxm->colors_nr(); i++) { int col; - const PaletteEntry& color = pxm->palette->getColor(i); if (mode->palette) col = color.parent_index; else { - col = mode->red_mask & ((EXTEND_COLOR(color.r)) >> mode->red_shift); - col |= mode->green_mask & ((EXTEND_COLOR(color.g)) >> mode->green_shift); - col |= mode->blue_mask & ((EXTEND_COLOR(color.b)) >> mode->blue_shift); + col = mode->format.ARGBToColor(0, color.r, color.g, color.b); col |= alpha_ormask; } result_colors[i] = col; diff --git a/engines/sci/gfx/gfx_resmgr.cpp b/engines/sci/gfx/gfx_resmgr.cpp index 98c5c12a70..9343b66cb8 100644 --- a/engines/sci/gfx/gfx_resmgr.cpp +++ b/engines/sci/gfx/gfx_resmgr.cpp @@ -268,7 +268,8 @@ void GfxResManager::setStaticPalette(Palette *newPalette) _staticPalette = newPalette; _staticPalette->name = "static palette"; - _staticPalette->mergeInto(_driver->getMode()->palette); + if (_driver->getMode()->palette) + _staticPalette->mergeInto(_driver->getMode()->palette); } #if 0 diff --git a/engines/sci/gfx/gfx_system.h b/engines/sci/gfx/gfx_system.h index 855f9b196e..fe93922e21 100644 --- a/engines/sci/gfx/gfx_system.h +++ b/engines/sci/gfx/gfx_system.h @@ -30,6 +30,7 @@ #include "common/rect.h" #include "sci/tools.h" #include "sci/gfx/palette.h" +#include "graphics/pixelformat.h" namespace Sci { @@ -74,8 +75,10 @@ struct gfx_mode_t { */ Palette *palette; + // TODO: remove those uint32 red_mask, green_mask, blue_mask, alpha_mask; short red_shift, green_shift, blue_shift, alpha_shift; + Graphics::PixelFormat format; }; diff --git a/engines/sci/gfx/gfx_tools.cpp b/engines/sci/gfx/gfx_tools.cpp index e3d35ecb14..9e81ec1a8a 100644 --- a/engines/sci/gfx/gfx_tools.cpp +++ b/engines/sci/gfx/gfx_tools.cpp @@ -49,6 +49,7 @@ gfx_mode_t *gfx_new_mode(int xfact, int yfact, const Graphics::PixelFormat &form mode->xfact = xfact; mode->yfact = yfact; mode->bytespp = format.bytesPerPixel; + mode->format = format; // FIXME: I am not sure whether the following assignments are quite right. // The only code using these are the built-in scalers of the SCI engine. @@ -60,10 +61,10 @@ gfx_mode_t *gfx_new_mode(int xfact, int yfact, const Graphics::PixelFormat &form mode->green_mask = format.ARGBToColor(0, 0, 0xFF, 0); mode->blue_mask = format.ARGBToColor(0, 0, 0, 0xFF); mode->alpha_mask = format.ARGBToColor(0xFF, 0, 0, 0); - mode->red_shift = format.rLoss; - mode->green_shift = format.gLoss; - mode->blue_shift = format.bLoss; - mode->alpha_shift = format.aLoss; + mode->red_shift = format.rShift; + mode->green_shift = format.gShift; + mode->blue_shift = format.bShift; + mode->alpha_shift = format.aShift; } else { mode->red_mask = mode->green_mask = mode->blue_mask = 0; mode->alpha_mask = 0; diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index f714ab0245..057f28b56f 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -404,8 +404,9 @@ static void init_aux_pixmap(gfx_pixmap_t **pixmap) { (*pixmap)->palette = new Palette(default_colors, DEFAULT_COLORS_NR); } -int gfxop_init(int version, GfxState *state, gfx_options_t *options, ResourceManager *resManager, - int xfact, int yfact, gfx_color_mode_t bpp) { +int gfxop_init(int version, GfxState *state, + gfx_options_t *options, ResourceManager *resManager, + Graphics::PixelFormat mode, int xfact, int yfact) { //int color_depth = bpp ? bpp : 1; //int initialized = 0; @@ -421,7 +422,7 @@ int gfxop_init(int version, GfxState *state, gfx_options_t *options, ResourceMan state->pic_port_bounds = gfx_rect(0, 10, 320, 190); state->_dirtyRects.clear(); - state->driver = new GfxDriver(xfact, yfact, bpp); + state->driver = new GfxDriver(xfact, yfact, mode); state->gfxResMan = new GfxResManager(version, state->options, state->driver, resManager); @@ -1131,8 +1132,10 @@ static int _gfxop_set_pointer(GfxState *state, gfx_pixmap_t *pxm, Common::Point // may change when a new PIC is loaded. The cursor has to be regenerated // from this pxm at that point. (An alternative might be to ensure the // cursor only uses colours in the static part of the palette?) - if (pxm && pxm->palette) + if (pxm && state->driver->getMode()->palette) { + assert(pxm->palette); pxm->palette->mergeInto(state->driver->getMode()->palette); + } state->driver->setPointer(pxm, hotspot); return GFX_OK; @@ -1712,7 +1715,8 @@ static int _gfxop_set_pic(GfxState *state) { // FIXME: The _gfxop_install_pixmap call below updates the OSystem palette. // This is too soon, since it causes brief palette corruption until the // screen is updated too. (Possibly related: EngineState::pic_not_valid .) - state->pic->visual_map->palette->forceInto(state->driver->getMode()->palette); + if (state->driver->getMode()->palette) + state->pic->visual_map->palette->forceInto(state->driver->getMode()->palette); _gfxop_install_pixmap(state->driver, state->pic->visual_map); #ifdef CUSTOM_GRAPHICS_OPTIONS @@ -1735,7 +1739,7 @@ int gfxop_new_pic(GfxState *state, int nr, int flags, int default_palette) { if (state->driver->getMode()->xfact == 1 && state->driver->getMode()->yfact == 1) { state->pic_unscaled = state->pic; } else { - state->pic = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, false); + state->pic_unscaled = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, false); } if (!state->pic || !state->pic_unscaled) { diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index b9a16d4a27..ec0a810224 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -138,17 +138,16 @@ struct GfxState { * @param[in] state The state to initialize * @param[in] xfact Horizontal scale factor * @param[in] yfact Vertical scale factors - * @param[in] bpp Bytes per pixel to initialize with, or 0 - * (GFX_COLOR_MODE_AUTO) to auto-detect + * @param[in] mode Graphics mode to use * @param[in] options Rendering options * @param[in] resManager Resource manager to use * @return GFX_OK on success, GFX_ERROR if that particular mode * is unavailable, or GFX_FATAL if the graphics driver * is unable to provide any useful graphics support */ -int gfxop_init(int version, GfxState *state, gfx_options_t *options, - ResourceManager *resManager, int xfact = 1, int yfact = 1, - gfx_color_mode_t bpp = GFX_COLOR_MODE_INDEX); +int gfxop_init(int version, GfxState *state, + gfx_options_t *options, ResourceManager *resManager, + Graphics::PixelFormat mode, int xfact = 1, int yfact = 1); /** * Deinitializes a currently active driver. diff --git a/engines/sci/gfx/res_pic.cpp b/engines/sci/gfx/res_pic.cpp index e7b34976b0..6c35ad314e 100644 --- a/engines/sci/gfx/res_pic.cpp +++ b/engines/sci/gfx/res_pic.cpp @@ -1548,7 +1548,7 @@ void gfxr_draw_pic01(gfxr_pic_t *pic, int flags, int default_palette, int size, view->index_height = CLIP<int>(view->index_height, 0, portBounds.height()); // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1byte/p, which handles masks and the rest for us + Graphics::PixelFormat format(1, 0, 0, 0, 0, 0, 0, 0, 0); // 1byte/p, which handles masks and the rest for us gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); @@ -1654,7 +1654,7 @@ void gfxr_draw_pic11(gfxr_pic_t *pic, int flags, int default_palette, int size, view->palette = pic->visual_map->palette->getref(); // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1 byte/p, which handles masks and the rest for us + Graphics::PixelFormat format(1, 0, 0, 0, 0, 0, 0, 0, 0); // 1 byte/p, which handles masks and the rest for us gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 9c94e2edde..dbb8d4784a 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -104,7 +104,14 @@ SciEngine::~SciEngine() { } Common::Error SciEngine::run() { + Graphics::PixelFormat gfxmode; +#ifdef ENABLE_RGB_COLOR + gfxmode = _system->getSupportedFormats().front(); + initGraphics(320, 200, false, &gfxmode); +#else initGraphics(320, 200, false); +#endif + gfxmode = _system->getScreenFormat(); // Create debugger console. It requires GFX to be initialized _console = new Console(this); @@ -204,7 +211,7 @@ Common::Error SciEngine::run() { // Default config ends #endif - if (gfxop_init(_resmgr->_sciVersion, &gfx_state, &gfx_options, _resmgr)) { + if (gfxop_init(_resmgr->_sciVersion, &gfx_state, &gfx_options, _resmgr, gfxmode, 1, 1)) { warning("Graphics initialization failed. Aborting..."); return Common::kUnknownError; } diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 88c258a2e6..52866279b8 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -2400,7 +2400,7 @@ void ScummEngine_v71he::postProcessAuxQueue() { uint8 *dst2 = pvs->getBackPixels(0, pvs->topline); switch (comp) { case 1: - Wiz::copyAuxImage(dst1, dst2, axfd + 10, pvs->w, pvs->h, x, y, w, h); + Wiz::copyAuxImage(dst1, dst2, axfd + 10, pvs->pitch, pvs->h, x, y, w, h, _bitDepth); break; default: error("unimplemented compression type %d", comp); @@ -2500,9 +2500,10 @@ void Actor::saveLoadWithSerializer(Serializer *ser) { MKLINE(Actor, _flip, sleByte, VER(32)), MKLINE(Actor, _heSkipLimbs, sleByte, VER(32)), - // Actor palette grew from 64 to 256 bytes + // Actor palette grew from 64 to 256 bytes and switched to uint16 in HE games MKARRAY_OLD(Actor, _palette[0], sleByte, 64, VER(8), VER(9)), - MKARRAY(Actor, _palette[0], sleByte, 256, VER(10)), + MKARRAY_OLD(Actor, _palette[0], sleByte, 256, VER(10), VER(77)), + MKARRAY(Actor, _palette[0], sleUint16, 256, VER(78)), MK_OBSOLETE(Actor, _mask, sleByte, VER(8), VER(9)), MKLINE(Actor, _shadowMode, sleByte, VER(8)), diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3e8fe6626b..d32f268b11 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -157,7 +157,7 @@ protected: }; - byte _palette[256]; + uint16 _palette[256]; int _elevation; uint16 _facing; uint16 _targetFacing; diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index ab7db2c4a7..f4bb8a2c8b 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -289,7 +289,7 @@ void AkosCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { } while ((uint16)mask); } -void AkosRenderer::setPalette(byte *new_palette) { +void AkosRenderer::setPalette(uint16 *new_palette) { uint size, i; size = _vm->getResourceDataSize(akpl); @@ -299,22 +299,23 @@ void AkosRenderer::setPalette(byte *new_palette) { if (size > 256) error("akos_setPalette: %d is too many colors", size); - if (_vm->_game.heversion >= 99 && _paletteNum) { - for (i = 0; i < size; i++) - _palette[i] = (byte)_vm->_hePalettes[_paletteNum * 1024 + 768 + akpl[i]]; - } else if ((_vm->_game.features & GF_16BIT_COLOR) && rgbs) { - for (i = 0; i < size; i++) { - if (new_palette[i] == 0xFF) { - uint8 col = akpl[i]; - uint8 r = rgbs[col * 3 + 0]; - uint8 g = rgbs[col * 3 + 1]; - uint8 b = rgbs[col * 3 + 2]; - - _palette[i] = _vm->remapPaletteColor(r, g, b, -1); - } else { - _palette[i] = new_palette[i]; + if (_vm->_game.features & GF_16BIT_COLOR) { + if (_paletteNum) { + for (i = 0; i < size; i++) + _palette[i] = READ_LE_UINT16(_vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768 + akpl[i] * 2); + } else if (rgbs) { + for (i = 0; i < size; i++) { + if (new_palette[i] == 0xFF) { + uint8 col = akpl[i]; + _palette[i] = _vm->get16BitColor(rgbs[col * 3 + 0], rgbs[col * 3 + 1], rgbs[col * 3 + 2]); + } else { + _palette[i] = new_palette[i]; + } } } + } else if (_vm->_game.heversion >= 99 && _paletteNum) { + for (i = 0; i < size; i++) + _palette[i] = (byte)_vm->_hePalettes[_paletteNum * _vm->_hePaletteSlot + 768 + akpl[i]]; } else { for (i = 0; i < size; i++) { _palette[i] = new_palette[i] != 0xFF ? new_palette[i] : akpl[i]; @@ -545,7 +546,7 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { byte *dst; byte len, maskbit; int y; - uint color, height, pcolor; + uint16 color, height, pcolor; const byte *scaleytab; bool masked; bool skip_column = false; @@ -589,7 +590,11 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { } else if (_shadow_mode == 2) { error("codec1_spec2"); // TODO } else if (_shadow_mode == 3) { - if (_vm->_game.heversion >= 90) { + if (_vm->_game.features & GF_16BIT_COLOR) { + uint16 srcColor = (pcolor >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dst) >> 1) & 0x7DEF; + pcolor = srcColor + dstColor; + } else if (_vm->_game.heversion >= 90) { pcolor = (pcolor << 8) + *dst; pcolor = xmap[pcolor]; } else if (pcolor < 8) { @@ -597,7 +602,11 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { pcolor = _shadow_table[pcolor]; } } - *dst = pcolor; + if (_vm->_bitDepth == 2) { + WRITE_UINT16(dst, pcolor); + } else { + *dst = pcolor; + } } } dst += _out.pitch; @@ -617,7 +626,7 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { if (v1.x < 0 || v1.x >= v1.boundsRect.right) return; maskbit = revBitMask(v1.x & 7); - v1.destptr += v1.scaleXstep; + v1.destptr += v1.scaleXstep * _vm->_bitDepth; skip_column = false; } else skip_column = true; @@ -987,7 +996,7 @@ byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) { if (_draw_bottom < rect.bottom) _draw_bottom = rect.bottom; - v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x; + v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x * _vm->_bitDepth; codec1_genericDecode(v1); @@ -1056,7 +1065,12 @@ byte AkosRenderer::codec5(int xmoveCur, int ymoveCur) { bdd.shadowMode = _shadow_mode; bdd.shadowPalette = _vm->_shadowPalette; - bdd.actorPalette = _useBompPalette ? _palette : 0; + bdd.actorPalette = 0; + if (_useBompPalette) { + for (uint i = 0; i < 256; i++) + bdd.actorPalette[i] = _palette[i]; + } + bdd.mirror = !_mirror; drawBomp(bdd); @@ -1176,6 +1190,8 @@ void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, in } byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) { + assert(_vm->_bitDepth == 1); + Common::Rect clip; int32 minx, miny, maxw, maxh; int32 skip_x, skip_y, cur_x, cur_y; @@ -1278,7 +1294,7 @@ byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) { int32 numskip_before = skip_x + (skip_y * _width); int32 numskip_after = _width - cur_x; - byte *dst = (byte *)_out.pixels + width_unk + height_unk * _out.pitch; + byte *dst = (byte *)_out.pixels + height_unk * _out.pitch + width_unk * _vm->_bitDepth; akos16Decompress(dst, _out.pitch, _srcptr, cur_x, out_height, dir, numskip_before, numskip_after, transparency, clip.left, clip.top, _zbuf); return 0; @@ -1335,18 +1351,27 @@ byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) { _draw_bottom = dst.bottom; const uint8 *palPtr = NULL; - if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1792; + if (_vm->_game.features & GF_16BIT_COLOR) { + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768; + if (_paletteNum) { + palPtr = _vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768; + } else if (rgbs) { + for (uint i = 0; i < 256; i++) + WRITE_LE_UINT16(_palette + i, _vm->get16BitColor(rgbs[i * 3 + 0], rgbs[i * 3 + 1], rgbs[i * 3 + 2])); + palPtr = (uint8 *)_palette; + } + } else if (_vm->_game.heversion >= 99) { + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768; } - byte *dstPtr = (byte *)_out.pixels + dst.left + dst.top * _out.pitch; + byte *dstPtr = (byte *)_out.pixels + dst.top * _out.pitch + dst.left * _vm->_bitDepth; if (_shadow_mode == 3) { - Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, _srcptr, src, 0, palPtr, xmap); + Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, xmap, _vm->_bitDepth); } else { if (palPtr != NULL) { - Wiz::decompressWizImage<kWizRMap>(dstPtr, _out.pitch, _srcptr, src, 0, palPtr); + Wiz::decompressWizImage<kWizRMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, NULL, _vm->_bitDepth); } else { - Wiz::decompressWizImage<kWizCopy>(dstPtr, _out.pitch, _srcptr, src, 0); + Wiz::decompressWizImage<kWizCopy>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, NULL, NULL, _vm->_bitDepth); } } #endif diff --git a/engines/scumm/akos.h b/engines/scumm/akos.h index be532b804d..9f4f09d4dc 100644 --- a/engines/scumm/akos.h +++ b/engines/scumm/akos.h @@ -60,7 +60,7 @@ protected: uint16 _codec; // actor _palette - byte _palette[256]; + uint16 _palette[256]; bool _useBompPalette; // pointer to various parts of the costume resource @@ -107,7 +107,7 @@ public: int16 _actorHitX, _actorHitY; bool _actorHitResult; - void setPalette(byte *_palette); + void setPalette(uint16 *_palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); diff --git a/engines/scumm/base-costume.cpp b/engines/scumm/base-costume.cpp index 795abb8685..ef706afaac 100644 --- a/engines/scumm/base-costume.cpp +++ b/engines/scumm/base-costume.cpp @@ -40,7 +40,7 @@ byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, int numStrips, const _out.pixels = vs.getPixels(0, 0); _actorX += _vm->_virtscr[kMainVirtScreen].xstart & 7; - _out.w = _out.pitch; + _out.w = _out.pitch / _vm->_bitDepth; _out.pixels = (byte *)_out.pixels - (_vm->_virtscr[kMainVirtScreen].xstart & 7); _numStrips = numStrips; diff --git a/engines/scumm/base-costume.h b/engines/scumm/base-costume.h index 59ca3ded1f..d41d795e34 100644 --- a/engines/scumm/base-costume.h +++ b/engines/scumm/base-costume.h @@ -145,7 +145,7 @@ public: } virtual ~BaseCostumeRenderer() {} - virtual void setPalette(byte *palette) = 0; + virtual void setPalette(uint16 *palette) = 0; virtual void setFacing(const Actor *a) = 0; virtual void setCostume(int costume, int shadow) = 0; diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 193fc434e4..d6dfa4c5bb 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -819,9 +819,9 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, byte imagePalette[256]; memset(imagePalette, 0, sizeof(imagePalette)); memcpy(imagePalette, _vm->_charsetColorMap, 4); - Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, imagePalette); + Wiz::copyWizImage(dstPtr, charPtr, vs->pitch, kDstScreen, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, imagePalette, NULL, _vm->_bitDepth); } else { - Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen); + Wiz::copyWizImage(dstPtr, charPtr, vs->pitch, kDstScreen, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, 0, NULL, NULL, _vm->_bitDepth); } if (_blitAlso && vs->hasTwoBuffers) { diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 82497de87a..39c2f73e88 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -791,7 +791,7 @@ byte ClassicCostumeRenderer::drawLimb(const Actor *a, int limb) { } -void NESCostumeRenderer::setPalette(byte *palette) { +void NESCostumeRenderer::setPalette(uint16 *palette) { // TODO } @@ -874,17 +874,20 @@ void ClassicCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) } while (mask&0xFFFF); } -void ClassicCostumeRenderer::setPalette(byte *palette) { +void ClassicCostumeRenderer::setPalette(uint16 *palette) { int i; byte color; if (_loaded._format == 0x57) { - memcpy(_palette, palette, 13); + for (i = 0; i < 13; i++) + _palette[i] = palette[i]; } else if (_vm->_game.features & GF_OLD_BUNDLE) { if (_vm->getCurrentLights() & LIGHTMODE_actor_use_colors) { - memcpy(_palette, palette, 16); + for (i = 0; i < 16; i++) + _palette[i] = palette[i]; } else { - memset(_palette, 8, 16); + for (i = 0; i < 16; i++) + _palette[i] = 8; _palette[12] = 0; } _palette[_loaded._palette[0]] = _palette[0]; diff --git a/engines/scumm/costume.h b/engines/scumm/costume.h index 003bd6ce2b..ecb12986cf 100644 --- a/engines/scumm/costume.h +++ b/engines/scumm/costume.h @@ -94,7 +94,7 @@ protected: public: ClassicCostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette); + void setPalette(uint16 *palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); @@ -116,7 +116,7 @@ protected: public: NESCostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette); + void setPalette(uint16 *palette); void setFacing(const Actor *a); void setCostume(int costume, int shadow); @@ -131,7 +131,7 @@ protected: public: C64CostumeRenderer(ScummEngine *vm) : BaseCostumeRenderer(vm), _loaded(vm) {} - void setPalette(byte *palette) {} + void setPalette(uint16 *palette) {} void setFacing(const Actor *a) {} void setCostume(int costume, int shadow); diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 64829114ca..66ac68bd95 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -111,11 +111,20 @@ void ScummEngine_v6::setCursorTransparency(int a) { } void ScummEngine::updateCursor() { - const int transColor = (_game.heversion >= 80) ? 5 : 255; + int transColor = (_game.heversion >= 80) ? 5 : 255; +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat format = _system->getScreenFormat(); + CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, + _cursor.hotspotX, _cursor.hotspotY, + (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), + (_game.heversion == 70 ? 2 : 1), + &format); +#else CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, _cursor.hotspotX, _cursor.hotspotY, (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), (_game.heversion == 70 ? 2 : 1)); +#endif } void ScummEngine_v6::grabCursor(int x, int y, int w, int h) { @@ -138,7 +147,7 @@ void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, in uint size; byte *dst; - size = width * height; + size = width * height * _bitDepth; if (size > sizeof(_grabbedCursor)) error("grabCursor: grabbed cursor too big"); @@ -148,8 +157,8 @@ void ScummEngine::setCursorFromBuffer(const byte *ptr, int width, int height, in dst = _grabbedCursor; for (; height; height--) { - memcpy(dst, ptr, width); - dst += width; + memcpy(dst, ptr, width * _bitDepth); + dst += width * _bitDepth; ptr += pitch; } @@ -166,8 +175,13 @@ void ScummEngine_v70he::setDefaultCursor() { static const byte palette[] = {0, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0}; - - memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); + + if (_bitDepth == 2) { + for (i = 0; i < 1024; i++) + WRITE_UINT16(_grabbedCursor + i * 2, 5); + } else { + memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); + } _cursor.hotspotX = _cursor.hotspotY = 2; src = default_he_cursor; @@ -180,10 +194,16 @@ void ScummEngine_v70he::setDefaultCursor() { for (j = 0; j < 32; j++) { switch ((p & (0x3 << 14)) >> 14) { case 1: - _grabbedCursor[32 * i + j] = 0xfe; + if (_bitDepth == 2) + WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[4], palette[5], palette[6])); + else + _grabbedCursor[32 * i + j] = 0xfe; break; case 2: - _grabbedCursor[32 * i + j] = 0xfd; + if (_bitDepth == 2) + WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[0], palette[1], palette[2])); + else + _grabbedCursor[32 * i + j] = 0xfd; break; default: break; @@ -195,9 +215,11 @@ void ScummEngine_v70he::setDefaultCursor() { } } - // Since white color position is not guaranteed - // we setup our own palette if supported by backend - CursorMan.replaceCursorPalette(palette, 0xfd, 3); + if (_bitDepth == 1) { + // Since white color position is not guaranteed + // we setup our own palette if supported by backend + CursorMan.replaceCursorPalette(palette, 0xfd, 3); + } updateCursor(); } diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 07640ca551..4574ece6d0 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -43,12 +43,12 @@ extern "C" void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height namespace Scumm { -static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); -static void fill(byte *dst, int dstPitch, byte color, int w, int h); +static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, uint8 bitDepth); +static void fill(byte *dst, int dstPitch, uint16 color, int w, int h, uint8 bitDepth); #ifndef USE_ARM_GFX_ASM -static void copy8Col(byte *dst, int dstPitch, const byte *src, int height); +static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8 bitDepth); #endif -static void clear8Col(byte *dst, int dstPitch, int height); +static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth); static void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height); static void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); @@ -231,6 +231,9 @@ GdiV2::~GdiV2() { free(_roomStrips); } +Gdi16Bit::Gdi16Bit(ScummEngine *vm) : Gdi(vm) { +} + void Gdi::init() { _numStrips = _vm->_screenWidth / 8; @@ -341,8 +344,8 @@ void ScummEngine::initVirtScreen(VirtScreenNumber slot, int top, int width, int vs->hasTwoBuffers = twobufs; vs->xstart = 0; vs->backBuf = NULL; - vs->bytesPerPixel = 1; - vs->pitch = width; + vs->bytesPerPixel = (_game.features & GF_16BIT_COLOR) ? 2 : 1; + vs->pitch = width * vs->bytesPerPixel; if (_game.version >= 7) { // Increase the pitch by one; needed to accomodate the extra screen @@ -586,7 +589,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i vsPitch = _screenWidth * m - width * m; } else { - vsPitch = vs->pitch - width; + vsPitch = vs->pitch - width * vs->bytesPerPixel; } @@ -612,36 +615,49 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i #else // We blit four pixels at a time, for improved performance. const uint32 *src32 = (const uint32 *)src; - const uint32 *text32 = (const uint32 *)text; uint32 *dst32 = (uint32 *)_compositeBuf; vsPitch >>= 2; - const int textPitch = (_textSurface.pitch - width * m) >> 2; - for (int h = height * m; h > 0; --h) { - for (int w = width*m; w > 0; w-=4) { - uint32 temp = *text32++; - - // Generate a byte mask for those text pixels (bytes) with - // value CHARSET_MASK_TRANSPARENCY. In the end, each byte - // in mask will be either equal to 0x00 or 0xFF. - // Doing it this way avoids branches and bytewise operations, - // at the cost of readability ;). - uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; - mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; - mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; - - // The following line is equivalent to this code: - // *dst32++ = (*src32++ & mask) | (temp & ~mask); - // However, some compilers can generate somewhat better - // machine code for this equivalent statement: - *dst32++ = ((temp ^ *src32++) & mask) ^ temp; + + if (_bitDepth == 2) { + // Sprites always seem to be used for subtitles in 16Bit color HE games, and not + // the charset renderer, so charset masking isn't required. + for (int h = height * m; h > 0; --h) { + for (int w = width * m; w > 0; w -= 4) { + *dst32++ = *src32++; + *dst32++ = *src32++; + } + src32 += vsPitch; + } + } else { + const uint32 *text32 = (const uint32 *)text; + const int textPitch = (_textSurface.pitch - width * m) >> 2; + for (int h = height * m; h > 0; --h) { + for (int w = width * m; w > 0; w -= 4) { + uint32 temp = *text32++; + + // Generate a byte mask for those text pixels (bytes) with + // value CHARSET_MASK_TRANSPARENCY. In the end, each byte + // in mask will be either equal to 0x00 or 0xFF. + // Doing it this way avoids branches and bytewise operations, + // at the cost of readability ;). + uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; + mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; + mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; + + // The following line is equivalent to this code: + // *dst32++ = (*src32++ & mask) | (temp & ~mask); + // However, some compilers can generate somewhat better + // machine code for this equivalent statement: + *dst32++ = ((temp ^ *src32++) & mask) ^ temp; + } + src32 += vsPitch; + text32 += textPitch; } - src32 += vsPitch; - text32 += textPitch; } #endif src = _compositeBuf; - pitch = width; + pitch = width * vs->bytesPerPixel; if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) { ditherHerc(_compositeBuf, _herculesBuf, width, &x, &y, &width, &height); @@ -976,13 +992,13 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) { return; if (vs->hasTwoBuffers && _currentRoom != 0 && isLightOn()) { - blit(screenBuf, vs->pitch, vs->getBackPixels(rect.left, rect.top), vs->pitch, width, height); + blit(screenBuf, vs->pitch, vs->getBackPixels(rect.left, rect.top), vs->pitch, width, height, vs->bytesPerPixel); if (vs->number == kMainVirtScreen && _charset->_hasMask) { byte *mask = (byte *)_textSurface.getBasePtr(rect.left, rect.top - _screenTop); - fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height); + fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height, _textSurface.bytesPerPixel); } } else { - fill(screenBuf, vs->pitch, backColor, width, height); + fill(screenBuf, vs->pitch, backColor, width, height, vs->bytesPerPixel); } } @@ -1011,7 +1027,7 @@ void ScummEngine::restoreCharsetBg() { if (vs->number != kMainVirtScreen) { // Restore from back buffer const byte *backBuf = vs->getBackPixels(0, 0); - blit(screenBuf, vs->pitch, backBuf, vs->pitch, vs->w, vs->h); + blit(screenBuf, vs->pitch, backBuf, vs->pitch, vs->w, vs->h, vs->bytesPerPixel); } } else { // Clear area @@ -1047,34 +1063,42 @@ byte *Gdi::getMaskBuffer(int x, int y, int z) { #pragma mark --- Misc --- #pragma mark - -static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { +static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, uint8 bitDepth) { assert(w > 0); assert(h > 0); assert(src != NULL); assert(dst != NULL); - if (w == srcPitch && w == dstPitch) { - memcpy(dst, src, w*h); + if ((w * bitDepth == srcPitch) && (w * bitDepth == dstPitch)) { + memcpy(dst, src, w * h * bitDepth); } else { do { - memcpy(dst, src, w); + memcpy(dst, src, w * bitDepth); dst += dstPitch; src += srcPitch; } while (--h); } } -static void fill(byte *dst, int dstPitch, byte color, int w, int h) { +static void fill(byte *dst, int dstPitch, uint16 color, int w, int h, uint8 bitDepth) { assert(h > 0); assert(dst != NULL); - if (w == dstPitch) { - memset(dst, color, w*h); - } else { + if (bitDepth == 2) { do { - memset(dst, color, w); + for (int i = 0; i < w; i++) + WRITE_UINT16(dst + i * 2, color); dst += dstPitch; } while (--h); + } else { + if (w == dstPitch) { + memset(dst, color, w * h); + } else { + do { + memset(dst, color, w); + dst += dstPitch; + } while (--h); + } } } @@ -1084,14 +1108,18 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) { #else -static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { +static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8 bitDepth) { do { #if defined(SCUMM_NEED_ALIGNMENT) - memcpy(dst, src, 8); + memcpy(dst, src, 8 * bitDepth); #else ((uint32 *)dst)[0] = ((const uint32 *)src)[0]; ((uint32 *)dst)[1] = ((const uint32 *)src)[1]; + if (bitDepth == 2) { + ((uint32 *)dst)[2] = ((const uint32 *)src)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src)[3]; + } #endif dst += dstPitch; src += dstPitch; @@ -1100,13 +1128,17 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { #endif /* USE_ARM_GFX_ASM */ -static void clear8Col(byte *dst, int dstPitch, int height) { +static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth) { do { #if defined(SCUMM_NEED_ALIGNMENT) - memset(dst, 0, 8); + memset(dst, 0, 8 * bitDepth); #else ((uint32 *)dst)[0] = 0; ((uint32 *)dst)[1] = 0; + if (bitDepth == 2) { + ((uint32 *)dst)[2] = 0; + ((uint32 *)dst)[3] = 0; + } #endif dst += dstPitch; } while (--height); @@ -1171,41 +1203,41 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) { if (color == -1) { if (vs->number != kMainVirtScreen) error("can only copy bg to main window"); - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); if (_charset->_hasMask) { byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop) * _textSurfaceMultiplier); - fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); + fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier, _textSurface.bytesPerPixel); } } else if (_game.heversion >= 72) { // Flags are used for different methods in HE games uint32 flags = color; if ((flags & 0x2000) || (flags & 0x4000000)) { - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if ((flags & 0x4000) || (flags & 0x2000000)) { - blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height); + blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if ((flags & 0x8000) || (flags & 0x1000000)) { flags &= (flags & 0x1000000) ? 0xFFFFFF : 0x7FFF; - fill(backbuff, vs->pitch, flags, width, height); - fill(bgbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); + fill(bgbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } else { - fill(backbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } } else if (_game.heversion >= 60) { // Flags are used for different methods in HE games uint16 flags = color; if (flags & 0x2000) { - blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); + blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if (flags & 0x4000) { - blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height); + blit(bgbuff, vs->pitch, backbuff, vs->pitch, width, height, vs->bytesPerPixel); } else if (flags & 0x8000) { flags &= 0x7FFF; - fill(backbuff, vs->pitch, flags, width, height); - fill(bgbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); + fill(bgbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } else { - fill(backbuff, vs->pitch, flags, width, height); + fill(backbuff, vs->pitch, flags, width, height, vs->bytesPerPixel); } } else { - fill(backbuff, vs->pitch, color, width, height); + fill(backbuff, vs->pitch, color, width, height, vs->bytesPerPixel); } } @@ -1243,7 +1275,7 @@ void ScummEngine_v5::drawFlashlight() { _flashlight.y, _flashlight.y + _flashlight.h, USAGE_BIT_DIRTY); if (_flashlight.buffer) { - fill(_flashlight.buffer, vs->pitch, 0, _flashlight.w, _flashlight.h); + fill(_flashlight.buffer, vs->pitch, 0, _flashlight.w, _flashlight.h, vs->bytesPerPixel); } _flashlight.isDrawn = false; } @@ -1290,7 +1322,7 @@ void ScummEngine_v5::drawFlashlight() { _flashlight.buffer = vs->getPixels(_flashlight.x, _flashlight.y); bgbak = vs->getBackPixels(_flashlight.x, _flashlight.y); - blit(_flashlight.buffer, vs->pitch, bgbak, vs->pitch, _flashlight.w, _flashlight.h); + blit(_flashlight.buffer, vs->pitch, bgbak, vs->pitch, _flashlight.w, _flashlight.h, vs->bytesPerPixel); // Round the corners. To do so, we simply hard-code a set of nicely // rounded corners. @@ -1599,7 +1631,7 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const warning("Gdi::drawBitmap, strip drawn to %d below window bottom %d", y + height, vs->h); } - _vertStripNextInc = height * vs->pitch - 1; + _vertStripNextInc = height * vs->pitch - 1 * vs->bytesPerPixel; _objectMode = (flag & dbObjectMode) == dbObjectMode; prepareDrawBitmap(ptr, vs, x, y, width, height, stripnr, numstrip); @@ -1632,9 +1664,9 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const // In the case of a double buffered virtual screen, we draw to // the backbuffer, otherwise to the primary surface memory. if (vs->hasTwoBuffers) - dstPtr = vs->backBuf + y * vs->pitch + x * 8; + dstPtr = vs->backBuf + y * vs->pitch + (x * 8 * vs->bytesPerPixel); else - dstPtr = (byte *)vs->pixels + y * vs->pitch + x * 8; + dstPtr = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->bytesPerPixel); transpStrip = drawStrip(dstPtr, vs, x, y, width, height, stripnr, smap_ptr); @@ -1643,11 +1675,11 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const transpStrip = true; if (vs->hasTwoBuffers) { - byte *frontBuf = (byte *)vs->pixels + y * vs->pitch + x * 8; + byte *frontBuf = (byte *)vs->pixels + y * vs->pitch + (x * 8 * vs->bytesPerPixel); if (lightsOn) - copy8Col(frontBuf, vs->pitch, dstPtr, height); + copy8Col(frontBuf, vs->pitch, dstPtr, height, vs->bytesPerPixel); else - clear8Col(frontBuf, vs->pitch, height); + clear8Col(frontBuf, vs->pitch, height, vs->bytesPerPixel); } decodeMask(x, y, width, height, stripnr, numzbuf, zplane_list, transpStrip, flag, tmsk_ptr); @@ -1875,7 +1907,7 @@ void Gdi::drawBMAPBg(const byte *ptr, VirtScreen *vs) { drawStripHE(dst, vs->pitch, bmap_ptr, vs->w, vs->h, true); break; case 150: - fill(dst, vs->pitch, *bmap_ptr, vs->w, vs->h); + fill(dst, vs->pitch, *bmap_ptr, vs->w, vs->h, vs->bytesPerPixel); break; default: // Alternative russian freddi3 uses badly formatted bitmaps @@ -1931,12 +1963,12 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, assert(bmap_ptr); byte code = *bmap_ptr++; - int scrX = _vm->_screenStartStrip * 8; + int scrX = _vm->_screenStartStrip * 8 * _vm->_bitDepth; if (code == 8 || code == 9) { Common::Rect rScreen(0, 0, vs->w, vs->h); byte *dst = (byte *)_vm->_virtscr[kMainVirtScreen].backBuf + scrX; - Wiz::copyWizImage(dst, bmap_ptr, vs->w, vs->h, x - scrX, y, w, h, &rScreen); + Wiz::copyWizImage(dst, bmap_ptr, vs->pitch, kDstScreen, vs->w, vs->h, x - scrX, y, w, h, &rScreen, 0, 0, 0, _vm->_bitDepth); } Common::Rect rect1(x, y, x + w, y + h); @@ -1986,7 +2018,7 @@ void ScummEngine_v70he::restoreBackgroundHE(Common::Rect rect, int dirtybit) { assert(rw <= _screenWidth && rw > 0); assert(rh <= _screenHeight && rh > 0); - blit(dst, _virtscr[kMainVirtScreen].pitch, src, _virtscr[kMainVirtScreen].pitch, rw, rh); + blit(dst, _virtscr[kMainVirtScreen].pitch, src, _virtscr[kMainVirtScreen].pitch, rw, rh, vs->bytesPerPixel); markRectAsDirty(kMainVirtScreen, rect, dirtybit); } #endif @@ -2016,15 +2048,15 @@ void Gdi::resetBackground(int top, int bottom, int strip) { if (bottom > vs->bdirty[strip]) vs->bdirty[strip] = bottom; - bgbak_ptr = (byte *)vs->backBuf + top * vs->pitch + (strip + vs->xstart/8) * 8; - backbuff_ptr = (byte *)vs->pixels + top * vs->pitch + (strip + vs->xstart/8) * 8; + bgbak_ptr = (byte *)vs->backBuf + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->bytesPerPixel; + backbuff_ptr = (byte *)vs->pixels + top * vs->pitch + (strip + vs->xstart/8) * 8 * vs->bytesPerPixel; numLinesToProcess = bottom - top; if (numLinesToProcess) { if (_vm->isLightOn()) { - copy8Col(backbuff_ptr, vs->pitch, bgbak_ptr, numLinesToProcess); + copy8Col(backbuff_ptr, vs->pitch, bgbak_ptr, numLinesToProcess, vs->bytesPerPixel); } else { - clear8Col(backbuff_ptr, vs->pitch, numLinesToProcess); + clear8Col(backbuff_ptr, vs->pitch, numLinesToProcess, vs->bytesPerPixel); } } } @@ -2775,12 +2807,12 @@ void Gdi::drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int h int x = width; while (1) { if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color]; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; --x; if (x == 0) { x = width; - dst += dstPitch - width; + dst += dstPitch - width * _vm->_bitDepth; --height; if (height == 0) return; @@ -2864,8 +2896,8 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; againPos: if (!READ_BIT) { @@ -2886,13 +2918,13 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, do { if (!--x) { x = 8; - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; if (!--height) return; } if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; } while (--reps); bits >>= 8; bits |= (*src++) << (cl - 8); @@ -2900,7 +2932,7 @@ void Gdi::drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, } } } while (--x); - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; } while (--height); } @@ -2916,8 +2948,8 @@ void Gdi::drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; - dst++; + writeRoomColor(dst, color); + dst += _vm->_bitDepth; if (!READ_BIT) { } else if (!READ_BIT) { FILL_BITS; @@ -2932,7 +2964,7 @@ void Gdi::drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, color += inc; } } while (--x); - dst += dstPitch - 8; + dst += dstPitch - 8 * _vm->_bitDepth; } while (--height); } @@ -2949,7 +2981,7 @@ void Gdi::drawStripBasicV(byte *dst, int dstPitch, const byte *src, int height, do { FILL_BITS; if (!transpCheck || color != _transparentColor) - *dst = _roomPalette[color] + _paletteMod; + writeRoomColor(dst, color); dst += dstPitch; if (!READ_BIT) { } else if (!READ_BIT) { @@ -3017,7 +3049,7 @@ void Gdi::drawStripRaw(byte *dst, int dstPitch, const byte *src, int height, con for (x = 0; x < 8; x ++) { byte color = *src++; if (!transpCheck || color != _transparentColor) - dst[x] = _roomPalette[color] + _paletteMod; + writeRoomColor(dst + x * _vm->_bitDepth, color); } dst += dstPitch; } while (--height); @@ -3140,6 +3172,14 @@ void Gdi::unkDecode11(byte *dst, int dstPitch, const byte *src, int height) cons #undef NEXT_ROW #undef READ_BIT_256 +void Gdi16Bit::writeRoomColor(byte *dst, byte color) const { + WRITE_UINT16(dst, READ_LE_UINT16(_vm->_hePalettes + 2048 + color * 2)); +} + +void Gdi::writeRoomColor(byte *dst, byte color) const { + *dst = _roomPalette[color] + _paletteMod; +} + #pragma mark - #pragma mark --- Transition effects --- diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index e4c1054450..0910d9bc59 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -155,11 +155,11 @@ struct VirtScreen : Graphics::Surface { } byte *getPixels(int x, int y) const { - return (byte *)pixels + xstart + y * pitch + x; + return (byte *)pixels + y * pitch + (xstart + x) * bytesPerPixel; } byte *getBackPixels(int x, int y) const { - return (byte *)backBuf + xstart + y * pitch + x; + return (byte *)backBuf + y * pitch + (xstart + x) * bytesPerPixel; } }; @@ -215,6 +215,7 @@ protected: void drawStrip3DO(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; void drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int height, const bool transpCheck) const; + virtual void writeRoomColor(byte *dst, byte color) const; /* Mask decompressors */ void decompressTMSK(byte *dst, const byte *tmsk, const byte *src, int height) const; @@ -361,6 +362,13 @@ public: virtual void roomChanged(byte *roomptr); }; +class Gdi16Bit : public Gdi { +protected: + virtual void writeRoomColor(byte *dst, byte color) const; +public: + Gdi16Bit(ScummEngine *vm); +}; + } // End of namespace Scumm #endif diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 0cc4419778..92b72bd9be 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -66,6 +66,32 @@ int MoviePlayer::load(const char *filename, int flags, int image) { return 0; } +void MoviePlayer::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { + uint h = getHeight(); + uint w = getWidth(); + + byte *src = _videoFrameBuffer; + + if (_vm->_game.features & GF_16BIT_COLOR) { + dst += y * pitch + x * 2; + do { + for (uint i = 0; i < w; i++) { + uint16 col = READ_LE_UINT16(_vm->_hePalettes + _vm->_hePaletteSlot + 768 + src[i] * 2); + WRITE_UINT16(dst + i * 2, col); + } + dst += pitch; + src += w; + } while (--h); + } else { + dst += y * pitch + x; + do { + memcpy(dst, src, w); + dst += pitch; + src += w; + } while (--h); + } +} + void MoviePlayer::handleNextFrame() { if (!isVideoLoaded()) { return; @@ -80,14 +106,14 @@ void MoviePlayer::handleNextFrame() { assert(dstPtr); uint8 *dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); assert(dst); - copyFrameToBuffer(dst, 0, 0, _vm->_screenWidth); + copyFrameToBuffer(dst, 0, 0, _vm->_screenWidth * _vm->_bitDepth); } else if (_flags & 1) { - copyFrameToBuffer(pvs->getBackPixels(0, 0), 0, 0, _vm->_screenWidth); + copyFrameToBuffer(pvs->getBackPixels(0, 0), 0, 0, pvs->pitch); Common::Rect imageRect(getWidth(), getHeight()); _vm->restoreBackgroundHE(imageRect); } else { - copyFrameToBuffer(pvs->getPixels(0, 0), 0, 0, _vm->_screenWidth); + copyFrameToBuffer(pvs->getPixels(0, 0), 0, 0, pvs->pitch); Common::Rect imageRect(getWidth(), getHeight()); _vm->markRectAsDirty(kMainVirtScreen, imageRect); diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h index 39f03960c4..e2fc1d04b7 100644 --- a/engines/scumm/he/animation_he.h +++ b/engines/scumm/he/animation_he.h @@ -54,6 +54,7 @@ public: int getImageNum(); int load(const char *filename, int flags, int image = 0); + void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch); void handleNextFrame(); protected: diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index c2079fa5fe..949113aeeb 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -455,6 +455,7 @@ protected: uint8 *getHEPaletteIndex(int palSlot); int getHEPaletteColor(int palSlot, int color); int getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end); + int getHEPalette16BitColorComponent(int component, int type); int getHEPaletteColorComponent(int palSlot, int color, int component); void setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b); void setHEPaletteFromPtr(int palSlot, const uint8 *palData); @@ -463,7 +464,7 @@ protected: void setHEPaletteFromRoom(int palSlot, int resId, int state); void restoreHEPalette(int palSlot); void copyHEPalette(int dstPalSlot, int srcPalSlot); - void copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor); + void copyHEPaletteColor(int palSlot, uint8 dstColor, uint16 srcColor); protected: /* HE version 90 script opcodes */ diff --git a/engines/scumm/he/palette_he.cpp b/engines/scumm/he/palette_he.cpp index d055b77ee2..812c39d173 100644 --- a/engines/scumm/he/palette_he.cpp +++ b/engines/scumm/he/palette_he.cpp @@ -31,6 +31,27 @@ namespace Scumm { +uint8 *ScummEngine::getHEPaletteSlot(uint16 palSlot) { + assertRange(0, palSlot, _numPalettes, "palette"); + + if (_game.heversion >= 99) { + if (palSlot) + return _hePalettes + palSlot * _hePaletteSlot + 768; + else + return _hePalettes + _hePaletteSlot + 768; + } + + return NULL; +} + +uint16 ScummEngine::get16BitColor(uint8 r, uint8 g, uint8 b) { + uint16 ar = (r >> 3) << 10; + uint16 ag = (g >> 3) << 5; + uint16 ab = (b >> 3) << 0; + uint16 col = ar | ag | ab; + return col; +} + void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { int r, g, b, sum, bestitem, bestsum; int ar, ag, ab; @@ -38,7 +59,7 @@ void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { src += 30; if (_game.heversion >= 99) { - palPtr = _hePalettes + 1024 + 30; + palPtr = _hePalettes + _hePaletteSlot + 30; } else { palPtr = _currentPalette + 30; } @@ -73,9 +94,9 @@ void ScummEngine_v71he::remapHEPalette(const uint8 *src, uint8 *dst) { uint8 *ScummEngine_v90he::getHEPaletteIndex(int palSlot) { if (palSlot) { assert(palSlot >= 1 && palSlot <= _numPalettes); - return _hePalettes + palSlot * 1024; + return _hePalettes + palSlot * _hePaletteSlot; } else { - return _hePalettes + 1024; + return _hePalettes + _hePaletteSlot; } } @@ -84,7 +105,7 @@ int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, assertRange(0, start, 255, "start palette slot"); assertRange(0, end, 255, "pend alette slot"); - uint8 *pal = _hePalettes + palSlot * 1024 + start * 3; + uint8 *pal = _hePalettes + palSlot * _hePaletteSlot + start * 3; int bestsum = 0x7FFFFFFF; int bestitem = start; @@ -105,39 +126,83 @@ int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, return bestitem; } +int ScummEngine_v90he::getHEPalette16BitColorComponent(int component, int type) { + uint16 col; + if (type == 2) { + col = (((component & 0xFFFF) >> 0) & 0x1F) << 3;; + } else if (type == 1) { + col = (((component & 0xFFFF) >> 5) & 0x1F) << 3; + } else { + col = (((component & 0xFFFF) >> 10) & 0x1F) << 3; + } + return col; +} + int ScummEngine_v90he::getHEPaletteColorComponent(int palSlot, int color, int component) { assertRange(1, palSlot, _numPalettes, "palette"); assertRange(0, color, 255, "palette slot"); - return _hePalettes[palSlot * 1024 + color * 3 + component % 3]; + return _hePalettes[palSlot * _hePaletteSlot + color * 3 + component % 3]; } int ScummEngine_v90he::getHEPaletteColor(int palSlot, int color) { assertRange(1, palSlot, _numPalettes, "palette"); assertRange(0, color, 255, "palette slot"); - return _hePalettes[palSlot * 1024 + 768 + color]; + if (_game.features & GF_16BIT_COLOR) + return READ_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + color * 2); + else + return _hePalettes[palSlot * _hePaletteSlot + 768 + color]; } void ScummEngine_v90he::setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b) { debug(7, "setHEPaletteColor(%d, %d, %d, %d, %d)", palSlot, color, r, g, b); assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *p = _hePalettes + palSlot * 1024 + color * 3; + + uint8 *p = _hePalettes + palSlot * _hePaletteSlot + color * 3; *(p + 0) = r; *(p + 1) = g; *(p + 2) = b; - _hePalettes[palSlot * 1024 + 768 + color] = color; + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + color * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[palSlot * _hePaletteSlot + 768 + color] = color; + } } void ScummEngine_v90he::setHEPaletteFromPtr(int palSlot, const uint8 *palData) { assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *pc = _hePalettes + palSlot * 1024; + + uint8 *pc = _hePalettes + palSlot * _hePaletteSlot; uint8 *pi = pc + 768; - for (int i = 0; i < 256; ++i) { - *pc++ = *palData++; - *pc++ = *palData++; - *pc++ = *palData++; - *pi++ = i; + if (_game.features & GF_16BIT_COLOR) { + for (int i = 0; i < 256; ++i) { + uint8 r = *pc++ = *palData++; + uint8 g = *pc++ = *palData++; + uint8 b = *pc++ = *palData++; + WRITE_LE_UINT16(pi, get16BitColor(r, g, b)); pi += 2; + } + } else { + for (int i = 0; i < 256; ++i) { + *pc++ = *palData++; + *pc++ = *palData++; + *pc++ = *palData++; + *pi++ = i; + } + } + + int i; + uint8 *palPtr = _hePalettes + palSlot * _hePaletteSlot + 768; + if (_game.features & GF_16BIT_COLOR) { + for (i = 0; i < 10; ++i) + WRITE_LE_UINT16(palPtr + i * 2, i); + for (i = 246; i < 256; ++i) + WRITE_LE_UINT16(palPtr + i * 2, i); + } else { + for (i = 0; i < 10; ++i) + *(palPtr + i) = i; + for (i = 246; i < 256; ++i) + *(palPtr + i) = i; } } @@ -176,8 +241,9 @@ void ScummEngine_v90he::setHEPaletteFromRoom(int palSlot, int resId, int state) void ScummEngine_v90he::restoreHEPalette(int palSlot) { debug(7, "restoreHEPalette(%d)", palSlot); assertRange(1, palSlot, _numPalettes, "palette"); + if (palSlot != 1) { - memcpy(_hePalettes + palSlot * 1024, _hePalettes + 1024, 1024); + memcpy(_hePalettes + palSlot * _hePaletteSlot, _hePalettes + _hePaletteSlot, _hePaletteSlot); } } @@ -185,18 +251,27 @@ void ScummEngine_v90he::copyHEPalette(int dstPalSlot, int srcPalSlot) { debug(7, "copyHEPalette(%d, %d)", dstPalSlot, srcPalSlot); assert(dstPalSlot >= 1 && dstPalSlot <= _numPalettes); assert(srcPalSlot >= 1 && srcPalSlot <= _numPalettes); + if (dstPalSlot != srcPalSlot) { - memcpy(_hePalettes + dstPalSlot * 1024, _hePalettes + srcPalSlot * 1024, 1024); + memcpy(_hePalettes + dstPalSlot * _hePaletteSlot, _hePalettes + srcPalSlot * _hePaletteSlot, _hePaletteSlot); } } -void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor) { +void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint16 srcColor) { debug(7, "copyHEPaletteColor(%d, %d, %d)", palSlot, dstColor, srcColor); assertRange(1, palSlot, _numPalettes, "palette"); - uint8 *dstPal = _hePalettes + palSlot * 1024 + dstColor * 3; - uint8 *srcPal = _hePalettes + 1024 + srcColor * 3; - memcpy(dstPal, srcPal, 3); - _hePalettes[palSlot * 1024 + 768 + dstColor] = srcColor; + + uint8 *dstPal = _hePalettes + palSlot * _hePaletteSlot + dstColor * 3; + uint8 *srcPal = _hePalettes + _hePaletteSlot + srcColor * 3; + if (_game.features & GF_16BIT_COLOR) { + dstPal[0] = (srcColor >> 10) << 3; + dstPal[1] = (srcColor >> 5) << 3; + dstPal[2] = (srcColor >> 0) << 3; + WRITE_LE_UINT16(_hePalettes + palSlot * _hePaletteSlot + 768 + dstColor * 2, srcColor); + } else { + memcpy(dstPal, srcPal, 3); + _hePalettes[palSlot * _hePaletteSlot + 768 + dstColor] = srcColor; + } } void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { @@ -209,7 +284,7 @@ void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { assertRange(0, numcolor, 256, "setPaletteFromPtr: numcolor"); - dest = _hePalettes + 1024; + dest = _hePalettes + _hePaletteSlot; for (i = 0; i < numcolor; i++) { r = *ptr++; @@ -220,48 +295,63 @@ void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { *dest++ = r; *dest++ = g; *dest++ = b; - _hePalettes[1792 + i] = i; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + i] = i; + } } else { dest += 3; } } - memcpy(_hePalettes, _hePalettes + 1024, 768); - - for (i = 0; i < 10; ++i) - _hePalettes[1792 + i] = i; - for (i = 246; i < 256; ++i) - _hePalettes[1792 + i] = i; + memcpy(_hePalettes, _hePalettes + _hePaletteSlot, 768); + if (_game.features & GF_16BIT_COLOR) { + for (i = 0; i < 10; ++i) + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, i); + for (i = 246; i < 256; ++i) + WRITE_LE_UINT16(_hePalettes + 2048 + i * 2, i); + } else { + for (i = 0; i < 10; ++i) + _hePalettes[1792 + i] = i; + for (i = 246; i < 256; ++i) + _hePalettes[1792 + i] = i; + } setDirtyColors(0, numcolor - 1); } void ScummEngine_v99he::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) { uint8 *src, *dst; - int color, j; + int j, r, g, b; src = _hePalettes + startColor * 3; - dst = _hePalettes + 1024 + startColor * 3; + dst = _hePalettes + _hePaletteSlot + startColor * 3; for (j = startColor; j <= endColor; j++) { - color = *src++; - color = color * redScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * greenScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * blueScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - _hePalettes[1792 + j] = j; + r = *src++; + r = r * redScale / 0xFF; + if (r > 255) + r = 255; + *dst++ = r; + + g = *src++; + g = g * greenScale / 0xFF; + if (g > 255) + g = 255; + *dst++ = g; + + b = *src++; + b = b * blueScale / 0xFF; + if (b > 255) + b = 255; + *dst++ = b; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + j * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + j] = j; + } setDirtyColors(j, endColor); } } @@ -272,26 +362,39 @@ void ScummEngine_v99he::copyPalColor(int dst, int src) { if ((uint) dst >= 256 || (uint) src >= 256) error("copyPalColor: invalid values, %d, %d", dst, src); - dp = &_hePalettes[1024 + dst * 3]; - sp = &_hePalettes[1024 + src * 3]; + dp = &_hePalettes[_hePaletteSlot + dst * 3]; + sp = &_hePalettes[_hePaletteSlot + src * 3]; dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; - _hePalettes[1792 + dst] = dst; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + dst * 2, get16BitColor(sp[0], sp[1], sp[2])); + } else { + _hePalettes[1792 + dst] = dst; + } setDirtyColors(dst, dst); } void ScummEngine_v99he::setPalColor(int idx, int r, int g, int b) { - _hePalettes[1024 + idx * 3 + 0] = r; - _hePalettes[1024 + idx * 3 + 1] = g; - _hePalettes[1024 + idx * 3 + 2] = b; - _hePalettes[1792 + idx] = idx; + _hePalettes[_hePaletteSlot + idx * 3 + 0] = r; + _hePalettes[_hePaletteSlot + idx * 3 + 1] = g; + _hePalettes[_hePaletteSlot + idx * 3 + 2] = b; + + if (_game.features & GF_16BIT_COLOR) { + WRITE_LE_UINT16(_hePalettes + 2048 + idx * 2, get16BitColor(r, g, b)); + } else { + _hePalettes[1792 + idx] = idx; + } setDirtyColors(idx, idx); } void ScummEngine_v99he::updatePalette() { + if (_game.features & GF_16BIT_COLOR) + return; + if (_palDirtyMax == -1) return; diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index fe0904d632..58a858ede4 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -1574,7 +1574,10 @@ void ScummEngine_v100he::o100_roomOps() { case 130: a = pop(); b = pop(); - copyPalColor(a, b); + if (_game.features & GF_16BIT_COLOR) + copyHEPaletteColor(1, a, b); + else + copyPalColor(a, b); break; case 131: // SO_ROOM_FADE @@ -2151,8 +2154,9 @@ void ScummEngine_v100he::o100_systemOps() { } void ScummEngine_v100he::o100_cursorCommand() { - int a, i; + int a, b, i; int args[16]; + byte subOp = fetchScriptByte(); switch (subOp) { @@ -2167,12 +2171,12 @@ void ScummEngine_v100he::o100_cursorCommand() { case 0x80: case 0x81: a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, 0); break; case 0x82: - pop(); + b = pop(); a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, b); break; case 0x86: // SO_CURSOR_ON Turn cursor on _cursor.state = 1; @@ -2575,7 +2579,8 @@ void ScummEngine_v100he::o100_getWizData() { } void ScummEngine_v100he::o100_getPaletteData() { - int b, c, d, e; + int c, d, e; + int r, g, b; int palSlot, color; byte subOp = fetchScriptByte(); @@ -2584,7 +2589,10 @@ void ScummEngine_v100he::o100_getPaletteData() { case 13: c = pop(); b = pop(); - push(getHEPaletteColorComponent(1, b, c)); + if (_game.features & GF_16BIT_COLOR) + push(getHEPalette16BitColorComponent(b, c)); + else + push(getHEPaletteColorComponent(1, b, c)); break; case 20: color = pop(); @@ -2595,20 +2603,26 @@ void ScummEngine_v100he::o100_getPaletteData() { e = pop(); d = pop(); palSlot = pop(); - pop(); - c = pop(); b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + g = pop(); + r = pop(); + push(getHEPaletteSimilarColor(palSlot, r, g, d, e)); break; case 53: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); b = pop(); b = MAX(0, b); b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + g = pop(); + g = MAX(0, g); + g = MIN(g, 255); + r = pop(); + r = MAX(0, r); + r = MIN(r, 255); + if (_game.features & GF_16BIT_COLOR) { + push(get16BitColor(r, g, b)); + } else { + push(getHEPaletteSimilarColor(1, r, g, 10, 245)); + } break; case 73: c = pop(); diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index 5ad447b1c7..b416a0e75d 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -115,6 +115,8 @@ int ScummEngine_v60he::convertFilePath(byte *dst) { int r = 0; if (dst[0] == '.' && dst[1] == '/') { // Game Data Path r = 2; + } else if (dst[2] == 'b' && dst[5] == 'k') { // Backyard Basketball INI + r = 13; } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (HE72 - HE100) r = 2; } else if (dst[0] == 'c' && dst[1] == ':') { // Save Game Path (HE60 - HE71) diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 64c63baa9d..9d5bd0b23d 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -1482,6 +1482,7 @@ void ScummEngine_v72he::o72_readFile() { fetchScriptByte(); size = pop(); slot = pop(); + assert(_hInFileTable[slot]); val = readFileToArray(slot, size); push(val); break; @@ -1571,7 +1572,7 @@ void ScummEngine_v72he::o72_rename() { } void ScummEngine_v72he::o72_getPixel() { - byte area; + uint16 area; int y = pop(); int x = pop(); @@ -1586,11 +1587,17 @@ void ScummEngine_v72he::o72_getPixel() { switch (subOp) { case 9: // HE 100 case 218: - area = *vs->getBackPixels(x, y - vs->topline); + if (_game.features & GF_16BIT_COLOR) + area = READ_UINT16(vs->getBackPixels(x, y - vs->topline)); + else + area = *vs->getBackPixels(x, y - vs->topline); break; case 8: // HE 100 case 219: - area = *vs->getPixels(x, y - vs->topline); + if (_game.features & GF_16BIT_COLOR) + area = READ_UINT16(vs->getPixels(x, y - vs->topline)); + else + area = *vs->getPixels(x, y - vs->topline); break; default: error("o72_getPixel: default case %d", subOp); @@ -1803,9 +1810,7 @@ void ScummEngine_v72he::o72_readINI() { switch (subOp) { case 43: // HE 100 case 6: // number - if (!strcmp((char *)option, "NoFontsInstalled")) { - push(1); - } else if (!strcmp((char *)option, "NoPrinting")) { + if (!strcmp((char *)option, "NoPrinting")) { push(1); } else if (!strcmp((char *)option, "TextOn")) { push(ConfMan.getBool("subtitles")); diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index b71a0f9e10..4b759dec53 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -241,7 +241,7 @@ void ScummEngine_v80he::o80_writeConfigFile() { } void ScummEngine_v80he::o80_cursorCommand() { - int a, i; + int a, b, i; int args[16]; byte subOp = fetchScriptByte(); @@ -250,12 +250,12 @@ void ScummEngine_v80he::o80_cursorCommand() { case 0x13: case 0x14: a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, 0); break; case 0x3C: - pop(); + b = pop(); a = pop(); - _wiz->loadWizCursor(a); + _wiz->loadWizCursor(a, b); break; case 0x90: // SO_CURSOR_ON Turn cursor on _cursor.state = 1; diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index f97771a4f8..7a7a1ff58b 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1253,7 +1253,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { void ScummEngine_v90he::o90_getWizData() { byte filename[4096]; - int state, resId; + int resId, state, type; int32 w, h; int32 x, y; @@ -1317,9 +1317,10 @@ void ScummEngine_v90he::o90_getWizData() { push(computeWizHistogram(resId, state, x, y, w, h)); break; case 139: - pop(); - pop(); - push(0); + type = pop(); + state = pop(); + resId = pop(); + push(_wiz->getWizImageData(resId, state, type)); break; case 141: pop(); @@ -2099,7 +2100,8 @@ void ScummEngine_v90he::o90_getObjectData() { } void ScummEngine_v90he::o90_getPaletteData() { - int b, c, d, e; + int c, d, e; + int r, g, b; int palSlot, color; byte subOp = fetchScriptByte(); @@ -2109,10 +2111,10 @@ void ScummEngine_v90he::o90_getPaletteData() { e = pop(); d = pop(); palSlot = pop(); - pop(); - c = pop(); b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + g = pop(); + r = pop(); + push(getHEPaletteSimilarColor(palSlot, r, g, d, e)); break; case 52: c = pop(); @@ -2128,17 +2130,27 @@ void ScummEngine_v90he::o90_getPaletteData() { case 132: c = pop(); b = pop(); - push(getHEPaletteColorComponent(1, b, c)); + if (_game.features & GF_16BIT_COLOR) + push(getHEPalette16BitColorComponent(b, c)); + else + push(getHEPaletteColorComponent(1, b, c)); break; case 217: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); b = pop(); b = MAX(0, b); b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + g = pop(); + g = MAX(0, g); + g = MIN(g, 255); + r = pop(); + r = MAX(0, r); + r = MIN(r, 255); + + if (_game.features & GF_16BIT_COLOR) { + push(get16BitColor(r, g, b)); + } else { + push(getHEPaletteSimilarColor(1, r, g, 10, 245)); + } break; default: error("o90_getPaletteData: Unknown case %d", subOp); diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index b23b7ac869..2e414f2a1e 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -254,7 +254,9 @@ bool Wiz::polygonContains(const WizPolygon &pol, int x, int y) { return r; } -void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch) { +void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitDepth) { + assert(bitDepth == 1); + Common::Rect dstRect(srcx, srcy, srcx + srcw, srcy + srch); dstRect.clip(dstw, dsth); @@ -263,8 +265,8 @@ void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int if (rh <= 0 || rw <= 0) return; - uint8 *dst1Ptr = dst1 + dstRect.left + dstRect.top * dstw; - uint8 *dst2Ptr = dst2 + dstRect.left + dstRect.top * dstw; + uint8 *dst1Ptr = dst1 + dstRect.top * dstw + dstRect.left; + uint8 *dst2Ptr = dst2 + dstRect.top * dstw + dstRect.left; const uint8 *dataPtr = src; while (rh--) { @@ -353,12 +355,24 @@ static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, return srcRect.isValidRect() && dstRect.isValidRect(); } -void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { - // TODO: Compressed 16 bits in 555 format +void Wiz::writeColor(uint8 *dstPtr, int dstType, uint16 color) { + switch (dstType) { + case kDstScreen: + WRITE_UINT16(dstPtr, color); + break; + case kDstMemory: + case kDstResource: + WRITE_LE_UINT16(dstPtr, color); + break; + default: + error("writeColor: Unknown dstType %d", dstType); + } +} +void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *xmapPtr) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - dst += r2.top * dstw + r2.left; + dst += r2.top * dstPitch + r2.left * 2; if (flags & kWIFFlipY) { const int dy = (srcy < 0) ? srcy : (srch - r1.height()); r1.translate(0, dy); @@ -368,17 +382,17 @@ void Wiz::copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, in r1.translate(dx, 0); } if (xmapPtr) { - decompress16BitWizImage<kWizXMap>(dst, dstw, src, r1, flags, palPtr, xmapPtr); + decompress16BitWizImage<kWizXMap>(dst, dstPitch, dstType, src, r1, flags, xmapPtr); } else { - decompress16BitWizImage<kWizCopy>(dst, dstw, src, r1, flags); + decompress16BitWizImage<kWizCopy>(dst, dstPitch, dstType, src, r1, flags); } } } -void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - dst += r2.left + r2.top * dstw; + dst += r2.top * dstPitch + r2.left * bitDepth; if (flags & kWIFFlipY) { const int dy = (srcy < 0) ? srcy : (srch - r1.height()); r1.translate(0, dy); @@ -388,11 +402,11 @@ void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int src r1.translate(dx, 0); } if (xmapPtr) { - decompressWizImage<kWizXMap>(dst, dstw, src, r1, flags, palPtr, xmapPtr); + decompressWizImage<kWizXMap>(dst, dstPitch, dstType, src, r1, flags, palPtr, xmapPtr, bitDepth); } else if (palPtr) { - decompressWizImage<kWizRMap>(dst, dstw, src, r1, flags, palPtr); + decompressWizImage<kWizRMap>(dst, dstPitch, dstType, src, r1, flags, palPtr, NULL, bitDepth); } else { - decompressWizImage<kWizCopy>(dst, dstw, src, r1, flags); + decompressWizImage<kWizCopy>(dst, dstPitch, dstType, src, r1, flags, NULL, NULL, bitDepth); } } } @@ -431,13 +445,100 @@ static void decodeWizMask(uint8 *&dst, uint8 &mask, int w, int maskType) { } } -void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP) { +void Wiz::copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr) { Common::Rect srcRect, dstRect; if (!calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, srcRect, dstRect)) { return; } - dstw = dstw / 8; - dst += dstRect.top * dstw + dstRect.left / 8; + dst += dstRect.top * dstPitch + dstRect.left * 2; + if (flags & kWIFFlipY) { + const int dy = (srcy < 0) ? srcy : (srch - srcRect.height()); + srcRect.translate(0, dy); + } + if (flags & kWIFFlipX) { + const int dx = (srcx < 0) ? srcx : (srcw - srcRect.width()); + srcRect.translate(dx, 0); + } + + const uint8 *dataPtr, *dataPtrNext; + const uint8 *maskPtr, *maskPtrNext; + uint8 code, *dstPtr, *dstPtrNext; + int h, w, dstInc; + + dataPtr = src; + dstPtr = dst; + maskPtr = mask; + + // Skip over the first 'srcRect->top' lines in the data + dataPtr += dstRect.top * dstPitch + dstRect.left * 2; + + h = dstRect.height(); + w = dstRect.width(); + if (h <= 0 || w <= 0) + return; + + dstInc = 2; + if (flags & kWIFFlipX) { + dstPtr += (w - 1) * 2; + dstInc = -2; + } + + while (h--) { + w = dstRect.width(); + uint16 lineSize = READ_LE_UINT16(maskPtr); maskPtr += 2; + dataPtrNext = dataPtr + dstPitch; + dstPtrNext = dstPtr + dstPitch; + maskPtrNext = maskPtr + lineSize; + if (lineSize != 0) { + while (w > 0) { + code = *maskPtr++; + if (code & 1) { + code >>= 1; + dataPtr += dstInc * code; + dstPtr += dstInc * code; + w -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (*maskPtr != 5) + write16BitColor<kWizCopy>(dstPtr, dataPtr, dstType, palPtr); + dataPtr += 2; + dstPtr += dstInc; + } + maskPtr++; + } else { + code = (code >> 2) + 1; + w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (*maskPtr != 5) + write16BitColor<kWizCopy>(dstPtr, dataPtr, dstType, palPtr); + dataPtr += 2; + dstPtr += dstInc; + maskPtr++; + } + } + } + } + dataPtr = dataPtrNext; + dstPtr = dstPtrNext; + maskPtr = maskPtrNext; + } +} + +void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstPitch, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP) { + Common::Rect srcRect, dstRect; + if (!calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, srcRect, dstRect)) { + return; + } + dstPitch /= 8; + dst += dstRect.top * dstPitch + dstRect.left / 8; const uint8 *dataPtr, *dataPtrNext; uint8 code, mask, *dstPtr, *dstPtrNext; @@ -462,7 +563,7 @@ void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, w = srcRect.width(); mask = revBitMask(dstRect.left & 7); off = READ_LE_UINT16(dataPtr); dataPtr += 2; - dstPtrNext = dstPtr + dstw; + dstPtrNext = dstPtr + dstPitch; dataPtrNext = dataPtr + off; if (off != 0) { while (w > 0) { @@ -520,7 +621,7 @@ void Wiz::copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, } } -void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { +void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitDepth) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { if (flags & kWIFFlipX) { @@ -537,19 +638,17 @@ void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int } int h = r1.height(); int w = r1.width(); - src += r1.left + r1.top * srcw; - dst += r2.left + r2.top * dstw; + src += r1.top * srcw + r1.left; + dst += r2.top * dstPitch + r2.left * bitDepth; if (palPtr) { - decompressRawWizImage<kWizRMap>(dst, dstw, src, srcw, w, h, transColor, palPtr); + decompressRawWizImage<kWizRMap>(dst, dstPitch, dstType, src, srcw, w, h, transColor, palPtr, bitDepth); } else { - decompressRawWizImage<kWizCopy>(dst, dstw, src, srcw, w, h, transColor); + decompressRawWizImage<kWizCopy>(dst, dstPitch, dstType, src, srcw, w, h, transColor, NULL, bitDepth); } } } -void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { - // TODO: RAW 16 bits in 555 format - +void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, int transColor) { Common::Rect r1, r2; if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { if (flags & kWIFFlipX) { @@ -567,37 +666,44 @@ void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int h = r1.height(); int w = r1.width(); src += (r1.top * srcw + r1.left) * 2; - dst += r2.top * dstw + r2.left; + dst += r2.top * dstPitch + r2.left * 2; while (h--) { - for (int i = 0; i < w; ++i) { + for (int i = 0; i < w; ++ i) { uint16 col = READ_LE_UINT16(src + 2 * i); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - uint8 color = _vm->convert16BitColor(col, r, g, b); - if (transColor == -1 || transColor != col) { - dst[i] = color; + writeColor(dst + i * 2, dstType, col); } } src += srcw * 2; - dst += dstw; + dst += dstPitch; } } } template <int type> -void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::write16BitColor(uint8 *dstPtr, const uint8 *dataPtr, int dstType, const uint8 *xmapPtr) { + uint16 col = READ_LE_UINT16(dataPtr); + if (type == kWizXMap) { + uint16 srcColor = (col >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dstPtr) >> 1) & 0x7DEF; + uint16 newColor = srcColor + dstColor; + writeColor(dstPtr, dstType, newColor); + } + if (type == kWizCopy) { + writeColor(dstPtr, dstType, col); + } +} + +template <int type> +void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *xmapPtr) { const uint8 *dataPtr, *dataPtrNext; - uint8 code, *dstPtr, *dstPtrNext; + uint8 code; + uint8 *dstPtr, *dstPtrNext; int h, w, xoff, dstInc; if (type == kWizXMap) { assert(xmapPtr != 0); } - if (type == kWizRMap) { - assert(palPtr != 0); - } dstPtr = dst; dataPtr = src; @@ -616,10 +722,10 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co dstPtr += (h - 1) * dstPitch; dstPitch = -dstPitch; } - dstInc = 1; + dstInc = 2; if (flags & kWIFFlipX) { - dstPtr += w - 1; - dstInc = -1; + dstPtr += (w - 1) * 2; + dstInc = -2; } while (h--) { @@ -658,21 +764,10 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co code += w; } while (code--) { - uint16 col = READ_LE_UINT16(dataPtr); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - col = _vm->convert16BitColor(col, r, g, b); - - if (type == kWizXMap) { - *dstPtr = xmapPtr[col * 256 + *dstPtr]; - } - if (type == kWizCopy) { - *dstPtr = col; - } + write16BitColor<type>(dstPtr, dataPtr, dstType, xmapPtr); dstPtr += dstInc; } - dataPtr+= 2; + dataPtr += 2; } else { code = (code >> 2) + 1; if (xoff > 0) { @@ -689,18 +784,7 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co code += w; } while (code--) { - uint16 col = READ_LE_UINT16(dataPtr); - uint8 r = ((col >> 10) & 0x1F) << 3; - uint8 g = ((col >> 5) & 0x1F) << 3; - uint8 b = ((col >> 0) & 0x1F) << 3; - col = _vm->convert16BitColor(col, r, g, b); - - if (type == kWizXMap) { - *dstPtr = xmapPtr[col * 256 + *dstPtr]; - } - if (type == kWizCopy) { - *dstPtr = col; - } + write16BitColor<type>(dstPtr, dataPtr, dstType, xmapPtr); dataPtr += 2; dstPtr += dstInc; } @@ -713,7 +797,36 @@ void Wiz::decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, co } template <int type> -void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { +void Wiz::write8BitColor(uint8 *dstPtr, const uint8 *dataPtr, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { + if (bitDepth == 2) { + if (type == kWizXMap) { + uint16 color = READ_LE_UINT16(palPtr + *dataPtr * 2); + uint16 srcColor = (color >> 1) & 0x7DEF; + uint16 dstColor = (READ_UINT16(dstPtr) >> 1) & 0x7DEF; + uint16 newColor = srcColor + dstColor; + writeColor(dstPtr, dstType, newColor); + } + if (type == kWizRMap) { + writeColor(dstPtr, dstType, READ_LE_UINT16(palPtr + *dataPtr * 2)); + } + if (type == kWizCopy) { + writeColor(dstPtr, dstType, *dataPtr); + } + } else { + if (type == kWizXMap) { + *dstPtr = xmapPtr[*dataPtr * 256 + *dstPtr]; + } + if (type == kWizRMap) { + *dstPtr = palPtr[*dataPtr]; + } + if (type == kWizCopy) { + *dstPtr = *dataPtr; + } + } +} + +template <int type> +void Wiz::decompressWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth) { const uint8 *dataPtr, *dataPtrNext; uint8 code, *dstPtr, *dstPtrNext; int h, w, xoff, dstInc; @@ -742,10 +855,10 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C dstPtr += (h - 1) * dstPitch; dstPitch = -dstPitch; } - dstInc = 1; + dstInc = bitDepth; if (flags & kWIFFlipX) { - dstPtr += w - 1; - dstInc = -1; + dstPtr += (w - 1) * bitDepth; + dstInc = -bitDepth; } while (h--) { @@ -784,15 +897,7 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C code += w; } while (code--) { - if (type == kWizXMap) { - *dstPtr = xmapPtr[*dataPtr * 256 + *dstPtr]; - } - if (type == kWizRMap) { - *dstPtr = palPtr[*dataPtr]; - } - if (type == kWizCopy) { - *dstPtr = *dataPtr; - } + write8BitColor<type>(dstPtr, dataPtr, dstType, palPtr, xmapPtr, bitDepth); dstPtr += dstInc; } dataPtr++; @@ -812,15 +917,8 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C code += w; } while (code--) { - if (type == kWizXMap) { - *dstPtr = xmapPtr[*dataPtr++ * 256 + *dstPtr]; - } - if (type == kWizRMap) { - *dstPtr = palPtr[*dataPtr++]; - } - if (type == kWizCopy) { - *dstPtr = *dataPtr++; - } + write8BitColor<type>(dstPtr, dataPtr, dstType, palPtr, xmapPtr, bitDepth); + dataPtr++; dstPtr += dstInc; } } @@ -832,7 +930,7 @@ void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const C } template <int type> -void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr) { +void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr, uint8 bitDepth) { if (type == kWizRMap) { assert(palPtr != 0); } @@ -845,10 +943,18 @@ void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int uint8 col = src[i]; if (transColor == -1 || transColor != col) { if (type == kWizRMap) { - dst[i] = palPtr[col]; + if (bitDepth == 2) { + writeColor(dst + i * 2, dstType, READ_LE_UINT16(palPtr + col * 2)); + } else { + dst[i] = palPtr[col]; + } } if (type == kWizCopy) { - dst[i] = col; + if (bitDepth == 2) { + writeColor(dst + i * 2, dstType, col); + } else { + dst[i] = col; + } } } } @@ -938,7 +1044,7 @@ uint16 Wiz::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint } if (bitDepth == 2) - return (READ_LE_UINT16(data) & 1) ? color : READ_LE_UINT16(data + 1); + return (READ_LE_UINT16(data) & 1) ? color : READ_LE_UINT16(data + 2); else return (data[0] & 1) ? color : data[1]; @@ -949,7 +1055,7 @@ uint16 Wiz::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, u return color; } if (bitDepth == 2) - return READ_LE_UINT16(data + y * w + x * 2); + return READ_LE_UINT16(data + (y * w + x) * 2); else return data[y * w + x]; } @@ -1038,6 +1144,23 @@ void Wiz::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPi } } +static int wizPackType2(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt) { + debug(9, "wizPackType2([%d,%d,%d,%d])", rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); + int w = rCapt.width(); + int h = rCapt.height(); + int size = w * h * 2; + if (dst) { + src += rCapt.top * srcPitch + rCapt.left * 2; + while (h--) { + for (int i = 0; i < w; i++) + WRITE_LE_UINT16(dst + i * 2, READ_UINT16(src + i * 2)); + dst += w * 2; + src += srcPitch; + } + } + return size; +} + static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 transColor) { debug(9, "wizPackType1(%d, [%d,%d,%d,%d])", transColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); src += rCapt.top * srcPitch + rCapt.left; @@ -1174,7 +1297,6 @@ static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common } void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, int compType) { - debug(5, "ScummEngine_v72he::captureWizImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); uint8 *src = NULL; VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (backBuffer) { @@ -1182,12 +1304,17 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in } else { src = pvs->getPixels(0, 0); } - Common::Rect rCapt(pvs->w, pvs->h); + captureImage(src, pvs->pitch, pvs->w, pvs->h, resNum, r, compType); +} + +void Wiz::captureImage(uint8 *src, int srcPitch, int srcw, int srch, int resNum, const Common::Rect& r, int compType) { + debug(0, "captureImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); + Common::Rect rCapt(srcw, srch); if (rCapt.intersects(r)) { rCapt.clip(r); const uint8 *palPtr; if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot; } else { palPtr = _vm->_currentPalette; } @@ -1196,15 +1323,21 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in int h = rCapt.height(); int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + if (_vm->_game.features & GF_16BIT_COLOR) + compType = 2; + // compute compressed size int dataSize = 0; int headerSize = palPtr ? 1080 : 36; switch (compType) { case 0: - dataSize = wizPackType0(0, src, pvs->pitch, rCapt); + dataSize = wizPackType0(0, src, srcPitch, rCapt); break; case 1: - dataSize = wizPackType1(0, src, pvs->pitch, rCapt, transColor); + dataSize = wizPackType1(0, src, srcPitch, rCapt, transColor); + break; + case 2: + dataSize = wizPackType2(0, src, srcPitch, rCapt); break; default: error("unhandled compression type %d", compType); @@ -1244,10 +1377,13 @@ void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, in // write compressed data switch (compType) { case 0: - wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt); + wizPackType0(wizImg + headerSize, src, srcPitch, rCapt); break; case 1: - wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, transColor); + wizPackType1(wizImg + headerSize, src, srcPitch, rCapt, transColor); + break; + case 2: + wizPackType2(wizImg + headerSize, src, srcPitch, rCapt); break; default: break; @@ -1274,24 +1410,15 @@ void Wiz::displayWizImage(WizImage *pwi) { drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0); } else { const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, 0); + drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0)); } } -uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette) { - debug(3, "drawWizImage(resNum %d, x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d palette %d)", resNum, x1, y1, flags, zorder, shadow, field_390, dstResNum, palette); +uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr) { + debug(3, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, field_390, dstResNum); uint8 *dataPtr; uint8 *dst = NULL; - const uint8 *palPtr = NULL; - if (_vm->_game.heversion >= 99) { - if (palette) { - palPtr = _vm->_hePalettes + palette * 1024 + 768; - } else { - palPtr = _vm->_hePalettes + 1792; - } - } - const uint8 *xmapPtr = NULL; if (shadow) { dataPtr = _vm->getResourceAddress(rtImage, shadow); @@ -1313,6 +1440,21 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int uint8 *wizd = _vm->findWrappedBlock(MKID_BE('WIZD'), dataPtr, state, 0); assert(wizd); + uint8 *mask = NULL; + if (maskNum) { + uint8 *maskPtr = _vm->getResourceAddress(rtImage, maskNum); + assert(maskPtr); + + wizh = _vm->findWrappedBlock(MKID_BE('WIZH'), maskPtr, maskState, 0); + assert(wizh); + assert(comp == 2 && READ_LE_UINT32(wizh + 0x0) == 1); + width = READ_LE_UINT32(wizh + 0x4); + height = READ_LE_UINT32(wizh + 0x8); + + mask = _vm->findWrappedBlock(MKID_BE('WIZD'), maskPtr, maskState, 0); + assert(mask); + } + if (flags & kWIFHasPalette) { uint8 *pal = _vm->findWrappedBlock(MKID_BE('RGBS'), dataPtr, state, 0); assert(pal); @@ -1334,13 +1476,25 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int error("WizImage printing is unimplemented"); } - int32 cw, ch; + int32 dstPitch, dstType, cw, ch; if (flags & kWIFBlitToMemBuffer) { - dst = (uint8 *)malloc(width * height); + dst = (uint8 *)malloc(width * height * _vm->_bitDepth); int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? (_vm->VAR(_vm->VAR_WIZ_TCOLOR)) : 5; - memset(dst, transColor, width * height); + + if (_vm->_bitDepth == 2) { + uint8 *tmpPtr = dst; + for (uint i = 0; i < height; i++) { + for (uint j = 0; j < width; j++) + WRITE_LE_UINT16(tmpPtr + j * 2, transColor); + tmpPtr += width * 2; + } + } else { + memset(dst, transColor, width * height); + } cw = width; ch = height; + dstPitch = cw * _vm->_bitDepth; + dstType = kDstMemory; } else { if (dstResNum) { uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); @@ -1348,6 +1502,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); assert(dst); getWizImageDim(dstResNum, 0, cw, ch); + dstPitch = cw * _vm->_bitDepth; + dstType = kDstResource; } else { VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (flags & kWIFMarkBufferDirty) { @@ -1357,6 +1513,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int } cw = pvs->w; ch = pvs->h; + dstPitch = pvs->pitch; + dstType = kDstScreen; } } @@ -1376,7 +1534,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int } } - if (flags & kWIFRemapPalette) { + if (flags & kWIFRemapPalette && _vm->_bitDepth == 1) { palPtr = rmap + 4; } @@ -1388,28 +1546,33 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int switch (comp) { case 0: - copyRawWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + copyRawWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor, _vm->_bitDepth); break; case 1: if (flags & 0x80) { dst = _vm->getMaskBuffer(0, 0, 1); - copyWizImageWithMask(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, 0, 2); + dstPitch /= _vm->_bitDepth; + copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 2); } else if (flags & 0x100) { dst = _vm->getMaskBuffer(0, 0, 1); - copyWizImageWithMask(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, 0, 1); + dstPitch /= _vm->_bitDepth; + copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 1); } else { - copyWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); + copyWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr, _vm->_bitDepth); } break; case 2: - copyRaw16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + if (maskNum) { + copyMaskWizImage(dst, wizd, mask, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr); + } else { + copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, transColor); + } break; case 4: // TODO: Unknown image type break; case 5: - // TODO: 16bit color compressed image - copy16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); + copy16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, xmapPtr); break; default: error("drawWizImage: Unhandled wiz compression type %d", comp); @@ -1512,6 +1675,74 @@ struct PolygonDrawData { } }; +void Wiz::captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int id2, int compType) { + debug(0, "captureWizPolygon: resNum %d, maskNum %d maskState %d, id1 %d id2 %d compType %d", resNum, maskNum, maskState, id1, id2, compType); + + int i, j; + WizPolygon *wp; + + wp = NULL; + for (i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == id1) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Polygon1 %d is not defined", id1); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon1 %d", wp->numVerts, id1); + } + + wp = NULL; + for (i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == id2) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Polygon2 %d is not defined", id2); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon2 %d", wp->numVerts, id2); + } + + int32 dstw, dsth, dstpitch; + int32 srcw, srch; + uint8 *imageBuffer; + + assert(maskNum); + const Common::Rect *r = NULL; + const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); + getWizImageDim(maskNum, maskState, srcw, srch); + + dstw = wp->bound.width(); + dsth = wp->bound.height(); + dstpitch = dstw * _vm->_bitDepth; + imageBuffer = (uint8 *)malloc(dstw * dsth * _vm->_bitDepth); + assert(imageBuffer); + + const uint16 transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + if (_vm->_bitDepth == 2) { + uint8 *tmpPtr = imageBuffer; + for (i = 0; i < dsth; i++) { + for (j = 0; j < dstw; j++) + WRITE_LE_UINT16(tmpPtr + j * 2, transColor); + tmpPtr += dstpitch; + } + } else { + memset(imageBuffer, transColor, dstw * dsth); + } + + Common::Rect bound; + drawWizPolygonImage(imageBuffer, src, NULL, dstpitch, kDstMemory, dstw, dsth, srcw, srch, bound, wp->vert, _vm->_bitDepth); + + captureImage(imageBuffer, dstpitch, dstw, dsth, resNum, wp->bound, compType); + free(imageBuffer); +} + void Wiz::drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int scale, const Common::Rect *r, int flags, int dstResNum, int palette) { Common::Point pts[4]; @@ -1539,11 +1770,10 @@ void Wiz::drawWizPolygon(int resNum, int state, int id, int flags, int shadow, i } void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette) { - debug(3, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); + debug(0, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); const Common::Rect *r = NULL; uint8 *srcWizBuf = NULL; bool freeBuffer = true; - int i; if (_vm->_game.heversion >= 99) { if (getWizImageData(resNum, state, 0) != 0 || (flags & (kWIFRemapPalette | kWIFFlipX | kWIFFlipY)) || palette != 0) { @@ -1552,8 +1782,10 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int if (flags & 0x800000) { debug(0, "drawWizPolygonTransform() unhandled flag 0x800000"); } - srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, flags, 0, palette); + + srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette)); } else { + assert(_vm->_bitDepth == 1); uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); assert(dataPtr); srcWizBuf = _vm->findWrappedBlock(MKID_BE('WIZD'), dataPtr, state, 0); @@ -1562,7 +1794,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int } } else { if (getWizImageData(resNum, state, 0) != 0) { - srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, palette); + srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette)); } else { uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); assert(dataPtr); @@ -1572,146 +1804,163 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int } } - if (srcWizBuf) { - uint8 *dst; - int32 dstw, dsth, dstpitch, wizW, wizH; - VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; - int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + assert(srcWizBuf); - if (dstResNum) { - uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); - assert(dstPtr); - dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); - assert(dst); - getWizImageDim(dstResNum, 0, dstw, dsth); - dstpitch = dstw; + uint8 *dst; + int32 dstw, dsth, dstpitch, dstType, wizW, wizH; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; + + if (dstResNum) { + uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); + assert(dstPtr); + dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); + assert(dst); + getWizImageDim(dstResNum, 0, dstw, dsth); + dstpitch = dstw * _vm->_bitDepth; + dstType = kDstResource; + } else { + if (flags & kWIFMarkBufferDirty) { + dst = pvs->getPixels(0, 0); } else { - if (flags & kWIFMarkBufferDirty) { - dst = pvs->getPixels(0, 0); - } else { - dst = pvs->getBackPixels(0, 0); + dst = pvs->getBackPixels(0, 0); + } + dstw = pvs->w; + dsth = pvs->h; + dstpitch = pvs->pitch; + dstType = kDstScreen; + } + + Common::Rect bound; + getWizImageDim(resNum, state, wizW, wizH); + drawWizPolygonImage(dst, srcWizBuf, 0, dstpitch, dstType, dstw, dsth, wizW, wizH, bound, wp, _vm->_bitDepth); + + if (flags & kWIFMarkBufferDirty) { + _vm->markRectAsDirty(kMainVirtScreen, bound); + } else { + _vm->restoreBackgroundHE(bound); + } + + if (freeBuffer) + free(srcWizBuf); +} + +void Wiz::drawWizPolygonImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstpitch, int dstType, int dstw, int dsth, int wizW, int wizH, Common::Rect &bound, Common::Point *wp, uint8 bitDepth) { + int i, transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + + Common::Point bbox[4]; + bbox[0].x = 0; + bbox[0].y = 0; + bbox[1].x = wizW - 1; + bbox[1].y = 0; + bbox[2].x = wizW - 1; + bbox[2].y = wizH - 1; + bbox[3].x = 0; + bbox[3].y = wizH - 1; + + int16 xmin_p, xmax_p, ymin_p, ymax_p; + xmin_p = ymin_p = (int16)0x7FFF; + xmax_p = ymax_p = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_p = MIN(wp[i].x, xmin_p); + xmax_p = MAX(wp[i].x, xmax_p); + ymin_p = MIN(wp[i].y, ymin_p); + ymax_p = MAX(wp[i].y, ymax_p); + } + + int16 xmin_b, xmax_b, ymin_b, ymax_b; + xmin_b = ymin_b = (int16)0x7FFF; + xmax_b = ymax_b = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_b = MIN(bbox[i].x, xmin_b); + xmax_b = MAX(bbox[i].x, xmax_b); + ymin_b = MIN(bbox[i].y, ymin_b); + ymax_b = MAX(bbox[i].y, ymax_b); + } + + PolygonDrawData pdd(ymax_p - ymin_p + 1); + pdd.mat[0].x = xmin_p; + pdd.mat[0].y = ymin_p; + pdd.mat[1].x = xmax_p; + pdd.mat[1].y = ymax_p; + pdd.mat[2].x = xmin_b; + pdd.mat[2].y = ymin_b; + pdd.mat[3].x = xmax_b; + pdd.mat[3].y = ymax_b; + + // precompute the transformation which remaps 'bbox' pixels to 'wp' + for (i = 0; i < 3; ++i) { + pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); + } + pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); + + pdd.rAreasNum = 0; + PolygonDrawData::ResultArea *pra = &pdd.ra[0]; + int32 yoff = pdd.mat[0].y * dstpitch; + int16 y_start = pdd.mat[0].y; + for (i = 0; i < pdd.pAreasNum; ++i) { + PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; + if (y_start >= 0 && y_start < dsth) { + int16 x1 = ppa->xmin; + if (x1 < 0) { + x1 = 0; } - dstw = pvs->w; - dsth = pvs->h; - dstpitch = pvs->pitch; - } - - getWizImageDim(resNum, state, wizW, wizH); - - Common::Point bbox[4]; - bbox[0].x = 0; - bbox[0].y = 0; - bbox[1].x = wizW - 1; - bbox[1].y = 0; - bbox[2].x = wizW - 1; - bbox[2].y = wizH - 1; - bbox[3].x = 0; - bbox[3].y = wizH - 1; - - int16 xmin_p, xmax_p, ymin_p, ymax_p; - xmin_p = ymin_p = (int16)0x7FFF; - xmax_p = ymax_p = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_p = MIN(wp[i].x, xmin_p); - xmax_p = MAX(wp[i].x, xmax_p); - ymin_p = MIN(wp[i].y, ymin_p); - ymax_p = MAX(wp[i].y, ymax_p); - } - - int16 xmin_b, xmax_b, ymin_b, ymax_b; - xmin_b = ymin_b = (int16)0x7FFF; - xmax_b = ymax_b = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_b = MIN(bbox[i].x, xmin_b); - xmax_b = MAX(bbox[i].x, xmax_b); - ymin_b = MIN(bbox[i].y, ymin_b); - ymax_b = MAX(bbox[i].y, ymax_b); - } - - PolygonDrawData pdd(ymax_p - ymin_p + 1); - pdd.mat[0].x = xmin_p; - pdd.mat[0].y = ymin_p; - pdd.mat[1].x = xmax_p; - pdd.mat[1].y = ymax_p; - pdd.mat[2].x = xmin_b; - pdd.mat[2].y = ymin_b; - pdd.mat[3].x = xmax_b; - pdd.mat[3].y = ymax_b; - - // precompute the transformation which remaps 'bbox' pixels to 'wp' - for (i = 0; i < 3; ++i) { - pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); - } - pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); - - pdd.rAreasNum = 0; - PolygonDrawData::ResultArea *pra = &pdd.ra[0]; - int32 yoff = pdd.mat[0].y * dstpitch; - int16 y_start = pdd.mat[0].y; - for (i = 0; i < pdd.pAreasNum; ++i) { - PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; - if (y_start >= 0 && y_start < dsth) { - int16 x1 = ppa->xmin; - if (x1 < 0) { - x1 = 0; - } - int16 x2 = ppa->xmax; - if (x2 >= dstw) { - x2 = dstw - 1; - } - int16 w = x2 - x1 + 1; - if (w > 0) { - int16 width = ppa->xmax - ppa->xmin + 1; - pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; - pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; - pra->dst_offs = yoff + x1; - pra->w = w; - pra->x_s = ppa->x1 << 16; - pra->y_s = ppa->y1 << 16; - int16 tmp = x1 - ppa->xmin; - if (tmp != 0) { - pra->x_s += pra->x_step * tmp; - pra->y_s += pra->y_step * tmp; - } - ++pra; - ++pdd.rAreasNum; - } + int16 x2 = ppa->xmax; + if (x2 >= dstw) { + x2 = dstw - 1; } - ++ppa; - yoff += dstpitch; - ++y_start; - } - - pra = &pdd.ra[0]; - for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { - uint8 *dstPtr = dst + pra->dst_offs; - int32 w = pra->w; - int32 x_acc = pra->x_s; - int32 y_acc = pra->y_s; - while (--w) { - int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); - assert(src_offs < wizW * wizH); - x_acc += pra->x_step; - y_acc += pra->y_step; - if (transColor == -1 || transColor != srcWizBuf[src_offs]) { - *dstPtr = srcWizBuf[src_offs]; + int16 w = x2 - x1 + 1; + if (w > 0) { + int16 width = ppa->xmax - ppa->xmin + 1; + pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; + pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; + pra->dst_offs = yoff + x1 * _vm->_bitDepth; + pra->w = w; + pra->x_s = ppa->x1 << 16; + pra->y_s = ppa->y1 << 16; + int16 tmp = x1 - ppa->xmin; + if (tmp != 0) { + pra->x_s += pra->x_step * tmp; + pra->y_s += pra->y_step * tmp; } - dstPtr++; + ++pra; + ++pdd.rAreasNum; } } - - Common::Rect bound(xmin_p, ymin_p, xmax_p + 1, ymax_p + 1); - if (flags & kWIFMarkBufferDirty) { - _vm->markRectAsDirty(kMainVirtScreen, bound); - } else { - _vm->restoreBackgroundHE(bound); + ++ppa; + yoff += dstpitch; + ++y_start; + } + + pra = &pdd.ra[0]; + for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { + uint8 *dstPtr = dst + pra->dst_offs; + int32 w = pra->w; + int32 x_acc = pra->x_s; + int32 y_acc = pra->y_s; + while (--w) { + int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); + assert(src_offs < wizW * wizH); + x_acc += pra->x_step; + y_acc += pra->y_step; + if (bitDepth == 2) { + if (transColor == -1 || transColor != READ_LE_UINT16(src + src_offs * 2)) { + //if (transColor == -1 || READ_LE_UINT16(dstPtr) != transColor) + writeColor(dstPtr, dstType, READ_LE_UINT16(src + src_offs * 2)); + } + } else { + if (transColor == -1 || transColor != src[src_offs]) + *dstPtr = src[src_offs]; + } + dstPtr += bitDepth; } - - if (freeBuffer) - free(srcWizBuf); } + + bound.left = xmin_p; + bound.top = ymin_p; + bound.right = xmax_p + 1; + bound.bottom = ymax_p + 1; } void Wiz::flushWizBuffer() { @@ -1721,13 +1970,13 @@ void Wiz::flushWizBuffer() { drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette); } else { const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, pwi->palette); + drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette)); } } _imagesNum = 0; } -void Wiz::loadWizCursor(int resId) { +void Wiz::loadWizCursor(int resId, int palette) { int32 x, y; getWizImageSpot(resId, 0, x, y); if (x < 0) { @@ -1742,11 +1991,12 @@ void Wiz::loadWizCursor(int resId) { } const Common::Rect *r = NULL; - uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); + uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette)); + int32 cw, ch; getWizImageDim(resId, 0, cw, ch); _vm->setCursorHotspot(x, y); - _vm->setCursorFromBuffer(cursor, cw, ch, cw); + _vm->setCursorFromBuffer(cursor, cw, ch, cw * _vm->_bitDepth); // Since we set up cursor palette for default cursor, disable it now CursorMan.disableCursorPalette(true); @@ -1758,7 +2008,7 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { int sourceImage = 0; if (params->processFlags & kWPFMaskImg) { sourceImage = params->sourceImage; - debug(0, "displayWizComplexImage() unhandled flag kWPFMaskImg"); + debug(0, "displayWizComplexImage() flag kWPFMaskImg"); } int palette = 0; if (params->processFlags & kWPFPaletteNum) { @@ -1826,15 +2076,14 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { ++_imagesNum; } else { if (sourceImage != 0) { - // TODO: Add support for kWPFMaskImg - drawWizImage(params->sourceImage, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); + drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette)); } else if (params->processFlags & (kWPFScaled | kWPFRotate)) { drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette); } else { if (flags & kWIFIsPolygon) { drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette); } else { - drawWizImage(params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); + drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette)); } } } @@ -1842,6 +2091,8 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int img_h) { const uint16 flags = 0xB; + const uint8 compType = (_vm->_game.features & GF_16BIT_COLOR) ? 2 : 0; + const uint8 bitDepth = (_vm->_game.features & GF_16BIT_COLOR) ? 2 : 1; int res_size = 0x1C; if (flags & 1) { res_size += 0x308; @@ -1852,11 +2103,11 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i if (flags & 8) { res_size += 0x10C; } - res_size += 8 + img_w * img_h; + res_size += 8 + img_w * img_h * bitDepth; const uint8 *palPtr; if (_vm->_game.heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; + palPtr = _vm->_hePalettes + _vm->_hePaletteSlot; } else { palPtr = _vm->_currentPalette; } @@ -1869,7 +2120,7 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i WRITE_BE_UINT32(res_data, res_size); res_data += 4; WRITE_BE_UINT32(res_data, 'WIZH'); res_data += 4; WRITE_BE_UINT32(res_data, 0x14); res_data += 4; - WRITE_LE_UINT32(res_data, 0); res_data += 4; + WRITE_LE_UINT32(res_data, compType); res_data += 4; WRITE_LE_UINT32(res_data, img_w); res_data += 4; WRITE_LE_UINT32(res_data, img_h); res_data += 4; if (flags & 1) { @@ -1892,7 +2143,7 @@ void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int i } } WRITE_BE_UINT32(res_data, 'WIZD'); res_data += 4; - WRITE_BE_UINT32(res_data, 8 + img_w * img_h); res_data += 4; + WRITE_BE_UINT32(res_data, 8 + img_w * img_h * bitDepth); res_data += 4; } _vm->_res->setModified(rtImage, resNum); } @@ -1909,7 +2160,8 @@ void Wiz::fillWizRect(const WizParameters *params) { int c = READ_LE_UINT32(wizh + 0x0); int w = READ_LE_UINT32(wizh + 0x4); int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); + assert(c == 0 || c == 2); + uint8 bitDepth = (c == 2) ? 2 : 1; Common::Rect areaRect, imageRect(w, h); if (params->processFlags & kWPFClipBox) { if (!imageRect.intersects(params->box)) { @@ -1932,10 +2184,15 @@ void Wiz::fillWizRect(const WizParameters *params) { assert(wizd); int dx = areaRect.width(); int dy = areaRect.height(); - wizd += areaRect.top * w + areaRect.left; + wizd += (areaRect.top * w + areaRect.left) * bitDepth; while (dy--) { - memset(wizd, color, dx); - wizd += w; + if (bitDepth == 2) { + for (int i = 0; i < dx; i++) + WRITE_LE_UINT16(wizd + i * 2, color); + } else { + memset(wizd, color, dx); + } + wizd += w * bitDepth; } } } @@ -1945,14 +2202,19 @@ void Wiz::fillWizRect(const WizParameters *params) { struct drawProcP { Common::Rect *imageRect; uint8 *wizd; - int width; + int pitch; + int depth; }; static void drawProc(int x, int y, int c, void *data) { drawProcP *param = (drawProcP *)data; if (param->imageRect->contains(x, y)) { - *(param->wizd + y * param->width + x) = c; + uint32 offs = y * param->pitch + x * param->depth; + if (param->depth == 2) + WRITE_LE_UINT16(param->wizd + offs, c); + else + *(param->wizd + offs) = c; } } @@ -1969,7 +2231,8 @@ void Wiz::fillWizLine(const WizParameters *params) { int c = READ_LE_UINT32(wizh + 0x0); int w = READ_LE_UINT32(wizh + 0x4); int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); + assert(c == 0 || c == 2); + uint8 bitDepth = (c == 2) ? 2 : 1; Common::Rect imageRect(w, h); if (params->processFlags & kWPFClipBox) { if (!imageRect.intersects(params->box)) { @@ -1992,13 +2255,13 @@ void Wiz::fillWizLine(const WizParameters *params) { lineP.imageRect = &imageRect; lineP.wizd = wizd; - lineP.width = w; + lineP.pitch = w * bitDepth; + lineP.depth = bitDepth; if (params->processFlags & kWPFParams) { assert (params->params2 == 1); // Catch untested usage Graphics::drawThickLine(x1, y1, x2, y2, params->params1, color, drawProc, &lineP); } else { - Graphics::drawLine(x1, y1, x2, y2, color, drawProc, &lineP); } } @@ -2060,7 +2323,7 @@ void Wiz::remapWizImagePal(const WizParameters *params) { } void Wiz::processWizImage(const WizParameters *params) { - byte filename[260]; + byte buffer[260]; debug(3, "processWizImage: processMode %d", params->processMode); switch (params->processMode) { @@ -2075,18 +2338,28 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 3: if (params->processFlags & kWPFUseFile) { - Common::File f; + Common::SeekableReadStream *f = NULL; + memcpy(buffer, params->filename, 260); + const char *filename = (char *)buffer + _vm->convertFilePath(buffer); - memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + if (!_vm->_saveFileMan->listSavefiles(filename).empty()) { + f = _vm->_saveFileMan->openForLoading(filename); + } else { + Common::File *nf = new Common::File(); + nf->open(filename); + if (!nf->isOpen()) + delete nf; + else + f = nf; + } - if (f.open((const char *)filename)) { - uint32 id = f.readUint32BE(); + if (f) { + uint32 id = f->readUint32BE(); if (id == MKID_BE('AWIZ') || id == MKID_BE('MULT')) { - uint32 size = f.readUint32BE(); - f.seek(0, SEEK_SET); + uint32 size = f->readUint32BE(); + f->seek(0, SEEK_SET); byte *p = _vm->_res->createResource(rtImage, params->img.resNum, size); - if (f.read(p, size) != size) { + if (f->read(p, size) != size) { _vm->_res->nukeResource(rtImage, params->img.resNum); error("i/o error when reading '%s'", filename); _vm->VAR(_vm->VAR_GAME_LOADED) = -2; @@ -2100,7 +2373,7 @@ void Wiz::processWizImage(const WizParameters *params) { _vm->VAR(_vm->VAR_GAME_LOADED) = -1; _vm->VAR(119) = -1; } - f.close(); + delete f; } else { _vm->VAR(_vm->VAR_GAME_LOADED) = -3; _vm->VAR(119) = -3; @@ -2110,7 +2383,9 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 4: if (params->processFlags & kWPFUseFile) { - Common::DumpFile f; + Common::OutSaveFile *f; + memcpy(buffer, params->filename, 260); + const char *filename = (char *)buffer + _vm->convertFilePath(buffer); switch (params->fileWriteMode) { case 2: @@ -2120,22 +2395,20 @@ void Wiz::processWizImage(const WizParameters *params) { // TODO Write image to file break; case 0: - memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); - - if (!f.open((const char *)filename)) { + if (!(f = _vm->_saveFileMan->openForSaving(filename))) { debug(0, "Unable to open for write '%s'", filename); _vm->VAR(119) = -3; } else { byte *p = _vm->getResourceAddress(rtImage, params->img.resNum); uint32 size = READ_BE_UINT32(p + 4); - if (f.write(p, size) != size) { - error("i/o error when writing '%s'", params->filename); + if (f->write(p, size) != size) { + error("i/o error when writing '%s'", filename); _vm->VAR(119) = -2; } else { _vm->VAR(119) = 0; } - f.close(); + f->finalize(); + delete f; } break; default: @@ -2148,9 +2421,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; // HE 99+ case 7: - // Used in PuttsFunShop/SamsFunShop/soccer2004 - // TODO: Capture polygon - _vm->_res->setModified(rtImage, params->img.resNum); + captureWizPolygon(params->img.resNum, params->sourceImage, (params->processFlags & kWPFNewState) ? params->img.state : 0, params->polygonId1, params->polygonId2, params->compType); break; case 8: { int img_w = 640; @@ -2167,6 +2438,9 @@ void Wiz::processWizImage(const WizParameters *params) { img_x = params->img.x1; img_y = params->img.y1; } + if (params->processFlags & kWPFParams) { + debug(0, "Compression %d Color Depth %d", params->params1, params->params2); + } createWizEmptyImage(params->img.resNum, img_x, img_y, img_w, img_h); } break; @@ -2304,7 +2578,7 @@ int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags ret = isWizPixelNonTransparent(wizd, x, y, w, h, 1); break; case 2: - ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; + ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; break; case 4: // TODO: Unknown image type diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h index fe63457ead..d8f984f710 100644 --- a/engines/scumm/he/wiz_he.h +++ b/engines/scumm/he/wiz_he.h @@ -142,6 +142,12 @@ enum { kWizCopy }; +enum DstSurface { + kDstScreen = 0, + kDstMemory = 1, + kDstResource = 2 +}; + class ScummEngine_v71he; class Wiz { @@ -188,27 +194,37 @@ public: void flushWizBuffer(); void getWizImageSpot(int resId, int state, int32 &x, int32 &y); - void loadWizCursor(int resId); + void loadWizCursor(int resId, int palette); void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType); + void captureImage(uint8 *src, int srcPitch, int srcw, int srch, int resNum, const Common::Rect& r, int compType); + void captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int id2, int compType); void displayWizComplexImage(const WizParameters *params); void displayWizImage(WizImage *pwi); void processWizImage(const WizParameters *params); - uint8 *drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette); + uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr); void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette); void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette); void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette); + void drawWizPolygonImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstpitch, int dstType, int dstw, int dsth, int wizW, int wizH, Common::Rect &bound, Common::Point *wp, uint8 bitDepth); + + static void copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr); + + static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitdepth); + static void copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstPitch, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP); + static void copyWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitdepth); + static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitdepth); + static void copy16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *xmapPtr); + static void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, int transColor); + template<int type> static void decompress16BitWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *xmapPtr = NULL); + template<int type> static void decompressWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitdepth); + template<int type> static void decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr, uint8 bitdepth); + + template<int type> static void write16BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *xmapPtr); + template<int type> static void write8BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth); + static void writeColor(uint8 *dstPtr, int dstType, uint16 color); - static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch); - static void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - static void copyWizImageWithMask(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int maskT, int maskP); - void copy16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - template<int type> static void decompressWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - template<int type> void decompress16BitWizImage(uint8 *dst, int dstPitch, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - template<int type> static void decompressRawWizImage(uint8 *dst, int dstPitch, const uint8 *src, int srcPitch, int w, int h, int transColor, const uint8 *palPtr = NULL); int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth); uint16 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color); uint16 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color); diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp index c356e7a06c..f59b59b40f 100644 --- a/engines/scumm/palette.cpp +++ b/engines/scumm/palette.cpp @@ -310,9 +310,6 @@ void ScummEngine::setDirtyColors(int min, int max) { _palDirtyMin = min; if (_palDirtyMax < max) _palDirtyMax = max; - - if (_hePaletteCache) - memset(_hePaletteCache, -1, 65536); } void ScummEngine::initCycl(const byte *ptr) { @@ -799,16 +796,6 @@ void ScummEngine_v8::desaturatePalette(int hueScale, int satScale, int lightScal #endif -int ScummEngine::convert16BitColor(uint16 color, uint8 r, uint8 g, uint8 b) { - // HACK: Find the closest matching color, and store in - // cache for faster access. - if (_hePaletteCache[color] == -1) { - _hePaletteCache[color] = remapPaletteColor(r, g, b, -1); - } - - return _hePaletteCache[color]; -} - int ScummEngine::remapPaletteColor(int r, int g, int b, int threshold) { byte *pal; int ar, ag, ab, i; diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 88802a205f..8359675032 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -920,7 +920,11 @@ bool ScummEngine::isResourceInUse(int type, int i) const { case rtCostume: return isCostumeInUse(i); case rtSound: - return _sound->isSoundInUse(i); + // Sound resource 1 is used for queued speech + if (_game.heversion >= 60 && i == 1) + return true; + else + return _sound->isSoundInUse(i); case rtCharset: return _charset->getCurID() == i; case rtImage: diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index cef13341b5..051873e147 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1505,7 +1505,7 @@ void ScummEngine_v90he::saveOrLoad(Serializer *s) { void ScummEngine_v99he::saveOrLoad(Serializer *s) { ScummEngine_v90he::saveOrLoad(s); - s->saveLoadArrayOf(_hePalettes, (_numPalettes + 1) * 1024, sizeof(_hePalettes[0]), sleUint8); + s->saveLoadArrayOf(_hePalettes, (_numPalettes + 1) * _hePaletteSlot, sizeof(_hePalettes[0]), sleUint8); } void ScummEngine_v100he::saveOrLoad(Serializer *s) { diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 29184ad023..49bfe39b21 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 77 +#define CURRENT_VER 78 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index dcbf95ef4b..57283c1fbe 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -109,7 +109,9 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _currentScript(0xFF), // Let debug() work on init stage _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) { - if (_game.platform == Common::kPlatformNES) { + if (_game.features & GF_16BIT_COLOR) { + _gdi = new Gdi16Bit(this); + } else if (_game.platform == Common::kPlatformNES) { _gdi = new GdiNES(this); } else if (_game.version <= 1) { _gdi = new GdiV1(this); @@ -248,6 +250,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _switchRoomEffect2 = 0; _switchRoomEffect = 0; + _bitDepth = 0; _doEffect = false; _snapScroll = false; _currentLights = 0; @@ -264,8 +267,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _palManipPalette = NULL; _palManipIntermediatePal = NULL; memset(gfxUsageBits, 0, sizeof(gfxUsageBits)); - _hePaletteCache = NULL; _hePalettes = NULL; + _hePaletteSlot = 0; _shadowPalette = NULL; _shadowPaletteSize = 0; memset(_currentPalette, 0, sizeof(_currentPalette)); @@ -521,9 +524,11 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _screenHeight = 200; } + _bitDepth = (_game.features & GF_16BIT_COLOR) ? 2 : 1; + // Allocate gfx compositing buffer (not needed for V7/V8 games). if (_game.version < 7) - _compositeBuf = (byte *)malloc(_screenWidth * _screenHeight); + _compositeBuf = (byte *)malloc(_screenWidth * _screenHeight * _bitDepth); else _compositeBuf = 0; @@ -814,7 +819,6 @@ ScummEngine_v90he::~ScummEngine_v90he() { delete _logicHE; } if (_game.heversion >= 99) { - free(_hePaletteCache); free(_hePalettes); } } @@ -1079,6 +1083,15 @@ Common::Error ScummEngine::init() { // CJK FT and DIG use usual NUT fonts, not FM-TOWNS ROM, so // there is no text surface for them. This takes that into account (_screenWidth * _textSurfaceMultiplier > 320)); + } else if (_game.features & GF_16BIT_COLOR) { +#ifdef ENABLE_RGB_COLOR + Graphics::PixelFormat format = Graphics::PixelFormat(2, 3, 3, 3, 8, 10, 5, 0, 0); + initGraphics(_screenWidth, _screenHeight, _screenWidth > 320, &format); + if (format != _system->getScreenFormat()) + return Common::kUnsupportedColorMode; +#else + error("16bit color support is required for this game"); +#endif } else { initGraphics(_screenWidth, _screenHeight, _screenWidth > 320); } @@ -1182,7 +1195,7 @@ void ScummEngine::setupScumm() { int maxHeapThreshold = -1; if (_game.features & GF_16BIT_COLOR) { - // 16Bit color games require double the memory, due to increased resource sizes. + // 16bit color games require double the memory, due to increased resource sizes. maxHeapThreshold = 12 * 1024 * 1024; } else if (_game.features & GF_NEW_COSTUMES) { // Since the new costumes are very big, we increase the heap limit, to avoid having @@ -1204,7 +1217,7 @@ void ScummEngine::setupScumm() { } free(_compositeBuf); - _compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier); + _compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier * _bitDepth); } #ifdef ENABLE_SCUMM_7_8 @@ -1546,11 +1559,9 @@ void ScummEngine_v99he::resetScumm() { ScummEngine_v90he::resetScumm(); - _hePaletteCache = (int16 *)malloc(65536); - memset(_hePaletteCache, -1, 65536); - - _hePalettes = (uint8 *)malloc((_numPalettes + 1) * 1024); - memset(_hePalettes, 0, (_numPalettes + 1) * 1024); + _hePaletteSlot = (_game.features & GF_16BIT_COLOR) ? 1280 : 1024; + _hePalettes = (uint8 *)malloc((_numPalettes + 1) * _hePaletteSlot); + memset(_hePalettes, 0, (_numPalettes + 1) * _hePaletteSlot); // Array 129 is set to base name len = strlen(_filenamePattern.pattern); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index e3be053810..badbb8ba9d 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -953,6 +953,7 @@ public: int _screenTop; Common::RenderMode _renderMode; + uint8 _bitDepth; protected: ColorCycle _colorCycle[16]; // Palette cycles @@ -972,7 +973,10 @@ protected: byte animate, animateIndex; int8 state; } _cursor; - byte _grabbedCursor[8192]; + + // HACK Double the array size to handle 16-bit images. + // this should be dynamically allocated based on game depth instead. + byte _grabbedCursor[16384]; byte _currentCursor; byte _newEffect, _switchRoomEffect2, _switchRoomEffect; @@ -1038,7 +1042,8 @@ protected: virtual void palManipulateInit(int resID, int start, int end, int time); void palManipulate(); public: - int convert16BitColor(uint16 color, uint8 r, uint8 g, uint8 b); + uint8 *getHEPaletteSlot(uint16 palSlot); + uint16 get16BitColor(uint8 r, uint8 g, uint8 b); int remapPaletteColor(int r, int g, int b, int threshold); // Used by Actor::remapActorPalette protected: void moveMemInPalRes(int start, int end, byte direction); @@ -1114,7 +1119,7 @@ public: // HE specific byte _HEV7ActorPalette[256]; uint8 *_hePalettes; - int16 *_hePaletteCache; + uint16 _hePaletteSlot; protected: int _shadowPaletteSize; |