aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Kohaut2019-07-15 00:26:18 +0200
committerPeter Kohaut2019-07-16 21:56:33 +0200
commit39e4fdb98c27f97ffffcfba8b6579697a4c809d2 (patch)
tree0aed595ef6ef7f11a5116f91449d5572a34fac44
parenta767a6800d2f76b90b66d7c0dcb96c0514350721 (diff)
downloadscummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.tar.gz
scummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.tar.bz2
scummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.zip
BLADERUNNER: Use ScummVM word wrapping algorithm
-rw-r--r--engines/bladerunner/actor.cpp2
-rw-r--r--engines/bladerunner/outtake.cpp2
-rw-r--r--engines/bladerunner/subtitles.cpp375
-rw-r--r--engines/bladerunner/subtitles.h31
4 files changed, 104 insertions, 306 deletions
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 62ffd6f3a1..84febccc2e 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -1181,7 +1181,7 @@ void Actor::speechPlay(int sentenceId, bool voiceOver) {
pan = (75 * (2 * CLIP<int>(screenPosition.x, 0, 640) - 640)) / 640; // map [0..640] to [-75..75]
}
- _vm->_subtitles->getInGameSubsText(_id, sentenceId);
+ _vm->_subtitles->loadInGameSubsText(_id, sentenceId);
_vm->_subtitles->show();
_vm->_audioSpeech->playSpeech(name, pan);
diff --git a/engines/bladerunner/outtake.cpp b/engines/bladerunner/outtake.cpp
index 74ac44a5fe..112a12085d 100644
--- a/engines/bladerunner/outtake.cpp
+++ b/engines/bladerunner/outtake.cpp
@@ -83,7 +83,7 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co
}
if (frame >= 0) {
- _vm->_subtitles->getOuttakeSubsText(resNameNoVQASuffix, frame);
+ _vm->_subtitles->loadOuttakeSubsText(resNameNoVQASuffix, frame);
_vm->_subtitles->tickOuttakes(_vm->_surfaceFront);
_vm->blitToScreen(_vm->_surfaceFront);
}
diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index dcd0f21d6b..2170638815 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -62,10 +62,10 @@ const char *Subtitles::SUBTITLES_FONT_FILENAME_EXTERNAL = "SUBTLS_E.FON";
const char *Subtitles::SUBTITLES_VERSION_TRENAME = "SBTLVERS"; // addon resource file for Subtitles version info - can only be SBTLVERS.TRE
/*
-* All entries need to have the language code appended (after a '_').
-* And all entries should get the suffix extension ".TRx"; the last letter in extension "TR*" should also be the language code
-* If/When adding new Text Resources here --> Update kMaxTextResourceEntries and also update method getIdxForSubsTreName()
-*/
+ * All entries need to have the language code appended (after a '_').
+ * And all entries should get the suffix extension ".TRx"; the last letter in extension "TR*" should also be the language code
+ * If/When adding new Text Resources here --> Update kMaxTextResourceEntries and also update method getIdxForSubsTreName()
+ */
const char *Subtitles::SUBTITLES_FILENAME_PREFIXES[kMaxTextResourceEntries] = {
"INGQUO", // 0 // (in-game subtitles, not VQA subtitles)
"WSTLGO", // 1 // all game (language) versions have the English ('E') version of WSTLGO
@@ -96,22 +96,23 @@ const char *Subtitles::SUBTITLES_FILENAME_PREFIXES[kMaxTextResourceEntries] = {
};
/**
-* Subtitles Constructor
-*/
+ * Subtitles Constructor
+ */
Subtitles::Subtitles(BladeRunnerEngine *vm) {
_vm = vm;
- _subtitlesSystemActive = false;
- // Initializing and reseting Subtitles
- for (int i = 0; i < kMaxTextResourceEntries; i++) {
+ _isSystemActive = false;
+ for (int i = 0; i < kMaxTextResourceEntries; ++i) {
_vqaSubsTextResourceEntries[i] = nullptr;
+ _gameSubsResourceEntriesFound[i] = false;
}
_font = nullptr;
+ _useUTF8 = false;
reset();
}
/**
-* Subtitles Destructor
-*/
+ * Subtitles Destructor
+ */
Subtitles::~Subtitles() {
reset();
}
@@ -136,8 +137,8 @@ void Subtitles::init(void) {
_subtitlesInfo.fontType = Subtitles::kSubtitlesFontTypeInternal;
}
- if ( _subtitlesInfo.fontName.empty()) {
- _subtitlesInfo.fontName = "SUBTLS_E.FON";
+ if (_subtitlesInfo.fontName.empty()) {
+ _subtitlesInfo.fontName = SUBTITLES_FONT_FILENAME_EXTERNAL;
}
debug("Subtitles version info: v%s (%s) %s by: %s",
@@ -162,8 +163,6 @@ void Subtitles::init(void) {
} else if (_subtitlesInfo.fontType == Subtitles::kSubtitlesFontTypeTTF) {
#if defined(USE_FREETYPE2)
Common::ScopedPtr<Common::SeekableReadStream> stream(_vm->getResourceStream(_subtitlesInfo.fontName));
- // Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember("NotoSansCJKsc-Medium.otf"));
-
_font = Graphics::loadTTFFont(*stream, 18);
_useUTF8 = true;
#else
@@ -195,22 +194,14 @@ void Subtitles::init(void) {
tmpConstructedFileName = Common::String(SUBTITLES_FILENAME_PREFIXES[i]) + "_" + _vm->_languageCode;
}
- if ( _vqaSubsTextResourceEntries[i]->open(tmpConstructedFileName, localizedResource)) {
+ if (_vqaSubsTextResourceEntries[i]->open(tmpConstructedFileName, localizedResource)) {
_gameSubsResourceEntriesFound[i] = true;
}
}
// Done - Loading text resources
//
- //
- // calculate the Screen Y position of the subtitle lines
- // getTextHeight("") returns the maxHeight of the font glyphs regardless of the actual text parameter
- // debug("Max height %d", _subsFont->getTextHeight(""));
- for (int i = 0; i < kMaxNumOfSubtitlesLines; ++i) {
- _subtitleLineScreenY[i] = 479 - kSubtitlesBottomYOffsetPx - ((kMaxNumOfSubtitlesLines - i) * (_font->getFontHeight() + 1));
- }
-
- _subtitlesSystemActive = true;
+ _isSystemActive = true;
}
Subtitles::SubtitlesInfo Subtitles::getSubtitlesInfo() const {
@@ -218,9 +209,8 @@ Subtitles::SubtitlesInfo Subtitles::getSubtitlesInfo() const {
}
/**
-*
-* Returns the index of the specified Text Resource filename in the SUBTITLES_FILENAME_PREFIXES table
-*/
+ * Returns the index of the specified Text Resource filename in the SUBTITLES_FILENAME_PREFIXES table
+ */
int Subtitles::getIdxForSubsTreName(const Common::String &treName) const {
Common::String tmpConstructedFileName = "";
for (int i = 0; i < kMaxTextResourceEntries; ++i) {
@@ -238,94 +228,77 @@ int Subtitles::getIdxForSubsTreName(const Common::String &treName) const {
}
/**
-* Get the active subtitle text by searching with actor ID and speech ID
-* Use this method for in-game dialogue - Not dialogue during a VQA cutscene
-* Returns the dialogue quote, but also sets the private _currentSubtitleTextFull member
-*/
-const char *Subtitles::getInGameSubsText(int actorId, int speech_id) {
- if (!_subtitlesSystemActive) {
- return "";
+ * Get the active subtitle text by searching with actor ID and speech ID
+ * Use this method for in-game dialogue - Not dialogue during a VQA cutscene
+ */
+void Subtitles::loadInGameSubsText(int actorId, int speech_id) {
+ if (!_isSystemActive) {
+ return;
}
int32 id = 10000 * actorId + speech_id;
if (!_gameSubsResourceEntriesFound[0]) {
- if (_currentSubtitleTextFull != "") {
- _currentSubtitleTextFull = "";
- _subtitlesQuoteChanged = true;
- }
- return "";
+ _currentText.clear();
+ return;
}
+
// Search in the first TextResource of the _vqaSubsTextResourceEntries table, which is the TextResource for in-game dialogue (i.e. not VQA dialogue)
- const Common::String &text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
- _currentSubtitleTextFull = Common::String(text);
- _subtitlesQuoteChanged = true;
- return _currentSubtitleTextFull.c_str();
+ const char *text = _vqaSubsTextResourceEntries[0]->getText((uint32)id);
+ _currentText = _useUTF8 ? Common::convertUtf8ToUtf32(text) : Common::U32String(text);
}
/**
-* Use this method for dialogue during VQA cutscenes
-* Returns the dialogue quote, but also sets the private _currentSubtitleTextFull member
-*/
-const char *Subtitles::getOuttakeSubsText(const Common::String &outtakesName, int frame) {
- if (!_subtitlesSystemActive) {
- return "";
+ * Use this method for dialogue during VQA cutscenes
+ */
+void Subtitles::loadOuttakeSubsText(const Common::String &outtakesName, int frame) {
+ if (!_isSystemActive) {
+ return;
}
int fileIdx = getIdxForSubsTreName(outtakesName);
if (fileIdx == -1 || !_gameSubsResourceEntriesFound[fileIdx]) {
- if (_currentSubtitleTextFull != "") {
- _currentSubtitleTextFull = "";
- _subtitlesQuoteChanged = true;
- }
- return "";
+ _currentText.clear();
+ return;
}
+
// Search in the requested TextResource at the fileIdx index of the _vqaSubsTextResourceEntries table for a quote that corresponds to the specified video frame
// debug("Number of resource quotes to search: %d, requested frame: %u", _vqaSubsTextResourceEntries[fileIdx]->getCount(), (uint32)frame );
- const Common::String &text = _vqaSubsTextResourceEntries[fileIdx]->getOuttakeTextByFrame((uint32)frame);
- //if (text != "") {
- // debug("Text = %s", text.c_str());
- //}
- if (_currentSubtitleTextFull != Common::String(text)) {
- _currentSubtitleTextFull = Common::String(text);
- _subtitlesQuoteChanged = true;
- }
- return _currentSubtitleTextFull.c_str();
+ const char *text = _vqaSubsTextResourceEntries[fileIdx]->getOuttakeTextByFrame((uint32)frame);
+ _currentText = _useUTF8 ? Common::convertUtf8ToUtf32(text) : Common::U32String(text);
}
/**
-* Explicitly set the active subtitle text to be displayed
-* Used for debug purposes mainly.
-*/
+ * Explicitly set the active subtitle text to be displayed
+ * Used for debug purposes mainly.
+ */
void Subtitles::setGameSubsText(Common::String dbgQuote, bool forceShowWhenNoSpeech) {
- if (_currentSubtitleTextFull != dbgQuote) {
- _currentSubtitleTextFull = dbgQuote;
- _subtitlesQuoteChanged = true;
- _forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
- }
+ _currentText = _useUTF8 ? Common::convertUtf8ToUtf32(dbgQuote) : dbgQuote;
+ _forceShowWhenNoSpeech = forceShowWhenNoSpeech; // overrides not showing subtitles when no one is speaking
}
/**
-* Sets the _isVisible member var to true if it's not already set
-* @return true if the member was set now, false if the member was already set
-*/
+ * Sets the _isVisible member var to true if it's not already set
+ * @return true if the member was set now, false if the member was already set
+ */
bool Subtitles::show() {
- if (!_subtitlesSystemActive) {
+ if (!_isSystemActive) {
return false;
}
if (_isVisible) {
return false;
}
+
_isVisible = true;
return true;
}
/**
-* Clears the _isVisible member var if not already clear.
-* @return true if the member was cleared, false if it was already clear.
-*/
+ * Clears the _isVisible member var if not already clear.
+ * @return true if the member was cleared, false if it was already clear.
+ */
bool Subtitles::hide() {
- if (!_subtitlesSystemActive) {
+ if (!_isSystemActive) {
return false;
}
@@ -338,22 +311,22 @@ bool Subtitles::hide() {
}
/**
-* Checks whether the subtitles should be visible or not
-* @return the value of the _isVisible member boolean var
-*/
+ * Checks whether the subtitles should be visible or not
+ * @return the value of the _isVisible member boolean var
+ */
bool Subtitles::isVisible() const {
- return !_subtitlesSystemActive || _isVisible;
+ return !_isSystemActive || _isVisible;
}
/**
-* Tick method specific for outtakes (VQA videos)
-*/
+ * Tick method specific for outtakes (VQA videos)
+ */
void Subtitles::tickOuttakes(Graphics::Surface &s) {
- if (!_subtitlesSystemActive || !_vm->isSubtitlesEnabled()) {
+ if (!_isSystemActive || !_vm->isSubtitlesEnabled()) {
return;
}
- if (_currentSubtitleTextFull.empty()) {
+ if (_currentText.empty()) {
_vm->_subtitles->hide();
} else {
_vm->_subtitles->show();
@@ -362,241 +335,72 @@ void Subtitles::tickOuttakes(Graphics::Surface &s) {
if (!_isVisible) { // keep it as a separate if
return;
}
+
draw(s);
}
/**
-* Tick method for in-game subtitles -- Not for outtake cutscenes (VQA videos)
-*/
+ * Tick method for in-game subtitles -- Not for outtake cutscenes (VQA videos)
+ */
void Subtitles::tick(Graphics::Surface &s) {
- if (!_subtitlesSystemActive || !_vm->isSubtitlesEnabled()) {
+ if (!_isSystemActive || !_vm->isSubtitlesEnabled()) {
return;
}
- if (!_vm->_audioSpeech->isPlaying() && !_forceShowWhenNoSpeech && _isVisible) {
+ if (_isVisible && !_forceShowWhenNoSpeech && !_vm->_audioSpeech->isPlaying()) {
_vm->_subtitles->hide(); // TODO might need a better system. Don't call it always.
}
- if (!_isVisible) { // keep it as a separate if
+ if (!_isVisible) { // keep it as a separate if
return;
}
+
draw(s);
}
/**
-* Draw method for drawing the subtitles on the display surface
-*/
+ * Draw method for drawing the subtitles on the display surface
+ */
void Subtitles::draw(Graphics::Surface &s) {
- if (!_subtitlesSystemActive || !_isVisible || _currentSubtitleTextFull.empty()) {
+ if (!_isSystemActive || !_isVisible || _currentText.empty()) {
return;
}
- if (_subtitlesQuoteChanged) {
- calculatePosition(); // Don't always call calc position, only when quote has changed
- _subtitlesQuoteChanged = false;
- }
- // multi-line quotes appear from top to bottom
- // ie. _subtitleLineQuote[0] is the top-most line
- // The default available lines for drawing are:
- // (kMaxNumOfSubtitlesLines - kStartFromSubtitleLineFromTop)
- // And by default we prefer drawing starting from line: kStartFromSubtitleLineFromTop.
- // However, if we have to draw more lines than the default available
- // we should then override the default starting line and start from further up instead
- int startingLineFromTop = kStartFromSubtitleLineFromTop;
- if (_currentSubtitleLines > kMaxNumOfSubtitlesLines - kStartFromSubtitleLineFromTop) {
- startingLineFromTop = kMaxNumOfSubtitlesLines - _currentSubtitleLines;
- }
+ Common::Array<Common::U32String> lines;
+ _font->wordWrapText(_currentText, kTextMaxWidth, lines);
+
+ int y = s.h - (kMarginBottom + MAX(kPreferedLine, lines.size()) * _font->getFontHeight());
- for (int i = 0, j = startingLineFromTop; i < _currentSubtitleLines; ++i, ++j) {
- Common::U32String text = _useUTF8 ? convertUtf8ToUtf32(_subtitleLineQuote[i]) : _subtitleLineQuote[i];
+ for (uint i = 0; i < lines.size(); i++, y += _font->getFontHeight()) {
switch (_subtitlesInfo.fontType) {
case Subtitles::kSubtitlesFontTypeInternal:
// shadow/outline is part of the font color data
- _font->drawString(&s, text, _subtitleLineScreenX[i], _subtitleLineScreenY[j], s.w, 0);
+ _font->drawString(&s, lines[i], 0, y, s.w, 0, Graphics::kTextAlignCenter);
break;
case Subtitles::kSubtitlesFontTypeTTF:
- _font->drawString(&s, text, _subtitleLineScreenX[i] - 1, _subtitleLineScreenY[j] - 1, s.w, s.format.RGBToColor( 0, 0, 0));
- _font->drawString(&s, text, _subtitleLineScreenX[i] + 1, _subtitleLineScreenY[j] - 1, s.w, s.format.RGBToColor( 0, 0, 0));
- _font->drawString(&s, text, _subtitleLineScreenX[i] - 1, _subtitleLineScreenY[j] + 1, s.w, s.format.RGBToColor( 0, 0, 0));
- _font->drawString(&s, text, _subtitleLineScreenX[i] + 1, _subtitleLineScreenY[j] + 1, s.w, s.format.RGBToColor( 0, 0, 0));
- _font->drawString(&s, text, _subtitleLineScreenX[i] , _subtitleLineScreenY[j] , s.w, s.format.RGBToColor(255, 255, 255));
- break;
- }
- }
-}
-
-/**
-* Calculate the position (X axis - horizontal) where the current active subtitle text should be displayed/drawn
-* This also determines if more than one lines should be drawn and what text goes into each line; splitting into multiple lines is done here
-*
-* The code first prioritizes splitting on the "new line" character.
-* That is, if the string contains at least one new line character, then line splitting occurs on new line characters exclusively.
-* The idea is that new line characters are put in the string explicitly by someone who wants specific control over line splitting
-* and thus they assume the responsibility for the resulting line segment widths (the code won't bother with them in this case).
-*
-* If there are NO "new line" characters, then the code will split lines on a space character (auto-split case).
-* For this case we only split if the full original line width exceeds a preset width threshold.
-* If the threshold is exceeded, then we parse the line and calculate how many lines we can split it into (starting from 2 lines)
-* to get segments smaller than the width threshold and also while maintaining (close to) even width across the resulting line segments.
-* What's happening here is that we loop dividing the original quote's character total by an increasing target number of line segments,
-* in order to get an "ideal" length for each segment (for evenness). Then we seek for split points (space character)
-* past the characters of the "ideal" length points.
-*
-* For the second case (auto-split), we don't account for the special case of a single word larger than max line length
-* (no spaces), as practically this won't ever happen.
-*
-* TODO: simplify this code
-* TODO: maybe calculate auto-split points taking into account on quote pixel width per character and not simply the character count
-* TODO: somehow merge with graphics/font.cpp -> wordWrapTextImpl ?
-*/
-void Subtitles::calculatePosition() {
- // wOrig is in pixels, origQuoteNumOfChars is num of chars in string
- int wOrig = _font->getStringWidth(_currentSubtitleTextFull) + 2; // +2 to account for left/ right shadow pixels (or for good measure)
- int origQuoteNumOfChars = _currentSubtitleTextFull.size();
- int tmpCharIndex = 0;
- bool drawSingleLineQuote = false;
-
- const uint8 *textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str();
- int tmpLineWidth[kMaxNumOfSubtitlesLines];
-
- // initialization of aux variables
- _currentSubtitleLines = 1;
- for (int j = 0; j < kMaxNumOfSubtitlesLines; ++j) {
- _subtitleLineSplitAtCharIndex[j] = 0;
- _subtitleLineQuote[j] = "";
- _subtitleLineScreenX[j] = 0;
- tmpLineWidth[j] = 0;
- }
+ _font->drawString(&s, lines[i], -1, y , s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
+ _font->drawString(&s, lines[i], 0, y - 1, s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
+ _font->drawString(&s, lines[i], 1, y , s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
+ _font->drawString(&s, lines[i], 0, y + 1, s.w, s.format.RGBToColor( 0, 0, 0), Graphics::kTextAlignCenter);
- while (*textCharacters != 0) {
- // check for new line explicit split case
- if (_currentSubtitleLines < kMaxNumOfSubtitlesLines
- && *textCharacters == '\n'
- && tmpCharIndex != 0
- && _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] == 0) {
- _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] = tmpCharIndex;
- _currentSubtitleLines += 1;
- }
- tmpCharIndex += 1;
- textCharacters += 1;
- }
- _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] = tmpCharIndex;
- if (_currentSubtitleLines > 1) { // This means that splitting on new line characters is possible
- //
- int j = 0; // j iterates over the subtitle line segments
- textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str(); // reset pointer to the start of the subtitle quote
- for (int i = 0; i < origQuoteNumOfChars ; ++i) { // i iterates over characters in the quote
- if (j < _currentSubtitleLines && i < _subtitleLineSplitAtCharIndex[j]) {
- _subtitleLineQuote[j] += textCharacters[i];
- } else { // i is now at a split point of the quote
- _subtitleLineQuote[j] += '\0';
- j += 1; // start next line
- }
- }
- _subtitleLineQuote[j] += '\0'; // the last line should also be NULL terminated
- //
- // Check widths and set starting X positions per line
- for (int k = 0; k < _currentSubtitleLines; ++k) {
- tmpLineWidth[k] = _font->getStringWidth(_subtitleLineQuote[k]) + 2;
- _subtitleLineScreenX[k] = (639 - tmpLineWidth[k]) / 2;
- _subtitleLineScreenX[k] = CLIP(_subtitleLineScreenX[k], 0, 639 - tmpLineWidth[k]);
- }
- } else {
- // Here we initially have _currentSubtitleLines == 1
- // We check quote for auto-splitting
- // Auto splitting requires space characters in the quote string (which should be ok for the typical cases)
- if (wOrig > kMaxWidthPerLineToAutoSplitThresholdPx) { // kMaxWidthPerLineToAutoSplitThresholdPx is a practical chosen width threshold for auto-splitting quotes purposes
- // Start by splitting in two lines. If the new parts are still too lengthy, re-try by splitting in three lines, etc.
- for (int linesToSplitInto = 2; linesToSplitInto <= kMaxNumOfSubtitlesLines; ++linesToSplitInto) {
- // find the first space after the middle
- _subtitleLineQuote[0] = "";
- _currentSubtitleLines = 1;
-
- textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str(); // reset pointer to the start of subtitle quote
- textCharacters += (origQuoteNumOfChars / linesToSplitInto);
- _subtitleLineSplitAtCharIndex[0] = (origQuoteNumOfChars / linesToSplitInto);
- while (*textCharacters != 0 && !Common::isSpace(*textCharacters)) { // seek for a space character
- _subtitleLineSplitAtCharIndex[0] += 1;
- textCharacters += 1;
- }
-// debug("space character at: %d", _subtitleLineSplitAtCharIndex[0]);
- if (Common::isSpace(*textCharacters)) { // if we found a space, we store the segment up to this point in the first _subtitleLineQuote entry
- textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str();
- for (int i = 0; i < _subtitleLineSplitAtCharIndex[0] ; ++i) {
- _subtitleLineQuote[0] += textCharacters[i];
- }
- _subtitleLineQuote[0] += '\0';
-// debug(" Line 0 quote %s", _subtitleLineQuote[0].c_str());
- tmpLineWidth[0] = _font->getStringWidth(_subtitleLineQuote[0]) + 2; // check the width of the first segment of the quote
- if (tmpLineWidth[0] > kMaxWidthPerLineToAutoSplitThresholdPx && linesToSplitInto < kMaxNumOfSubtitlesLines) {
- // we exceed max width so we reset process by trying to split into more lines
- continue; // re-try the For-loop with increased linesToSplitInto by 1
- } else {
- // keep current split, proceed with splitting the quote for the rest of the subtitle lines (linesToSplitInto)
- for (int j = 2; j <= linesToSplitInto; ++j) {
- textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str(); // reset pointer to the start of subtitle quote
- textCharacters += ((j * origQuoteNumOfChars) / linesToSplitInto); // move pointer to start of split-seek point for this line segment
- _subtitleLineSplitAtCharIndex[_currentSubtitleLines] = ((j * origQuoteNumOfChars) / linesToSplitInto);
- while (*textCharacters != 0 && !Common::isSpace(*textCharacters)) {
- _subtitleLineSplitAtCharIndex[_currentSubtitleLines] += 1;
- textCharacters += 1;
- }
- textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str(); // reset pointer to the start of subtitle quote
- for (int i = _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] + 1; i < _subtitleLineSplitAtCharIndex[_currentSubtitleLines]; ++i) {
- _subtitleLineQuote[_currentSubtitleLines] += textCharacters[i];
- }
- _subtitleLineQuote[_currentSubtitleLines] += '\0';
-// debug(" Line %d, space blank at: %d, quote %s", _currentSubtitleLines, _subtitleLineSplitAtCharIndex[_currentSubtitleLines], _subtitleLineQuote[_currentSubtitleLines].c_str());
- _currentSubtitleLines += 1;
- }
- //
- // Check widths and set starting X positions per line
- for (int j = 0; j < _currentSubtitleLines; ++j) {
- tmpLineWidth[j] = _font->getStringWidth(_subtitleLineQuote[j]) + 2;
- _subtitleLineScreenX[j] = (639 - tmpLineWidth[j]) / 2;
- _subtitleLineScreenX[j] = CLIP(_subtitleLineScreenX[j], 0, 639 - tmpLineWidth[j]);
- }
- break; // end the for-loop on linesToSplitInto
- }
- } else {
- // the line exceeds max width but has no space characters
- // we treat it as single line quote (it will appear clipped). This won't happen practically though.
- drawSingleLineQuote = true;
- break; // end the for-loop on linesToSplitInto
- }
- }
- } else { // the width of the line is smaller than the max width
- drawSingleLineQuote = true;
- }
- if (drawSingleLineQuote) {
- _subtitleLineQuote[0] = _currentSubtitleTextFull;
- _subtitleLineScreenX[0] = (639 - wOrig) / 2;
- _subtitleLineScreenX[0] = CLIP(_subtitleLineScreenX[0], 0, 639 - wOrig);
+ _font->drawString(&s, lines[i], 0, y , s.w, s.format.RGBToColor(255, 255, 255), Graphics::kTextAlignCenter);
+ break;
}
}
- //debug("calculatePosition: %d %d", w, _screenFirstLineX);
}
/**
-* Initialize a few basic member vars
-*/
+ * Initialize a few basic member vars
+ */
void Subtitles::clear() {
_isVisible = false;
_forceShowWhenNoSpeech = false;
- _currentSubtitleTextFull = "";
- for (int i = 0; i < kMaxNumOfSubtitlesLines; ++i) {
- _subtitleLineQuote[i] = "";
- _subtitleLineScreenY[i] = 0;
- _subtitleLineScreenX[i] = 0;
- _subtitleLineSplitAtCharIndex[i] = 0;
- }
- _subtitlesQuoteChanged = true;
- _currentSubtitleLines = 0;
+ _currentText.clear();
}
/**
-* Initialize/ reset member vars, close open file descriptors and garbage collect subtitle fonts and text resource
-*/
+ * Initialize/reset member vars, close open file descriptors and garbage collect subtitle fonts and text resource
+ */
void Subtitles::reset() {
clear();
@@ -605,7 +409,7 @@ void Subtitles::reset() {
_subtitlesInfo.dateOfCompile = "N/A";
_subtitlesInfo.languageMode = "N/A";
- for (int i = 0; i != kMaxTextResourceEntries; ++i) {
+ for (int i = 0; i < kMaxTextResourceEntries; ++i) {
if (_vqaSubsTextResourceEntries[i] != nullptr) {
delete _vqaSubsTextResourceEntries[i];
_vqaSubsTextResourceEntries[i] = nullptr;
@@ -617,6 +421,7 @@ void Subtitles::reset() {
delete _font;
_font = nullptr;
}
+
_useUTF8 = false;
}
diff --git a/engines/bladerunner/subtitles.h b/engines/bladerunner/subtitles.h
index eb45a35a3f..1de059b071 100644
--- a/engines/bladerunner/subtitles.h
+++ b/engines/bladerunner/subtitles.h
@@ -26,6 +26,7 @@
#include "bladerunner/bladerunner.h"
#include "common/str.h"
+#include "common/ustr.h"
namespace Graphics {
class Font;
@@ -41,11 +42,10 @@ class Subtitles {
//
// Subtitles could be in 6 possible languages are EN_ANY, DE_DEU, FR_FRA, IT_ITA, RU_RUS, ES_ESP
// with corresponding _vm->_languageCode values: "E", "G", "F", "I", "E", "S" (Russian version is built on top of English one)
- static const int kMaxNumOfSubtitlesLines = 4; // At least one quote in the game requires 4 lines to be displayed correctly
- static const int kStartFromSubtitleLineFromTop = 2; // Prefer drawing from this line (the top-most of available subtitle lines index is 0) by default
- static const int kSubtitlesBottomYOffsetPx = 12; // In pixels. This is the bottom margin beneath the subtitles space
- static const int kMaxWidthPerLineToAutoSplitThresholdPx = 610; // In pixels
- static const int kMaxTextResourceEntries = 1 + 25; // Support in-game subs (1) and all possible VQAs (25) with spoken dialogue or translatable text
+ static const uint kPreferedLine = 2; // Prefer drawing from this line (the bottom-most of available subtitle lines index is 0) by default
+ static const int kMarginBottom = 12; // In pixels. This is the bottom margin beneath the subtitles space
+ static const int kTextMaxWidth = 610; // In pixels
+ static const int kMaxTextResourceEntries = 1 + 25; // Support in-game subs (1) and all possible VQAs (25) with spoken dialogue or translatable text
static const char *SUBTITLES_FILENAME_PREFIXES[kMaxTextResourceEntries];
static const char *SUBTITLES_FONT_FILENAME_EXTERNAL;
static const char *SUBTITLES_VERSION_TRENAME;
@@ -72,29 +72,23 @@ class Subtitles {
Graphics::Font *_font;
bool _useUTF8;
- bool _isVisible;
- bool _forceShowWhenNoSpeech;
- Common::String _currentSubtitleTextFull;
- Common::String _subtitleLineQuote[kMaxNumOfSubtitlesLines];
- int _subtitleLineScreenY[kMaxNumOfSubtitlesLines];
- int _subtitleLineScreenX[kMaxNumOfSubtitlesLines];
- int _subtitleLineSplitAtCharIndex[kMaxNumOfSubtitlesLines];
- int _currentSubtitleLines;
- bool _subtitlesQuoteChanged;
+ bool _isVisible;
+ bool _forceShowWhenNoSpeech;
+ Common::U32String _currentText;
bool _gameSubsResourceEntriesFound[kMaxTextResourceEntries]; // false if a TRE file did not open successfully
- bool _subtitlesSystemActive; // true if the whole subtitles subsystem should be disabled (due to missing required resources)
+ bool _isSystemActive; // true if the whole subtitles subsystem should be disabled (due to missing required resources)
public:
Subtitles(BladeRunnerEngine *vm);
~Subtitles();
- bool isSystemActive() const { return _subtitlesSystemActive; }
+ bool isSystemActive() const { return _isSystemActive; }
void init();
SubtitlesInfo getSubtitlesInfo() const;
- const char *getInGameSubsText(int actorId, int speech_id); // get the text for actorId, quoteId (in-game subs)
- const char *getOuttakeSubsText(const Common::String &outtakesName, int frame); // get the text for this frame if any
+ void loadInGameSubsText(int actorId, int speech_id); // get the text for actorId, quoteId (in-game subs)
+ void loadOuttakeSubsText(const Common::String &outtakesName, int frame); // get the text for this frame if any
void setGameSubsText(Common::String dbgQuote, bool force); // for debugging - explicit set subs text
bool show();
@@ -105,7 +99,6 @@ public:
private:
void draw(Graphics::Surface &s);
- void calculatePosition();
int getIdxForSubsTreName(const Common::String &treName) const;