[Scummvm-git-logs] scummvm master -> 6cb386374e337e0f87d98e6b48724ce1931107c3
neuromancer
noreply at scummvm.org
Sat Jan 31 19:31:46 UTC 2026
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
50f5468286 PRIVATE: fix subtitle in the main menu.
149f5a98ca VIDEO: add static isSfxFile helper + getter for SRT entries.
31100bbc04 PRIVATE: fix SFX subtitles interrupting dialogues.
638319e7ea PRIVATE: fix sound priority order.
2022b9c5a8 PRIVATE: refactor to use two slot approach.
6cb386374e PRIVATE: refactor isSfx().
Commit: 50f54682860d66ae3e42a4f65f8bfdab30dac1b2
https://github.com/scummvm/scummvm/commit/50f54682860d66ae3e42a4f65f8bfdab30dac1b2
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
PRIVATE: fix subtitle in the main menu.
previously, if a dialogue is being played while we are in the main menu and in between that dialogue we click quit the scummvm overlay shows up and if we click cancel there the current playing dialogue's subtitles won't come back, the subtitles will come back in the next dialogue, this commit fixes that by ensuring that even if we don't have a video decoder but a subtitled sound is playing we redraw the subtitles.
Changed paths:
engines/private/private.cpp
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index a54d8974761..ba9131eec73 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -2966,6 +2966,9 @@ void PrivateEngine::pauseEngineIntern(bool pause) {
// automatically, so we don't need to pass 'true'.
adjustSubtitleSize();
_subtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
+ } else if (_subtitledSound && isSoundPlaying(*_subtitledSound)) {
+ adjustSubtitleSize();
+ _subtitles->drawSubtitle(_mixer->getElapsedTime(_subtitledSound->handle).msecs(), false, _sfxSubtitles);
}
}
}
Commit: 149f5a98ca49b7a675fe2f4b3c21461629eb5f6c
https://github.com/scummvm/scummvm/commit/149f5a98ca49b7a675fe2f4b3c21461629eb5f6c
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
VIDEO: add static isSfxFile helper + getter for SRT entries.
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index c423fefba00..e4bc68732fd 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -466,6 +466,28 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
return true;
}
+bool Subtitles::isSfxFile(const Common::Path &fname) {
+ // create a temporary parser
+ SRTParser parser;
+
+ // try to parse the file
+ if (!parser.parseFile(fname))
+ return false; // file doesn't exist or is invalid we assume it's not a sfx
+
+ // get the entries
+ const Common::Array<SRTEntry *> &entries = parser.getEntries();
+
+ // since the function SRTParser::parseTextAndTags reads text from left to right, if the line starts immediately
+ // with the <sfx> tag, it will always be the first item in the list
+ // so, we don't have to search the whole array
+ if (!entries.empty() && !entries[0]->parts.empty()) {
+ if (entries[0]->parts[0].tag == "sfx") {
+ return true;
+ }
+ }
+ return false;
+}
+
void Subtitles::clearSubtitle() const {
if (!_loaded)
return;
diff --git a/video/subtitles.h b/video/subtitles.h
index 056da15bf73..7c34636867a 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -69,6 +69,7 @@ public:
bool parseFile(const Common::Path &fname);
void parseTextAndTags(const Common::String &text, Common::Array<SubtitlePart> &parts) const;
const Common::Array<SubtitlePart> *getSubtitleParts(uint32 timestamp) const;
+ const Common::Array<SRTEntry *> &getEntries() const { return _entries; }
private:
Common::Array<SRTEntry *> _entries;
@@ -91,6 +92,7 @@ public:
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
+ static bool isSfxFile(const Common::Path &fname);
bool isLoaded() const { return _loaded || _subtitleDev; }
virtual void clearSubtitle() const;
Commit: 31100bbc041ac89da805dd865e0497f76bd7850f
https://github.com/scummvm/scummvm/commit/31100bbc041ac89da805dd865e0497f76bd7850f
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
PRIVATE: fix SFX subtitles interrupting dialogues.
added getSubtitlePath() helper, so that both loadSubtitles and isSfxFile can use the same path without repeating code, updated playSound() to check if a file exists and if it is an SFX file, added a hashmap to cache if a file is sfx or not to avoid parsing the file path at every check.
Changed paths:
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index ba9131eec73..c23ca342dde 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -2359,7 +2359,15 @@ void PrivateEngine::playSound(Sound &sound, const Common::String &name, bool loo
_mixer->stopHandle(sound.handle);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &sound.handle, stream, -1, Audio::Mixer::kMaxChannelVolume);
- loadSubtitles(path, &sound);
+ bool shouldLoad = true;
+ if (_subtitledSound && isSoundPlaying(*_subtitledSound)) {
+ // if current is speech and new is sfx, block it
+ // speech gets priority over sound effects
+ if (!isSfx(_subtitledSound->name) && isSfx(name))
+ shouldLoad = false;
+ }
+
+ if (shouldLoad) loadSubtitles(path, &sound);
}
void PrivateEngine::stopForegroundSounds() {
@@ -2491,21 +2499,46 @@ void PrivateEngine::adjustSubtitleSize() {
}
}
-void PrivateEngine::loadSubtitles(const Common::Path &path, Sound *sound) {
- debugC(1, kPrivateDebugFunction, "%s(%s)", __FUNCTION__, path.toString().c_str());
- if (!_useSubtitles)
- return;
+bool PrivateEngine::isSfx(const Common::String &filename) {
+ if (_sfxCache.contains(filename))
+ return _sfxCache[filename];
+ Common::Path path = getSubtitlePath(filename);
+
+ // check the file content
+ bool result = Video::Subtitles::isSfxFile(path);
+ // update cache
+ _sfxCache[filename] = result;
+
+ return result;
+}
+
+Common::Path PrivateEngine::getSubtitlePath(const Common::String &soundName) {
+ // call convertPath to fix slashes, make lowercase etc.
+ Common::Path path = convertPath(soundName);
+ // add extension and replace '/' with '_' (audio/file -> audio_file)
Common::String subPathStr = path.toString() + ".srt";
- subPathStr.toLowercase();
subPathStr.replace('/', '_');
+
+ // get language code
Common::String language(Common::getLanguageCode(_language));
if (language == "us")
language = "en";
+ // construct full path: subtitles/language/subPathStr
Common::Path subPath = "subtitles";
subPath = subPath.appendComponent(language);
subPath = subPath.appendComponent(subPathStr);
+
+ return subPath;
+}
+
+void PrivateEngine::loadSubtitles(const Common::Path &path, Sound *sound) {
+ debugC(1, kPrivateDebugFunction, "%s(%s)", __FUNCTION__, path.toString().c_str());
+ if (!_useSubtitles)
+ return;
+
+ Common::Path subPath = getSubtitlePath(path.toString());
debugC(1, kPrivateDebugFunction, "Loading subtitles from %s", subPath.toString().c_str());
destroySubtitles();
diff --git a/engines/private/private.h b/engines/private/private.h
index ff48d62ea88..ccbd33abe53 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -236,6 +236,11 @@ private:
Graphics::PixelFormat _pixelFormat;
Image::ImageDecoder *_image;
int _screenW, _screenH;
+ // cache to store if a sound is sfx or not to avoid repeated parsing
+ Common::HashMap<Common::String, bool> _sfxCache;
+
+ // helper to generate the correct subtitle path
+ Common::Path getSubtitlePath(const Common::String &soundName);
public:
bool _shouldHighlightMasks;
@@ -305,6 +310,7 @@ public:
void loadSubtitles(const Common::Path &path, Sound *sound = nullptr);
void destroySubtitles();
void adjustSubtitleSize();
+ bool isSfx(const Common::String &filename);
Video::Subtitles *_subtitles;
Sound *_subtitledSound;
bool _useSubtitles;
Commit: 638319e7eaecfb22e26dbf087759730315cde602
https://github.com/scummvm/scummvm/commit/638319e7eaecfb22e26dbf087759730315cde602
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
PRIVATE: fix sound priority order.
previously, only one sound could be loaded at a time which made it difficult to check if a sound is a sfx or speech because we had to parse it twice once to check then once to load, this commit adds an array to handle active subtitles for each sound handle and one for video subtitles.
Changed paths:
engines/private/private.cpp
engines/private/private.h
video/subtitles.cpp
video/subtitles.h
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index c23ca342dde..e72c1eaae47 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -55,7 +55,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
: Engine(syst), _gameDescription(gd), _image(nullptr), _videoDecoder(nullptr),
_compositeSurface(nullptr), _transparentColor(0), _frameImage(nullptr),
_framePalette(nullptr),
- _subtitles(nullptr), _subtitledSound(nullptr), _sfxSubtitles(false), _useSubtitles(false),
+ _videoSubtitles(nullptr), _sfxSubtitles(false), _useSubtitles(false),
_defaultCursor(nullptr),
_screenW(640), _screenH(480) {
_highlightMasks = false;
@@ -131,6 +131,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
PrivateEngine::~PrivateEngine() {
destroyVideo();
+ destroySubtitles();
delete _compositeSurface;
if (_frameImage != nullptr) {
@@ -501,17 +502,7 @@ Common::Error PrivateEngine::run() {
_system->updateScreen();
_system->delayMillis(10);
- if (_subtitles != nullptr) {
- if (_subtitledSound != nullptr && isSoundPlaying(*_subtitledSound)) {
- _subtitles->drawSubtitle(_mixer->getElapsedTime(_subtitledSound->handle).msecs(), false, _sfxSubtitles);
- }
- /* Only destroy subtitles if we are not playing a video.
- If _videoDecoder is valid (even if paused), we must keep the subtitles
- in memory so they are available when the video resumes. */
- else if (_videoDecoder == nullptr) {
- destroySubtitles();
- }
- }
+ updateSubtitles();
}
return Common::kNoError;
}
@@ -907,7 +898,7 @@ void PrivateEngine::selectPauseGame(Common::Point mousePos) {
_pausedVideo = _videoDecoder;
_pausedMovieName = _currentMovie;
}
- if (_subtitles) {
+ if (_videoSubtitles || !_activeSubtitles.empty()) {
_system->hideOverlay();
}
@@ -960,14 +951,31 @@ void PrivateEngine::resumeGame() {
// the screen was likely wiped by the pause menu
// to account for the subtitle which was already rendered and we wiped the screen before it finished we must
// force the subtitle system to ignore its cache and redraw the text.
- if (_subtitles) {
+ // calling adjustSubtitleSize() makes the next drawSubtitle call perform a full redraw
+ // automatically, so we don't need to pass 'true'
+ adjustSubtitleSize();
+ if (_videoSubtitles || !_activeSubtitles.empty()) {
_system->showOverlay(false);
_system->clearOverlay();
- // calling adjustSubtitleSize() makes the next drawSubtitle call perform a full redraw
- // automatically, so we don't need to pass 'true'
- adjustSubtitleSize();
- if (_videoDecoder)
- _subtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
+
+ // redraw video subtitles
+ if (_videoDecoder && _videoSubtitles)
+ _videoSubtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
+
+ bool speechPlaying = isSpeechActive();
+ // draw all remaining active subtitles
+ // (later entries draw on top of earlier ones)
+ for (const auto &entry : _activeSubtitles) {
+
+ // if this is an sfx subtitle, and speech is currently playing, skip drawing it
+ // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
+ if (entry.isSfx && speechPlaying)
+ continue;
+
+ // otherwise, draw it using the current time
+ uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
+ entry.subs->drawSubtitle(time, false, _sfxSubtitles);
+ }
}
}
@@ -2359,15 +2367,7 @@ void PrivateEngine::playSound(Sound &sound, const Common::String &name, bool loo
_mixer->stopHandle(sound.handle);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &sound.handle, stream, -1, Audio::Mixer::kMaxChannelVolume);
- bool shouldLoad = true;
- if (_subtitledSound && isSoundPlaying(*_subtitledSound)) {
- // if current is speech and new is sfx, block it
- // speech gets priority over sound effects
- if (!isSfx(_subtitledSound->name) && isSfx(name))
- shouldLoad = false;
- }
-
- if (shouldLoad) loadSubtitles(path, &sound);
+ loadSubtitles(path, &sound);
}
void PrivateEngine::stopForegroundSounds() {
@@ -2398,16 +2398,22 @@ bool PrivateEngine::isSoundPlaying(Sound &sound) {
return _mixer->isSoundHandleActive(sound.handle);
}
+bool PrivateEngine::isSpeechActive() {
+ for (const auto &entry : _activeSubtitles) {
+ // a sound is speech if it is not marked as sfx
+ // we also ensure the sound handle is actually still playing in the mixer
+ if (!entry.isSfx && _mixer->isSoundHandleActive(entry.subtitledSound.handle))
+ return true;
+ }
+ return false;
+}
+
void PrivateEngine::waitForSoundsToStop() {
while (isSoundPlaying()) {
// since this is a blocking wait loop, the main engine loop in run() is not called until this loop finishes
// we must manually update and draw subtitles here otherwise sounds
// played via fSyncSound will play audio but show no subtitles.
- if (_subtitles != nullptr) {
- if (_subtitledSound != nullptr && isSoundPlaying(*_subtitledSound)) {
- _subtitles->drawSubtitle(_mixer->getElapsedTime(_subtitledSound->handle).msecs(), false, _sfxSubtitles);
- }
- }
+ updateSubtitles();
if (consumeEvents()) {
stopSounds();
return;
@@ -2454,62 +2460,53 @@ bool PrivateEngine::consumeEvents() {
void PrivateEngine::adjustSubtitleSize() {
debugC(1, kPrivateDebugFunction, "%s()", __FUNCTION__);
- if (_subtitles) {
- // 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 MAIN_MENU_HEIGHT_PERCENT = 0.093f; // ~200px at 2160p
- const float ALTERNATE_MODE_HEIGHT_PERCENT = 0.102f; // ~220px at 2160p
- const float DEFAULT_HEIGHT_PERCENT = 0.074f; // ~160px 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 = _system->getOverlayHeight();
- int16 w = _system->getOverlayWidth();
-
- int bottomMargin = int(h * BOTTOM_MARGIN_PERCENT);
-
- // If we are in the main menu, we need to adjust the position of the subtitles
- if (_mode == 0) {
- int topOffset = int(h * MAIN_MENU_HEIGHT_PERCENT);
- _subtitles->setBBox(Common::Rect(HORIZONTAL_MARGIN,
- h - topOffset,
- w - HORIZONTAL_MARGIN,
- h - bottomMargin));
- } else if (_mode == -1) {
- int topOffset = int(h * ALTERNATE_MODE_HEIGHT_PERCENT);
- _subtitles->setBBox(Common::Rect(HORIZONTAL_MARGIN,
- h - topOffset,
- w - HORIZONTAL_MARGIN,
- h - bottomMargin));
- } else {
- int topOffset = int(h * DEFAULT_HEIGHT_PERCENT);
- _subtitles->setBBox(Common::Rect(HORIZONTAL_MARGIN,
- h - topOffset,
- w - HORIZONTAL_MARGIN,
- h - bottomMargin));
- }
-
- int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
- _subtitles->setColor(0xff, 0xff, 0x80);
- _subtitles->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
- _subtitles->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
+ if (!_videoSubtitles && _activeSubtitles.empty()) return;
+ // calculate layout first then apply to both active sounds and video subtitled sound
+ // 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 MAIN_MENU_HEIGHT_PERCENT = 0.093f; // ~200px at 2160p
+ const float ALTERNATE_MODE_HEIGHT_PERCENT = 0.102f; // ~220px at 2160p
+ const float DEFAULT_HEIGHT_PERCENT = 0.074f; // ~160px 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 = _system->getOverlayHeight();
+ int16 w = _system->getOverlayWidth();
+
+ int bottomMargin = int(h * BOTTOM_MARGIN_PERCENT);
+ int topOffset = 0;
+
+ // If we are in the main menu, we need to adjust the position of the subtitles
+ if (_mode == 0) {
+ topOffset = int(h * MAIN_MENU_HEIGHT_PERCENT);
+ } else if (_mode == -1) {
+ topOffset = int(h * ALTERNATE_MODE_HEIGHT_PERCENT);
+ } else {
+ topOffset = int(h * DEFAULT_HEIGHT_PERCENT);
}
-}
-
-bool PrivateEngine::isSfx(const Common::String &filename) {
- if (_sfxCache.contains(filename))
- return _sfxCache[filename];
- Common::Path path = getSubtitlePath(filename);
+ Common::Rect rect(HORIZONTAL_MARGIN, h - topOffset, w - HORIZONTAL_MARGIN, h - bottomMargin);
+ int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
- // check the file content
- bool result = Video::Subtitles::isSfxFile(path);
- // update cache
- _sfxCache[filename] = result;
+ // apply to video subtitles
+ if (_videoSubtitles) {
+ _videoSubtitles->setBBox(rect);
+ _videoSubtitles->setColor(0xff, 0xff, 0x80);
+ _videoSubtitles->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ _videoSubtitles->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
+ }
- return result;
+ // apply to all active audio aubtitles
+ for (auto &entry : _activeSubtitles) {
+ if (entry.subs) {
+ entry.subs->setBBox(rect);
+ entry.subs->setColor(0xff, 0xff, 0x80);
+ entry.subs->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ entry.subs->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
+ }
+ }
}
Common::Path PrivateEngine::getSubtitlePath(const Common::String &soundName) {
@@ -2541,30 +2538,79 @@ void PrivateEngine::loadSubtitles(const Common::Path &path, Sound *sound) {
Common::Path subPath = getSubtitlePath(path.toString());
debugC(1, kPrivateDebugFunction, "Loading subtitles from %s", subPath.toString().c_str());
- destroySubtitles();
+ // instantiate and load on heap once
+ Video::Subtitles *newSub = new Video::Subtitles();
+ newSub->loadSRTFile(subPath);
- _subtitles = new Video::Subtitles();
- _subtitles->loadSRTFile(subPath);
- if (!_subtitles->isLoaded()) {
- delete _subtitles;
- _subtitles = nullptr;
+ // if the subtitle failed loading we should return
+ if (!newSub->isLoaded()) {
+ delete newSub;
return;
}
+ bool isSfx = newSub->isSfx();
+ if (sound) {
+ // we do not check priority here and we do not delete any loaded sounds if they have low priority
+ // we simply store it, the active list acts as our cache
+ // updateSubtitles will decide if it should be visible
+ ActiveSubtitle entry;
+ entry.subtitledSound = *sound;
+ entry.subs = newSub;
+ entry.isSfx = isSfx;
+ _activeSubtitles.push_back(entry);
+ } else {
+ // if sound is null, we assume this is for the video decoder
+ if (_videoSubtitles)
+ delete _videoSubtitles;
+ _videoSubtitles = newSub;
+ }
+ // we skip clearing the overlay because updateSubtitle() handles it in the main loop
+ // if we clear here as well then minor flickering occurs
+ adjustSubtitleSize();
+}
- _subtitledSound = sound;
+void PrivateEngine::updateSubtitles() {
+ if (!_useSubtitles)
+ return;
- _system->showOverlay(false);
- _system->clearOverlay();
- adjustSubtitleSize();
+ // remove subtitles for sounds that finished playing
+ auto it = _activeSubtitles.begin();
+ while (it != _activeSubtitles.end()) {
+ if (!_mixer->isSoundHandleActive(it->subtitledSound.handle)) {
+ delete it->subs;
+ it = _activeSubtitles.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ bool speechPlaying = isSpeechActive();
+
+ // draw all remaining active subtitles
+ // (later entries draw on top of earlier ones)
+ for (const auto &entry : _activeSubtitles) {
+
+ // if this is an sfx subtitle, and speech is currently playing, skip drawing it
+ // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
+ if (entry.isSfx && speechPlaying)
+ continue;
+
+ // otherwise, draw it using the current time
+ uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
+ entry.subs->drawSubtitle(time, false, _sfxSubtitles);
+ }
}
void PrivateEngine::destroySubtitles() {
- if (_subtitles != nullptr) {
- delete _subtitles;
- _subtitles = nullptr;
- _system->hideOverlay();
- _subtitledSound = nullptr;
+ for (auto &entry : _activeSubtitles)
+ delete entry.subs;
+
+ _activeSubtitles.clear();
+
+ if (_videoSubtitles) {
+ delete _videoSubtitles;
+ _videoSubtitles = nullptr;
}
+ _system->hideOverlay();
}
void PrivateEngine::playVideo(const Common::String &name) {
@@ -2975,9 +3021,10 @@ void PrivateEngine::drawScreen() {
_system->copyRectToScreen(sa.getPixels(), sa.pitch, _origin.x, _origin.y, sa.w, sa.h);
}
- if (_subtitles && _videoDecoder && !_videoDecoder->isPaused()) {
- _subtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
- }
+ // audio subtitles are handled in updateSubtitles() in the main loop so only draw video subtitles here
+ if (_videoSubtitles && _videoDecoder && !_videoDecoder->isPaused())
+ _videoSubtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
+
_system->updateScreen();
}
@@ -2985,7 +3032,7 @@ void PrivateEngine::pauseEngineIntern(bool pause) {
Engine::pauseEngineIntern(pause);
// If we are unpausing (returning from quit dialog, etc.)
- if (!pause && _subtitles) {
+ if (!pause) {
// reset the overlay
_system->showOverlay(false);
_system->clearOverlay();
@@ -2994,14 +3041,27 @@ void PrivateEngine::pauseEngineIntern(bool pause) {
// the screen was likely wiped by the dialog/menu
// to account for the subtitle which was already rendered and we wiped the screen before it finished we must
// force the subtitle system to ignore its cache and redraw the text.
- if (_videoDecoder) {
- // calling adjustSubtitleSize() makes the next drawSubtitle call perform a full redraw
- // automatically, so we don't need to pass 'true'.
- adjustSubtitleSize();
- _subtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
- } else if (_subtitledSound && isSoundPlaying(*_subtitledSound)) {
- adjustSubtitleSize();
- _subtitles->drawSubtitle(_mixer->getElapsedTime(_subtitledSound->handle).msecs(), false, _sfxSubtitles);
+ // calling adjustSubtitleSize() makes the next drawSubtitle call perform a full redraw
+ // automatically, so we don't need to pass 'true'.
+ adjustSubtitleSize();
+ if (_videoDecoder && _videoSubtitles)
+ _videoSubtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
+
+ bool speechPlaying = isSpeechActive();
+ // draw all remaining active subtitles
+ // (later entries draw on top of earlier ones)
+ for (const auto &entry : _activeSubtitles) {
+
+ // if this is an sfx subtitle, and speech is currently playing, skip drawing it
+ // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
+ if (entry.isSfx && speechPlaying)
+ continue;
+
+ // otherwise, draw it using the current time
+ if (entry.subs && _mixer->isSoundHandleActive(entry.subtitledSound.handle)) {
+ uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
+ entry.subs->drawSubtitle(time, false, _sfxSubtitles);
+ }
}
}
}
diff --git a/engines/private/private.h b/engines/private/private.h
index ccbd33abe53..18b2e3a38b7 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -229,6 +229,13 @@ typedef Common::Array<DiaryPage> DiaryPages;
typedef Common::HashMap<Common::String, bool> PlayedMediaTable;
+struct ActiveSubtitle {
+ Sound subtitledSound;
+ Video::Subtitles *subs;
+ bool isSfx;
+
+ ActiveSubtitle() : subs(nullptr), isSfx(false) {}
+};
class PrivateEngine : public Engine {
private:
@@ -236,8 +243,6 @@ private:
Graphics::PixelFormat _pixelFormat;
Image::ImageDecoder *_image;
int _screenW, _screenH;
- // cache to store if a sound is sfx or not to avoid repeated parsing
- Common::HashMap<Common::String, bool> _sfxCache;
// helper to generate the correct subtitle path
Common::Path getSubtitlePath(const Common::String &soundName);
@@ -308,11 +313,13 @@ public:
void destroyVideo();
void loadSubtitles(const Common::Path &path, Sound *sound = nullptr);
+ // use to clean up sounds which have finished playing once
+ void updateSubtitles();
void destroySubtitles();
void adjustSubtitleSize();
- bool isSfx(const Common::String &filename);
- Video::Subtitles *_subtitles;
- Sound *_subtitledSound;
+ Video::Subtitles *_videoSubtitles;
+ // list of subtitles attached to sound effects/speech this will allow multiple subtitles to be loaded without losing already loaded one
+ Common::List<ActiveSubtitle> _activeSubtitles;
bool _useSubtitles;
bool _sfxSubtitles;
@@ -460,6 +467,7 @@ public:
void stopSound(Sound &sound);
bool isSoundPlaying();
bool isSoundPlaying(Sound &sound);
+ bool isSpeechActive();
void waitForSoundsToStop();
bool consumeEvents();
Sound _bgSound;
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index e4bc68732fd..c5dc1045a47 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -466,23 +466,12 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
return true;
}
-bool Subtitles::isSfxFile(const Common::Path &fname) {
- // create a temporary parser
- SRTParser parser;
-
- // try to parse the file
- if (!parser.parseFile(fname))
- return false; // file doesn't exist or is invalid we assume it's not a sfx
-
- // get the entries
- const Common::Array<SRTEntry *> &entries = parser.getEntries();
-
- // since the function SRTParser::parseTextAndTags reads text from left to right, if the line starts immediately
- // with the <sfx> tag, it will always be the first item in the list
- // so, we don't have to search the whole array
- if (!entries.empty() && !entries[0]->parts.empty()) {
- if (entries[0]->parts[0].tag == "sfx") {
- return true;
+bool Subtitles::isSfx() const {
+ if (_srtParser) {
+ const Common::Array<SRTEntry *> &entries = _srtParser->getEntries();
+ if (!entries.empty() && !entries[0]->parts.empty()) {
+ if (entries[0]->parts[0].tag == "sfx")
+ return true;
}
}
return false;
diff --git a/video/subtitles.h b/video/subtitles.h
index 7c34636867a..62bd6ff8a5b 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -92,7 +92,7 @@ public:
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
- static bool isSfxFile(const Common::Path &fname);
+ bool isSfx() const;
bool isLoaded() const { return _loaded || _subtitleDev; }
virtual void clearSubtitle() const;
Commit: 2022b9c5a8ecc8aa6284dd17ffaa3dceeaebdba7
https://github.com/scummvm/scummvm/commit/2022b9c5a8ecc8aa6284dd17ffaa3dceeaebdba7
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
PRIVATE: refactor to use two slot approach.
Changed paths:
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index e72c1eaae47..45c82bcee1c 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -880,6 +880,16 @@ const char *PrivateEngine::getSymbolName(const char *name, const char *strippedN
return strippedName;
}
+bool PrivateEngine::isSlotActive(const SubtitleSlot &slot) {
+ return slot.subs != nullptr && _mixer->isSoundHandleActive(slot.handle);
+}
+
+bool PrivateEngine::isSfxSubtitle(const Video::Subtitles *subs) {
+ if (!subs)
+ return false;
+ return subs->isSfx();
+}
+
void PrivateEngine::selectPauseGame(Common::Point mousePos) {
if (_mode == 1) {
uint32 tol = 15;
@@ -898,7 +908,7 @@ void PrivateEngine::selectPauseGame(Common::Point mousePos) {
_pausedVideo = _videoDecoder;
_pausedMovieName = _currentMovie;
}
- if (_videoSubtitles || !_activeSubtitles.empty()) {
+ if (_videoSubtitles || _voiceSlot.subs || _sfxSlot.subs) {
_system->hideOverlay();
}
@@ -935,7 +945,7 @@ void PrivateEngine::resumeGame() {
// we do this unconditionally because the casebook might have loaded
// different subtitles while we were paused
if (!_currentMovie.empty()) {
- loadSubtitles(convertPath(_currentMovie));
+ loadSubtitles(convertPath(_currentMovie), kSubtitleVideo);
}
if (_videoDecoder) {
@@ -954,7 +964,7 @@ void PrivateEngine::resumeGame() {
// calling adjustSubtitleSize() makes the next drawSubtitle call perform a full redraw
// automatically, so we don't need to pass 'true'
adjustSubtitleSize();
- if (_videoSubtitles || !_activeSubtitles.empty()) {
+ if (_videoSubtitles || _voiceSlot.subs || _sfxSlot.subs) {
_system->showOverlay(false);
_system->clearOverlay();
@@ -962,19 +972,13 @@ void PrivateEngine::resumeGame() {
if (_videoDecoder && _videoSubtitles)
_videoSubtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
- bool speechPlaying = isSpeechActive();
// draw all remaining active subtitles
- // (later entries draw on top of earlier ones)
- for (const auto &entry : _activeSubtitles) {
-
- // if this is an sfx subtitle, and speech is currently playing, skip drawing it
- // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
- if (entry.isSfx && speechPlaying)
- continue;
-
- // otherwise, draw it using the current time
- uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
- entry.subs->drawSubtitle(time, false, _sfxSubtitles);
+ if (isSlotActive(_voiceSlot)) {
+ uint32 time = _mixer->getElapsedTime(_voiceSlot.handle).msecs();
+ _voiceSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
+ } else if (isSlotActive(_sfxSlot)) {
+ uint32 time = _mixer->getElapsedTime(_sfxSlot.handle).msecs();
+ _sfxSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
}
}
}
@@ -2367,7 +2371,7 @@ void PrivateEngine::playSound(Sound &sound, const Common::String &name, bool loo
_mixer->stopHandle(sound.handle);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &sound.handle, stream, -1, Audio::Mixer::kMaxChannelVolume);
- loadSubtitles(path, &sound);
+ loadSubtitles(path, kSubtitleAudio, &sound);
}
void PrivateEngine::stopForegroundSounds() {
@@ -2387,6 +2391,14 @@ void PrivateEngine::stopSounds() {
void PrivateEngine::stopSound(Sound &sound) {
_mixer->stopHandle(sound.handle);
+ if (_voiceSlot.handle == sound.handle && _voiceSlot.subs) {
+ delete _voiceSlot.subs;
+ _voiceSlot.subs = nullptr;
+ }
+ if (_sfxSlot.handle == sound.handle && _sfxSlot.subs) {
+ delete _sfxSlot.subs;
+ _sfxSlot.subs = nullptr;
+ }
sound.name.clear();
}
@@ -2398,16 +2410,6 @@ bool PrivateEngine::isSoundPlaying(Sound &sound) {
return _mixer->isSoundHandleActive(sound.handle);
}
-bool PrivateEngine::isSpeechActive() {
- for (const auto &entry : _activeSubtitles) {
- // a sound is speech if it is not marked as sfx
- // we also ensure the sound handle is actually still playing in the mixer
- if (!entry.isSfx && _mixer->isSoundHandleActive(entry.subtitledSound.handle))
- return true;
- }
- return false;
-}
-
void PrivateEngine::waitForSoundsToStop() {
while (isSoundPlaying()) {
// since this is a blocking wait loop, the main engine loop in run() is not called until this loop finishes
@@ -2460,7 +2462,7 @@ bool PrivateEngine::consumeEvents() {
void PrivateEngine::adjustSubtitleSize() {
debugC(1, kPrivateDebugFunction, "%s()", __FUNCTION__);
- if (!_videoSubtitles && _activeSubtitles.empty()) return;
+ if (!_videoSubtitles && !_voiceSlot.subs && !_sfxSlot.subs) return;
// calculate layout first then apply to both active sounds and video subtitled sound
// Subtitle positioning constants (as percentages of screen height)
const int HORIZONTAL_MARGIN = 20;
@@ -2498,14 +2500,18 @@ void PrivateEngine::adjustSubtitleSize() {
_videoSubtitles->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
}
- // apply to all active audio aubtitles
- for (auto &entry : _activeSubtitles) {
- if (entry.subs) {
- entry.subs->setBBox(rect);
- entry.subs->setColor(0xff, 0xff, 0x80);
- entry.subs->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
- entry.subs->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
- }
+ // apply to all active audio subtitles
+ if (_voiceSlot.subs) {
+ _voiceSlot.subs->setBBox(rect);
+ _voiceSlot.subs->setColor(0xff, 0xff, 0x80);
+ _voiceSlot.subs->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ _voiceSlot.subs->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
+ }
+ if (_sfxSlot.subs) {
+ _sfxSlot.subs->setBBox(rect);
+ _sfxSlot.subs->setColor(0xff, 0xff, 0x80);
+ _sfxSlot.subs->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ _sfxSlot.subs->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
}
}
@@ -2530,7 +2536,7 @@ Common::Path PrivateEngine::getSubtitlePath(const Common::String &soundName) {
return subPath;
}
-void PrivateEngine::loadSubtitles(const Common::Path &path, Sound *sound) {
+void PrivateEngine::loadSubtitles(const Common::Path &path, SubtitleType type, Sound *sound) {
debugC(1, kPrivateDebugFunction, "%s(%s)", __FUNCTION__, path.toString().c_str());
if (!_useSubtitles)
return;
@@ -2547,22 +2553,43 @@ void PrivateEngine::loadSubtitles(const Common::Path &path, Sound *sound) {
delete newSub;
return;
}
- bool isSfx = newSub->isSfx();
- if (sound) {
- // we do not check priority here and we do not delete any loaded sounds if they have low priority
- // we simply store it, the active list acts as our cache
- // updateSubtitles will decide if it should be visible
- ActiveSubtitle entry;
- entry.subtitledSound = *sound;
- entry.subs = newSub;
- entry.isSfx = isSfx;
- _activeSubtitles.push_back(entry);
- } else {
- // if sound is null, we assume this is for the video decoder
+ if (type == kSubtitleVideo) {
if (_videoSubtitles)
delete _videoSubtitles;
_videoSubtitles = newSub;
}
+ else if (type == kSubtitleAudio) {
+ if (!sound) {
+ warning("PrivateEngine::loadSubtitles: Audio type requested but no Sound provided");
+ delete newSub;
+ return;
+ }
+
+ bool isSfx = isSfxSubtitle(newSub);
+
+ if (isSfx) {
+ // if voice is currently playing, ignore incoming sfx
+ if (isSlotActive(_voiceSlot)) {
+ delete newSub;
+ return;
+ }
+
+ // load sfx (overwrites any previous sfx)
+ if (_sfxSlot.subs)
+ delete _sfxSlot.subs;
+
+ _sfxSlot.handle = sound->handle;
+ _sfxSlot.subs = newSub;
+
+ } else {
+ // voice always loads and takes priority
+ if (_voiceSlot.subs)
+ delete _voiceSlot.subs;
+
+ _voiceSlot.handle = sound->handle;
+ _voiceSlot.subs = newSub;
+ }
+ }
// we skip clearing the overlay because updateSubtitle() handles it in the main loop
// if we clear here as well then minor flickering occurs
adjustSubtitleSize();
@@ -2573,39 +2600,36 @@ void PrivateEngine::updateSubtitles() {
return;
// remove subtitles for sounds that finished playing
- auto it = _activeSubtitles.begin();
- while (it != _activeSubtitles.end()) {
- if (!_mixer->isSoundHandleActive(it->subtitledSound.handle)) {
- delete it->subs;
- it = _activeSubtitles.erase(it);
- } else {
- it++;
- }
+ if (_voiceSlot.subs && !_mixer->isSoundHandleActive(_voiceSlot.handle)) {
+ delete _voiceSlot.subs;
+ _voiceSlot.subs = nullptr;
}
- bool speechPlaying = isSpeechActive();
-
- // draw all remaining active subtitles
- // (later entries draw on top of earlier ones)
- for (const auto &entry : _activeSubtitles) {
-
- // if this is an sfx subtitle, and speech is currently playing, skip drawing it
- // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
- if (entry.isSfx && speechPlaying)
- continue;
+ if (_sfxSlot.subs && !_mixer->isSoundHandleActive(_sfxSlot.handle)) {
+ delete _sfxSlot.subs;
+ _sfxSlot.subs = nullptr;
+ }
- // otherwise, draw it using the current time
- uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
- entry.subs->drawSubtitle(time, false, _sfxSubtitles);
+ if (_voiceSlot.subs) {
+ // if voice is active draw voice only
+ uint32 time = _mixer->getElapsedTime(_voiceSlot.handle).msecs();
+ _voiceSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
+ } else if (_sfxSlot.subs) {
+ // if voice is empty draw sfx
+ uint32 time = _mixer->getElapsedTime(_sfxSlot.handle).msecs();
+ _sfxSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
}
}
void PrivateEngine::destroySubtitles() {
- for (auto &entry : _activeSubtitles)
- delete entry.subs;
-
- _activeSubtitles.clear();
-
+ if (_voiceSlot.subs) {
+ delete _voiceSlot.subs;
+ _voiceSlot.subs = nullptr;
+ }
+ if (_sfxSlot.subs) {
+ delete _sfxSlot.subs;
+ _sfxSlot.subs = nullptr;
+ }
if (_videoSubtitles) {
delete _videoSubtitles;
_videoSubtitles = nullptr;
@@ -2625,7 +2649,7 @@ void PrivateEngine::playVideo(const Common::String &name) {
if (!_videoDecoder->loadStream(file))
error("unable to load video %s", path.toString().c_str());
- loadSubtitles(path);
+ loadSubtitles(path, kSubtitleVideo);
_videoDecoder->start();
// set the view screen based on the video, unless playing from diary
@@ -3047,21 +3071,13 @@ void PrivateEngine::pauseEngineIntern(bool pause) {
if (_videoDecoder && _videoSubtitles)
_videoSubtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
- bool speechPlaying = isSpeechActive();
// draw all remaining active subtitles
- // (later entries draw on top of earlier ones)
- for (const auto &entry : _activeSubtitles) {
-
- // if this is an sfx subtitle, and speech is currently playing, skip drawing it
- // the subtitle stays in the list (in memory), but is not drawn this frame because a speech is playing
- if (entry.isSfx && speechPlaying)
- continue;
-
- // otherwise, draw it using the current time
- if (entry.subs && _mixer->isSoundHandleActive(entry.subtitledSound.handle)) {
- uint32 time = _mixer->getElapsedTime(entry.subtitledSound.handle).msecs();
- entry.subs->drawSubtitle(time, false, _sfxSubtitles);
- }
+ if (isSlotActive(_voiceSlot)) {
+ uint32 time = _mixer->getElapsedTime(_voiceSlot.handle).msecs();
+ _voiceSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
+ } else if (isSlotActive(_sfxSlot)) {
+ uint32 time = _mixer->getElapsedTime(_sfxSlot.handle).msecs();
+ _sfxSlot.subs->drawSubtitle(time, false, _sfxSubtitles);
}
}
}
diff --git a/engines/private/private.h b/engines/private/private.h
index 18b2e3a38b7..d9f25a3c236 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -229,12 +229,16 @@ typedef Common::Array<DiaryPage> DiaryPages;
typedef Common::HashMap<Common::String, bool> PlayedMediaTable;
-struct ActiveSubtitle {
- Sound subtitledSound;
+enum SubtitleType {
+ kSubtitleAudio,
+ kSubtitleVideo
+};
+
+struct SubtitleSlot {
+ Audio::SoundHandle handle;
Video::Subtitles *subs;
- bool isSfx;
- ActiveSubtitle() : subs(nullptr), isSfx(false) {}
+ SubtitleSlot() : subs(nullptr) {}
};
class PrivateEngine : public Engine {
@@ -247,6 +251,9 @@ private:
// helper to generate the correct subtitle path
Common::Path getSubtitlePath(const Common::String &soundName);
+ bool isSfxSubtitle(const Video::Subtitles *subs);
+ bool isSlotActive(const SubtitleSlot &slot);
+
public:
bool _shouldHighlightMasks;
bool _highlightMasks;
@@ -312,14 +319,14 @@ public:
void skipVideo();
void destroyVideo();
- void loadSubtitles(const Common::Path &path, Sound *sound = nullptr);
+ void loadSubtitles(const Common::Path &path, SubtitleType type, Sound *sound = nullptr);
// use to clean up sounds which have finished playing once
void updateSubtitles();
void destroySubtitles();
void adjustSubtitleSize();
Video::Subtitles *_videoSubtitles;
- // list of subtitles attached to sound effects/speech this will allow multiple subtitles to be loaded without losing already loaded one
- Common::List<ActiveSubtitle> _activeSubtitles;
+ SubtitleSlot _voiceSlot; // high priority (speech)
+ SubtitleSlot _sfxSlot; // low priority (sfxs)
bool _useSubtitles;
bool _sfxSubtitles;
@@ -467,7 +474,6 @@ public:
void stopSound(Sound &sound);
bool isSoundPlaying();
bool isSoundPlaying(Sound &sound);
- bool isSpeechActive();
void waitForSoundsToStop();
bool consumeEvents();
Sound _bgSound;
Commit: 6cb386374e337e0f87d98e6b48724ce1931107c3
https://github.com/scummvm/scummvm/commit/6cb386374e337e0f87d98e6b48724ce1931107c3
Author: dhruv (dhruvranger97 at gmail.com)
Date: 2026-01-31T20:31:41+01:00
Commit Message:
PRIVATE: refactor isSfx().
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index c5dc1045a47..1266b03b399 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -276,6 +276,13 @@ const Common::Array<SubtitlePart> *SRTParser::getSubtitleParts(uint32 timestamp)
return &(*entry)->parts;
}
+bool SRTParser::isSfx() const {
+ if (_entries.empty() || _entries[0]->parts.empty())
+ return false;
+
+ return _entries[0]->parts[0].tag == "sfx";
+}
+
#define SHADOW 1
Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(true),
@@ -466,17 +473,6 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
return true;
}
-bool Subtitles::isSfx() const {
- if (_srtParser) {
- const Common::Array<SRTEntry *> &entries = _srtParser->getEntries();
- if (!entries.empty() && !entries[0]->parts.empty()) {
- if (entries[0]->parts[0].tag == "sfx")
- return true;
- }
- }
- return false;
-}
-
void Subtitles::clearSubtitle() const {
if (!_loaded)
return;
diff --git a/video/subtitles.h b/video/subtitles.h
index 62bd6ff8a5b..c47d162c445 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -69,7 +69,7 @@ public:
bool parseFile(const Common::Path &fname);
void parseTextAndTags(const Common::String &text, Common::Array<SubtitlePart> &parts) const;
const Common::Array<SubtitlePart> *getSubtitleParts(uint32 timestamp) const;
- const Common::Array<SRTEntry *> &getEntries() const { return _entries; }
+ bool isSfx() const;
private:
Common::Array<SRTEntry *> _entries;
@@ -92,7 +92,11 @@ public:
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
- bool isSfx() const;
+ bool isSfx() const {
+ if (!_srtParser)
+ return false;
+ return _srtParser->isSfx();
+ }
bool isLoaded() const { return _loaded || _subtitleDev; }
virtual void clearSubtitle() const;
More information about the Scummvm-git-logs
mailing list