aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/tony/gfxcore.cpp79
-rw-r--r--engines/tony/gfxcore.h22
-rw-r--r--engines/tony/gfxengine.cpp4
-rw-r--r--engines/tony/gfxengine.h4
-rw-r--r--engines/tony/loc.cpp34
-rw-r--r--engines/tony/loc.h3
-rw-r--r--engines/tony/tony.cpp3
-rw-r--r--engines/tony/utils.cpp4
-rw-r--r--engines/tony/utils.h1
-rw-r--r--engines/tony/window.cpp35
-rw-r--r--engines/tony/window.h3
11 files changed, 167 insertions, 25 deletions
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index e168d2b7c9..d34923e455 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -256,6 +256,7 @@ RMGfxClearTask RMGfxTargetBuffer::taskClear;
RMGfxTargetBuffer::RMGfxTargetBuffer() {
_otlist = NULL;
_otSize = 0;
+ _trackDirtyRects = false;
// csModifyingOT = g_system->createMutex();
}
@@ -380,6 +381,66 @@ void RMGfxTargetBuffer::addClearTask(void) {
addPrim(new RMGfxPrimitive(&taskClear));
}
+void RMGfxTargetBuffer::addDirtyRect(const Common::Rect &r) {
+ assert(r.isValidRect());
+ if (_trackDirtyRects && r.width() > 0 && r.height() > 0)
+ _currentDirtyRects.push_back(r);
+}
+
+Common::List<Common::Rect> &RMGfxTargetBuffer::getDirtyRects() {
+ // Copy rects from both the current and previous frame into the output dirty rects list
+ Common::List<Common::Rect>::iterator i;
+ _dirtyRects.clear();
+ for (i = _previousDirtyRects.begin(); i != _previousDirtyRects.end(); ++i)
+ _dirtyRects.push_back(*i);
+ for (i = _currentDirtyRects.begin(); i != _currentDirtyRects.end(); ++i)
+ _dirtyRects.push_back(*i);
+
+ mergeDirtyRects();
+ return _dirtyRects;
+}
+
+/**
+ * Move the set of dirty rects from the finished current frame into the previous frame list.
+ */
+void RMGfxTargetBuffer::clearDirtyRects() {
+ Common::List<Common::Rect>::iterator i;
+ _previousDirtyRects.clear();
+ for (i = _currentDirtyRects.begin(); i != _currentDirtyRects.end(); ++i)
+ _previousDirtyRects.push_back(*i);
+
+ _currentDirtyRects.clear();
+}
+
+/**
+ * Merges any clipping rectangles that overlap to try and reduce
+ * the total number of clip rectangles.
+ */
+void RMGfxTargetBuffer::mergeDirtyRects() {
+ if (_dirtyRects.size() <= 1)
+ return;
+
+ Common::List<Common::Rect>::iterator rOuter, rInner;
+
+ for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
+ rInner = rOuter;
+ while (++rInner != _dirtyRects.end()) {
+
+ if ((*rOuter).intersects(*rInner)) {
+ // these two rectangles overlap or
+ // are next to each other - merge them
+
+ (*rOuter).extend(*rInner);
+
+ // remove the inner rect from the list
+ _dirtyRects.erase(rInner);
+
+ // move back to beginning of list
+ rInner = rOuter;
+ }
+ }
+ }
+}
/****************************************************************************\
* RMGfxSourceBufferPal Methods
@@ -550,6 +611,9 @@ void RMGfxSourceBuffer8::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimit
buf += bufx - width;
}
}
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(dst._x1, dst._y1, dst._x1 + width, dst._y1 + height));
}
RMGfxSourceBuffer8::RMGfxSourceBuffer8(int dimx, int dimy, bool bUseDDraw)
@@ -660,7 +724,8 @@ void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrim
}
}
- return;
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(dst._x1, dst._y1, dst._x1 + width, dst._y1 + height));
}
@@ -857,6 +922,9 @@ void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPri
buf += bigBuf.getDimx();
}
}
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + width, y1 + height));
}
@@ -1709,6 +1777,9 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
// Skip to the next line
buf += bigBuf.getDimx();
}
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + width, y1 + height));
}
@@ -1871,6 +1942,9 @@ void RMGfxSourceBuffer16::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimi
raw += _dimx;
}
}
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + dimx, y1 + dimy));
}
void RMGfxSourceBuffer16::prepareImage(void) {
@@ -1922,6 +1996,9 @@ void RMGfxBox::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim)
uint16 *buf = bigBuf;
RMRect rcDst;
+ // Specify the drawn area
+ bigBuf.addDirtyRect(rcDst);
+
// It takes the destination rectangle
rcDst = prim->getDst();
buf += rcDst._y1 * bigBuf.getDimx() + rcDst._x1;
diff --git a/engines/tony/gfxcore.h b/engines/tony/gfxcore.h
index 9a00ed1646..82862d6846 100644
--- a/engines/tony/gfxcore.h
+++ b/engines/tony/gfxcore.h
@@ -112,11 +112,13 @@ public:
_task = NULL;
_src.setEmpty();
_dst.setEmpty();
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task) {
_task = task;
_bFlag = 0;
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMRect &dst) {
@@ -132,6 +134,7 @@ public:
_src.topLeft() = src;
_dst = dst;
_bFlag = 0;
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task, const RMPoint &src, RMPoint &dst) {
@@ -139,6 +142,7 @@ public:
_src.topLeft() = src;
_dst.topLeft() = dst;
_bFlag = 0;
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMPoint &dst) {
@@ -146,6 +150,7 @@ public:
_src = src;
_dst.topLeft() = dst;
_bFlag = 0;
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task, const RMRect &dst) {
@@ -153,6 +158,7 @@ public:
_dst = dst;
_src.setEmpty();
_bFlag = 0;
+ _bStretch = false;
}
RMGfxPrimitive(RMGfxTask *task, const RMPoint &dst) {
@@ -160,6 +166,7 @@ public:
_dst.topLeft() = dst;
_src.setEmpty();
_bFlag = 0;
+ _bStretch = false;
}
virtual ~RMGfxPrimitive() { }
@@ -553,6 +560,10 @@ private:
}
};
+ bool _trackDirtyRects;
+ Common::List<Common::Rect> _currentDirtyRects, _previousDirtyRects, _dirtyRects;
+
+ void mergeDirtyRects();
private:
// OSystem::MutexRef csModifyingOT;
@@ -587,6 +598,17 @@ public:
void offsetY(int nLines) {
RMGfxBuffer::offsetY(nLines, 16);
}
+
+ // Dirty rect methods
+ void addDirtyRect(const Common::Rect &r);
+ Common::List<Common::Rect> &getDirtyRects();
+ void clearDirtyRects();
+ void setTrackDirtyRects(bool v) {
+ _trackDirtyRects = v;
+ }
+ bool getTrackDirtyRects() const {
+ return _trackDirtyRects;
+ }
};
diff --git a/engines/tony/gfxengine.cpp b/engines/tony/gfxengine.cpp
index deae0cb641..3ea83a8867 100644
--- a/engines/tony/gfxengine.cpp
+++ b/engines/tony/gfxengine.cpp
@@ -63,6 +63,7 @@ RMGfxEngine::RMGfxEngine() {
// Create big buffer where the frame will be rendered
_bigBuf.create(RM_BBX, RM_BBY, 16);
_bigBuf.offsetY(RM_SKIPY);
+ _bigBuf.setTrackDirtyRects(true);
_csMainLoop = NULL;
_nCurLoc = 0;
@@ -475,8 +476,7 @@ void RMGfxEngine::init() {
delete load;
// Display 'Loading' screen
- // TODO: The loading screen isn't currently optimal, since the game doesn't respond to events
- // whilst the mpalInit code is being executed.
+ _bigBuf.addDirtyRect(Common::Rect(0, 0, RM_SX, RM_SY));
_vm->_window.getNewFrame(*this, NULL);
_vm->_window.repaint();
diff --git a/engines/tony/gfxengine.h b/engines/tony/gfxengine.h
index 18c13d8d3d..1a37de98e1 100644
--- a/engines/tony/gfxengine.h
+++ b/engines/tony/gfxengine.h
@@ -109,8 +109,8 @@ public:
void enableMouse(void);
void disableMouse(void);
- operator byte *() {
- return (byte *)_bigBuf;
+ operator RMGfxTargetBuffer &() {
+ return _bigBuf;
}
RMInput &getInput() {
return _input;
diff --git a/engines/tony/loc.cpp b/engines/tony/loc.cpp
index b2bf3b3565..26a13037c0 100644
--- a/engines/tony/loc.cpp
+++ b/engines/tony/loc.cpp
@@ -710,14 +710,13 @@ void RMItem::setStatus(int nStatus) {
}
void RMItem::setPattern(int nPattern, bool bPlayP0) {
- int i;
-
assert(nPattern >= 0 && nPattern <= _nPatterns);
- if (_sfx)
+ if (_sfx) {
if (_nCurPattern > 0)
_patterns[_nCurPattern].stopSfx(_sfx);
-
+ }
+
// Remember the current pattern
_nCurPattern = nPattern;
@@ -728,10 +727,12 @@ void RMItem::setPattern(int nPattern, bool bPlayP0) {
_nCurSprite = -1;
// Look for the sound effect for pattern 0
- if (bPlayP0)
- for (i = 0; i < _nSfx; i++)
+ if (bPlayP0) {
+ for (int i = 0; i < _nSfx; i++) {
if (strcmp(_sfx[i]._name, "p0") == 0)
_sfx[i].play();
+ }
+ }
}
}
@@ -783,6 +784,8 @@ RMItem::RMItem() {
_bPal = 0;
_nCurSprite = 0;
+ _bIsActive = false;
+
_hEndPattern = CoroScheduler.createEvent(false, false);
}
@@ -1933,6 +1936,8 @@ RMLocation::RMLocation() {
_nItems = 0;
_items = NULL;
_buf = NULL;
+ _prevScroll.set(-1, -1);
+ _prevFixedScroll.set(-1, -1);
}
@@ -1967,11 +1972,8 @@ bool RMLocation::load(const char *lpszFileName) {
* @returns True if succeeded OK, false in case of error.
*/
bool RMLocation::load(Common::File &file) {
- int size;
bool bRet;
- // Get the file size
- size = file.size();
file.seek(0);
RMFileStreamSlow fs;
@@ -2126,6 +2128,8 @@ bool RMLocation::loadLOX(RMDataStream &ds) {
*/
void RMLocation::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
CORO_BEGIN_CONTEXT;
+ bool priorTracking;
+ bool hasChanges;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
@@ -2137,9 +2141,21 @@ void RMLocation::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
prim->setDst(_fixedScroll);
+ // Check whether dirty rects are being tracked, and if there are changes, leave tracking
+ // turned on so a dirty rect will be added for the entire background
+ _ctx->priorTracking = bigBuf.getTrackDirtyRects();
+ _ctx->hasChanges = (_prevScroll != _curScroll) || (_prevFixedScroll != _fixedScroll);
+ bigBuf.setTrackDirtyRects(_ctx->priorTracking && _ctx->hasChanges);
+
// Invoke the drawing method fo the image class, which will draw the location background
CORO_INVOKE_2(_buf->draw, bigBuf, prim);
+ if (_ctx->hasChanges) {
+ _prevScroll = _curScroll;
+ _prevFixedScroll = _fixedScroll;
+ }
+ bigBuf.setTrackDirtyRects(_ctx->priorTracking);
+
CORO_END_CODE;
}
diff --git a/engines/tony/loc.h b/engines/tony/loc.h
index 4231c99eab..944e206ae2 100644
--- a/engines/tony/loc.h
+++ b/engines/tony/loc.h
@@ -539,6 +539,9 @@ private:
RMPoint _curScroll; // Current scroll position
RMPoint _fixedScroll;
+ RMPoint _prevScroll; // Previous scroll position
+ RMPoint _prevFixedScroll;
+
public:
// @@@@@@@@@@@@@@@@@@@@@@@
RMPoint TEMPTonyStart;
diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp
index b1e45c8bfa..28726f0a33 100644
--- a/engines/tony/tony.cpp
+++ b/engines/tony/tony.cpp
@@ -623,8 +623,9 @@ Common::Error TonyEngine::saveGameState(int slot, const Common::String &desc) {
if (!GLOBALS._gfxEngine)
return Common::kUnknownError;
+ RMGfxTargetBuffer &bigBuf = *GLOBALS._gfxEngine;
RMSnapshot s;
- s.grabScreenshot(*GLOBALS._gfxEngine, 4, _curThumbnail);
+ s.grabScreenshot(bigBuf, 4, _curThumbnail);
GLOBALS._gfxEngine->saveState(getSaveStateFileName(slot), (byte *)_curThumbnail, desc);
return Common::kNoError;
diff --git a/engines/tony/utils.cpp b/engines/tony/utils.cpp
index 8e751a811a..f9c2622eb2 100644
--- a/engines/tony/utils.cpp
+++ b/engines/tony/utils.cpp
@@ -922,6 +922,10 @@ int RMRect::size() const {
return width() * height();
}
+RMRect::operator Common::Rect() const {
+ return Common::Rect(_x1, _y1, _x2, _y2);
+}
+
bool RMRect::isEmpty() const {
return (_x1 == 0 && _y1 == 0 && _x2 == 0 && _y2 == 0);
}
diff --git a/engines/tony/utils.h b/engines/tony/utils.h
index 33e2db7d7e..82c5bb020c 100644
--- a/engines/tony/utils.h
+++ b/engines/tony/utils.h
@@ -268,6 +268,7 @@ public:
int height() const;
bool isEmpty() const;
int size() const;
+ operator Common::Rect() const;
// Set
void setRect(int x1, int y1, int x2, int y2);
diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp
index db21be0ded..bf0094ff2a 100644
--- a/engines/tony/window.cpp
+++ b/engines/tony/window.cpp
@@ -40,7 +40,6 @@ namespace Tony {
\****************************************************************************/
RMWindow::RMWindow() {
-
}
RMWindow::~RMWindow() {
@@ -61,6 +60,7 @@ void RMWindow::init() {
_bGrabScreenshot = false;
_bGrabThumbnail = false;
_bGrabMovie = false;
+ _wiping = false;
}
/**
@@ -108,13 +108,29 @@ void RMWindow::wipeEffect(Common::Rect &rcBoundEllipse) {
}
}
-void RMWindow::getNewFrame(byte *lpBuf, Common::Rect *rcBoundEllipse) {
+void RMWindow::getNewFrame(RMGfxTargetBuffer &bigBuf, Common::Rect *rcBoundEllipse) {
+ // Get a pointer to the bytes of the source buffer
+ byte *lpBuf = bigBuf;
+
if (rcBoundEllipse != NULL) {
// Circular wipe effect
getNewFrameWipe(lpBuf, *rcBoundEllipse);
- } else {
- // Standard screen copy
+ _wiping = true;
+ } else if (_wiping) {
+ // Just finished a wiping effect, so copy the full screen
g_system->copyRectToScreen(lpBuf, RM_SX * 2, 0, 0, RM_SX, RM_SY);
+ _wiping = false;
+
+ } else {
+ // Standard screen copy - iterate through the dirty rects
+ Common::List<Common::Rect> dirtyRects = bigBuf.getDirtyRects();
+ Common::List<Common::Rect>::iterator i;
+
+ for (i = dirtyRects.begin(); i != dirtyRects.end(); ++i) {
+ Common::Rect &r = *i;
+ const byte *lpSrc = lpBuf + (RM_SX * 2) * r.top + (r.left * 2);
+ g_system->copyRectToScreen(lpSrc, RM_SX * 2, r.left, r.top, r.width(), r.height());
+ }
}
if (_bGrabThumbnail) {
@@ -124,6 +140,9 @@ void RMWindow::getNewFrame(byte *lpBuf, Common::Rect *rcBoundEllipse) {
s.grabScreenshot(lpBuf, 4, _wThumbBuf);
_bGrabThumbnail = false;
}
+
+ // Clear the dirty rect list
+ bigBuf.clearDirtyRects();
}
/**
@@ -214,10 +233,7 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
int dimx = RM_SX / dezoom;
int dimy = RM_SY / dezoom;
- int u, v, curv;
-
uint32 k = 0;
- int sommar, sommab, sommag;
uint16 *cursrc;
if (lpDestBuf == NULL)
@@ -247,10 +263,11 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
for (int y = 0; y < dimy; y++) {
for (int x = 0; x < dimx; x++) {
cursrc = &src[RM_SKIPX + x * dezoom];
+ int sommar, sommab, sommag, curv;
sommar = sommab = sommag = 0;
- for (v = 0; v < dezoom; v++) {
- for (u = 0; u < dezoom; u++) {
+ for (int v = 0; v < dezoom; v++) {
+ for (int u = 0; u < dezoom; u++) {
if (lpDestBuf == NULL)
curv = -v;
else
diff --git a/engines/tony/window.h b/engines/tony/window.h
index 34f0c1cb51..6189dd391f 100644
--- a/engines/tony/window.h
+++ b/engines/tony/window.h
@@ -64,6 +64,7 @@ protected:
int lastsecond, lastfcount;
int mskRed, mskGreen, mskBlue;
+ bool _wiping;
bool _bGrabScreenshot;
bool _bGrabThumbnail;
@@ -90,7 +91,7 @@ public:
void switchFullscreen(bool bFull) {}
// Reads the next frame
- void getNewFrame(byte *lpBuf, Common::Rect *rcBoundEllipse);
+ void getNewFrame(RMGfxTargetBuffer &lpBuf, Common::Rect *rcBoundEllipse);
// Request a thumbnail be grabbed during the next frame
void grabThumbnail(uint16 *buf);