diff options
-rw-r--r-- | engines/tsage/blue_force/blueforce_dialogs.cpp | 4 | ||||
-rw-r--r-- | engines/tsage/converse.cpp | 2 | ||||
-rw-r--r-- | engines/tsage/core.cpp | 4 | ||||
-rw-r--r-- | engines/tsage/events.cpp | 6 | ||||
-rw-r--r-- | engines/tsage/globals.cpp | 8 | ||||
-rw-r--r-- | engines/tsage/graphics.cpp | 144 | ||||
-rw-r--r-- | engines/tsage/graphics.h | 14 | ||||
-rw-r--r-- | engines/tsage/ringworld/ringworld_dialogs.cpp | 4 | ||||
-rw-r--r-- | engines/tsage/ringworld/ringworld_logic.cpp | 2 | ||||
-rw-r--r-- | engines/tsage/ringworld/ringworld_scenes3.cpp | 6 | ||||
-rw-r--r-- | engines/tsage/ringworld/ringworld_scenes5.cpp | 4 | ||||
-rw-r--r-- | engines/tsage/ringworld2/ringworld2_dialogs.cpp | 2 | ||||
-rw-r--r-- | engines/tsage/scenes.cpp | 2 |
13 files changed, 156 insertions, 46 deletions
diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp index b9b3ad6c22..6f294d263a 100644 --- a/engines/tsage/blue_force/blueforce_dialogs.cpp +++ b/engines/tsage/blue_force/blueforce_dialogs.cpp @@ -163,7 +163,7 @@ void RightClickDialog::execute() { } g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } // Execute the specified action @@ -243,7 +243,7 @@ void AmmoBeltDialog::execute() { } g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } _gfxManager.deactivate(); diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index b802f71ff3..00c0b3a1f1 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -451,7 +451,7 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { while (!g_globals->_events.getEvent(event, EVENT_KEYPRESS | EVENT_BUTTON_DOWN | EVENT_MOUSE_MOVE) && !g_vm->shouldQuit()) { g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } if (g_vm->shouldQuit()) break; diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index 9d7c8abf0a..c243624608 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -1415,7 +1415,7 @@ void ScenePalette::fade(const byte *adjustData, bool fullAdjust, int percent) { // Set the altered pale4tte g_system->getPaletteManager()->setPalette((const byte *)&tempPalette[0], 0, 256); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } PaletteRotation *ScenePalette::addRotation(int start, int end, int rotationMode, int duration, Action *action) { @@ -1708,7 +1708,7 @@ void SceneItem::display(int resNum, int lineNum, ...) { // Keep event on-screen until a mouse or keypress while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS)) { - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); } diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp index 152570b187..21dc86b8ec 100644 --- a/engines/tsage/events.cpp +++ b/engines/tsage/events.cpp @@ -49,8 +49,8 @@ bool EventsClass::pollEvent() { _priorFrameTime = milli; ++_frameNumber; - // Update screen - g_system->updateScreen(); + // Update the physical screen with any updates to the screen surface + GLOBALS._screenSurface.copyToScreen(); } if (!g_system->getEventManager()->pollEvent(_event)) return false; @@ -395,7 +395,7 @@ void EventsClass::delay(int numFrames) { _priorFrameTime = g_system->getMillis(); } - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); _prevDelayFrame = _frameNumber; _priorFrameTime = g_system->getMillis(); } diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 769ad4c054..1d0e37d071 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -108,9 +108,15 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface _color2 = _gfxColors.foreground; _color3 = _gfxColors.foreground; } - _screenSurface.setScreenSurface(); + + // Set up a buffer for the screen surface + _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT); + _screenSurface.trackDirtyRects(); + + // Add the global graphics manager to the graphic manager list _gfxManagers.push_back(&_gfxManagerInstance); + // Set up the global scene objects list _sceneObjects = &_sceneObjectsInstance; _sceneObjects_queue.push_front(_sceneObjects); diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index 171167c2ea..bc4ce75c22 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -220,11 +220,10 @@ void Rect::synchronize(Serializer &s) { GfxSurface::GfxSurface() : _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) { _disableUpdates = false; - _screenSurface = false; _lockSurfaceCtr = 0; _customSurface = NULL; - _screenSurfaceP = NULL; _transColor = -1; + _trackDirtyRects = false; } GfxSurface::GfxSurface(const GfxSurface &s) { @@ -241,12 +240,41 @@ GfxSurface::~GfxSurface() { } /** - * Specifies that the surface will encapsulate the ScummVM screen surface + * Turns on dirty rectangle tracking for the surface */ -void GfxSurface::setScreenSurface() { - _screenSurface = true; - _customSurface = NULL; - _lockSurfaceCtr = 0; +void GfxSurface::trackDirtyRects() { + _trackDirtyRects = true; +} + +void GfxSurface::addDirtyRect(const Rect &r) { + if (_trackDirtyRects) + _dirtyRects.push_back(Rect(r.left, r.top, + MIN(r.right + 1, SCREEN_WIDTH), MIN(r.bottom + 1, SCREEN_HEIGHT))); +} + +/** + * Copies all areas specified by the dirty rect list to the screen + */ +void GfxSurface::copyToScreen() { + assert(_trackDirtyRects); + + // Merge any overlapping dirty rects + mergeDirtyRects(); + + // Loop through the dirty rect list to copy the affected areas to the sc + for (Common::List<Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { + Rect r = *i; + + const byte *srcP = (const byte *)_customSurface->getBasePtr(r.left, r.top); + g_system->copyRectToScreen(srcP, _customSurface->pitch, r.left, r.top, + r.width(), r.height()); + } + + // Update the physical screen + g_system->updateScreen(); + + // Now that the dirty rects have been copied, clear the dirty rect list + _dirtyRects.clear(); } /** @@ -254,11 +282,13 @@ void GfxSurface::setScreenSurface() { */ void GfxSurface::create(int width, int height) { assert((width >= 0) && (height >= 0)); - _screenSurface = false; + + // Delete any prior internal surface that may have been previously created if (_customSurface) { _customSurface->free(); delete _customSurface; } + _customSurface = new Graphics::Surface(); _customSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); Common::fill((byte *)_customSurface->pixels, (byte *)_customSurface->pixels + (width * height), 0); @@ -271,13 +301,7 @@ void GfxSurface::create(int width, int height) { Graphics::Surface GfxSurface::lockSurface() { ++_lockSurfaceCtr; - Graphics::Surface *src; - if (_screenSurface) { - if (_lockSurfaceCtr == 1) - _screenSurfaceP = g_system->lockScreen(); - src = _screenSurfaceP; - } else - src = _customSurface; + Graphics::Surface *src = _customSurface; assert(src); // Setup the returned surface either as one pointing to the same pixels as the source, or @@ -298,15 +322,10 @@ Graphics::Surface GfxSurface::lockSurface() { void GfxSurface::unlockSurface() { assert(_lockSurfaceCtr > 0); --_lockSurfaceCtr; - - if ((_lockSurfaceCtr == 0) && _screenSurface) { - g_system->unlockScreen(); - } } void GfxSurface::synchronize(Serializer &s) { assert(!_lockSurfaceCtr); - assert(!_screenSurface); s.syncAsByte(_disableUpdates); _bounds.synchronize(s); @@ -351,6 +370,7 @@ void GfxSurface::fillRect(const Rect &bounds, int color) { Graphics::Surface surface = lockSurface(); surface.fillRect(bounds, color); unlockSurface(); + addDirtyRect(bounds); } GfxSurface &GfxSurface::operator=(const GfxSurface &s) { @@ -363,7 +383,6 @@ GfxSurface &GfxSurface::operator=(const GfxSurface &s) { } _customSurface = s._customSurface; - _screenSurface = s._screenSurface; _disableUpdates = s._disableUpdates; _bounds = s._bounds; _centroid = s._centroid; @@ -567,10 +586,17 @@ void GfxSurface::copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, Regi if (destBounds.bottom > destSurface.h) destBounds.bottom = destSurface.h; - if (destBounds.isValidRect()) { + if (destBounds.isValidRect() && (destBounds.left < SCREEN_WIDTH) && (destBounds.right >= 0) && + (destBounds.top < SCREEN_HEIGHT) && (destBounds.bottom >= 0)) { + // Register the affected area as dirty + addDirtyRect(Rect(destBounds.left + _bounds.left, destBounds.top + _bounds.top, + destBounds.right + _bounds.left, destBounds.bottom + _bounds.top)); + + // Get pointers to the source and destination surface areas const byte *pSrc = (const byte *)srcSurface.getBasePtr(srcX, srcY); byte *pDest = (byte *)destSurface.getBasePtr(destBounds.left, destBounds.top); + // Loop through copying each row for (int y = 0; y < destBounds.height(); ++y, pSrc += srcSurface.pitch, pDest += destSurface.pitch) { if (!priorityRegion && (src._transColor == -1)) @@ -595,6 +621,7 @@ void GfxSurface::copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, Regi } } + // Unlock the surfaces unlockSurface(); srcImage.unlockSurface(); } @@ -613,6 +640,68 @@ void GfxSurface::draw(const Common::Point &pt, Rect *rect) { } } +/** + * Merges any clipping rectangles that overlap to try and reduce + * the total number of clip rectangles. + */ +void GfxSurface::mergeDirtyRects() { + if (_dirtyRects.size() <= 1) + return; + + Common::List<Rect>::iterator rOuter, rInner; + + for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { + rInner = rOuter; + while (++rInner != _dirtyRects.end()) { + + if (looseIntersectRectangle(*rOuter, *rInner)) { + // these two rectangles overlap or + // are next to each other - merge them + + unionRectangle(*rOuter, *rOuter, *rInner); + + // remove the inner rect from the list + _dirtyRects.erase(rInner); + + // move back to beginning of list + rInner = rOuter; + } + } + } +} + +/** + * Check if the two rectangles are next to each other. + * @param pSrc1 a source rectangle + * @param pSrc2 a source rectangle + */ +bool GfxSurface::looseIntersectRectangle(const Rect &src1, const Rect &src2) { + Rect destRect; + + destRect.left = MAX(src1.left, src2.left); + destRect.top = MAX(src1.top, src2.top); + destRect.right = MIN(src1.right, src2.right); + destRect.bottom = MIN(src1.bottom, src2.bottom); + + return destRect.isValidRect(); +} + +/** + * Creates the union of two rectangles. + * Returns True if there is a union. + * @param pDest destination rectangle that is to receive the new union + * @param pSrc1 a source rectangle + * @param pSrc2 a source rectangle + */ +bool GfxSurface::unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2) { + destRect.left = MIN(src1.left, src2.left); + destRect.top = MIN(src1.top, src2.top); + destRect.right = MAX(src1.right, src2.right); + destRect.bottom = MAX(src1.bottom, src2.bottom); + + return !destRect.isEmpty(); +} + /*--------------------------------------------------------------------------*/ GfxElement::GfxElement() { @@ -639,6 +728,9 @@ void GfxElement::highlight() { GfxManager &gfxManager = g_globals->gfxManager(); Graphics::Surface surface = gfxManager.lockSurface(); + // Mark the area is dirty + gfxManager.addDirtyRect(_bounds); + // Scan through the contents of the element, switching any occurances of the foreground // color with the background color and vice versa Rect tempRect(_bounds); @@ -734,6 +826,7 @@ void GfxElement::drawFrame() { gfxManager.fillRect2(tempRect.right, tempRect.top + 2, 1, tempRect.height() - 3, 0); gfxManager.unlockSurface(); + gfxManager.addDirtyRect(_bounds); } /** @@ -1090,7 +1183,7 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) { } g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } _gfxManager.deactivate(); @@ -1174,6 +1267,11 @@ void GfxManager::fillArea(int xp, int yp, int color) { _surface.fillRect(tempRect, color); } +void GfxManager::addDirtyRect(const Rect &r) { + _surface.addDirtyRect(Rect(r.left + _bounds.left, r.top + _bounds.top, + r.right + _bounds.left, r.bottom + _bounds.top)); +} + void GfxManager::fillRect(const Rect &bounds, int color) { _surface.setBounds(_bounds); _surface.fillRect(bounds, color); diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h index dba3401700..e32994505c 100644 --- a/engines/tsage/graphics.h +++ b/engines/tsage/graphics.h @@ -74,12 +74,16 @@ public: class GfxSurface { private: Graphics::Surface *_customSurface; - Graphics::Surface *_screenSurfaceP; int _lockSurfaceCtr; - bool _screenSurface; bool _disableUpdates; Rect _bounds; + bool _trackDirtyRects; + Common::List<Rect> _dirtyRects; + + void mergeDirtyRects(); + bool looseIntersectRectangle(const Rect &src1, const Rect &src2); + bool unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2); public: Common::Point _centroid; int _transColor; @@ -88,7 +92,9 @@ public: GfxSurface(const GfxSurface &s); ~GfxSurface(); - void setScreenSurface(); + void trackDirtyRects(); + void addDirtyRect(const Rect &r); + void copyToScreen(); Graphics::Surface lockSurface(); void unlockSurface(); void synchronize(Serializer &s); @@ -274,6 +280,7 @@ public: return _surface.lockSurface(); } void unlockSurface() { _surface.unlockSurface(); } + void addDirtyRect(const Rect &r); void fillArea(int xp, int yp, int color); void fillRect(const Rect &bounds, int color); void fillRect2(int xs, int ys, int width, int height, int color); @@ -301,7 +308,6 @@ public: void copyFrom(GfxSurface &src, int destX, int destY) { _surface.setBounds(_bounds); _surface.copyFrom(src, destX, destY); - g_system->updateScreen(); } GfxSurface &getSurface() { _surface.setBounds(_bounds); diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp index 37101c9c58..d0d5ab7b4a 100644 --- a/engines/tsage/ringworld/ringworld_dialogs.cpp +++ b/engines/tsage/ringworld/ringworld_dialogs.cpp @@ -183,7 +183,7 @@ void RightClickDialog::execute() { } g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } // Execute the specified action @@ -394,7 +394,7 @@ void InventoryDialog::execute() { Event event; while (!g_globals->_events.getEvent(event) && !g_vm->shouldQuit()) { g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } if (g_vm->shouldQuit()) break; diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp index c87b95e0b8..2497327a01 100644 --- a/engines/tsage/ringworld/ringworld_logic.cpp +++ b/engines/tsage/ringworld/ringworld_logic.cpp @@ -315,7 +315,7 @@ void SceneArea::wait() { // Wait until a mouse or keypress Event event; while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event)) { - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); } diff --git a/engines/tsage/ringworld/ringworld_scenes3.cpp b/engines/tsage/ringworld/ringworld_scenes3.cpp index 81190aea7b..6f3d1ed93a 100644 --- a/engines/tsage/ringworld/ringworld_scenes3.cpp +++ b/engines/tsage/ringworld/ringworld_scenes3.cpp @@ -532,7 +532,7 @@ void Scene2100::Action1::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); continue; } @@ -2263,7 +2263,7 @@ void Scene2150::Action1::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); continue; } @@ -5118,7 +5118,7 @@ void Scene2320::Action3::signal() { // Wait for an event Event event; if (!g_globals->_events.getEvent(event)) { - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); continue; } diff --git a/engines/tsage/ringworld/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp index 49726eba2e..7c8da54fac 100644 --- a/engines/tsage/ringworld/ringworld_scenes5.cpp +++ b/engines/tsage/ringworld/ringworld_scenes5.cpp @@ -2810,7 +2810,7 @@ void Scene4150::Action1::signal() { case 4: { for (int idx = 100; idx >= 0; idx -= 5) { g_globals->_scenePalette.fade(adjustData, false, idx); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); } @@ -2838,7 +2838,7 @@ void Scene4150::Action1::signal() { case 7: for (int idx = 100; idx >= 0; idx -= 5) { g_globals->_scenePalette.fade(adjustData, false, idx); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); } diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index ddb4eae9c4..6035b37e19 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -153,7 +153,7 @@ void RightClickDialog::execute() { } g_system->delayMillis(10); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); } // Execute the specified action diff --git a/engines/tsage/scenes.cpp b/engines/tsage/scenes.cpp index 6362c63bc3..03c7d8d0ae 100644 --- a/engines/tsage/scenes.cpp +++ b/engines/tsage/scenes.cpp @@ -133,7 +133,7 @@ void SceneManager::fadeInIfNecessary() { percent = 100; g_globals->_scenePalette.fade((const byte *)&adjustData, false, percent); - g_system->updateScreen(); + GLOBALS._screenSurface.copyToScreen(); g_system->delayMillis(10); } |