[Scummvm-git-logs] scummvm master -> 73d2d99ad61cfa926ea60d63b19955ffc6a96b45
Scorpeg
noreply at scummvm.org
Sun Oct 4 15:12:26 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:
73d2d99ad6 PHOENIXVR: Better subtitle handling
Commit: 73d2d99ad61cfa926ea60d63b19955ffc6a96b45
https://github.com/scummvm/scummvm/commit/73d2d99ad61cfa926ea60d63b19955ffc6a96b45
Author: Scorp (scorp at mrs.mn)
Date: 2026-10-04T18:12:13+03:00
Commit Message:
PHOENIXVR: Better subtitle handling
Changed paths:
A engines/phoenixvr/subtitles.cpp
A engines/phoenixvr/subtitles.h
engines/phoenixvr/credits.pl
engines/phoenixvr/module.mk
engines/phoenixvr/phoenixvr.cpp
engines/phoenixvr/phoenixvr.h
diff --git a/engines/phoenixvr/credits.pl b/engines/phoenixvr/credits.pl
index bfdcc50b4ba..d37790df65a 100644
--- a/engines/phoenixvr/credits.pl
+++ b/engines/phoenixvr/credits.pl
@@ -1,5 +1,5 @@
begin_section("PhoenixVR");
add_person("Vladimir Menshakov", "whoozle", "");
- add_person("Hermann Noll", "Helco", "Help with 3D VR projections");
add_person("", "Scorp", "Dracula 1/2 and Messenger support, Engine improvements");
+ add_person("Hermann Noll", "Helco", "Help with 3D VR projections");
end_section();
diff --git a/engines/phoenixvr/module.mk b/engines/phoenixvr/module.mk
index 6d3ef3e84ff..16bd09064e3 100644
--- a/engines/phoenixvr/module.mk
+++ b/engines/phoenixvr/module.mk
@@ -16,6 +16,7 @@ MODULE_OBJS = \
script.o \
script_v1.o \
script_v2.o \
+ subtitles.o \
variables.o \
vr.o
diff --git a/engines/phoenixvr/phoenixvr.cpp b/engines/phoenixvr/phoenixvr.cpp
index 8c77f56f0b6..c784f3ca99e 100644
--- a/engines/phoenixvr/phoenixvr.cpp
+++ b/engines/phoenixvr/phoenixvr.cpp
@@ -51,10 +51,10 @@
#include "phoenixvr/pakf.h"
#include "phoenixvr/region_set.h"
#include "phoenixvr/script.h"
+#include "phoenixvr/subtitles.h"
#include "phoenixvr/vr.h"
#include "video/4xm_decoder.h"
#include "video/smk_decoder.h"
-#include "video/subtitles.h"
namespace PhoenixVR {
@@ -946,7 +946,7 @@ void PhoenixVREngine::playSound(const Common::String &sound, Audio::Mixer::Sound
_mixer->playStream(type, &h, Audio::makeWAVStream(stream.release(), DisposeAfterUse::YES), -1, volume, spatial ? 0 : panToBalance(_globalPan));
if (loops < 0 || music)
_mixer->loopChannel(h);
- Common::SharedPtr<Video::Subtitles> subtitles;
+ Common::SharedPtr<Subtitles> subtitles;
if (!music)
subtitles = loadSubtitles(sound);
@@ -1001,21 +1001,21 @@ Common::Path PhoenixVREngine::getSubtitlePath(const Common::String &path) const
return Common::Path("subtitle").appendComponent(language).appendComponent(filename);
}
-Common::SharedPtr<Video::Subtitles> PhoenixVREngine::loadSubtitles(const Common::String &path) const {
- Common::SharedPtr<Video::Subtitles> subtitles;
+Common::SharedPtr<Subtitles> PhoenixVREngine::loadSubtitles(const Common::String &path) const {
+ Common::SharedPtr<Subtitles> subtitles;
if (!ConfMan.getBool("subtitles"))
return subtitles;
- subtitles = Common::SharedPtr<Video::Subtitles>(new Video::Subtitles());
+ subtitles = Common::SharedPtr<Subtitles>(new Subtitles(_screen));
subtitles->loadSRTFile(getSubtitlePath(path));
if (!subtitles->isLoaded())
- return Common::SharedPtr<Video::Subtitles>();
+ return Common::SharedPtr<Subtitles>();
setupSubtitles(*subtitles);
return subtitles;
}
-void PhoenixVREngine::setupSubtitles(Video::Subtitles &subtitles) const {
+void PhoenixVREngine::setupSubtitles(Subtitles &subtitles) const {
// Subtitle positioning constants (as percentages of screen height)
const int HORIZONTAL_MARGIN = 20;
const int MIN_BOTTOM_MARGIN = 4;
@@ -1024,19 +1024,19 @@ void PhoenixVREngine::setupSubtitles(Video::Subtitles &subtitles) const {
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;
+ const int MIN_FONT_SIZE = 16;
+ const float BASE_FONT_SIZE_PERCENT = 1.0f / 48.0f;
- int16 h = g_system->getOverlayHeight();
- int16 w = g_system->getOverlayWidth();
+ int16 h = _screen->h;
+ int16 w = _screen->w;
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);
+ subtitles.setFont("LiberationSans-Regular.ttf", fontSize, Subtitles::kFontStyleRegular);
+ subtitles.setFont("LiberationSans-Italic.ttf", fontSize, Subtitles::kFontStyleItalic);
}
void PhoenixVREngine::playMovie(const Common::String &movie) {
@@ -1066,14 +1066,10 @@ void PhoenixVREngine::playMovie(const Common::String &movie) {
dec->start();
_currentDecoder = dec.get();
- Common::SharedPtr<Video::Subtitles> subtitles = loadSubtitles(movie);
- if (subtitles) {
- g_system->showOverlay(false);
- g_system->clearOverlay();
- }
-
+ Common::SharedPtr<Subtitles> subtitles = loadSubtitles(movie);
bool playing = true;
Common::ScopedPtr<Graphics::Palette> palette;
+ const Graphics::Surface *frame = nullptr;
while (!shouldQuit() && playing && !dec->endOfVideo()) {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
@@ -1091,28 +1087,24 @@ void PhoenixVREngine::playMovie(const Common::String &movie) {
}
}
if (dec->needsUpdate()) {
- auto *s = dec->decodeNextFrame();
+ frame = dec->decodeNextFrame();
if (dec->hasDirtyPalette()) {
palette.reset(new Graphics::Palette(dec->getPalette(), 256));
}
- if (s) {
- if (!s->format.isCLUT8() || palette) {
- Common::Point dstPos((g_system->getWidth() - s->w) / 2, (g_system->getHeight() - s->h) / 2);
- _screen->simpleBlitFrom(*s, dstPos, Graphics::FLIP_NONE, false, 0xff, palette.get());
- }
- }
+ }
+ if (frame && (!frame->format.isCLUT8() || palette)) {
+ Common::Point dstPos((g_system->getWidth() - frame->w) / 2, (g_system->getHeight() - frame->h) / 2);
+ _screen->simpleBlitFrom(*frame, dstPos, Graphics::FLIP_NONE, false, 0xff, palette.get());
}
// 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);
+ subtitles->drawSubtitle(dec->getTime());
_screen->update();
_frameLimiter.startFrame();
}
- if (subtitles)
- g_system->hideOverlay();
_system->lockMouse(_vr.isVR());
_currentDecoder = nullptr;
}
@@ -1932,7 +1924,7 @@ void PhoenixVREngine::drawAudioSubtitles() {
for (auto &kv : _sounds) {
auto &sound = kv._value;
if (sound.subtitles && _mixer->isSoundHandleActive(sound.handle))
- sound.subtitles->drawSubtitle(_mixer->getElapsedTime(sound.handle).msecs(), false);
+ sound.subtitles->drawSubtitle(_mixer->getElapsedTime(sound.handle).msecs());
}
}
diff --git a/engines/phoenixvr/phoenixvr.h b/engines/phoenixvr/phoenixvr.h
index c6cd3dfdf64..9d9ad428a62 100644
--- a/engines/phoenixvr/phoenixvr.h
+++ b/engines/phoenixvr/phoenixvr.h
@@ -54,13 +54,10 @@ namespace Graphics {
class Font;
}
-namespace Video {
-class Subtitles;
-}
-
namespace PhoenixVR {
class ARN;
+class Subtitles;
struct PhoenixVRGameDescription;
struct GameState;
@@ -299,8 +296,8 @@ private:
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;
+ Common::SharedPtr<Subtitles> loadSubtitles(const Common::String &path) const;
+ void setupSubtitles(Subtitles &subtitles) const;
void drawAudioSubtitles();
void processGenericEvents(const Common::Event &event);
@@ -340,7 +337,7 @@ private:
float angle;
uint8 volume;
int loops;
- Common::SharedPtr<Video::Subtitles> subtitles;
+ Common::SharedPtr<Subtitles> subtitles;
};
Common::HashMap<Common::String, Sound, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _sounds;
diff --git a/engines/phoenixvr/subtitles.cpp b/engines/phoenixvr/subtitles.cpp
new file mode 100644
index 00000000000..adbba5aaf48
--- /dev/null
+++ b/engines/phoenixvr/subtitles.cpp
@@ -0,0 +1,98 @@
+/* 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 "phoenixvr/subtitles.h"
+
+#include "graphics/font.h"
+#include "graphics/managed_surface.h"
+
+namespace PhoenixVR {
+
+Subtitles::Subtitles(Graphics::ManagedSurface *target) : _target(target) {
+}
+
+Subtitles::~Subtitles() {
+ _outlined.free();
+}
+
+void Subtitles::setBBox(const Common::Rect &bbox) {
+ Video::Subtitles::setBBox(bbox);
+ _bbox = bbox;
+ _outlined.create(bbox.width() + 2 * kOutlineWidth, bbox.height() + 2 * kOutlineWidth,
+ Graphics::PixelFormat::createFormatRGBA32());
+ clearSubtitle();
+}
+
+void Subtitles::setColor(byte r, byte g, byte b) {
+ Video::Subtitles::setColor(r, g, b);
+ _textColor = _outlined.format.ARGBToColor(255, r, g, b);
+}
+
+void Subtitles::clearSubtitle() const {
+ _parts = nullptr;
+ _bounds.setEmpty();
+ _runs.clear();
+}
+
+void Subtitles::drawSubtitleText(const Graphics::Font &font, const Common::U32String &text, int x, int y, int width) const {
+ _runs.push_back(TextRun{&font, text, x, y, width});
+}
+
+void Subtitles::drawSubtitle(uint32 timestamp) {
+ _runs.clear();
+ Video::Subtitles::drawSubtitle(timestamp);
+ if (!_runs.empty())
+ renderOutline();
+ if (!_parts || _parts->empty() || (*_parts)[0].tag == "sfx" || _bounds.isEmpty())
+ return;
+
+ const Common::Point position(_bbox.left - kOutlineWidth + _bounds.left,
+ _bbox.top - kOutlineWidth + _bounds.top);
+ _target->simpleBlitFrom(_outlined, _bounds, position, Graphics::FLIP_NONE, true);
+}
+
+void Subtitles::renderOutline() {
+ _outlined.fillRect(Common::Rect(_outlined.w, _outlined.h), 0);
+ _bounds.setEmpty();
+ const uint32 black = _outlined.format.ARGBToColor(255, 0, 0, 0);
+
+ for (const auto &run : _runs) {
+ const Common::Rect bounds(run.x, run.y, run.x + run.width + 2 * kOutlineWidth,
+ run.y + run.font->getFontHeight() + 2 * kOutlineWidth);
+ if (_bounds.isEmpty())
+ _bounds = bounds;
+ else
+ _bounds.extend(bounds);
+ for (int y = -kOutlineWidth; y <= kOutlineWidth; ++y) {
+ for (int x = -kOutlineWidth; x <= kOutlineWidth; ++x) {
+ if ((x || y) && 4 * (x * x + y * y) <= (2 * kOutlineWidth + 1) * (2 * kOutlineWidth + 1))
+ run.font->drawString(&_outlined, run.text, run.x + kOutlineWidth + x, run.y + kOutlineWidth + y,
+ run.width, black, Graphics::kTextAlignLeft);
+ }
+ }
+ }
+ for (const auto &run : _runs)
+ run.font->drawString(&_outlined, run.text, run.x + kOutlineWidth, run.y + kOutlineWidth,
+ run.width, _textColor, Graphics::kTextAlignLeft);
+ _bounds.clip(_outlined.w, _outlined.h);
+}
+
+} // namespace PhoenixVR
diff --git a/engines/phoenixvr/subtitles.h b/engines/phoenixvr/subtitles.h
new file mode 100644
index 00000000000..2a0bbb6d832
--- /dev/null
+++ b/engines/phoenixvr/subtitles.h
@@ -0,0 +1,67 @@
+/* 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 PHOENIXVR_SUBTITLES_H
+#define PHOENIXVR_SUBTITLES_H
+
+#include "common/path.h"
+#include "video/subtitles.h"
+
+namespace Graphics {
+class ManagedSurface;
+}
+
+namespace PhoenixVR {
+
+class Subtitles : public Video::Subtitles {
+public:
+ explicit Subtitles(Graphics::ManagedSurface *target);
+ ~Subtitles() override;
+
+ void setBBox(const Common::Rect &bbox);
+ void setColor(byte r, byte g, byte b);
+ void drawSubtitle(uint32 timestamp);
+ void clearSubtitle() const override;
+
+protected:
+ void drawSubtitleText(const Graphics::Font &font, const Common::U32String &text, int x, int y, int width) const override;
+ void updateSubtitleOverlay() const override {}
+
+private:
+ struct TextRun {
+ const Graphics::Font *font;
+ Common::U32String text;
+ int x, y, width;
+ };
+ void renderOutline();
+
+ static const int kOutlineWidth = 3;
+ Graphics::ManagedSurface *_target;
+ mutable Graphics::Surface _outlined;
+ Common::Rect _bbox;
+ mutable Common::Rect _bounds;
+ mutable Common::Array<TextRun> _runs;
+ uint32 _textColor = 0;
+};
+
+} // namespace PhoenixVR
+
+#endif
More information about the Scummvm-git-logs
mailing list