From 82b2b2d65d0398cb1f3a17f421cbf78f52286faa Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 3 Sep 2014 22:09:50 -0400 Subject: MADS: Properly implement drawing to a subset of the screen --- engines/mads/messages.cpp | 3 +- engines/mads/msurface.h | 3 +- engines/mads/nebular/dialogs_nebular.cpp | 30 ++++++++++++------- engines/mads/nebular/dialogs_nebular.h | 2 ++ engines/mads/nebular/menu_nebular.cpp | 8 ++--- engines/mads/scene.cpp | 10 +++++-- engines/mads/scene.h | 2 ++ engines/mads/screen.cpp | 50 +++++++++++++++++++++----------- engines/mads/screen.h | 24 ++++++++------- engines/mads/sprites.cpp | 2 -- 10 files changed, 82 insertions(+), 52 deletions(-) diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp index d41696044b..e83b69d210 100644 --- a/engines/mads/messages.cpp +++ b/engines/mads/messages.cpp @@ -546,8 +546,7 @@ void TextDisplayList::draw(MSurface *s) { for (uint idx = 0; idx < size(); ++idx) { TextDisplay &td = (*this)[idx]; if (td._active && (td._expire >= 0)) { - Common::Point destPos(td._bounds.left + _vm->_screen._offset.x, - td._bounds.top + _vm->_screen._offset.y); + Common::Point destPos(td._bounds.left, td._bounds.top); td._font->setColors(0xFF, td._color1, td._color2, 0); td._font->writeString(s, td._msg, destPos, td._spacing, td._bounds.width()); } diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index cd6bde1271..3a5bf22eed 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -51,10 +51,9 @@ struct SpriteInfo { * MADS graphics surface */ class MSurface : public Graphics::Surface { -private: - bool _freeFlag; protected: static MADSEngine *_vm; + bool _freeFlag; public: /** * Sets the engine refrence used all surfaces diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index 5b0fb7b538..ff119536ec 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -346,7 +346,6 @@ void DialogsNebular::showScummVMSaveDialog() { } scene->_spriteSlots.reset(); - _vm->_screen._offset.y = 0; scene->loadScene(scene->_currentSceneId, game._aaName, true); scene->_userInterface.noInventoryAnim(); game._scene.drawElements(kTransitionFadeIn, false); @@ -560,7 +559,8 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) { } FullScreenDialog::~FullScreenDialog() { - _vm->_screen._offset.y = 0; + _vm->_screen.resetClipBounds(); + _vm->_game->_scene.restrictScene(); } void FullScreenDialog::display() { @@ -577,7 +577,6 @@ void FullScreenDialog::display() { scene._currentSceneId = currentSceneId; scene._nextSceneId = nextSceneId; - _vm->_screen._offset.y = 22; _vm->_events->initVars(); game._kernelMode = KERNEL_ROOM_INIT; @@ -590,11 +589,7 @@ void FullScreenDialog::display() { _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16); } - _vm->_screen.empty(); - _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2); - _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2); - game._scene._spriteSlots.fullRefresh(); - + // Set Fx state and palette entries game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition; game._trigger = 0; @@ -604,6 +599,18 @@ void FullScreenDialog::display() { _vm->_palette->setEntry(13, 45, 45, 0); _vm->_palette->setEntry(14, 63, 63, 63); _vm->_palette->setEntry(15, 45, 45, 45); + + + // Clear the screen and draw the upper and lower horizontal lines + _vm->_screen.empty(); + _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2); + _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2); + _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); + + // Restrict the screen to the area between the two lines + _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH, + DIALOG_TOP + MADS_SCENE_HEIGHT)); + _vm->_game->_scene.restrictScene(); } /*------------------------------------------------------------------------*/ @@ -667,7 +674,7 @@ void GameDialog::display() { } GameDialog::~GameDialog() { - _vm->_screen._offset.y = 0; + _vm->_screen.resetClipBounds(); } void GameDialog::clearLines() { @@ -868,10 +875,11 @@ void GameDialog::handleEvents() { _vm->_events->pollEvents(); // Scan for objects in the dialog - int objIndex = screenObjects.scan(events.currentPos() - _vm->_screen._offset, LAYER_GUI); + Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP); + int objIndex = screenObjects.scan(mousePos, LAYER_GUI); if (_movedFlag) { - int yp = events.currentPos().y - _vm->_screen._offset.y; + int yp = mousePos.y; if (yp < screenObjects[1]._bounds.top) { if (!events._mouseReleased) _lines[1]._state = DLGSTATE_SELECTED; diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index 1468db38c8..f64f992611 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -31,6 +31,8 @@ namespace MADS { namespace Nebular { +#define DIALOG_TOP 22 + enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 }; class DialogsNebular : public Dialogs { diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp index b0b0c5e003..d5a1d8538d 100644 --- a/engines/mads/nebular/menu_nebular.cpp +++ b/engines/mads/nebular/menu_nebular.cpp @@ -35,7 +35,6 @@ namespace Nebular { #define NEBULAR_MENUSCREEN 990 #define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2) #define MADS_MENU_ANIM_DELAY 70 -#define DIALOG_TOP 22 MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) { _breakFlag = false; @@ -57,7 +56,6 @@ void MenuView::show() { while (!_breakFlag && !_vm->shouldQuit()) { if (_redrawFlag) { _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx); - _vm->_screen.copyRectToScreen(Common::Rect(0, 0, 320, 200)); _redrawFlag = false; } @@ -111,10 +109,10 @@ void MainMenu::display() { // Register the menu item area in the screen objects MSprite *frame0 = _menuItems[i]->getFrame(0); Common::Point pt(frame0->_offset.x - (frame0->w / 2), - frame0->_offset.y - frame0->h + _vm->_screen._offset.y); + frame0->_offset.y - frame0->h); screenObjects.add( - Common::Rect(pt.x, pt.y, pt.x + frame0->w, pt.y + frame0->h), - LAYER_GUI, CAT_COMMAND, i); + Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w, + pt.y + frame0->h + DIALOG_TOP), LAYER_GUI, CAT_COMMAND, i); } // Set the cursor for when it's shown diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index cb68d38eec..ad24dd4f60 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -63,8 +63,7 @@ Scene::Scene(MADSEngine *vm) _paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF)); // Set up a scene surface that maps to our physical screen drawing surface - _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, - _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); + restrictScene(); // Set up the verb list _verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE)); @@ -85,6 +84,11 @@ Scene::~Scene() { delete _animationData; } +void Scene::restrictScene() { + _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, + _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); +} + void Scene::clearVocab() { _activeVocabs.clear(); } @@ -511,7 +515,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { _vm->_sound->startQueuedCommands(); } else { // Copy dirty areas to the screen - _dirtyAreas.copyToScreen(_vm->_screen._offset); + _dirtyAreas.copyToScreen(); } _spriteSlots.cleanUp(); diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 407d70dc85..ee7864cfee 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -142,6 +142,8 @@ public: */ ~Scene(); + void restrictScene(); + /** * Clear the vocabulary list */ diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index ab5dff56ff..590e63ac9e 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -212,8 +212,7 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common: Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); - Common::Point destPos(bounds.left + _vm->_screen._offset.x, - bounds.top + _vm->_screen._offset.y); + Common::Point destPos(bounds.left, bounds.top); if ((*this)[i]._active && bounds.isValidRect()) { srcSurface->copyTo(destSurface, bounds, destPos); @@ -221,17 +220,14 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common: } } -void DirtyAreas::copyToScreen(const Common::Point &posAdjust) { +void DirtyAreas::copyToScreen() { for (uint i = 0; i < size(); ++i) { - const Common::Rect &srcBounds = (*this)[i]._bounds; + const Common::Rect &bounds = (*this)[i]._bounds; // Check if this is a sane rectangle before attempting to create it - if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom) + if (bounds.left >= bounds.right || bounds.top >= bounds.bottom) continue; - Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, - srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); - if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) { _vm->_screen.copyRectToScreen(bounds); } @@ -561,23 +557,32 @@ void ScreenObjects::synchronize(Common::Serializer &s) { ScreenSurface::ScreenSurface() { _shakeCountdown = -1; _random = 0x4D2; + _surfacePixels = nullptr; } void ScreenSurface::init() { - setSize(g_system->getWidth(), g_system->getHeight()); -} + // Set the size for the screen + setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); -void ScreenSurface::copyRectToScreen(const Common::Point &destPos, - const Common::Rect &bounds) { - const byte *buf = getBasePtr(destPos.x, destPos.y); + // Store a copy of the raw pixels pointer for the screen, since the surface + // itself may be later changed to only a subset of the screen + _surfacePixels = (byte *)getPixels(); + _freeFlag = false; +} - if (bounds.width() != 0 && bounds.height() != 0) - g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top, - bounds.width(), bounds.height()); +ScreenSurface::~ScreenSurface() { + delete[] _surfacePixels; } void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) { - copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds); + const byte *buf = getBasePtr(bounds.left, bounds.top); + + Common::Rect destBounds = bounds; + destBounds.translate(_clipBounds.left, _clipBounds.top); + + if (bounds.width() != 0 && bounds.height() != 0) + g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top, + destBounds.width(), destBounds.height()); } void ScreenSurface::updateScreen() { @@ -659,4 +664,15 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag } } +void ScreenSurface::setClipBounds(const Common::Rect &r) { + _clipBounds = r; + setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height()); + this->pitch = MADS_SCREEN_WIDTH; +} + +void ScreenSurface::resetClipBounds() { + setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); +} + + } // End of namespace MADS diff --git a/engines/mads/screen.h b/engines/mads/screen.h index 7937e15456..9d01ca82e3 100644 --- a/engines/mads/screen.h +++ b/engines/mads/screen.h @@ -117,8 +117,8 @@ public: /** * Use the lsit of dirty areas to copy areas of the screen surface to * the physical screen - * @param posAdjust Position adjustment */ - void copyToScreen(const Common::Point &posAdjust); + */ + void copyToScreen(); void reset(); }; @@ -205,8 +205,9 @@ public: class ScreenSurface : public MSurface { private: uint16 _random; + byte *_surfacePixels; + Common::Rect _clipBounds; public: - Common::Point _offset; int _shakeCountdown; public: /** @@ -215,17 +216,14 @@ public: ScreenSurface(); /** - * Initialize the surface + * Destructor */ - void init(); + ~ScreenSurface(); /** - * Copys an area of the screen surface to a given destination position on - * the ScummVM physical screen buffer - * @param destPos Destination position - * @param bounds Area of screen surface to copy + * Initialize the surface */ - void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds); + void init(); /** * Copys an area of the screen surface to the ScmmVM physical screen buffer @@ -239,6 +237,12 @@ public: void updateScreen(); void transition(ScreenTransition transitionType, bool surfaceFlag); + + void setClipBounds(const Common::Rect &r); + + void resetClipBounds(); + + const Common::Rect &getClipBounds() { return _clipBounds; } }; } // End of namespace MADS diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp index 2bf13eeb5a..cd358077b5 100644 --- a/engines/mads/sprites.cpp +++ b/engines/mads/sprites.cpp @@ -331,8 +331,6 @@ void SpriteSlots::drawSprites(MSurface *s) { xp = slot._position.x - (sprite->w / 2) - scene._posAdjust.x; yp = slot._position.y - sprite->h - scene._posAdjust.y + 1; } - xp += _vm->_screen._offset.x; - yp += _vm->_screen._offset.y; if (slot._depth > 1) { // Draw the frame with depth processing -- cgit v1.2.3