[Scummvm-git-logs] scummvm master -> 8771bc95a2f976c63ed6d473f692ed33741d11bf
neuromancer
noreply at scummvm.org
Mon Aug 18 15:41:08 UTC 2025
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
24b38ae23c VIDEO: parse tags in subtitles and allow multiples fonts
8771bc95a2 PRIVATE: use new subtitles code
Commit: 24b38ae23c2c5edb1bebe0eb654c5bfae3aecb68
https://github.com/scummvm/scummvm/commit/24b38ae23c2c5edb1bebe0eb654c5bfae3aecb68
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-08-18T17:43:49+02:00
Commit Message:
VIDEO: parse tags in subtitles and allow multiples fonts
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 555619a41b7..1fb801d57f5 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -49,6 +49,35 @@ void SRTParser::cleanup() {
_entries.clear();
}
+Common::String SRTParser::SRTParser::parseTag(Common::String &text) const {
+ // Parse tags in _subtitle
+ // <i> and </i> for italics
+ // <sfx> and </sfx> for sound effects
+
+ Common::String tag;
+ Common::String::size_type pos = text.find("<i>");
+ debug(1, "Subtitles: %s", text.c_str());
+ if (pos != Common::String::npos) {
+ text.erase(pos, 3);
+ pos = text.find("</i>");
+ if (pos != Common::String::npos) {
+ text.erase(pos, 4);
+ }
+ tag = "i";
+ } else {
+ pos = text.find("<sfx>");
+ if (pos != Common::String::npos) {
+ text.erase(pos, 5);
+ pos = text.find("</sfx>");
+ if (pos != Common::String::npos) {
+ text.erase(pos, 6);
+ }
+ tag = "sfx";
+ }
+ }
+ return tag;
+}
+
bool parseTime(const char **pptr, uint32 *res) {
int hours, mins, secs, msecs;
const char *ptr = *pptr;
@@ -206,7 +235,8 @@ bool SRTParser::parseFile(const Common::Path &fname) {
break;
}
- _entries.push_back(new SRTEntry(seq, start, end, text));
+ Common::String tag = parseTag(text);
+ _entries.push_back(new SRTEntry(seq, start, end, text, tag));
}
qsort(_entries.data(), _entries.size(), sizeof(SRTEntry *), &SRTEntryComparator);
@@ -228,9 +258,21 @@ Common::String SRTParser::getSubtitle(uint32 timestamp) const {
return (*entry)->text;
}
+Common::String SRTParser::getTag(uint32 timestamp) const {
+ SRTEntry test(0, timestamp, 0, "");
+ SRTEntry *testptr = &test;
+
+ const SRTEntry **entry = (const SRTEntry **)bsearch(&testptr, _entries.data(), _entries.size(), sizeof(SRTEntry *), &SRTEntryComparatorBSearch);
+
+ if (entry == NULL)
+ return "";
+
+ return (*entry)->tag;
+}
+
#define SHADOW 1
-Subtitles::Subtitles() : _loaded(false), _font(nullptr), _hPad(0), _vPad(0), _overlayHasAlpha(true),
+Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(true),
_lastOverlayWidth(-1), _lastOverlayHeight(-1) {
_surface = new Graphics::Surface();
_subtitleDev = ConfMan.getBool("subtitle_dev");
@@ -240,33 +282,36 @@ Subtitles::~Subtitles() {
delete _surface;
}
-void Subtitles::setFont(const char *fontname, int height) {
+void Subtitles::setFont(const char *fontname, int height, Common::String type) {
+ Graphics::Font *font = nullptr;
_fontHeight = height;
#ifdef USE_FREETYPE2
Common::File *file = new Common::File();
if (file->open(fontname)) {
- _font = Graphics::loadTTFFont(file, DisposeAfterUse::YES, _fontHeight, Graphics::kTTFSizeModeCharacter, 96);
- if (!_font)
+ font = Graphics::loadTTFFont(file, DisposeAfterUse::YES, _fontHeight, Graphics::kTTFSizeModeCharacter, 96);
+ if (!font)
delete file;
+ else
+ _fonts[type] = font;
} else {
delete file;
}
- if (!_font) {
- _font = Graphics::loadTTFFontFromArchive(fontname, _fontHeight, Graphics::kTTFSizeModeCharacter, 96);
+ if (!font) {
+ _fonts[type] = Graphics::loadTTFFontFromArchive(fontname, _fontHeight, Graphics::kTTFSizeModeCharacter, 96);
}
#endif
- if (!_font) {
+ if (!_fonts[type]) {
debug(1, "Cannot load font %s directly", fontname);
- _font = FontMan.getFontByName(fontname);
+ _fonts[type] = FontMan.getFontByName(fontname);
}
- if (!_font) {
+ if (!_fonts[type]) {
warning("Cannot load font %s", fontname);
- _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ _fonts[type] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
}
}
@@ -302,10 +347,12 @@ void Subtitles::setPadding(uint16 horizontal, uint16 vertical) {
_vPad = vertical;
}
-bool Subtitles::drawSubtitle(uint32 timestamp, bool force) const {
+bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) {
Common::String subtitle;
+ Common::String tag;
if (_loaded) {
subtitle = _srtParser.getSubtitle(timestamp);
+ tag = _srtParser.getTag(timestamp);
} else if (_subtitleDev) {
subtitle = _fname.toString('/');
uint32 hours, mins, secs, msecs;
@@ -357,10 +404,13 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force) const {
return false;
if (force || subtitle != _subtitle) {
- debug(1, "%d: %s", timestamp, subtitle.c_str());
+ debug(1, "%d: %s with tag %s", timestamp, subtitle.c_str(), tag.c_str());
_subtitle = subtitle;
- renderSubtitle();
+ _tag = tag;
+
+ if (_tag != "sfx" || showSFX)
+ renderSubtitle();
}
if (_overlayHasAlpha) {
@@ -382,8 +432,10 @@ void Subtitles::renderSubtitle() const {
_surface->fillRect(Common::Rect(0, 0, _surface->w, _surface->h), _transparentColor);
Common::Array<Common::U32String> lines;
+ Common::String fontType = _tag == "i" ? "italic" : "regular";
+ const Graphics::Font *font = _fonts[fontType] ? _fonts[fontType] : _fonts["regular"];
- _font->wordWrapText(convertUtf8ToUtf32(_subtitle), _realBBox.width(), lines);
+ font->wordWrapText(convertUtf8ToUtf32(_subtitle), _realBBox.width(), lines);
if (lines.empty()) {
_drawRect.left = 0;
@@ -398,7 +450,7 @@ void Subtitles::renderSubtitle() const {
int width = 0;
for (uint i = 0; i < lines.size(); i++)
- width = MAX(_font->getStringWidth(lines[i]), width);
+ width = MAX(font->getStringWidth(lines[i]), width);
width = MIN(width + 2 * _hPad, (int)_realBBox.width());
int originX = (_realBBox.width() - width) / 2;
@@ -406,14 +458,14 @@ void Subtitles::renderSubtitle() const {
for (uint i = 0; i < lines.size(); i++) {
Common::U32String line = convertBiDiU32String(lines[i]).visual;
- _font->drawString(_surface, line, originX, height, width, _blackColor, Graphics::kTextAlignCenter);
- _font->drawString(_surface, line, originX + SHADOW * 2, height, width, _blackColor, Graphics::kTextAlignCenter);
- _font->drawString(_surface, line, originX, height + SHADOW * 2, width, _blackColor, Graphics::kTextAlignCenter);
- _font->drawString(_surface, line, originX + SHADOW * 2, height + SHADOW * 2, width, _blackColor, Graphics::kTextAlignCenter);
+ font->drawString(_surface, line, originX, height, width, _blackColor, Graphics::kTextAlignCenter);
+ font->drawString(_surface, line, originX + SHADOW * 2, height, width, _blackColor, Graphics::kTextAlignCenter);
+ font->drawString(_surface, line, originX, height + SHADOW * 2, width, _blackColor, Graphics::kTextAlignCenter);
+ font->drawString(_surface, line, originX + SHADOW * 2, height + SHADOW * 2, width, _blackColor, Graphics::kTextAlignCenter);
- _font->drawString(_surface, line, originX + SHADOW, height + SHADOW, width, _color, Graphics::kTextAlignCenter);
+ font->drawString(_surface, line, originX + SHADOW, height + SHADOW, width, _color, Graphics::kTextAlignCenter);
- height += _font->getFontHeight();
+ height += font->getFontHeight();
if (height + _vPad > _realBBox.bottom)
break;
diff --git a/video/subtitles.h b/video/subtitles.h
index c11e4a4f6d0..1f5aba94a31 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -24,6 +24,7 @@
#include "common/str.h"
#include "common/array.h"
+#include "common/hashmap.h"
#include "common/rect.h"
namespace Graphics {
@@ -39,9 +40,10 @@ struct SRTEntry {
uint32 end;
Common::String text;
+ Common::String tag;
- SRTEntry(uint seq_, uint32 start_, uint32 end_, Common::String text_) {
- seq = seq_; start = start_; end = end_; text = text_;
+ SRTEntry(uint seq_, uint32 start_, uint32 end_, Common::String text_, Common::String tag_ = "") {
+ seq = seq_; start = start_; end = end_; text = text_; tag = tag_;
}
};
@@ -52,7 +54,9 @@ public:
void cleanup();
bool parseFile(const Common::Path &fname);
+ Common::String parseTag(Common::String &text) const;
Common::String getSubtitle(uint32 timestamp) const;
+ Common::String getTag(uint32 timestamp) const;
private:
Common::Array<SRTEntry *> _entries;
@@ -65,11 +69,11 @@ public:
void loadSRTFile(const Common::Path &fname);
void close() { _loaded = false; _subtitle.clear(); _fname.clear(); _srtParser.cleanup(); }
- void setFont(const char *fontname, int height = 18);
+ void setFont(const char *fontname, int height = 18, Common::String type = "regular");
void setBBox(const Common::Rect &bbox);
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
- bool drawSubtitle(uint32 timestamp, bool force = false) const;
+ bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false);
bool isLoaded() const { return _loaded || _subtitleDev; }
private:
@@ -80,7 +84,7 @@ private:
bool _subtitleDev;
bool _overlayHasAlpha;
- const Graphics::Font *_font;
+ Common::HashMap<Common::String, const Graphics::Font *> _fonts;
int _fontHeight;
Graphics::Surface *_surface;
@@ -92,6 +96,7 @@ private:
Common::Path _fname;
mutable Common::String _subtitle;
+ mutable Common::String _tag;
uint32 _color;
uint32 _blackColor;
uint32 _transparentColor;
Commit: 8771bc95a2f976c63ed6d473f692ed33741d11bf
https://github.com/scummvm/scummvm/commit/8771bc95a2f976c63ed6d473f692ed33741d11bf
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-08-18T17:43:49+02:00
Commit Message:
PRIVATE: use new subtitles code
Changed paths:
engines/private/detection.cpp
engines/private/detection.h
engines/private/metaengine.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/detection.cpp b/engines/private/detection.cpp
index bbff2208f58..8bab26f24ac 100644
--- a/engines/private/detection.cpp
+++ b/engines/private/detection.cpp
@@ -48,7 +48,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_USA,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // Demo from the US release v1.0.0.23
@@ -58,7 +58,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_USA,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // EU release (UK)
@@ -68,7 +68,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // Demo from the EU release
@@ -78,7 +78,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_GRB,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // Demo from PCGamer Disc 2.6 JULY 1996 v1.0.0.12
@@ -88,7 +88,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_USA,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // Another demo
@@ -98,7 +98,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::EN_USA,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // EU release (ES)
@@ -108,7 +108,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // Demo from the EU release (ES)
@@ -118,7 +118,7 @@ static const ADGameDescription gameDescriptions[] = {
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_DEMO,
- GUIO2(GUIO_NOMIDI, GAMEOPTION_SUBTITLES)
+ GUIO3(GUIO_NOMIDI, GAMEOPTION_SUBTITLES, GAMEOPTION_SFX_SUBTITLES)
},
{
"private-eye", // EU release (FR)
diff --git a/engines/private/detection.h b/engines/private/detection.h
index a57788c4db6..1ddbc8ef4ae 100644
--- a/engines/private/detection.h
+++ b/engines/private/detection.h
@@ -2,5 +2,6 @@
#define PRIVATE_DETECTION_H
#define GAMEOPTION_SUBTITLES GUIO_GAMEOPTIONS1
+#define GAMEOPTION_SFX_SUBTITLES GUIO_GAMEOPTIONS2
#endif // PRIVATE_DETECTION_H
\ No newline at end of file
diff --git a/engines/private/metaengine.cpp b/engines/private/metaengine.cpp
index 26d642953e5..42f861e6e5a 100644
--- a/engines/private/metaengine.cpp
+++ b/engines/private/metaengine.cpp
@@ -38,6 +38,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
+ {
+ GAMEOPTION_SFX_SUBTITLES,
+ {
+ _s("Display SFX subtitles"),
+ _s("Use SFX subtitles."),
+ "sfxSubtitles",
+ false,
+ 0,
+ 0
+ }
+ },
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 425e1e45aff..89c77bf1b82 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -52,7 +52,7 @@ extern int parse(const char *);
PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
: Engine(syst), _gameDescription(gd), _image(nullptr), _videoDecoder(nullptr),
_compositeSurface(nullptr), _transparentColor(0), _frameImage(nullptr),
- _framePalette(nullptr), _maxNumberClicks(0), _sirenWarning(0), _subtitles(nullptr),
+ _framePalette(nullptr), _maxNumberClicks(0), _sirenWarning(0), _subtitles(nullptr), _sfxSubtitles(false),
_screenW(640), _screenH(480) {
_rnd = new Common::RandomSource("private");
@@ -203,10 +203,15 @@ Common::Error PrivateEngine::run() {
// Only enable if subtitles are available
bool useSubtitles = false;
if (!Common::parseBool(ConfMan.get("subtitles"), useSubtitles))
- error("Failed to parse bool from cheats options");
+ warning("Failed to parse bool from subtitles options");
+
+ if (!Common::parseBool(ConfMan.get("sfxSubtitles"), _sfxSubtitles))
+ warning("Failed to parse bool from sfxSubtitles options");
if (useSubtitles) {
g_system->showOverlay(false);
+ } else if (_sfxSubtitles) {
+ warning("SFX subtitles are enabled, but no subtitles will be shown");
}
_language = Common::parseLanguage(ConfMan.get("language"));
@@ -1500,17 +1505,19 @@ void PrivateEngine::loadSubtitles(const Common::Path &path) {
_subtitles->loadSRTFile(subPath);
g_system->showOverlay(false);
int16 h = g_system->getOverlayHeight();
-
+ float scale = h / 2160.f;
// If we are in the main menu, we need to adjust the position of the subtitles
- if (_currentSetting == getMainDesktopSetting()) {
- _subtitles->setBBox(Common::Rect(20, h - 100, g_system->getOverlayWidth() - 20, h - 20));
+ if (_mode == 0) {
+ _subtitles->setBBox(Common::Rect(20, h - 200 * scale, g_system->getOverlayWidth() - 20, h - 20));
+ } else if (_mode == -1) {
+ _subtitles->setBBox(Common::Rect(20, h - 220 * scale, g_system->getOverlayWidth() - 20, h - 20));
} else {
- _subtitles->setBBox(Common::Rect(20, h - 160, g_system->getOverlayWidth() - 20, h - 20));
+ _subtitles->setBBox(Common::Rect(20, h - 160 * scale, g_system->getOverlayWidth() - 20, h - 20));
}
-
+ int fontSize = MAX(8, int(50 * scale));
_subtitles->setColor(0xff, 0xff, 0x80);
- _subtitles->setFont("LiberationSans-Regular.ttf", 50);
-
+ _subtitles->setFont("LiberationSans-Regular.ttf", fontSize, "regular");
+ _subtitles->setFont("NotoSerif-Italic.ttf", fontSize, "italic");
} else {
delete _subtitles;
_subtitles = nullptr;
@@ -1721,7 +1728,7 @@ void PrivateEngine::drawScreen() {
}
if (_subtitles && _videoDecoder && !_videoDecoder->isPaused())
- _subtitles->drawSubtitle(_videoDecoder->getTime(), false);
+ _subtitles->drawSubtitle(_videoDecoder->getTime(), false, _sfxSubtitles);
g_system->updateScreen();
}
diff --git a/engines/private/private.h b/engines/private/private.h
index 599215b4875..7cf35e0fe98 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -221,6 +221,7 @@ public:
void loadSubtitles(const Common::Path &path);
Video::Subtitles *_subtitles;
+ bool _sfxSubtitles;
Graphics::Surface *decodeImage(const Common::String &file, byte **palette);
//byte *decodePalette(const Common::String &name);
More information about the Scummvm-git-logs
mailing list