diff options
-rw-r--r-- | engines/sci/engine/kernel.h | 2 | ||||
-rw-r--r-- | engines/sci/engine/kernel_tables.h | 7 | ||||
-rw-r--r-- | engines/sci/engine/kevent.cpp | 9 | ||||
-rw-r--r-- | engines/sci/engine/kgraphics32.cpp | 40 | ||||
-rw-r--r-- | engines/sci/engine/savegame.cpp | 24 | ||||
-rw-r--r-- | engines/sci/engine/savegame.h | 2 | ||||
-rw-r--r-- | engines/sci/engine/workarounds.cpp | 1 | ||||
-rw-r--r-- | engines/sci/event.cpp | 9 | ||||
-rw-r--r-- | engines/sci/graphics/cursor32.cpp | 367 | ||||
-rw-r--r-- | engines/sci/graphics/cursor32.h | 248 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 18 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.h | 18 | ||||
-rw-r--r-- | engines/sci/graphics/video32.cpp | 6 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 12 | ||||
-rw-r--r-- | engines/sci/sci.h | 2 |
16 files changed, 736 insertions, 30 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index b02a7e545a..77927ba7d5 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -421,6 +421,8 @@ reg_t kStubNull(EngineState *s, int argc, reg_t *argv); #ifdef ENABLE_SCI32 // SCI2 Kernel Functions +reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv); + reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv); reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv); reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 76c24b09e3..097eb8b405 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -693,10 +693,11 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL }, { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r0)", NULL, NULL }, { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL }, - { MAP_CALL(SetCursor), SIG_SINCE_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL }, - // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL }, - { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds }, + { MAP_CALL(SetCursor), SIG_SCI16, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds }, +#ifdef ENABLE_SCI32 + { "SetCursor", kSetCursor32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)", NULL, kSetCursor_workarounds }, +#endif { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL }, { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL }, { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index d7a716a504..56ee2f594c 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -86,11 +86,14 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) mousePos = curEvent.mousePosSci; - else + else { #endif mousePos = curEvent.mousePos; - // Limit the mouse cursor position, if necessary - g_sci->_gfxCursor->refreshPosition(); + // Limit the mouse cursor position, if necessary + g_sci->_gfxCursor->refreshPosition(); +#ifdef ENABLE_SCI32 + } +#endif if (g_sci->getVocabulary()) g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index e458109cc2..2286a66de1 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -38,7 +38,6 @@ #include "sci/graphics/compare.h" #include "sci/graphics/controls16.h" #include "sci/graphics/coordadjuster.h" -#include "sci/graphics/cursor.h" #include "sci/graphics/palette.h" #include "sci/graphics/paint16.h" #include "sci/graphics/picture.h" @@ -48,6 +47,7 @@ #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/cursor32.h" #include "sci/graphics/celobj32.h" #include "sci/graphics/controls32.h" #include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class @@ -64,6 +64,44 @@ namespace Sci { extern void showScummVMDialog(const Common::String &message); +reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv) { + switch (argc) { + case 1: { + if (argv[0].toSint16() == -2) { + g_sci->_gfxCursor32->clearRestrictedArea(); + } else { + if (argv[0].isNull()) { + g_sci->_gfxCursor32->hide(); + } else { + g_sci->_gfxCursor32->show(); + } + } + break; + } + case 2: { + const Common::Point position(argv[0].toSint16(), argv[1].toSint16()); + g_sci->_gfxCursor32->setPosition(position); + break; + } + case 3: { + g_sci->_gfxCursor32->setView(argv[0].toUint16(), argv[1].toSint16(), argv[2].toSint16()); + break; + } + case 4: { + const Common::Rect restrictRect(argv[0].toSint16(), + argv[1].toSint16(), + argv[2].toSint16() + 1, + argv[3].toSint16() + 1); + g_sci->_gfxCursor32->setRestrictedArea(restrictRect); + break; + } + default: + error("kSetCursor: Invalid number of arguments (%d)", argc); + } + + return s->r_acc; +} + reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { const Buffer &buffer = g_sci->_gfxFrameout->getCurrentBuffer(); if (buffer.screenWidth < 640 || buffer.screenHeight < 400) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 7804b7892d..eeddda8390 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -48,6 +48,7 @@ #include "sci/sound/music.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/cursor32.h" #include "sci/graphics/frameout.h" #include "sci/graphics/palette32.h" #include "sci/graphics/remap32.h" @@ -889,6 +890,29 @@ void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) { _needsUpdate = true; } } + +void GfxCursor32::saveLoadWithSerializer(Common::Serializer &s) { + if (s.getVersion() < 37) { + return; + } + + s.syncAsSint32LE(_hideCount); + s.syncAsSint16LE(_restrictedArea.left); + s.syncAsSint16LE(_restrictedArea.top); + s.syncAsSint16LE(_restrictedArea.right); + s.syncAsSint16LE(_restrictedArea.bottom); + s.syncAsUint16LE(_cursorInfo.resourceId); + s.syncAsUint16LE(_cursorInfo.loopNo); + s.syncAsUint16LE(_cursorInfo.celNo); + + if (s.isLoading()) { + hide(); + setView(_cursorInfo.resourceId, _cursorInfo.loopNo, _cursorInfo.celNo); + if (!_hideCount) { + show(); + } + } +} #endif void GfxPorts::saveLoadWithSerializer(Common::Serializer &s) { diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index 1bf66864e8..51dbbedd87 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -37,7 +37,7 @@ struct EngineState; * * Version - new/changed feature * ============================= - * 37 - Segment entry data changed to pointers + * 37 - Segment entry data changed to pointers, SCI32 cursor * 36 - SCI32 bitmap segment * 35 - SCI32 remap * 34 - SCI32 palettes, and store play time in ticks diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 9b3b329418..15f229f2d8 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -688,6 +688,7 @@ const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kSetCursor_workarounds[] = { { GID_KQ5, -1, 768, 0, "KQCursor", "init", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // CD: gets called with 4 additional "900d" parameters + { GID_MOTHERGOOSEHIRES,0, 0, -1, "MG", "setCursor", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // At the start of the game, an object is passed as the cel number SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index 4ad2a0cfa3..b267d2ebc2 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -30,6 +30,7 @@ #include "sci/engine/state.h" #include "sci/engine/kernel.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/cursor32.h" #include "sci/graphics/frameout.h" #endif #include "sci/graphics/screen.h" @@ -168,9 +169,17 @@ SciEvent EventManager::getScummVMEvent() { if (getSciVersion() >= SCI_VERSION_2) { const Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); + if (ev.type == Common::EVENT_MOUSEMOVE) { + // This will clamp `mousePos` according to the restricted zone, + // so any cursor or screen item associated with the mouse position + // does not bounce when it hits the edge (or ignore the edge) + g_sci->_gfxCursor32->deviceMoved(mousePos); + } + Common::Point mousePosSci = mousePos; mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); noEvent.mousePosSci = input.mousePosSci = mousePosSci; + } else { #endif g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp new file mode 100644 index 0000000000..a5491eec2a --- /dev/null +++ b/engines/sci/graphics/cursor32.cpp @@ -0,0 +1,367 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" +#include "graphics/cursorman.h" +#include "sci/graphics/celobj32.h" +#include "sci/graphics/cursor32.h" +#include "sci/graphics/frameout.h" + +namespace Sci { + +GfxCursor32::GfxCursor32() : + _hideCount(0), + _position(0, 0), + _writeToVMAP(false) { + CursorMan.showMouse(false); +} + +void GfxCursor32::init(const Buffer &vmap) { + _vmap = vmap; + _vmapRegion.rect = Common::Rect(_vmap.screenWidth, _vmap.screenHeight); + _vmapRegion.data = (byte *)_vmap.getPixels(); + _restrictedArea = _vmapRegion.rect; +} + +GfxCursor32::~GfxCursor32() { + CursorMan.showMouse(true); + free(_cursor.data); + free(_cursorBack.data); + free(_drawBuff1.data); + free(_drawBuff2.data); + free(_savedVmapRegion.data); +} + +void GfxCursor32::hide() { + if (_hideCount++) { + return; + } + + if (!_cursorBack.rect.isEmpty()) { + drawToHardware(_cursorBack); + } +} + +void GfxCursor32::revealCursor() { + _cursorBack.rect = _cursor.rect; + _cursorBack.rect.clip(_vmapRegion.rect); + if (_cursorBack.rect.isEmpty()) { + return; + } + + readVideo(_cursorBack); + _drawBuff1.rect = _cursor.rect; + copy(_drawBuff1, _cursorBack); + paint(_drawBuff1, _cursor); + drawToHardware(_drawBuff1); +} + +void GfxCursor32::paint(DrawRegion &target, const DrawRegion &source) { + if (source.rect.isEmpty()) { + return; + } + + Common::Rect drawRect(source.rect); + drawRect.clip(target.rect); + if (drawRect.isEmpty()) { + return; + } + + const int16 sourceXOffset = drawRect.left - source.rect.left; + const int16 sourceYOffset = drawRect.top - source.rect.top; + const int16 drawRectWidth = drawRect.width(); + const int16 drawRectHeight = drawRect.height(); + + byte *targetPixel = target.data + ((drawRect.top - target.rect.top) * target.rect.width()) + (drawRect.left - target.rect.left); + const byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset; + const uint8 skipColor = source.skipColor; + + const int16 sourceStride = source.rect.width() - drawRectWidth; + const int16 targetStride = target.rect.width() - drawRectWidth; + + for (int16 y = 0; y < drawRectHeight; ++y) { + for (int16 x = 0; x < drawRectWidth; ++x) { + if (*sourcePixel != skipColor) { + *targetPixel = *sourcePixel; + } + ++targetPixel; + ++sourcePixel; + } + sourcePixel += sourceStride; + targetPixel += targetStride; + } +} + +void GfxCursor32::drawToHardware(const DrawRegion &source) { + Common::Rect drawRect(source.rect); + drawRect.clip(_vmapRegion.rect); + const int16 sourceXOffset = drawRect.left - source.rect.left; + const int16 sourceYOffset = drawRect.top - source.rect.top; + byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset; + + g_system->copyRectToScreen(sourcePixel, source.rect.width(), drawRect.left, drawRect.top, drawRect.width(), drawRect.height()); +} + +void GfxCursor32::unhide() { + if (_hideCount == 0 || --_hideCount) { + return; + } + + _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y); + revealCursor(); +} + +void GfxCursor32::show() { + if (_hideCount) { + _hideCount = 0; + _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y); + revealCursor(); + } +} + +void GfxCursor32::setRestrictedArea(const Common::Rect &rect) { + _restrictedArea = rect; + + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + mulru(_restrictedArea, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 0); + + if (_position.x < rect.left) { + _position.x = rect.left; + } + if (_position.x >= rect.right) { + _position.x = rect.right - 1; + } + if (_position.y < rect.top) { + _position.y = rect.top; + } + if (_position.y >= rect.bottom) { + _position.y = rect.bottom - 1; + } + + g_system->warpMouse(_position.x, _position.y); +} + +void GfxCursor32::clearRestrictedArea() { + _restrictedArea = _vmapRegion.rect; +} + +void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) { + hide(); + + _cursorInfo.resourceId = viewId; + _cursorInfo.loopNo = loopNo; + _cursorInfo.celNo = celNo; + + if (viewId != -1) { + CelObjView view(viewId, loopNo, celNo); + + _hotSpot = view._displace; + _width = view._width; + _height = view._height; + + _cursor.data = (byte *)realloc(_cursor.data, _width * _height); + _cursor.rect = Common::Rect(_width, _height); + memset(_cursor.data, 255, _width * _height); + _cursor.skipColor = 255; + + Buffer target(_width, _height, _cursor.data); + view.draw(target, _cursor.rect, Common::Point(0, 0), false); + } else { + _hotSpot = Common::Point(0, 0); + _width = _height = 1; + _cursor.data = (byte *)realloc(_cursor.data, _width * _height); + _cursor.rect = Common::Rect(_width, _height); + *_cursor.data = _cursor.skipColor; + _cursorBack.rect = _cursor.rect; + _cursorBack.rect.clip(_vmapRegion.rect); + if (!_cursorBack.rect.isEmpty()) { + readVideo(_cursorBack); + } + } + + _cursorBack.data = (byte *)realloc(_cursorBack.data, _width * _height); + _drawBuff1.data = (byte *)realloc(_drawBuff1.data, _width * _height); + _drawBuff2.data = (byte *)realloc(_drawBuff2.data, _width * _height * 4); + _savedVmapRegion.data = (byte *)realloc(_savedVmapRegion.data, _width * _height); + + unhide(); +} + +void GfxCursor32::readVideo(DrawRegion &target) { + if (g_sci->_gfxFrameout->_frameNowVisible) { + copy(target, _vmapRegion); + } else { + // NOTE: SSCI would read the background for the cursor directly out of + // video memory here, but as far as can be determined, this does not + // seem to actually be necessary for proper cursor rendering + } +} + +void GfxCursor32::copy(DrawRegion &target, const DrawRegion &source) { + if (source.rect.isEmpty()) { + return; + } + + Common::Rect drawRect(source.rect); + drawRect.clip(target.rect); + if (drawRect.isEmpty()) { + return; + } + + const int16 sourceXOffset = drawRect.left - source.rect.left; + const int16 sourceYOffset = drawRect.top - source.rect.top; + const int16 drawWidth = drawRect.width(); + const int16 drawHeight = drawRect.height(); + + byte *targetPixel = target.data + ((drawRect.top - target.rect.top) * target.rect.width()) + (drawRect.left - target.rect.left); + const byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset; + + const int16 sourceStride = source.rect.width(); + const int16 targetStride = target.rect.width(); + + for (int y = 0; y < drawHeight; ++y) { + memcpy(targetPixel, sourcePixel, drawWidth); + targetPixel += targetStride; + sourcePixel += sourceStride; + } +} + +void GfxCursor32::setPosition(const Common::Point &position) { + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + + _position.x = (position.x * Ratio(screenWidth, scriptWidth)).toInt(); + _position.y = (position.y * Ratio(screenHeight, scriptHeight)).toInt(); + + g_system->warpMouse(_position.x, _position.y); +} + +void GfxCursor32::gonnaPaint(Common::Rect paintRect) { + if (!_hideCount && !_writeToVMAP && !_cursorBack.rect.isEmpty()) { + paintRect.left &= ~3; + paintRect.right |= 3; + if (_cursorBack.rect.intersects(paintRect)) { + _writeToVMAP = true; + } + } +} + +void GfxCursor32::paintStarting() { + if (_writeToVMAP) { + _savedVmapRegion.rect = _cursor.rect; + copy(_savedVmapRegion, _vmapRegion); + paint(_vmapRegion, _cursor); + } +} + +void GfxCursor32::donePainting() { + if (_writeToVMAP) { + copy(_vmapRegion, _savedVmapRegion); + _savedVmapRegion.rect = Common::Rect(); + _writeToVMAP = false; + } + + if (!_hideCount && !_cursorBack.rect.isEmpty()) { + copy(_cursorBack, _vmapRegion); + } +} + +void GfxCursor32::deviceMoved(Common::Point &position) { + if (position.x < _restrictedArea.left) { + position.x = _restrictedArea.left; + } + if (position.x >= _restrictedArea.right) { + position.x = _restrictedArea.right - 1; + } + if (position.y < _restrictedArea.top) { + position.y = _restrictedArea.top; + } + if (position.y >= _restrictedArea.bottom) { + position.y = _restrictedArea.bottom - 1; + } + + _position = position; + + g_system->warpMouse(position.x, position.y); + move(); +} + +void GfxCursor32::move() { + if (_hideCount) { + return; + } + + // If it was off the screen, just show it and return + _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y); + if (_cursorBack.rect.isEmpty()) { + revealCursor(); + return; + } + + // If we just moved entirely off screen, remove background & return + if (!_cursor.rect.intersects(_vmapRegion.rect)) { + drawToHardware(_cursorBack); + return; + } + + if (!_cursor.rect.intersects(_cursorBack.rect)) { + _drawBuff1.rect = _cursor.rect; + _drawBuff1.rect.clip(_vmapRegion.rect); + readVideo(_drawBuff1); + + _drawBuff2.rect = _drawBuff1.rect; + copy(_drawBuff2, _drawBuff1); + + paint(_drawBuff1, _cursor); + drawToHardware(_drawBuff1); + + // erase + drawToHardware(_cursorBack); + + _cursorBack.rect = _cursor.rect; + _cursorBack.rect.clip(_vmapRegion.rect); + copy(_cursorBack, _drawBuff2); + } else { + Common::Rect mergedRect(_cursorBack.rect); + mergedRect.extend(_cursor.rect); + mergedRect.clip(_vmapRegion.rect); + + _drawBuff2.rect = mergedRect; + readVideo(_drawBuff2); + + copy(_drawBuff2, _cursorBack); + + _cursorBack.rect = _cursor.rect; + _cursorBack.rect.clip(_vmapRegion.rect); + copy(_cursorBack, _drawBuff2); + + paint(_drawBuff2, _cursor); + drawToHardware(_drawBuff2); + } +} +} // End of namespace Sci diff --git a/engines/sci/graphics/cursor32.h b/engines/sci/graphics/cursor32.h new file mode 100644 index 0000000000..fe621e9d55 --- /dev/null +++ b/engines/sci/graphics/cursor32.h @@ -0,0 +1,248 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SCI_GRAPHICS_CURSOR32_H +#define SCI_GRAPHICS_CURSOR32_H + +#include "common/rect.h" +#include "common/serializer.h" +#include "sci/graphics/helpers.h" + +namespace Sci { + +class GfxCursor32 : Common::Serializable { +public: + GfxCursor32(); + ~GfxCursor32(); + + /** + * Initialises the cursor system with the given + * buffer to use as the output buffer for + * rendering the cursor. + */ + void init(const Buffer &vmap); + + /** + * Called when the hardware mouse moves. + */ + void deviceMoved(Common::Point &position); + + /** + * Called by GfxFrameout once for each show + * rectangle that is going to be drawn to + * hardware. + */ + void gonnaPaint(Common::Rect paintRect); + + /** + * Called by GfxFrameout when the rendering to + * hardware begins. + */ + void paintStarting(); + + /** + * Called by GfxFrameout when the output buffer + * has finished rendering to hardware. + */ + void donePainting(); + + /** + * Hides the cursor. Each call to `hide` will + * increment a hide counter, which must be + * returned to 0 before the cursor will be + * shown again. + */ + void hide(); + + /** + * Shows the cursor, if the hide counter is + * returned to 0. + */ + void unhide(); + + /** + * Shows the cursor regardless of the state of + * the hide counter. + */ + void show(); + + /** + * Sets the view used to render the cursor. + */ + void setView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo); + + /** + * Explicitly sets the position of the cursor, + * in game script coordinates. + */ + void setPosition(const Common::Point &position); + + /** + * Sets the region that the mouse is allowed + * to move within. + */ + void setRestrictedArea(const Common::Rect &rect); + + /** + * Removes restrictions on mouse movement. + */ + void clearRestrictedArea(); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); + +private: + struct DrawRegion { + Common::Rect rect; + byte *data; + uint8 skipColor; + + DrawRegion() : rect(), data(nullptr) {} + }; + + /** + * Information about the current cursor. + * Used to restore cursor when loading a + * savegame. + */ + CelInfo32 _cursorInfo; + + /** + * Content behind the cursor? TODO + */ + DrawRegion _cursorBack; + + /** + * Scratch buffer. + */ + DrawRegion _drawBuff1; + + /** + * Scratch buffer 2. + */ + DrawRegion _drawBuff2; + + /** + * A draw region representing the current + * output buffer. + */ + DrawRegion _vmapRegion; + + /** + * The content behind the cursor in the + * output buffer. + */ + DrawRegion _savedVmapRegion; + + /** + * The cursor bitmap. + */ + DrawRegion _cursor; + + /** + * The width and height of the cursor, + * in screen coordinates. + */ + int16 _width, _height; + + /** + * The output buffer where the cursor is + * rendered. + */ + Buffer _vmap; + + /** + * The number of times the cursor has been + * hidden. + */ + int _hideCount; + + /** + * The rendered position of the cursor, in + * screen coordinates. + */ + Common::Point _position; + + /** + * The position of the cursor hot spot, relative + * to the cursor origin, in screen pixels. + */ + Common::Point _hotSpot; + + /** + * The area within which the cursor is allowed + * to move, in screen pixels. + */ + Common::Rect _restrictedArea; + + /** + * Indicates whether or not the cursor needs to + * be repainted on the output buffer due to a + * change of graphics in the area underneath the + * cursor. + */ + bool _writeToVMAP; + + /** + * Reads data from the output buffer or hardware + * to the given draw region. + */ + void readVideo(DrawRegion &target); + + /** + * Reads data from the output buffer to the + * given draw region. + */ + void readVideoFromVmap(DrawRegion &target); + + /** + * Copies pixel data from the given source to + * the given target. + */ + void copy(DrawRegion &target, const DrawRegion &source); + + /** + * Draws from the given source onto the given + * target, skipping pixels in the source that + * match the `skipColor` property. + */ + void paint(DrawRegion &target, const DrawRegion &source); + + /** + * Draws the cursor to the position it was + * drawn to prior to moving offscreen or being + * hidden by a call to `hide`. + */ + void revealCursor(); + + /** + * Draws the given source to the output buffer. + */ + void drawToHardware(const DrawRegion &source); + + /** + * Renders the cursor at its new location. + */ + void move(); +}; + +} // End of namespace Sci +#endif diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 7661fe5be2..aad321521e 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -42,6 +42,7 @@ #include "sci/graphics/cache.h" #include "sci/graphics/coordadjuster.h" #include "sci/graphics/compare.h" +#include "sci/graphics/cursor32.h" #include "sci/graphics/font.h" #include "sci/graphics/screen.h" #include "sci/graphics/paint32.h" @@ -56,9 +57,10 @@ namespace Sci { -GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions) : +GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions, GfxCursor32 *cursor) : _isHiRes(ConfMan.getBool("enable_high_resolution_graphics")), _palette(palette), + _cursor(cursor), _resMan(resMan), _segMan(segMan), _transitions(transitions), @@ -1120,6 +1122,10 @@ void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showLi } void GfxFrameout::showBits() { + if (!_showList.size()) { + return; + } + for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) { Common::Rect rounded(**rect); // NOTE: SCI engine used BR-inclusive rects so used slightly @@ -1127,13 +1133,10 @@ void GfxFrameout::showBits() { // was always even. rounded.left &= ~1; rounded.right = (rounded.right + 1) & ~1; - - // TODO: - // _cursor->GonnaPaint(rounded); + _cursor->gonnaPaint(rounded); } - // TODO: - // _cursor->PaintStarting(); + _cursor->paintStarting(); for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) { Common::Rect rounded(**rect); @@ -1155,8 +1158,7 @@ void GfxFrameout::showBits() { g_system->copyRectToScreen(sourceBuffer, _currentBuffer.screenWidth, rounded.left, rounded.top, rounded.width(), rounded.height()); } - // TODO: - // _cursor->DonePainting(); + _cursor->donePainting(); _showList.clear(); } diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 8107316371..6cd0416a7a 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -30,6 +30,7 @@ namespace Sci { typedef Common::Array<DrawList> ScreenItemListList; typedef Common::Array<RectList> EraseListList; +class GfxCursor32; class GfxCoordAdjuster32; class GfxTransitions32; struct PlaneShowStyle; @@ -40,13 +41,14 @@ struct PlaneShowStyle; */ class GfxFrameout { private: + GfxCursor32 *_cursor; GfxCoordAdjuster32 *_coordAdjuster; GfxPalette32 *_palette; ResourceManager *_resMan; SegManager *_segMan; public: - GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions); + GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions, GfxCursor32 *cursor); ~GfxFrameout(); bool _isHiRes; @@ -196,13 +198,6 @@ private: bool _remapOccurred; /** - * Whether or not the data in the current buffer is what - * is visible to the user. During rendering updates, - * this flag is set to false. - */ - bool _frameNowVisible; - - /** * TODO: Document * TODO: Depending upon if the engine ever modifies this * rect, it may be stupid to store it separately instead @@ -309,6 +304,13 @@ private: public: /** + * Whether or not the data in the current buffer is what + * is visible to the user. During rendering updates, + * this flag is set to false. + */ + bool _frameNowVisible; + + /** * Whether palMorphFrameOut should be used instead of * frameOut for rendering. Used by kMorphOn to * explicitly enable palMorphFrameOut for one frame. diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp index 51be08dac9..f4aa7664d3 100644 --- a/engines/sci/graphics/video32.cpp +++ b/engines/sci/graphics/video32.cpp @@ -31,7 +31,7 @@ #include "sci/engine/vm_types.h" // for reg_t #include "sci/event.h" // for SciEvent, EventManager, SCI_... #include "sci/graphics/celobj32.h" // for CelInfo32, ::kLowResX, ::kLo... -#include "sci/graphics/cursor.h" // for GfxCursor +#include "sci/graphics/cursor32.h" // for GfxCursor32 #include "sci/graphics/frameout.h" // for GfxFrameout #include "sci/graphics/helpers.h" // for Color, Palette #include "sci/graphics/palette32.h" // for GfxPalette32 @@ -597,7 +597,7 @@ VMDPlayer::IOStatus VMDPlayer::close() { } if (!_showCursor) { - g_sci->_gfxCursor->kernelShow(); + g_sci->_gfxCursor32->unhide(); } _lastYieldedFrameNo = 0; @@ -658,7 +658,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) { _isInitialized = true; if (!_showCursor) { - g_sci->_gfxCursor->kernelHide(); + g_sci->_gfxCursor32->hide(); } Common::Rect vmdRect(_x, diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 18d97ea57e..eb2c6a148b 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -93,6 +93,7 @@ MODULE_OBJS += \ graphics/text32.o \ graphics/transitions32.o \ graphics/video32.o \ + graphics/cursor32.o \ sound/audio32.o \ sound/decoders/sol.o \ video/robot_decoder.o diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 61317ecb97..842384ed1a 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -65,6 +65,7 @@ #ifdef ENABLE_SCI32 #include "sci/graphics/controls32.h" +#include "sci/graphics/cursor32.h" #include "sci/graphics/frameout.h" #include "sci/graphics/palette32.h" #include "sci/graphics/remap32.h" @@ -96,6 +97,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam #ifdef ENABLE_SCI32 _audio32 = nullptr; _video32 = nullptr; + _gfxCursor32 = nullptr; #endif _features = 0; _resMan = 0; @@ -176,6 +178,7 @@ SciEngine::~SciEngine() { // destruction of screen items in the Video32 destructor relies on these // components delete _video32; + delete _gfxCursor32; delete _gfxPalette32; delete _gfxTransitions32; delete _gfxFrameout; @@ -708,6 +711,7 @@ void SciEngine::initGraphics() { _gfxPalette32 = 0; _gfxRemap32 = 0; _gfxTransitions32 = 0; + _gfxCursor32 = 0; #endif if (hasMacIconBar()) @@ -727,23 +731,25 @@ void SciEngine::initGraphics() { #endif _gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16); - _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { // SCI32 graphic objects creation _gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan); - _gfxCursor->init(_gfxCoordAdjuster, _eventMan); + _gfxCursor32 = new GfxCursor32(); _gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_gamestate->_segMan); _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan); - _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxPalette32, _gfxTransitions32); + _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxPalette32, _gfxTransitions32, _gfxCursor32); + _gfxCursor32->init(_gfxFrameout->getCurrentBuffer()); _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _gfxFrameout->run(); } else { #endif + _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen); + // SCI0-SCI1.1 graphic objects creation _gfxPorts = new GfxPorts(_gamestate->_segMan, _gfxScreen); _gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts); diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 0425d21564..881df3d87a 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -98,6 +98,7 @@ class GfxFrameout; class Audio32; class Video32; class GfxTransitions32; +class GfxCursor32; #endif // our engine debug levels @@ -391,6 +392,7 @@ public: RobotDecoder *_robotDecoder; GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx GfxTransitions32 *_gfxTransitions32; + GfxCursor32 *_gfxCursor32; #endif AudioPlayer *_audio; |