[Scummvm-git-logs] scummvm master -> b39f380b8e73f9d17abe3f2746a1a69500f504cd

sev- noreply at scummvm.org
Sun Apr 5 22:32:22 UTC 2026


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
43f42b8db2 GRAPHICS: Split out dirty rectangle tracking from Graphics::Screen
5576fe97e8 3DS: Improve dirty rectangle tracking for emulated pixel formats
b39f380b8e 3DS: Implement OSystem::fillScreen()


Commit: 43f42b8db22798100dc278cb0422f92113dd6d14
    https://github.com/scummvm/scummvm/commit/43f42b8db22798100dc278cb0422f92113dd6d14
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-04-06T00:32:17+02:00

Commit Message:
GRAPHICS: Split out dirty rectangle tracking from Graphics::Screen

Changed paths:
  A graphics/dirtyrects.cpp
  A graphics/dirtyrects.h
    engines/petka/objects/object_case.cpp
    engines/petka/video.cpp
    engines/petka/video.h
    graphics/module.mk
    graphics/screen.cpp
    graphics/screen.h


diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 4a89e385b4b..ec8a6001223 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -103,10 +103,10 @@ void QObjectCase::draw() {
 
 		QSystem *sys = g_vm->getQSystem();
 
-		const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
+		const Graphics::DirtyRectList &dirty = g_vm->videoSystem()->rects();
 		const Common::Array<Common::Rect> &mskRects = flc->getMskRects();
 
-		for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
+		for (Graphics::DirtyRectList::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
 			for (uint i = 0; i < mskRects.size(); ++i) {
 				Common::Rect destRect = mskRects[i].findIntersectingRect(*it);
 				Common::Rect srcRect = destRect;
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 5cc2ef1155d..5f2dd779c1c 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -51,13 +51,13 @@ void VideoSystem::update() {
 
 	interface->update(time - _time);
 
-	mergeDirtyRects();
+	_dirtyRects.merge();
 
 	_allowAddingRects = false;
 	interface->draw();
 	_allowAddingRects = true;
 
-	for (Common::Rect &r : _dirtyRects) {
+	for (const Common::Rect &r : _dirtyRects) {
 		const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
 		g_system->copyRectToScreen(srcP, pitch, r.left, r.top, r.width(), r.height());
 	}
@@ -103,7 +103,7 @@ void VideoSystem::addDirtyMskRects(FlicDecoder &flc) {
 	addDirtyMskRects(Common::Point(0, 0), flc);
 }
 
-const Common::List<Common::Rect> &VideoSystem::rects() const {
+const Graphics::DirtyRectList &VideoSystem::rects() const {
 	return _dirtyRects;
 }
 
diff --git a/engines/petka/video.h b/engines/petka/video.h
index 1dce23b3cfb..8fe55fc3825 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -22,6 +22,7 @@
 #ifndef PETKA_SCREEN_H
 #define PETKA_SCREEN_H
 
+#include "graphics/dirtyrects.h"
 #include "graphics/screen.h"
 
 namespace Petka {
@@ -46,7 +47,7 @@ public:
 
 	void setShake(bool shake);
 
-	const Common::List<Common::Rect> &rects() const;
+	const Graphics::DirtyRectList &rects() const;
 
 private:
 	PetkaEngine &_vm;
diff --git a/graphics/dirtyrects.cpp b/graphics/dirtyrects.cpp
new file mode 100644
index 00000000000..96ca17963e1
--- /dev/null
+++ b/graphics/dirtyrects.cpp
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "graphics/dirtyrects.h"
+
+namespace Graphics {
+
+void DirtyRectList::merge() {
+	Common::List<Common::Rect>::iterator rOuter, rInner;
+
+	// Process the dirty rect list to find any rects to merge
+	for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
+		rInner = rOuter;
+		while (++rInner != _dirtyRects.end()) {
+
+			if ((*rOuter).intersects(*rInner)) {
+				// These two rectangles overlap, so merge them
+				unionRectangle(*rOuter, *rOuter, *rInner);
+
+				// remove the inner rect from the list
+				_dirtyRects.erase(rInner);
+
+				// move back to beginning of list
+				rInner = rOuter;
+			}
+		}
+	}
+}
+
+bool DirtyRectList::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
+	destRect = src1;
+	destRect.extend(src2);
+
+	return !destRect.isEmpty();
+}
+
+} // End of namespace Graphics
diff --git a/graphics/dirtyrects.h b/graphics/dirtyrects.h
new file mode 100644
index 00000000000..2205a5429df
--- /dev/null
+++ b/graphics/dirtyrects.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GRAPHICS_DIRTYRECTS_H
+#define GRAPHICS_DIRTYRECTS_H
+
+#include "common/list.h"
+#include "common/rect.h"
+
+namespace Graphics {
+
+/**
+ * @defgroup graphics_dirtyrects DirtyRects
+ * @ingroup graphics
+ *
+ * @brief DirtyRectList class for tracking dirty rectangles.
+ *
+ * @{
+ */
+
+/**
+ * This class keeps track of any areas of a surface that are updated
+ * by drawing calls.
+ */
+class DirtyRectList {
+public:
+	typedef Common::List<Common::Rect>::const_iterator	const_iterator; /*!< Const-qualified list iterator. */
+
+protected:
+	/**
+	 * List of affected areas of the screen
+	 */
+	Common::List<Common::Rect> _dirtyRects;
+
+protected:
+	/**
+	 * Returns the union of two dirty area rectangles
+	 */
+	bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
+
+public:
+	/**
+	 * Merges together overlapping dirty areas of the screen
+	 */
+	void merge();
+
+	/**
+	 * Returns true if there are no pending screen updates (dirty areas)
+	 */
+	bool empty() const { return _dirtyRects.empty(); }
+
+	/**
+	 * Clear the current dirty rects list
+	 */
+	void clear() { _dirtyRects.clear(); }
+
+	/**
+	 * Adds a rectangle to the list of modified areas of the screen during the
+	 * current frame
+	 */
+	template<class... TArgs>
+	void emplace_back(TArgs &&...args) { _dirtyRects.emplace_back(Common::forward<TArgs>(args)...); }
+
+	/**
+	 * Adds a rectangle to the list of modified areas of the screen during the
+	 * current frame
+	 */
+	void push_back(const Common::Rect &r) { _dirtyRects.push_back(r); }
+
+	/**
+	 * Adds a rectangle to the list of modified areas of the screen during the
+	 * current frame
+	 */
+	void push_back(Common::Rect &&r) { _dirtyRects.push_back(Common::move(r)); }
+
+	/** Return a const iterator to the start of the list.
+	 *  This can be used, for example, to iterate from the first element
+	 *  of the list to the last element of the list.
+	 */
+	const_iterator	begin() const {
+		return _dirtyRects.begin();
+	}
+
+	/** Return a const iterator to the end of the list. */
+	const_iterator	end() const {
+		return _dirtyRects.end();
+	}
+};
+ /** @} */
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index 2b7ecb44f63..5e4a60e89a2 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -9,6 +9,7 @@ MODULE_OBJS := \
 	blit/blit-scale.o \
 	color_quantizer.o \
 	cursorman.o \
+	dirtyrects.o \
 	font.o \
 	fontman.o \
 	fonts/amigafont.o \
diff --git a/graphics/screen.cpp b/graphics/screen.cpp
index be81655b064..f529790cd5e 100644
--- a/graphics/screen.cpp
+++ b/graphics/screen.cpp
@@ -40,10 +40,10 @@ Screen::Screen(int width, int height, PixelFormat pixelFormat): ManagedSurface()
 
 void Screen::update() {
 	// Merge the dirty rects
-	mergeDirtyRects();
+	_dirtyRects.merge();
 
 	// Loop through copying dirty areas to the physical screen
-	Common::List<Common::Rect>::iterator i;
+	DirtyRectList::const_iterator i;
 	for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
 		const Common::Rect &r = *i;
 		const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
@@ -75,35 +75,6 @@ void Screen::makeAllDirty() {
 	addDirtyRect(Common::Rect(0, 0, this->w, this->h));
 }
 
-void Screen::mergeDirtyRects() {
-	Common::List<Common::Rect>::iterator rOuter, rInner;
-
-	// Process the dirty rect list to find any rects to merge
-	for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
-		rInner = rOuter;
-		while (++rInner != _dirtyRects.end()) {
-
-			if ((*rOuter).intersects(*rInner)) {
-				// These two rectangles overlap, so merge them
-				unionRectangle(*rOuter, *rOuter, *rInner);
-
-				// remove the inner rect from the list
-				_dirtyRects.erase(rInner);
-
-				// move back to beginning of list
-				rInner = rOuter;
-			}
-		}
-	}
-}
-
-bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
-	destRect = src1;
-	destRect.extend(src2);
-
-	return !destRect.isEmpty();
-}
-
 void Screen::getPalette(byte palette[PALETTE_SIZE]) {
 	assert(format.bytesPerPixel == 1);
 	g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
diff --git a/graphics/screen.h b/graphics/screen.h
index 67d04f81c6e..5018afa8d62 100644
--- a/graphics/screen.h
+++ b/graphics/screen.h
@@ -23,10 +23,9 @@
 #define GRAPHICS_SCREEN_H
 
 #include "graphics/managed_surface.h"
+#include "graphics/dirtyrects.h"
 #include "graphics/palette.h"
 #include "graphics/pixelformat.h"
-#include "common/list.h"
-#include "common/rect.h"
 
 namespace Graphics {
 
@@ -50,17 +49,8 @@ protected:
 	/**
 	 * List of affected areas of the screen
 	 */
-	Common::List<Common::Rect> _dirtyRects;
-protected:
-	/**
-	 * Merges together overlapping dirty areas of the screen
-	 */
-	void mergeDirtyRects();
+	DirtyRectList _dirtyRects;
 
-	/**
-	 * Returns the union of two dirty area rectangles
-	 */
-	bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
 public:
 	Screen();
 	Screen(int width, int height);


Commit: 5576fe97e8175b8ecdad6561d6b46b7383bf26e4
    https://github.com/scummvm/scummvm/commit/5576fe97e8175b8ecdad6561d6b46b7383bf26e4
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-04-06T00:32:17+02:00

Commit Message:
3DS: Improve dirty rectangle tracking for emulated pixel formats

Changed paths:
    backends/platform/3ds/osystem-graphics.cpp
    backends/platform/3ds/osystem.cpp
    backends/platform/3ds/osystem.h


diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index bfc9e62d097..6009f99d055 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -355,7 +355,9 @@ void OSystem_3DS::setPalette(const byte *colors, uint start, uint num) {
 	assert(start + num <= 256);
 	memcpy(_palette + 3 * start, colors, 3 * num);
 	Graphics::convertPaletteToMap(_paletteMap + start, colors, num, _modeCLUT8.surfaceFormat);
-	_gameTextureDirty = true;
+
+	// Palette changes invalidate the entire surface
+	_dirtyRects.emplace_back(getWidth(), getHeight());
 }
 
 void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) const {
@@ -394,41 +396,29 @@ void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
 	}
 
 	_gameScreen.copyRectToSurface(buf, pitch, x, y, w, h);
-
-	if (_pfGame == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
-		byte *dst = (byte *)_gameTopTexture.getBasePtr(x, y);
-		copyRect555To5551(dst, (const byte *)buf, _gameTopTexture.pitch, pitch, w, h);
-	} else if (_gfxState.gfxMode == &_modeCLUT8) {
-		byte *dst = (byte *)_gameTopTexture.getBasePtr(x, y);
-		Graphics::crossBlitMap(dst, (const byte *)buf, _gameTopTexture.pitch, pitch,
-			w, h, _gameTopTexture.format.bytesPerPixel, _paletteMap);
-	} else {
-		byte *dst = (byte *)_gameTopTexture.getBasePtr(x, y);
-		Graphics::crossBlit(dst, (const byte *)buf, _gameTopTexture.pitch, pitch,
-			w, h, _gameTopTexture.format, _pfGame);
-	}
-
-	_gameTopTexture.markDirty();
+	_dirtyRects.emplace_back(x, y, x + w, y + h);
 }
 
 void OSystem_3DS::flushGameScreen() {
-	if (_pfGame == _gameTopTexture.format) {
+	if (_pfGame == _gameTopTexture.format)
 		return;
-	} else if (_pfGame == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
-		const byte *src = (const byte *)_gameScreen.getPixels();
-		byte *dst = (byte *)_gameTopTexture.getPixels();
-		copyRect555To5551(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
-			_gameScreen.w, _gameScreen.h);
-	} else if (_gfxState.gfxMode == &_modeCLUT8) {
-		const byte *src = (const byte *)_gameScreen.getPixels();
-		byte *dst = (byte *)_gameTopTexture.getPixels();
-		Graphics::crossBlitMap(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
-			_gameScreen.w, _gameScreen.h, _gameTopTexture.format.bytesPerPixel, _paletteMap);
-	} else {
-		const byte *src = (const byte *)_gameScreen.getPixels();
-		byte *dst = (byte *)_gameTopTexture.getPixels();
-		Graphics::crossBlit(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
-			_gameScreen.w, _gameScreen.h, _gameTopTexture.format, _pfGame);
+
+	_dirtyRects.merge();
+
+	for (const Common::Rect &r : _dirtyRects) {
+		const byte *src = (const byte *)_gameScreen.getBasePtr(r.left, r.top);
+		byte *dst = (byte *)_gameTopTexture.getBasePtr(r.left, r.top);
+
+		if (_pfGame == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
+			copyRect555To5551(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
+				r.width(), r.height());
+		} else if (_gfxState.gfxMode == &_modeCLUT8) {
+			Graphics::crossBlitMap(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
+				r.width(), r.height(), _gameTopTexture.format.bytesPerPixel, _paletteMap);
+		} else {
+			Graphics::crossBlit(dst, src, _gameTopTexture.pitch, _gameScreen.pitch,
+				r.width(), r.height(), _gameTopTexture.format, _pfGame);
+		}
 	}
 
 	_gameTopTexture.markDirty();
@@ -445,7 +435,7 @@ void OSystem_3DS::unlockScreen() {
 	if (_pfGame == _gameTopTexture.format)
 		_gameTopTexture.markDirty();
 	else
-		_gameTextureDirty = true;
+		_dirtyRects.emplace_back(getWidth(), getHeight());
 }
 
 void OSystem_3DS::updateScreen() {
@@ -453,9 +443,9 @@ void OSystem_3DS::updateScreen() {
 		return;
 	}
 
-	if (_gameTextureDirty) {
+	if (!_dirtyRects.empty()) {
 		flushGameScreen();
-		_gameTextureDirty = false;
+		_dirtyRects.clear();
 	}
 
 // 	updateFocus();
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index a152d5c084b..137a5b1d5b5 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -77,7 +77,6 @@ OSystem_3DS::OSystem_3DS():
 	_magY(0),
 	_magWidth(400),
 	_magHeight(240),
-	_gameTextureDirty(false),
 	_filteringEnabled(true),
 	_overlayVisible(false),
 	_overlayInGUI(false),
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index 962f981a32b..78e02582a05 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -25,6 +25,7 @@
 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
 
 #include "backends/base-backend.h"
+#include "graphics/dirtyrects.h"
 #include "graphics/paletteman.h"
 #include "base/main.h"
 #include "audio/mixer_intern.h"
@@ -236,7 +237,7 @@ private:
 	uint32 _paletteMap[256];
 
 	Graphics::Surface _gameScreen;
-	bool _gameTextureDirty;
+	Graphics::DirtyRectList _dirtyRects;
 	Sprite _gameTopTexture;
 	Sprite _gameBottomTexture;
 	Sprite _overlay;


Commit: b39f380b8e73f9d17abe3f2746a1a69500f504cd
    https://github.com/scummvm/scummvm/commit/b39f380b8e73f9d17abe3f2746a1a69500f504cd
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-04-06T00:32:17+02:00

Commit Message:
3DS: Implement OSystem::fillScreen()

Changed paths:
    backends/platform/3ds/osystem-graphics.cpp
    backends/platform/3ds/osystem.h


diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 6009f99d055..f1736aa30af 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -387,6 +387,21 @@ static void copyRect555To5551(byte *dst, const byte *src, const uint dstPitch, c
 	}
 }
 
+void OSystem_3DS::fillScreen(uint32 col) {
+	fillScreen(Common::Rect(getWidth(), getHeight()), col);
+}
+
+void OSystem_3DS::fillScreen(const Common::Rect &r, uint32 col) {
+	if (_pfGame == _gameTopTexture.format) {
+		_gameTopTexture.fillRect(r, col);
+		_gameTopTexture.markDirty();
+		return;
+	}
+
+	_gameScreen.fillRect(r, col);
+	_dirtyRects.push_back(r);
+}
+
 void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
 								   int y, int w, int h) {
 	if (_pfGame == _gameTopTexture.format) {
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index 78e02582a05..8eddd741b4f 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -160,6 +160,8 @@ public:
 	                      int h);
 	Graphics::Surface *lockScreen();
 	void unlockScreen();
+	void fillScreen(uint32 col);
+	void fillScreen(const Common::Rect &r, uint32 col);
 	void updateScreen();
 	void setShakePos(int shakeXOffset, int shakeYOffset);
 	void setFocusRectangle(const Common::Rect &rect);




More information about the Scummvm-git-logs mailing list