diff options
author | Peter Kohaut | 2019-07-15 00:26:18 +0200 |
---|---|---|
committer | Peter Kohaut | 2019-07-16 21:56:33 +0200 |
commit | 39e4fdb98c27f97ffffcfba8b6579697a4c809d2 (patch) | |
tree | 0aed595ef6ef7f11a5116f91449d5572a34fac44 /engines/bladerunner | |
parent | a767a6800d2f76b90b66d7c0dcb96c0514350721 (diff) | |
download | scummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.tar.gz scummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.tar.bz2 scummvm-rg350-39e4fdb98c27f97ffffcfba8b6579697a4c809d2.zip |
BLADERUNNER: Use ScummVM word wrapping algorithm
Diffstat (limited to 'engines/bladerunner')
-rw-r--r-- | engines/bladerunner/actor.cpp | 2 | ||||
-rw-r--r-- | engines/bladerunner/outtake.cpp | 2 | ||||
-rw-r--r-- | engines/bladerunner/subtitles.cpp | 375 | ||||
-rw-r--r-- | engines/bladerunner/subtitles.h | 31 |
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; |