[Scummvm-git-logs] scummvm master -> f2509c1836f4ab900941d2d8c083abda169d7007
whoozle
noreply at scummvm.org
Fri Jun 12 08:51:05 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f2509c1836 PHOENIXVR: Add subtitle support
Commit: f2509c1836f4ab900941d2d8c083abda169d7007
https://github.com/scummvm/scummvm/commit/f2509c1836f4ab900941d2d8c083abda169d7007
Author: Scorp (scorp at mrs.mn)
Date: 2026-06-12T09:50:33+01:00
Commit Message:
PHOENIXVR: Add subtitle support
Changed paths:
engines/phoenixvr/phoenixvr.cpp
engines/phoenixvr/phoenixvr.h
diff --git a/engines/phoenixvr/phoenixvr.cpp b/engines/phoenixvr/phoenixvr.cpp
index 58672d84f74..cc0623bbf3c 100644
--- a/engines/phoenixvr/phoenixvr.cpp
+++ b/engines/phoenixvr/phoenixvr.cpp
@@ -26,6 +26,7 @@
#include "common/config-manager.h"
#include "common/events.h"
#include "common/file.h"
+#include "common/language.h"
#include "common/memstream.h"
#include "common/savefile.h"
#include "common/scummsys.h"
@@ -50,6 +51,7 @@
#include "phoenixvr/vr.h"
#include "video/4xm_decoder.h"
#include "video/smk_decoder.h"
+#include "video/subtitles.h"
namespace PhoenixVR {
@@ -589,6 +591,7 @@ void PhoenixVREngine::until(const Common::String &var, int value) {
// Delay for a bit. All events loops should have a delay
// to prevent the system being unduly loaded
_frameLimiter.delayBeforeSwap();
+ drawAudioSubtitles();
_screen->update();
frameDuration = _frameLimiter.startFrame();
}
@@ -620,6 +623,7 @@ void PhoenixVREngine::wait(float seconds) {
// Delay for a bit. All events loops should have a delay
// to prevent the system being unduly loaded
_frameLimiter.delayBeforeSwap();
+ drawAudioSubtitles();
_screen->update();
frameDuration = _frameLimiter.startFrame();
}
@@ -751,7 +755,11 @@ void PhoenixVREngine::playSound(const Common::String &sound, Audio::Mixer::Sound
_mixer->playStream(type, &h, Audio::makeWAVStream(stream.release(), DisposeAfterUse::YES), -1, volume);
if (loops < 0 || music)
_mixer->loopChannel(h);
- _sounds[sound] = Sound{h, spatial, angle, volume, loops};
+ Common::SharedPtr<Video::Subtitles> subtitles;
+ if (!music)
+ subtitles = loadSubtitles(sound);
+
+ _sounds[sound] = Sound{h, spatial, angle, volume, loops, subtitles};
}
void PhoenixVREngine::stopSound(const Common::String &sound) {
@@ -761,6 +769,8 @@ void PhoenixVREngine::stopSound(const Common::String &sound) {
auto it = _sounds.find(sound);
if (it != _sounds.end()) {
_mixer->stopHandle(it->_value.handle);
+ if (it->_value.subtitles)
+ it->_value.subtitles->clearSubtitle();
_sounds.erase(it);
}
}
@@ -768,9 +778,64 @@ void PhoenixVREngine::stopSound(const Common::String &sound) {
void PhoenixVREngine::stopAllSounds() {
_mixer->stopAll();
_currentMusic.clear();
+ for (auto &kv : _sounds) {
+ if (kv._value.subtitles)
+ kv._value.subtitles->clearSubtitle();
+ }
_sounds.clear();
}
+Common::Path PhoenixVREngine::getSubtitlePath(const Common::String &path) const {
+ Common::Path assetPath(removeDrive(path), '\\');
+ Common::String filename = assetPath.toString('/') + ".srt";
+ filename.replace('/', '_');
+ filename.replace('\\', '_');
+
+ Common::String language = Common::getLanguageCode(_gameDescription->language);
+ if (language == "us")
+ language = "en";
+
+ return Common::Path("subtitle").appendComponent(language).appendComponent(filename);
+}
+
+Common::SharedPtr<Video::Subtitles> PhoenixVREngine::loadSubtitles(const Common::String &path) const {
+ Common::SharedPtr<Video::Subtitles> subtitles;
+ if (!ConfMan.getBool("subtitles"))
+ return subtitles;
+
+ subtitles = Common::SharedPtr<Video::Subtitles>(new Video::Subtitles());
+ subtitles->loadSRTFile(getSubtitlePath(path));
+ if (!subtitles->isLoaded())
+ return Common::SharedPtr<Video::Subtitles>();
+
+ setupSubtitles(*subtitles);
+ return subtitles;
+}
+
+void PhoenixVREngine::setupSubtitles(Video::Subtitles &subtitles) const {
+ // Subtitle positioning constants (as percentages of screen height)
+ const int HORIZONTAL_MARGIN = 20;
+ const int MIN_BOTTOM_MARGIN = 4;
+ const int MIN_SUBTITLE_HEIGHT = 90;
+ const float BOTTOM_MARGIN_PERCENT = 0.01f;
+ const float SUBTITLE_HEIGHT_PERCENT = 0.2f;
+
+ // Font sizing constants (as percentage of screen height)
+ const int MIN_FONT_SIZE = 18;
+ const float BASE_FONT_SIZE_PERCENT = 1.0f / 36.0f;
+
+ int16 h = g_system->getOverlayHeight();
+ int16 w = g_system->getOverlayWidth();
+ int bottomMargin = MAX<int>(MIN_BOTTOM_MARGIN, int(h * BOTTOM_MARGIN_PERCENT));
+ int topOffset = MAX<int>(MIN_SUBTITLE_HEIGHT, int(h * SUBTITLE_HEIGHT_PERCENT));
+ int fontSize = MAX<int>(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
+
+ subtitles.setBBox(Common::Rect(HORIZONTAL_MARGIN, h - topOffset, w - HORIZONTAL_MARGIN, h - bottomMargin));
+ subtitles.setColor(0xff, 0xff, 0x80);
+ subtitles.setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ subtitles.setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
+}
+
void PhoenixVREngine::playMovie(const Common::String &movie) {
debug("playMovie %s", movie.c_str());
Common::ScopedPtr<Video::VideoDecoder> dec;
@@ -797,6 +862,12 @@ void PhoenixVREngine::playMovie(const Common::String &movie) {
_system->lockMouse(false);
dec->start();
+ Common::SharedPtr<Video::Subtitles> subtitles = loadSubtitles(movie);
+ if (subtitles) {
+ g_system->showOverlay(false);
+ g_system->clearOverlay();
+ }
+
bool playing = true;
Common::ScopedPtr<Graphics::Palette> palette;
while (!shouldQuit() && playing && !dec->endOfVideo()) {
@@ -828,9 +899,13 @@ void PhoenixVREngine::playMovie(const Common::String &movie) {
// Delay for a bit. All events loops should have a delay
// to prevent the system being unduly loaded
_frameLimiter.delayBeforeSwap();
+ if (subtitles && !dec->isPaused())
+ subtitles->drawSubtitle(dec->getTime(), false);
_screen->update();
_frameLimiter.startFrame();
}
+ if (subtitles)
+ g_system->hideOverlay();
_system->lockMouse(_vr.isVR());
_mixer->pauseAll(false);
}
@@ -1134,7 +1209,12 @@ void PhoenixVREngine::tick(float dt) {
}
for (auto &sound : finishedSounds) {
debug("sound %s stopped", sound.c_str());
- _sounds.erase(sound);
+ auto it = _sounds.find(sound);
+ if (it != _sounds.end()) {
+ if (it->_value.subtitles)
+ it->_value.subtitles->clearSubtitle();
+ _sounds.erase(it);
+ }
}
if (!_nextScript.empty()) {
@@ -1227,6 +1307,17 @@ void PhoenixVREngine::tick(float dt) {
}
}
+void PhoenixVREngine::drawAudioSubtitles() {
+ if (!ConfMan.getBool("subtitles"))
+ return;
+
+ for (auto &kv : _sounds) {
+ auto &sound = kv._value;
+ if (sound.subtitles && _mixer->isSoundHandleActive(sound.handle))
+ sound.subtitles->drawSubtitle(_mixer->getElapsedTime(sound.handle).msecs(), false);
+ }
+}
+
Common::Error PhoenixVREngine::run() {
initGraphics(640, 480, nullptr);
@@ -1426,6 +1517,7 @@ Common::Error PhoenixVREngine::run() {
// Delay for a bit. All events loops should have a delay
// to prevent the system being unduly loaded
_frameLimiter.delayBeforeSwap();
+ drawAudioSubtitles();
_screen->update();
frameDuration = _frameLimiter.startFrame();
}
diff --git a/engines/phoenixvr/phoenixvr.h b/engines/phoenixvr/phoenixvr.h
index 0860fe659c2..8261d67ac50 100644
--- a/engines/phoenixvr/phoenixvr.h
+++ b/engines/phoenixvr/phoenixvr.h
@@ -27,6 +27,7 @@
#include "common/fs.h"
#include "common/hash-str.h"
#include "common/keyboard.h"
+#include "common/ptr.h"
#include "common/random.h"
#include "common/scummsys.h"
#include "common/serializer.h"
@@ -48,6 +49,10 @@ namespace Graphics {
class Font;
}
+namespace Video {
+class Subtitles;
+}
+
namespace PhoenixVR {
class ARN;
@@ -96,6 +101,7 @@ public:
bool hasFeature(EngineFeature f) const override {
return (f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsSubtitleOptions) ||
(f == kSupportsReturnToLauncher);
};
@@ -217,6 +223,10 @@ private:
void renderFade(int color);
void resetState();
const Graphics::Font *getFont(int size, bool bold) const;
+ Common::Path getSubtitlePath(const Common::String &path) const;
+ Common::SharedPtr<Video::Subtitles> loadSubtitles(const Common::String &path) const;
+ void setupSubtitles(Video::Subtitles &subtitles) const;
+ void drawAudioSubtitles();
private:
bool _hasFocus = true;
@@ -244,6 +254,7 @@ private:
float angle;
uint8 volume;
int loops;
+ Common::SharedPtr<Video::Subtitles> subtitles;
};
Common::HashMap<Common::String, Sound, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _sounds;
Common::ScopedPtr<Script> _script;
More information about the Scummvm-git-logs
mailing list