mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 06:08:35 +00:00
TSAGE: Implemented a cleaner version of dirty rect handling
This commit is contained in:
parent
54d0f8124e
commit
be706b1846
@ -250,11 +250,44 @@ void GfxSurface::setScreenSurface() {
|
||||
* Updates the physical screen with the screen surface buffer
|
||||
*/
|
||||
void GfxSurface::updateScreen() {
|
||||
g_system->copyRectToScreen((const byte *)this->_customSurface->pixels,
|
||||
SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rect to the dirty rect list
|
||||
*/
|
||||
void GfxSurface::addDirtyRect(const Rect &r) {
|
||||
if (_trackDirtyRects) {
|
||||
// Get the bounds and adjust to allow for sub-screen areas
|
||||
Rect r2 = r;
|
||||
r2.translate(_bounds.left, _bounds.top);
|
||||
|
||||
// Add to the dirty rect list
|
||||
_dirtyRects.push_back(Rect(r2.left, r2.top,
|
||||
MIN(r2.right + 1, SCREEN_WIDTH), MIN(r2.bottom + 1, SCREEN_HEIGHT)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Specifies that the surface should maintain it's own internal surface
|
||||
*/
|
||||
@ -346,6 +379,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) {
|
||||
@ -562,6 +596,9 @@ void GfxSurface::copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, Regi
|
||||
destBounds.bottom = destSurface.h;
|
||||
|
||||
if (destBounds.isValidRect()) {
|
||||
// Register the affected area as dirty
|
||||
addDirtyRect(destBounds);
|
||||
|
||||
const byte *pSrc = (const byte *)srcSurface.getBasePtr(srcX, srcY);
|
||||
byte *pDest = (byte *)destSurface.getBasePtr(destBounds.left, destBounds.top);
|
||||
|
||||
@ -607,6 +644,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() {
|
||||
@ -646,6 +745,9 @@ void GfxElement::highlight() {
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the affected area as dirty
|
||||
gfxManager.getSurface().addDirtyRect(tempRect);
|
||||
|
||||
// Release the surface
|
||||
gfxManager.unlockSurface();
|
||||
}
|
||||
@ -1422,7 +1524,12 @@ int GfxFont::writeChar(const char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the affected area as dirty
|
||||
_gfxManager->getSurface().addDirtyRect(charRect);
|
||||
|
||||
// Move the text writing position
|
||||
_position.x += charWidth;
|
||||
|
||||
_gfxManager->unlockSurface();
|
||||
return charWidth;
|
||||
}
|
||||
|
@ -75,10 +75,17 @@ class GfxSurface {
|
||||
private:
|
||||
Graphics::Surface *_customSurface;
|
||||
int _lockSurfaceCtr;
|
||||
bool _trackDirtyRects;
|
||||
|
||||
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;
|
||||
@ -89,6 +96,7 @@ public:
|
||||
|
||||
void setScreenSurface();
|
||||
void updateScreen();
|
||||
void addDirtyRect(const Rect &r);
|
||||
Graphics::Surface lockSurface();
|
||||
void unlockSurface();
|
||||
void synchronize(Serializer &s);
|
||||
|
Loading…
Reference in New Issue
Block a user