BACKENDS: ATARI: Additional fixes for cursor background

- leftovers after highlighted dirty rectangle

- not updating _surface if moving to fast left/right from screen borders
  (_width == _srcRect.width())

- not drawing cursor if repeatedly intersecting with a refreshing dirty
  rect

- leftover rectangle when leaving game overlay to the launcher

- massive simplification
This commit is contained in:
Miro Kropacek
2025-04-11 22:23:08 +02:00
parent 4afb49840e
commit 5680536655
6 changed files with 49 additions and 46 deletions
+11 -8
View File
@@ -70,7 +70,7 @@ void Cursor::update() {
_dstRect.right * dstBitsPerPixel / 8, // fake 4bpp by 8bpp's width/2
_dstRect.bottom);
// this is used only in intersects() and flushBackground()
// this is used only in flushBackground()
_alignedDstRect = _manager->alignRect(
_dstRect.left + _xOffset,
_dstRect.top,
@@ -201,8 +201,14 @@ Common::Rect Cursor::flushBackground(const Common::Rect &alignedRect, bool direc
return _savedRect;
if (!alignedRect.isEmpty() && alignedRect.contains(_alignedDstRect)) {
// better would be _visibilityChanged but update() ignores it
_positionChanged = true;
_savedRect = Common::Rect();
} else if (alignedRect.isEmpty() || alignedRect.intersects(_alignedDstRect)) {
// better would be _visibilityChanged but update() ignores it
_positionChanged = true;
if (directRendering)
restoreBackground();
else
@@ -232,17 +238,15 @@ void Cursor::saveBackground() {
_savedBackground.copyRectToSurface(dstSurface, 0, 0, _savedRect);
}
bool Cursor::draw(bool force) {
if (!isVisible() || (!force && !isChanged()))
return false;
void Cursor::draw() {
Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
if (_surfaceChanged || _width != _srcRect.width()) {
// TODO: check for change, not just different width so it's not called over and over again when clipped ...
if (_surfaceChanged || _srcRect != _previousSrcRect) {
_previousSrcRect = _srcRect;
// TODO: some sort of in-place C2P directly into convertSurfaceTo() ...
convertSurfaceTo(dstSurface.format);
{
@@ -270,7 +274,6 @@ bool Cursor::draw(bool force) {
Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
_visibilityChanged = _positionChanged = _surfaceChanged = false;
return true;
}
void Cursor::restoreBackground() {
+4 -7
View File
@@ -47,7 +47,7 @@ struct Cursor {
_surfaceChanged = true;
_visibilityChanged = false;
_savedRect = _alignedDstRect = Common::Rect();
_savedRect = _previousSrcRect = _alignedDstRect = Common::Rect();
}
// updates outOfScreen OR srcRect/dstRect (only if visible/needed)
@@ -97,13 +97,9 @@ struct Cursor {
return _positionChanged || _surfaceChanged || _visibilityChanged;
}
bool intersects(const Common::Rect &alignedRect) const {
return alignedRect.intersects(_alignedDstRect);
}
Common::Rect flushBackground(const Common::Rect &alignedRect, bool directRendering);
void saveBackground();
bool draw(bool force);
void draw();
private:
void restoreBackground();
@@ -126,8 +122,9 @@ private:
Common::Rect _srcRect;
Common::Rect _dstRect;
Graphics::Surface _savedBackground; // used by direct rendering
Graphics::Surface _savedBackground;
Common::Rect _savedRect;
Common::Rect _previousSrcRect;
Common::Rect _alignedDstRect;
// related to 'surface'
+25 -28
View File
@@ -407,6 +407,7 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
atari_debug("endGFXTransaction");
_pendingState.inTransaction = false;
_ignoreCursorChanges = false;
int error = OSystem::TransactionError::kTransactionSuccess;
bool hasPendingGraphicsMode = false;
@@ -914,7 +915,10 @@ Graphics::Surface *AtariGraphicsManager::lockOverlay() {
}
bool AtariGraphicsManager::showMouse(bool visible) {
//atari_debug("showMouse: %d", visible);
//atari_debug("showMouse: %d; ignored: %d", visible, _ignoreCursorChanges);
if (_ignoreCursorChanges)
return visible;
bool lastOverlay, lastFront, lastBack1 = false;
@@ -951,7 +955,11 @@ void AtariGraphicsManager::warpMouse(int x, int y) {
void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor,
bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
//atari_debug("setMouseCursor: %d, %d, %d, %d, %d, %d", w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1);
//atari_debug("setMouseCursor: %d, %d, %d, %d, %d, %d; ignored: %d",
// w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1, _ignoreCursorChanges);
if (_ignoreCursorChanges)
return;
if (mask)
atari_warning("AtariGraphicsManager::setMouseCursor: Masks are not supported");
@@ -1001,6 +1009,8 @@ bool AtariGraphicsManager::notifyEvent(const Common::Event &event) {
surf.fillRect(Common::Rect(surf.w, surf.h), 0);
_ignoreHideOverlay = true;
// gui manager would want to hide overlay, set game cursor etc
_ignoreCursorChanges = true;
return false;
}
break;
@@ -1092,10 +1102,9 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
lockSuperBlitter();
if (cursor.isChanged()) {
const Common::Rect rect = cursor.flushBackground(Common::Rect(), directRendering);
// 'updated' is skipped in direct drawing but in such case there's never triple-buffering active
if (!directRendering && !rect.isEmpty()) {
copyRectToSurface(*dstSurface, srcSurface, rect.left, rect.top, rect);
const Common::Rect cursorBackgroundRect = cursor.flushBackground(Common::Rect(), directRendering);
if (!cursorBackgroundRect.isEmpty()) {
copyRectToSurface(*dstSurface, srcSurface, cursorBackgroundRect.left, cursorBackgroundRect.top, cursorBackgroundRect);
updated |= true;
}
}
@@ -1103,36 +1112,24 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
// update cursor rects and visibility flag (if out of screen)
cursor.update();
const bool cursorDrawEnabled = cursor.isVisible();
bool forceCursorDraw = cursorDrawEnabled && (dstScreen->fullRedraw || cursor.isChanged());
const bool drawCursor = cursor.isVisible() && (dstScreen->fullRedraw || cursor.isChanged());
for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
if (cursorDrawEnabled && !forceCursorDraw) {
forceCursorDraw = cursor.intersects(*it);
// any '*it' shall never intersect cursor background; that was handled in addDirtyRect()
if (forceCursorDraw) {
const Common::Rect rect = cursor.flushBackground(*it, directRendering);
// 'updated' is skipped in direct drawing but in such case there's never triple-buffering active
if (!directRendering && !rect.isEmpty()) {
copyRectToSurface(*dstSurface, srcSurface, rect.left, rect.top, rect);
updated |= true;
}
}
}
if (!directRendering) {
if (!directRendering) {
for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
copyRectToSurface(*dstSurface, srcSurface, it->left, it->top, *it);
updated |= true;
}
}
if (directRendering && (forceCursorDraw || cursor.isChanged()))
updated |= !dirtyRects.empty();
} else if (drawCursor) {
cursor.saveBackground();
}
// unlock here because cursor.draw() is a software blit
unlockSuperBlitter();
updated |= cursor.draw(forceCursorDraw);
if (drawCursor) {
cursor.draw();
updated |= true;
}
dstScreen->clearDirtyRects();
+1
View File
@@ -245,6 +245,7 @@ private:
int _overlayState = kOverlayHidden;
bool _ignoreHideOverlay = true;
Graphics::Surface _overlaySurface;
bool _ignoreCursorChanges = false;
Palette _palette;
Palette _overlayPalette;
+4 -3
View File
@@ -159,9 +159,10 @@ void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int
dirtyRects.insert(alignedRect);
// this takes care of a dirty rect touching the cursor background; however there's still
// the case when a dirty rect touches the cursor itself: in such case the cursor background
// will be restored one more time while iterating over dirty rects
// Check whether the cursor background intersects the dirty rect. Has to be done here,
// before the actual drawing (especially in case of direct rendering). There's one more
// check in AtariGraphicsManager::updateScreenInternal for the case when there are no
// dirty rectangles but the cursor itself has changed.
const Common::Rect cursorBackgroundRect = cursor.flushBackground(alignedRect, directRendering);
if (!cursorBackgroundRect.isEmpty()) {
dirtyRects.insert(cursorBackgroundRect);
@@ -351,6 +351,8 @@ void OSystem_Atari::initBackend() {
}
void OSystem_Atari::engineInit() {
//atari_debug("engineInit");
g_gameEngineActive = true;
const Common::ConfigManager::Domain *activeDomain = ConfMan.getActiveDomain();
@@ -381,6 +383,8 @@ void OSystem_Atari::engineInit() {
}
void OSystem_Atari::engineDone() {
//atari_debug("engineDone");
g_gameEngineActive = false;
g_unalignedPitch = false;
}