[Scummvm-git-logs] scummvm master -> 3159fa505b9b71164cdfa0d27076ff3e8701ac0e
dreammaster
noreply at scummvm.org
Wed Dec 31 21:07:07 UTC 2025
This automated email contains information about 18 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
6507527c49 VIDEO: Move the subtitle bounding box recalculation code
6b09d6eb2b VIDEO: Allow overriding the Subtitles class for other types of subs
bb14821887 M4: Extend the engine to support in-game subtitles
82eac59fc5 M4: Don't clear subtitles if they're not loaded
df746d3600 M4: Only show subtitles when they're enabled in the game audio settings
9b14308cbb M4: Also clear the overlay when clearing subtitles
d005b2d84d M4: Clear the overlay before showing it, instead of when hiding it
8c170537c9 VIDEO: Simplify subtitle code
02b1e6ecf6 M4: Remove unused return value
d8db8fc917 M4: Don't use a pointer for the subtitle instance
b930babbd4 VIDEO: Use a pointer for SRT parser in the Subtitles class
99438dc786 M4: Allow toggling speech and subtitles
af15f6266d VIDEO: Move overlay manipulation code in the base Subtitles class
90f6e3d406 VIDEO: Store the number of split subtitle lines to be rendered
bd18e39e99 M4: Adapt the subtitle bounding box, depending on the lines drawn
c2055a8567 VIDEO: Reduce scope of member variables in the base Subtitles class
e8bc9649ca COMMON: Add helper methods to the TranslationManager
3159fa505b M4: Use the translation manager to handle the subtitle functionality
Commit: 6507527c49045a03db3ffd18e045241a00e6b506
https://github.com/scummvm/scummvm/commit/6507527c49045a03db3ffd18e045241a00e6b506
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Move the subtitle bounding box recalculation code
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index ab7b85ff29c..d9b1529e9b9 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -359,37 +359,7 @@ void Subtitles::setPadding(uint16 horizontal, uint16 vertical) {
_vPad = vertical;
}
-bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
- const Common::Array<SubtitlePart> *parts;
- bool isSFX = false;
- if (_loaded) {
- parts = _srtParser.getSubtitleParts(timestamp);
- if (parts && !parts->empty()) {
- isSFX = (*parts)[0].tag == "sfx";
- }
- } else if (_subtitleDev) {
- // Force refresh
- _parts = nullptr;
-
- Common::String subtitle = _fname.toString('/');
- uint32 hours, mins, secs, msecs;
- secs = timestamp / 1000;
- hours = secs / 3600;
- mins = (secs / 60) % 60;
- secs %= 60;
- msecs = timestamp % 1000;
- subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);
-
- if (_devParts.empty()) {
- _devParts.push_back(SubtitlePart("", ""));
- }
- _devParts[0].text = subtitle;
-
- parts = &_devParts;
- } else {
- return false;
- }
-
+bool Subtitles::recalculateBoundingBox() const {
int16 width = g_system->getOverlayWidth(),
height = g_system->getOverlayHeight();
@@ -421,9 +391,46 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
_realBBox.left = 0;
}
- force = true;
+ return true;
}
+ return false;
+}
+
+bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
+ const Common::Array<SubtitlePart> *parts;
+ bool isSFX = false;
+ if (_loaded) {
+ parts = _srtParser.getSubtitleParts(timestamp);
+ if (parts && !parts->empty()) {
+ isSFX = (*parts)[0].tag == "sfx";
+ }
+ } else if (_subtitleDev) {
+ // Force refresh
+ _parts = nullptr;
+
+ Common::String subtitle = _fname.toString('/');
+ uint32 hours, mins, secs, msecs;
+ secs = timestamp / 1000;
+ hours = secs / 3600;
+ mins = (secs / 60) % 60;
+ secs %= 60;
+ msecs = timestamp % 1000;
+ subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);
+
+ if (_devParts.empty()) {
+ _devParts.push_back(SubtitlePart("", ""));
+ }
+ _devParts[0].text = subtitle;
+
+ parts = &_devParts;
+ } else {
+ return false;
+ }
+
+ if (recalculateBoundingBox())
+ force = true;
+
if (!force && _overlayHasAlpha && parts == _parts)
return false;
diff --git a/video/subtitles.h b/video/subtitles.h
index 23c86abc1be..29c26b9d645 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -94,6 +94,7 @@ public:
bool isLoaded() const { return _loaded || _subtitleDev; }
private:
+ bool recalculateBoundingBox() const;
void renderSubtitle() const;
SRTParser _srtParser;
Commit: 6b09d6eb2bcbeae0587eb600707ac827723c3d6d
https://github.com/scummvm/scummvm/commit/6b09d6eb2bcbeae0587eb600707ac827723c3d6d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Allow overriding the Subtitles class for other types of subs
This will be used by the subtitle code in the M4 engine
Changed paths:
video/subtitles.h
diff --git a/video/subtitles.h b/video/subtitles.h
index 29c26b9d645..3eaf39a13de 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -93,32 +93,35 @@ public:
bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
bool isLoaded() const { return _loaded || _subtitleDev; }
-private:
+protected:
bool recalculateBoundingBox() const;
void renderSubtitle() const;
- SRTParser _srtParser;
bool _loaded;
- bool _subtitleDev;
bool _overlayHasAlpha;
+ mutable Graphics::Surface _surface;
+ mutable const Common::Array<SubtitlePart> *_parts;
+ mutable Common::Rect _drawRect;
+ mutable Common::Rect _realBBox;
+
+ uint32 _transparentColor;
+
+private:
+
+ SRTParser _srtParser;
+ bool _subtitleDev;
mutable Common::Array<SubtitlePart> _devParts;
Common::HashMap<int, const Graphics::Font *> _fonts;
int _fontHeight;
- mutable Graphics::Surface _surface;
-
- mutable Common::Rect _drawRect;
Common::Rect _requestedBBox;
- mutable Common::Rect _realBBox;
mutable int16 _lastOverlayWidth, _lastOverlayHeight;
Common::Path _fname;
- mutable const Common::Array<SubtitlePart> *_parts;
uint32 _color;
uint32 _blackColor;
- uint32 _transparentColor;
uint16 _hPad;
uint16 _vPad;
};
Commit: bb14821887d9522870dda714ae6bcbfed6df5c78
https://github.com/scummvm/scummvm/commit/bb14821887d9522870dda714ae6bcbfed6df5c78
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Extend the engine to support in-game subtitles
This is an enhancement over the original engine, which doesn't support
subtitles. Thus, to prevent possible issues with graphics rendering,
the ScummVM overlay layer is used to render subtitles.
The subtitle rendering feature uses the common subtitle code, and it
has been adapted from the subtitle code used in the private engine.
English subtitles have been generated using OpenAI's Whisper, and have
been stored into getText .POT Files. In the future, these subtitles
could also be translated to other languages, using Weblate.
Changed paths:
A engines/m4/subtitles.cpp
A engines/m4/subtitles.h
engines/m4/core/rooms.cpp
engines/m4/m4.cpp
engines/m4/m4.h
engines/m4/module.mk
engines/m4/platform/sound/digi.cpp
diff --git a/engines/m4/core/rooms.cpp b/engines/m4/core/rooms.cpp
index f7878bfb844..f311e8c6c54 100644
--- a/engines/m4/core/rooms.cpp
+++ b/engines/m4/core/rooms.cpp
@@ -328,6 +328,7 @@ void Sections::game_control_cycle() {
// Ensure the screen is updated
g_system->updateScreen();
g_system->delayMillis(10);
+ g_engine->updateSubtitleOverlay();
if (g_engine->shouldQuit())
_G(kernel).going = false;
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index 6838c03fd82..4bb57cc9a6d 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -51,6 +51,7 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc) : Engine(sy
}
M4Engine::~M4Engine() {
+ delete _subtitles;
}
void M4Engine::initializePath(const Common::FSNode &gamePath) {
@@ -89,6 +90,8 @@ Common::Error M4Engine::run() {
initGraphics(640, 480);
syncSoundSettings();
+ _subtitles = new M4Subtitles();
+
// Instantiate globals and setup
Vars *vars = createVars();
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 436c609da4d..d4cfdeade55 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -37,6 +37,7 @@
#include "m4/detection.h"
#include "m4/vars.h"
#include "m4/core/rooms.h"
+#include "m4/subtitles.h"
namespace M4 {
@@ -46,6 +47,7 @@ class M4Engine : public Engine, public Sections {
private:
const M4GameDescription *_gameDescription;
Common::RandomSource _randomSource;
+ M4Subtitles *_subtitles;
/**
* Main game loop
@@ -180,6 +182,18 @@ public:
* Show the engine information
*/
virtual void showEngineInfo() = 0;
+
+ void drawSubtitle(const Common::String &soundId) const {
+ _subtitles->drawSubtitle(soundId);
+ }
+
+ void clearSubtitle() const {
+ _subtitles->clearSubtitle();
+ }
+
+ void updateSubtitleOverlay() const {
+ _subtitles->updateSubtitleOverlay();
+ }
};
extern M4Engine *g_engine;
diff --git a/engines/m4/module.mk b/engines/m4/module.mk
index 8a79b3545c5..c7ec28cf33f 100644
--- a/engines/m4/module.mk
+++ b/engines/m4/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS = \
m4.o \
console.o \
metaengine.o \
+ subtitles.o \
vars.o \
adv_db_r/db_catalog.o \
adv_r/adv_background.o \
diff --git a/engines/m4/platform/sound/digi.cpp b/engines/m4/platform/sound/digi.cpp
index 38be5b66f31..cabdbe899d3 100644
--- a/engines/m4/platform/sound/digi.cpp
+++ b/engines/m4/platform/sound/digi.cpp
@@ -27,6 +27,7 @@
#include "m4/core/imath.h"
#include "m4/fileio/extensions.h"
#include "m4/vars.h"
+#include "m4/m4.h"
namespace M4 {
namespace Sound {
@@ -118,6 +119,9 @@ int32 Digi::play(const Common::String &name, uint channel, int32 vol, int32 trig
// Assure no prior sound for the channel is playing
stop(channel);
+ if (!loop)
+ g_engine->drawSubtitle(name);
+
// Load in the new sound
preload(name, false, room_num);
DigiEntry &entry = _sounds[name];
@@ -164,6 +168,7 @@ void Digi::stop(uint channel, bool calledFromUnload) {
_mixer->stopHandle(c._soundHandle);
c._trigger = -1;
c._name.clear();
+ g_engine->clearSubtitle();
if (!calledFromUnload) {
digi_unload(name);
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
new file mode 100644
index 00000000000..2d988590f0e
--- /dev/null
+++ b/engines/m4/subtitles.cpp
@@ -0,0 +1,153 @@
+/* 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 "common/file.h"
+#include "common/system.h"
+
+#include "m4/m4.h"
+#include "m4/subtitles.h"
+#include "m4/platform/sound/digi.h"
+
+namespace M4 {
+
+M4Subtitles::M4Subtitles() {
+ _loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
+ if (_loaded) {
+ setupSubtitles();
+ g_system->showOverlay(false);
+ }
+}
+
+M4Subtitles::~M4Subtitles() {
+ clearSubtitle();
+}
+
+void M4Subtitles::setupSubtitles() {
+ // Subtitle positioning constants (as percentages of screen height)
+ const int HORIZONTAL_MARGIN = 20;
+ const float BOTTOM_MARGIN_PERCENT = 0.009f; // ~20px at 2160p
+ const float DEFAULT_HEIGHT_PERCENT = IS_RIDDLE ? 0.2f : 0.26f; // ~432px at 2160p
+
+ // Font sizing constants (as percentage of screen height)
+ const int MIN_FONT_SIZE = 8;
+ const float BASE_FONT_SIZE_PERCENT = 0.023f; // ~50px at 2160p
+
+ int16 h = g_system->getOverlayHeight();
+ int16 w = g_system->getOverlayWidth();
+ int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
+
+ int bottomMargin = int(h * BOTTOM_MARGIN_PERCENT);
+
+ int topOffset = int(h * DEFAULT_HEIGHT_PERCENT);
+ setBBox(Common::Rect(HORIZONTAL_MARGIN,
+ h - topOffset,
+ w - HORIZONTAL_MARGIN,
+ h - bottomMargin));
+
+ setColor(0xff, 0xff, 0xff);
+ setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+}
+
+bool M4Subtitles::loadSubtitles(const Common::String &filename) {
+ Common::File inFile;
+ Common::String line;
+ Common::String lastComment;
+
+ if (!inFile.open(filename.c_str()))
+ return false;
+
+ while (!inFile.eos()) {
+ line = inFile.readLine();
+
+ if (line.hasPrefix("#: ")) {
+ lastComment = line.substr(3);
+ }
+
+ if (line.hasPrefix("msgid ") && !lastComment.empty()) {
+ _subtitles[lastComment] = line.substr(7, line.size() - 7 - 1); // Remove trailing "
+ }
+ }
+
+ inFile.close();
+
+ return true;
+}
+
+Common::String M4Subtitles::getSubtitle(const Common::String &audioFile) const {
+ if (!_loaded)
+ return "";
+
+ Common::String key = audioFile;
+ key.toUppercase();
+ return _subtitles.contains(key) ? _subtitles[key] : "";
+}
+
+bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
+ Common::String subtitle = getSubtitle(audioFile);
+ if (subtitle.empty())
+ return false;
+
+ Common::Array<Video::SubtitlePart> parts;
+ parts.push_back(Video::SubtitlePart(subtitle, ""));
+ _parts = &parts;
+
+ recalculateBoundingBox();
+ renderSubtitle();
+ _parts = nullptr;
+
+ g_system->showOverlay(false);
+ updateSubtitleOverlay();
+
+ return true;
+}
+
+void M4Subtitles::updateSubtitleOverlay() const {
+ if (!_loaded)
+ return;
+
+ if (!digi_play_state(1) && !digi_play_state(2)) {
+ // No subtitle to show
+ g_system->hideOverlay();
+ return;
+ } else {
+ if (!g_system->isOverlayVisible())
+ g_system->showOverlay(false);
+ }
+
+ if (_overlayHasAlpha) {
+ // When we have alpha, draw the whole surface without thinking it more
+ g_system->copyRectToOverlay(_surface.getPixels(), _surface.pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
+ } else {
+ // When overlay doesn't have alpha, showing it hides the underlying game screen
+ // We force a copy of the game screen to the overlay by clearing it
+ // We then draw the smallest possible surface to minimize black rectangle behind text
+ g_system->clearOverlay();
+ g_system->copyRectToOverlay((byte *)_surface.getPixels() + _drawRect.top * _surface.pitch + _drawRect.left * _surface.format.bytesPerPixel, _surface.pitch,
+ _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
+ }
+}
+
+void M4Subtitles::clearSubtitle() const {
+ g_system->hideOverlay();
+ _drawRect.setEmpty();
+ _surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
+}
+
+} // namespace M4
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
new file mode 100644
index 00000000000..8fec6ca333d
--- /dev/null
+++ b/engines/m4/subtitles.h
@@ -0,0 +1,49 @@
+/* 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 M4_SUBTITLES_H
+#define M4_SUBTITLES_H
+
+#include "common/hashmap.h"
+#include "video/subtitles.h"
+
+namespace M4 {
+
+class M4Subtitles : Video::Subtitles {
+public:
+ M4Subtitles();
+ ~M4Subtitles();
+
+ Common::String getSubtitle(const Common::String &audioFile) const;
+ bool drawSubtitle(const Common::String &audioFile) const;
+ void clearSubtitle() const;
+ void updateSubtitleOverlay() const;
+
+private:
+ void setupSubtitles();
+ bool loadSubtitles(const Common::String &filename);
+
+ Common::HashMap<Common::String, Common::String> _subtitles;
+};
+
+} // namespace M4
+
+#endif /* M4_SUBTITLES_H */
Commit: 82eac59fc57cbd4cca10cb3ae851e168104f76c5
https://github.com/scummvm/scummvm/commit/82eac59fc57cbd4cca10cb3ae851e168104f76c5
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Don't clear subtitles if they're not loaded
Changed paths:
engines/m4/subtitles.cpp
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index 2d988590f0e..f46ebdd9d57 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -145,6 +145,9 @@ void M4Subtitles::updateSubtitleOverlay() const {
}
void M4Subtitles::clearSubtitle() const {
+ if (!_loaded)
+ return;
+
g_system->hideOverlay();
_drawRect.setEmpty();
_surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
Commit: df746d3600203145d77a3c6135ae0c1991eaa4ba
https://github.com/scummvm/scummvm/commit/df746d3600203145d77a3c6135ae0c1991eaa4ba
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Only show subtitles when they're enabled in the game audio settings
Changed paths:
engines/m4/subtitles.cpp
engines/m4/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index f46ebdd9d57..a9d2ab6739f 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "common/config-manager.h"
#include "common/file.h"
#include "common/system.h"
@@ -29,6 +30,7 @@ namespace M4 {
M4Subtitles::M4Subtitles() {
_loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
+ _subtitlesEnabled = ConfMan.getBool("subtitles");
if (_loaded) {
setupSubtitles();
g_system->showOverlay(false);
@@ -91,15 +93,15 @@ bool M4Subtitles::loadSubtitles(const Common::String &filename) {
}
Common::String M4Subtitles::getSubtitle(const Common::String &audioFile) const {
- if (!_loaded)
- return "";
-
Common::String key = audioFile;
key.toUppercase();
return _subtitles.contains(key) ? _subtitles[key] : "";
}
bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
+ if (!_loaded || !_subtitlesEnabled)
+ return false;
+
Common::String subtitle = getSubtitle(audioFile);
if (subtitle.empty())
return false;
@@ -119,7 +121,7 @@ bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
}
void M4Subtitles::updateSubtitleOverlay() const {
- if (!_loaded)
+ if (!_loaded || !_subtitlesEnabled)
return;
if (!digi_play_state(1) && !digi_play_state(2)) {
@@ -145,7 +147,7 @@ void M4Subtitles::updateSubtitleOverlay() const {
}
void M4Subtitles::clearSubtitle() const {
- if (!_loaded)
+ if (!_loaded || !_subtitlesEnabled)
return;
g_system->hideOverlay();
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 8fec6ca333d..43627deadee 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -32,7 +32,6 @@ public:
M4Subtitles();
~M4Subtitles();
- Common::String getSubtitle(const Common::String &audioFile) const;
bool drawSubtitle(const Common::String &audioFile) const;
void clearSubtitle() const;
void updateSubtitleOverlay() const;
@@ -40,8 +39,10 @@ public:
private:
void setupSubtitles();
bool loadSubtitles(const Common::String &filename);
+ Common::String getSubtitle(const Common::String &audioFile) const;
Common::HashMap<Common::String, Common::String> _subtitles;
+ bool _subtitlesEnabled;
};
} // namespace M4
Commit: 9b14308cbb76819d7b385430798d47f5cd7165e3
https://github.com/scummvm/scummvm/commit/9b14308cbb76819d7b385430798d47f5cd7165e3
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Also clear the overlay when clearing subtitles
Fixes leftover content from screens that also use the overlay, e.g. the
save/load screen
Changed paths:
engines/m4/subtitles.cpp
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index a9d2ab6739f..d48f3161d1e 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -151,6 +151,7 @@ void M4Subtitles::clearSubtitle() const {
return;
g_system->hideOverlay();
+ g_system->clearOverlay();
_drawRect.setEmpty();
_surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
}
Commit: d005b2d84ddc8a9d3a07925f636f2996663ffc78
https://github.com/scummvm/scummvm/commit/d005b2d84ddc8a9d3a07925f636f2996663ffc78
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Clear the overlay before showing it, instead of when hiding it
Changed paths:
engines/m4/subtitles.cpp
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index d48f3161d1e..485ab5b58d4 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -31,10 +31,8 @@ namespace M4 {
M4Subtitles::M4Subtitles() {
_loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
_subtitlesEnabled = ConfMan.getBool("subtitles");
- if (_loaded) {
+ if (_loaded)
setupSubtitles();
- g_system->showOverlay(false);
- }
}
M4Subtitles::~M4Subtitles() {
@@ -114,7 +112,6 @@ bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
renderSubtitle();
_parts = nullptr;
- g_system->showOverlay(false);
updateSubtitleOverlay();
return true;
@@ -129,8 +126,10 @@ void M4Subtitles::updateSubtitleOverlay() const {
g_system->hideOverlay();
return;
} else {
- if (!g_system->isOverlayVisible())
+ if (!g_system->isOverlayVisible()) {
+ g_system->clearOverlay();
g_system->showOverlay(false);
+ }
}
if (_overlayHasAlpha) {
@@ -151,7 +150,6 @@ void M4Subtitles::clearSubtitle() const {
return;
g_system->hideOverlay();
- g_system->clearOverlay();
_drawRect.setEmpty();
_surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
}
Commit: 8c170537c9df6426d3c14f13f867ca632127e461
https://github.com/scummvm/scummvm/commit/8c170537c9df6426d3c14f13f867ca632127e461
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Simplify subtitle code
Changed paths:
video/subtitles.cpp
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index d9b1529e9b9..d1a74b48946 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -428,8 +428,7 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
return false;
}
- if (recalculateBoundingBox())
- force = true;
+ force |= recalculateBoundingBox();
if (!force && _overlayHasAlpha && parts == _parts)
return false;
Commit: 02b1e6ecf69ac9b33dd9fb160fc1e6c9cfe83a70
https://github.com/scummvm/scummvm/commit/02b1e6ecf69ac9b33dd9fb160fc1e6c9cfe83a70
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Remove unused return value
Changed paths:
engines/m4/subtitles.cpp
engines/m4/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index 485ab5b58d4..8cd3e3b5ecd 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -96,13 +96,13 @@ Common::String M4Subtitles::getSubtitle(const Common::String &audioFile) const {
return _subtitles.contains(key) ? _subtitles[key] : "";
}
-bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
+void M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
if (!_loaded || !_subtitlesEnabled)
- return false;
+ return;
Common::String subtitle = getSubtitle(audioFile);
if (subtitle.empty())
- return false;
+ return;
Common::Array<Video::SubtitlePart> parts;
parts.push_back(Video::SubtitlePart(subtitle, ""));
@@ -113,8 +113,6 @@ bool M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
_parts = nullptr;
updateSubtitleOverlay();
-
- return true;
}
void M4Subtitles::updateSubtitleOverlay() const {
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 43627deadee..863888fe7eb 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -32,7 +32,7 @@ public:
M4Subtitles();
~M4Subtitles();
- bool drawSubtitle(const Common::String &audioFile) const;
+ void drawSubtitle(const Common::String &audioFile) const;
void clearSubtitle() const;
void updateSubtitleOverlay() const;
Commit: d8db8fc917ce2fc198b9c52b4a8c07c2bdab27d7
https://github.com/scummvm/scummvm/commit/d8db8fc917ce2fc198b9c52b4a8c07c2bdab27d7
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Don't use a pointer for the subtitle instance
We create it on start and delete it on destruction, so a pointer isn't
needed
Changed paths:
engines/m4/m4.cpp
engines/m4/m4.h
engines/m4/subtitles.cpp
engines/m4/subtitles.h
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index 4bb57cc9a6d..37cb1725528 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -50,10 +50,6 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc) : Engine(sy
g_engine = this;
}
-M4Engine::~M4Engine() {
- delete _subtitles;
-}
-
void M4Engine::initializePath(const Common::FSNode &gamePath) {
Engine::initializePath(gamePath);
SearchMan.addSubDirectoryMatching(gamePath, "goodstuf");
@@ -90,7 +86,7 @@ Common::Error M4Engine::run() {
initGraphics(640, 480);
syncSoundSettings();
- _subtitles = new M4Subtitles();
+ _subtitles.load();
// Instantiate globals and setup
Vars *vars = createVars();
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index d4cfdeade55..cd0cd925489 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -47,7 +47,7 @@ class M4Engine : public Engine, public Sections {
private:
const M4GameDescription *_gameDescription;
Common::RandomSource _randomSource;
- M4Subtitles *_subtitles;
+ M4Subtitles _subtitles;
/**
* Main game loop
@@ -78,7 +78,7 @@ protected:
public:
M4Engine(OSystem *syst, const M4GameDescription *gameDesc);
- ~M4Engine() override;
+ ~M4Engine() override = default;
uint32 getFeatures() const;
@@ -184,15 +184,15 @@ public:
virtual void showEngineInfo() = 0;
void drawSubtitle(const Common::String &soundId) const {
- _subtitles->drawSubtitle(soundId);
+ _subtitles.drawSubtitle(soundId);
}
void clearSubtitle() const {
- _subtitles->clearSubtitle();
+ _subtitles.clearSubtitle();
}
void updateSubtitleOverlay() const {
- _subtitles->updateSubtitleOverlay();
+ _subtitles.updateSubtitleOverlay();
}
};
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index 8cd3e3b5ecd..f71077b95d1 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -29,16 +29,19 @@
namespace M4 {
M4Subtitles::M4Subtitles() {
- _loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
_subtitlesEnabled = ConfMan.getBool("subtitles");
- if (_loaded)
- setupSubtitles();
}
M4Subtitles::~M4Subtitles() {
clearSubtitle();
}
+void M4Subtitles::load() {
+ _loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
+ if (_loaded)
+ setupSubtitles();
+}
+
void M4Subtitles::setupSubtitles() {
// Subtitle positioning constants (as percentages of screen height)
const int HORIZONTAL_MARGIN = 20;
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 863888fe7eb..8aaf2f4248b 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -35,6 +35,7 @@ public:
void drawSubtitle(const Common::String &audioFile) const;
void clearSubtitle() const;
void updateSubtitleOverlay() const;
+ void load();
private:
void setupSubtitles();
Commit: b930babbd46c4b94670ca1506cd5b962ac38e982
https://github.com/scummvm/scummvm/commit/b930babbd46c4b94670ca1506cd5b962ac38e982
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Use a pointer for SRT parser in the Subtitles class
Overridden classes may not need it
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index d1a74b48946..5b284d4b95e 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -284,7 +284,9 @@ Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(tr
}
Subtitles::~Subtitles() {
+ close();
_surface.free();
+
for (const auto &font : _fonts) {
FontMan.mayDeleteFont(font._value);
}
@@ -331,10 +333,19 @@ void Subtitles::setFont(const char *fontname, int height, FontStyle type) {
void Subtitles::loadSRTFile(const Common::Path &fname) {
debug(1, "loadSRTFile('%s')", fname.toString().c_str());
- if (_subtitleDev) {
+ if (_subtitleDev)
_fname = fname;
- }
- _loaded = _srtParser.parseFile(fname);
+
+ _srtParser = new SRTParser();
+ _loaded = _srtParser->parseFile(fname);
+}
+
+void Subtitles::close() {
+ _loaded = false;
+ _parts = nullptr;
+ _fname.clear();
+ delete _srtParser;
+ _srtParser = nullptr;
}
void Subtitles::setBBox(const Common::Rect &bbox) {
@@ -400,8 +411,8 @@ bool Subtitles::recalculateBoundingBox() const {
bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
const Common::Array<SubtitlePart> *parts;
bool isSFX = false;
- if (_loaded) {
- parts = _srtParser.getSubtitleParts(timestamp);
+ if (_loaded && _srtParser) {
+ parts = _srtParser->getSubtitleParts(timestamp);
if (parts && !parts->empty()) {
isSFX = (*parts)[0].tag == "sfx";
}
diff --git a/video/subtitles.h b/video/subtitles.h
index 3eaf39a13de..ccb3042c615 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -85,7 +85,7 @@ public:
~Subtitles();
void loadSRTFile(const Common::Path &fname);
- void close() { _loaded = false; _parts = nullptr; _fname.clear(); _srtParser.cleanup(); }
+ void close();
void setFont(const char *fontname, int height = 18, FontStyle type = kFontStyleRegular);
void setBBox(const Common::Rect &bbox);
void setColor(byte r, byte g, byte b);
@@ -108,7 +108,7 @@ protected:
private:
- SRTParser _srtParser;
+ SRTParser *_srtParser = nullptr;
bool _subtitleDev;
mutable Common::Array<SubtitlePart> _devParts;
Commit: 99438dc7861dc31824b3f090025fcabc37df967c
https://github.com/scummvm/scummvm/commit/99438dc7861dc31824b3f090025fcabc37df967c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Allow toggling speech and subtitles
Now that we have subtitles for the supported M4 games, we can drop the
GUI_NOSPEECH flag from detection entries
Changed paths:
engines/m4/detection_tables.h
diff --git a/engines/m4/detection_tables.h b/engines/m4/detection_tables.h
index a173b5a7dc4..9da9f2e0ceb 100644
--- a/engines/m4/detection_tables.h
+++ b/engines/m4/detection_tables.h
@@ -37,7 +37,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesCD
@@ -50,7 +50,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::FR_FRA,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesCD
@@ -63,7 +63,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesCD
@@ -85,7 +85,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::RU_RUS,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesCD
@@ -98,7 +98,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesDemo
@@ -111,7 +111,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_DEMO,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesDemo
@@ -124,7 +124,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Burger,
kFeaturesNonInteractiveDemo
@@ -138,7 +138,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -151,7 +151,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -164,7 +164,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -177,7 +177,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::FR_FRA,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -190,7 +190,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -203,7 +203,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::IT_ITA,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesCD
@@ -216,7 +216,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesDemo
@@ -229,7 +229,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesDemo
@@ -245,7 +245,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesDemo
@@ -258,7 +258,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesDemo
@@ -271,7 +271,7 @@ static const M4GameDescription gameDescriptions[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GUIO_NOASPECT, GUIO_NOMUSIC, GUIO_NOSPEECH)
+ GUIO2(GUIO_NOASPECT, GUIO_NOMUSIC)
},
GType_Riddle,
kFeaturesDemo
Commit: af15f6266da54eff450e25037e872ea2bd980ba9
https://github.com/scummvm/scummvm/commit/af15f6266da54eff450e25037e872ea2bd980ba9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Move overlay manipulation code in the base Subtitles class
Changed paths:
engines/m4/subtitles.cpp
engines/m4/subtitles.h
video/subtitles.cpp
video/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index f71077b95d1..f4f5a9ea82c 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -118,41 +118,22 @@ void M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
updateSubtitleOverlay();
}
+bool M4Subtitles::shouldShowSubtitle() const {
+ return digi_play_state(1) || digi_play_state(2);
+}
+
void M4Subtitles::updateSubtitleOverlay() const {
- if (!_loaded || !_subtitlesEnabled)
+ if (!_subtitlesEnabled)
return;
- if (!digi_play_state(1) && !digi_play_state(2)) {
- // No subtitle to show
- g_system->hideOverlay();
- return;
- } else {
- if (!g_system->isOverlayVisible()) {
- g_system->clearOverlay();
- g_system->showOverlay(false);
- }
- }
-
- if (_overlayHasAlpha) {
- // When we have alpha, draw the whole surface without thinking it more
- g_system->copyRectToOverlay(_surface.getPixels(), _surface.pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
- } else {
- // When overlay doesn't have alpha, showing it hides the underlying game screen
- // We force a copy of the game screen to the overlay by clearing it
- // We then draw the smallest possible surface to minimize black rectangle behind text
- g_system->clearOverlay();
- g_system->copyRectToOverlay((byte *)_surface.getPixels() + _drawRect.top * _surface.pitch + _drawRect.left * _surface.format.bytesPerPixel, _surface.pitch,
- _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
- }
+ Subtitles::updateSubtitleOverlay();
}
void M4Subtitles::clearSubtitle() const {
- if (!_loaded || !_subtitlesEnabled)
+ if (!_subtitlesEnabled)
return;
- g_system->hideOverlay();
- _drawRect.setEmpty();
- _surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
+ Subtitles::clearSubtitle();
}
} // namespace M4
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 8aaf2f4248b..158c290fc4b 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -33,8 +33,9 @@ public:
~M4Subtitles();
void drawSubtitle(const Common::String &audioFile) const;
- void clearSubtitle() const;
- void updateSubtitleOverlay() const;
+ void clearSubtitle() const override;
+ void updateSubtitleOverlay() const override;
+ bool shouldShowSubtitle() const override;
void load();
private:
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 5b284d4b95e..912e1e0e05a 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -461,6 +461,34 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
renderSubtitle();
}
+ updateSubtitleOverlay();
+
+ return true;
+}
+
+void Subtitles::clearSubtitle() const {
+ if (!_loaded)
+ return;
+
+ g_system->hideOverlay();
+ _drawRect.setEmpty();
+ _surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
+}
+
+void Subtitles::updateSubtitleOverlay() const {
+ if (!_loaded)
+ return;
+
+ if (!shouldShowSubtitle()) {
+ g_system->hideOverlay();
+ return;
+ }
+
+ if (!g_system->isOverlayVisible()) {
+ g_system->clearOverlay();
+ g_system->showOverlay(false);
+ }
+
if (_overlayHasAlpha) {
// When we have alpha, draw the whole surface without thinking it more
g_system->copyRectToOverlay(_surface.getPixels(), _surface.pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
@@ -470,10 +498,8 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
// We then draw the smallest possible surface to minimize black rectangle behind text
g_system->clearOverlay();
g_system->copyRectToOverlay((byte *)_surface.getPixels() + _drawRect.top * _surface.pitch + _drawRect.left * _surface.format.bytesPerPixel, _surface.pitch,
- _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
+ _realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
}
-
- return true;
}
struct SubtitleRenderingPart {
diff --git a/video/subtitles.h b/video/subtitles.h
index ccb3042c615..d7620a9ca06 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -92,10 +92,13 @@ public:
void setPadding(uint16 horizontal, uint16 vertical);
bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
bool isLoaded() const { return _loaded || _subtitleDev; }
+ virtual void clearSubtitle() const;
protected:
bool recalculateBoundingBox() const;
void renderSubtitle() const;
+ virtual void updateSubtitleOverlay() const;
+ virtual bool shouldShowSubtitle() const { return true; }
bool _loaded;
bool _overlayHasAlpha;
Commit: 90f6e3d406861bd0668c7c8e7c95d6b7e5aeee27
https://github.com/scummvm/scummvm/commit/90f6e3d406861bd0668c7c8e7c95d6b7e5aeee27
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Store the number of split subtitle lines to be rendered
This is needed in cases where we need to displace the subtitle bounding
box, depending on the number of lines to be drawn
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 912e1e0e05a..c423fefba00 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -555,6 +555,8 @@ void Subtitles::renderSubtitle() const {
}
}
+ _splitPartCount = (uint16)splitParts.size();
+
// Then, center all lines and calculate the drawing box
auto lineBegin = splitParts.begin();
int minX = _realBBox.width();
diff --git a/video/subtitles.h b/video/subtitles.h
index d7620a9ca06..8d847b3a250 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -103,9 +103,10 @@ protected:
bool _loaded;
bool _overlayHasAlpha;
mutable Graphics::Surface _surface;
- mutable const Common::Array<SubtitlePart> *_parts;
+ mutable const Common::Array<SubtitlePart> *_parts = nullptr;
mutable Common::Rect _drawRect;
mutable Common::Rect _realBBox;
+ mutable uint16 _splitPartCount = 0;
uint32 _transparentColor;
Commit: bd18e39e998214b248897d82b349a39a984fa120
https://github.com/scummvm/scummvm/commit/bd18e39e998214b248897d82b349a39a984fa120
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Adapt the subtitle bounding box, depending on the lines drawn
This ensures that the subtitles won't be rendered on top of inventory
items, when a lot of subtitle text is shown
Changed paths:
engines/m4/subtitles.cpp
engines/m4/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index f4f5a9ea82c..e4109b7a5f9 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -48,10 +48,6 @@ void M4Subtitles::setupSubtitles() {
const float BOTTOM_MARGIN_PERCENT = 0.009f; // ~20px at 2160p
const float DEFAULT_HEIGHT_PERCENT = IS_RIDDLE ? 0.2f : 0.26f; // ~432px at 2160p
- // Font sizing constants (as percentage of screen height)
- const int MIN_FONT_SIZE = 8;
- const float BASE_FONT_SIZE_PERCENT = 0.023f; // ~50px at 2160p
-
int16 h = g_system->getOverlayHeight();
int16 w = g_system->getOverlayWidth();
int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
@@ -113,9 +109,16 @@ void M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
recalculateBoundingBox();
renderSubtitle();
+ _subtitleYOffset = nudgeSubtitle();
_parts = nullptr;
+}
+
+int16 M4Subtitles::nudgeSubtitle() const {
+ // Nudge subtitle text box upwards, depending on the lines to draw
+ int16 h = g_system->getOverlayHeight();
+ int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
- updateSubtitleOverlay();
+ return _splitPartCount > 0 ? static_cast<int16>((_splitPartCount - 1) * fontSize) : 0;
}
bool M4Subtitles::shouldShowSubtitle() const {
@@ -126,7 +129,9 @@ void M4Subtitles::updateSubtitleOverlay() const {
if (!_subtitlesEnabled)
return;
+ _realBBox.translate(0, -_subtitleYOffset);
Subtitles::updateSubtitleOverlay();
+ _realBBox.translate(0, _subtitleYOffset);
}
void M4Subtitles::clearSubtitle() const {
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 158c290fc4b..63a41354318 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -42,9 +42,15 @@ private:
void setupSubtitles();
bool loadSubtitles(const Common::String &filename);
Common::String getSubtitle(const Common::String &audioFile) const;
+ int16 nudgeSubtitle() const;
Common::HashMap<Common::String, Common::String> _subtitles;
bool _subtitlesEnabled;
+ mutable int16 _subtitleYOffset = 0;
+
+ // Font sizing constants (as percentage of screen height)
+ const int MIN_FONT_SIZE = 8;
+ const float BASE_FONT_SIZE_PERCENT = 0.023f; // ~50px at 2160p
};
} // namespace M4
Commit: c2055a85679517db3e919723dd9139a468557b6d
https://github.com/scummvm/scummvm/commit/c2055a85679517db3e919723dd9139a468557b6d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
VIDEO: Reduce scope of member variables in the base Subtitles class
Changed paths:
engines/m4/subtitles.cpp
video/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index e4109b7a5f9..2bbda8675f1 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -129,9 +129,9 @@ void M4Subtitles::updateSubtitleOverlay() const {
if (!_subtitlesEnabled)
return;
- _realBBox.translate(0, -_subtitleYOffset);
+ translateBBox(0, -_subtitleYOffset);
Subtitles::updateSubtitleOverlay();
- _realBBox.translate(0, _subtitleYOffset);
+ translateBBox(0, _subtitleYOffset);
}
void M4Subtitles::clearSubtitle() const {
diff --git a/video/subtitles.h b/video/subtitles.h
index 8d847b3a250..e6b671370ba 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -97,35 +97,35 @@ public:
protected:
bool recalculateBoundingBox() const;
void renderSubtitle() const;
+ void translateBBox(int16 dx, int16 dy) const { _realBBox.translate(dx, dy); }
virtual void updateSubtitleOverlay() const;
virtual bool shouldShowSubtitle() const { return true; }
bool _loaded;
- bool _overlayHasAlpha;
- mutable Graphics::Surface _surface;
mutable const Common::Array<SubtitlePart> *_parts = nullptr;
- mutable Common::Rect _drawRect;
- mutable Common::Rect _realBBox;
mutable uint16 _splitPartCount = 0;
- uint32 _transparentColor;
-
private:
-
SRTParser *_srtParser = nullptr;
bool _subtitleDev;
+ bool _overlayHasAlpha;
mutable Common::Array<SubtitlePart> _devParts;
Common::HashMap<int, const Graphics::Font *> _fonts;
int _fontHeight;
+ mutable Graphics::Surface _surface;
+
+ mutable Common::Rect _drawRect;
Common::Rect _requestedBBox;
+ mutable Common::Rect _realBBox;
mutable int16 _lastOverlayWidth, _lastOverlayHeight;
Common::Path _fname;
uint32 _color;
uint32 _blackColor;
+ uint32 _transparentColor;
uint16 _hPad;
uint16 _vPad;
};
Commit: e8bc9649cab1ef753f2202736c7ce3e86cb0f331
https://github.com/scummvm/scummvm/commit/e8bc9649cab1ef753f2202736c7ce3e86cb0f331
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
COMMON: Add helper methods to the TranslationManager
Added a method to get a translation from its index, as well as another
method to get a list of loaded contexts.
These are needed for the subtitle functionality in the M4 engine, to
create a mapping of the contexts (Which are the source audio files
in M4) with their respective translation entry.
Changed paths:
common/translation.cpp
common/translation.h
diff --git a/common/translation.cpp b/common/translation.cpp
index 900466157b2..483013356a6 100644
--- a/common/translation.cpp
+++ b/common/translation.cpp
@@ -163,6 +163,13 @@ U32String TranslationManager::getTranslation(const char *message, const char *co
return U32String(message);
}
+U32String TranslationManager::getTranslation(uint32 index) const {
+ if (index >= _currentTranslationMessages.size())
+ return U32String("");
+
+ return _currentTranslationMessages[index].msgstr.decode();
+}
+
String TranslationManager::getCurrentLanguage() const {
if (_currentLang == -1)
return "en";
@@ -181,6 +188,16 @@ U32String TranslationManager::getTranslation(const String &message, const String
return getTranslation(message.c_str(), context.c_str());
}
+const StringArray TranslationManager::getContexts() const {
+ StringArray contexts;
+
+ for (const auto &m : _currentTranslationMessages) {
+ contexts.push_back(m.msgctxt);
+ }
+
+ return contexts;
+}
+
const TLangArray TranslationManager::getSupportedLanguageNames() const {
TLangArray languages;
diff --git a/common/translation.h b/common/translation.h
index 5b2b6f80bce..4c756fa0825 100644
--- a/common/translation.h
+++ b/common/translation.h
@@ -174,6 +174,22 @@ public:
*/
U32String getTranslation(const String &message, const String &context) const;
+ /**
+ * Return the translation of the message with the given index into
+ * the current language.
+ *
+ * In case the index is out of bounds, return an empty message,
+ * as a U32String.
+ */
+ U32String getTranslation(uint32 index) const;
+
+ /**
+ * Return a list of all the loaded contexts.
+ *
+ * @return A list of all the loaded contexts.
+ */
+ const StringArray getContexts() const;
+
/**
* Return a list of supported languages.
*
Commit: 3159fa505b9b71164cdfa0d27076ff3e8701ac0e
https://github.com/scummvm/scummvm/commit/3159fa505b9b71164cdfa0d27076ff3e8701ac0e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-01-01T08:06:55+11:00
Commit Message:
M4: Use the translation manager to handle the subtitle functionality
This allows us to use translation packages, using the
create_translation tool, which supports multiple translations.
Changed paths:
engines/m4/subtitles.cpp
engines/m4/subtitles.h
diff --git a/engines/m4/subtitles.cpp b/engines/m4/subtitles.cpp
index 2bbda8675f1..74105729192 100644
--- a/engines/m4/subtitles.cpp
+++ b/engines/m4/subtitles.cpp
@@ -21,6 +21,7 @@
#include "common/config-manager.h"
#include "common/file.h"
#include "common/system.h"
+#include "common/translation.h"
#include "m4/m4.h"
#include "m4/subtitles.h"
@@ -37,7 +38,22 @@ M4Subtitles::~M4Subtitles() {
}
void M4Subtitles::load() {
- _loaded = loadSubtitles(IS_RIDDLE ? "riddle.pot" : "burger.pot");
+ Common::StringArray soundFiles;
+ uint32 index = 0;
+
+#ifdef USE_TRANSLATION
+ _transMan = new Common::TranslationManager(IS_RIDDLE ? "riddle_translations.dat" : "burger_translations.dat");
+ _transMan->setLanguage(TransMan.getCurrentLanguage());
+ soundFiles = _transMan->getContexts();
+
+ for (const auto &soundFile : soundFiles) {
+ Common::String key = soundFile;
+ key.toUppercase();
+ _subtitleIndices[key] = index++;
+ }
+#endif
+
+ _loaded = !soundFiles.empty();
if (_loaded)
setupSubtitles();
}
@@ -64,35 +80,17 @@ void M4Subtitles::setupSubtitles() {
setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
}
-bool M4Subtitles::loadSubtitles(const Common::String &filename) {
- Common::File inFile;
- Common::String line;
- Common::String lastComment;
-
- if (!inFile.open(filename.c_str()))
- return false;
-
- while (!inFile.eos()) {
- line = inFile.readLine();
-
- if (line.hasPrefix("#: ")) {
- lastComment = line.substr(3);
- }
-
- if (line.hasPrefix("msgid ") && !lastComment.empty()) {
- _subtitles[lastComment] = line.substr(7, line.size() - 7 - 1); // Remove trailing "
- }
- }
-
- inFile.close();
-
- return true;
-}
-
Common::String M4Subtitles::getSubtitle(const Common::String &audioFile) const {
+#ifdef USE_TRANSLATION
Common::String key = audioFile;
key.toUppercase();
- return _subtitles.contains(key) ? _subtitles[key] : "";
+
+ if (_subtitleIndices.contains(key)) {
+ return _transMan->getTranslation(_subtitleIndices[key]).encode();
+ }
+#endif
+
+ return "";
}
void M4Subtitles::drawSubtitle(const Common::String &audioFile) const {
diff --git a/engines/m4/subtitles.h b/engines/m4/subtitles.h
index 63a41354318..6b13f7e417b 100644
--- a/engines/m4/subtitles.h
+++ b/engines/m4/subtitles.h
@@ -25,6 +25,10 @@
#include "common/hashmap.h"
#include "video/subtitles.h"
+namespace Common {
+class TranslationManager;
+} // namespace Common
+
namespace M4 {
class M4Subtitles : Video::Subtitles {
@@ -40,17 +44,20 @@ public:
private:
void setupSubtitles();
- bool loadSubtitles(const Common::String &filename);
Common::String getSubtitle(const Common::String &audioFile) const;
int16 nudgeSubtitle() const;
- Common::HashMap<Common::String, Common::String> _subtitles;
+ Common::HashMap<Common::String, uint32> _subtitleIndices;
bool _subtitlesEnabled;
mutable int16 _subtitleYOffset = 0;
// Font sizing constants (as percentage of screen height)
const int MIN_FONT_SIZE = 8;
const float BASE_FONT_SIZE_PERCENT = 0.023f; // ~50px at 2160p
+
+#ifdef USE_TRANSLATION
+ Common::TranslationManager *_transMan = nullptr;
+#endif
};
} // namespace M4
More information about the Scummvm-git-logs
mailing list