[Scummvm-git-logs] scummvm master -> 90688204d2f7da59c67c9b34a793af43e3fb56fa

antoniou79 antoniou at cti.gr
Sat Mar 9 19:03:17 CET 2019


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
90688204d2 BLADERUNNER: Subtitles code improvements


Commit: 90688204d2f7da59c67c9b34a793af43e3fb56fa
    https://github.com/scummvm/scummvm/commit/90688204d2f7da59c67c9b34a793af43e3fb56fa
Author: Thanasis Antoniou (a.antoniou79 at gmail.com)
Date: 2019-03-09T20:01:29+02:00

Commit Message:
BLADERUNNER: Subtitles code improvements

Allow for 4 lines of subtitles, but start from using 2 lines by default

Also added debugger command to allow for immediate text testing for subtitles

Changed paths:
    engines/bladerunner/actor.cpp
    engines/bladerunner/debugger.cpp
    engines/bladerunner/debugger.h
    engines/bladerunner/subtitles.cpp
    engines/bladerunner/subtitles.h


diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 44dd3a6..e1a5f98 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -592,10 +592,6 @@ bool Actor::tick(bool forceDraw, Common::Rect *screenRect) {
 		timeLeft = 0;
 	}
 
-	if (!isSpeeching()) {
-		_vm->_subtitles->hide();
-	}
-
 	if (needsUpdate) {
 		int newAnimation = 0, newFrame = 0;
 		_vm->_aiScripts->updateAnimation(_id, &newAnimation, &newFrame);
diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index f8101f6..08c26e3 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -50,6 +50,7 @@
 #include "bladerunner/waypoints.h"
 #include "bladerunner/zbuffer.h"
 #include "bladerunner/overlays.h"
+#include "bladerunner/subtitles.h"
 
 
 #include "common/debug.h"
@@ -91,6 +92,7 @@ Debugger::Debugger(BladeRunnerEngine *vm) : GUI::Debugger() {
 	registerCmd("load", WRAP_METHOD(Debugger, cmdLoad));
 	registerCmd("save", WRAP_METHOD(Debugger, cmdSave));
 	registerCmd("overlay", WRAP_METHOD(Debugger, cmdOverlay));
+	registerCmd("subtitle", WRAP_METHOD(Debugger, cmdSubtitle));
 }
 
 Debugger::~Debugger() {
@@ -800,6 +802,36 @@ bool Debugger::cmdOverlay(int argc, const char **argv) {
 	return true;
 }
 
+/**
+*
+* Show an explicitly specified string as a subtitle
+*/
+bool Debugger::cmdSubtitle(int argc, const char **argv) {
+	bool invalidSyntax = false;
+
+	if (argc != 2) {
+		invalidSyntax = true;
+	} else {
+		Common::String subtitleText = argv[1];
+		if (subtitleText == "reset") {
+			_vm->_subtitles->setGameSubsText("", false);
+		} else {
+			debugPrintf("Showing text: %s\n", subtitleText.c_str());
+			_vm->_subtitles->setGameSubsText(subtitleText, true);
+			_vm->_subtitles->show();
+		}
+	}
+
+	if (invalidSyntax) {
+		debugPrintf("Show specified text as subtitle or clear the current subtitle (with the reset option).\n");
+		debugPrintf("Use double quotes to encapsulate the text.\n");
+		debugPrintf("Usage: %s (\"<text_to_display>\" | reset)\n", argv[0]);
+	}
+	return true;
+
+}
+
+
 void Debugger::drawDebuggerOverlay() {
 	if (_viewSceneObjects) drawSceneObjects();
 	if (_viewScreenEffects) drawScreenEffects();
diff --git a/engines/bladerunner/debugger.h b/engines/bladerunner/debugger.h
index f425543..5770ad7 100644
--- a/engines/bladerunner/debugger.h
+++ b/engines/bladerunner/debugger.h
@@ -74,6 +74,7 @@ public:
 	bool cmdLoad(int argc, const char **argv);
 	bool cmdSave(int argc, const char **argv);
 	bool cmdOverlay(int argc, const char **argv);
+	bool cmdSubtitle(int argc, const char **argv);
 
 	void drawDebuggerOverlay();
 
diff --git a/engines/bladerunner/subtitles.cpp b/engines/bladerunner/subtitles.cpp
index 1ef22cb..4157d75 100644
--- a/engines/bladerunner/subtitles.cpp
+++ b/engines/bladerunner/subtitles.cpp
@@ -22,25 +22,24 @@
 
 #include "bladerunner/subtitles.h"
 
-#include "bladerunner/bladerunner.h"
 #include "bladerunner/font.h"
 #include "bladerunner/text_resource.h"
 #include "bladerunner/audio_speech.h"
-#include "common/debug.h"
+//#include "common/debug.h"
 
 namespace BladeRunner {
 
 /*
  * Optional support for subtitles
+ *
  * CHECK what happens in VQA where the audio plays separately (are the finales such VQAs ?)
- * TODO? Catch error for bad symbol in a quote (one that causes the font to crash) - this could happen with the corrupted internal font (TAHOMA18) -> font crash or bad font display / garbage character
- * TODO? Use another escape sequence to progressively display text in a line (like in SCUMM games) <-- this could be very useful with very long lines - might also need an extra manual time or ticks parameter to determine when during the display of the first segment we should switch to the second.
- * TODO? A more advanced subtitles system
- *          TODO: subtitles could be independent from sound playing (but should disappear when switching between UI screens)
+ * TODO? Use another escape sequence to progressively display text in a line (like in SCUMM games) <-- this could be very useful with very long lines
+ *			- might also need an extra manual time or ticks parameter to determine when during the display of the first segment we should switch to the second.
+ * TODO? A more advanced subtitles system:
+ *          TODO: subtitles could be independent from sound playing (but probably should disappear when switching between UI screens)
  *          TODO?: Support for queuing subtitles when more than one subtitle should play for a spoken dialogue (due to a very long quote)
  *          TODO?: Predefine a minimum time for a subtitle to appear, before it is interrupted by the next one. (might need queuing)
  *          TODO?: If the subtitle is the last one then extend its duration to another predefined delay.
- *          TODO?: A system to auto-split a dialogue after some max characters per both lines to a new dialogue set (delete previous 2 lines, start a new one(s) with the rest of the quote).
  *
  * DONE Removed support for internal font TAHOMA18 - this particular font is corrupted!
  * DONE Create and Support proper external FON for subtitles.
@@ -150,7 +149,7 @@ void Subtitles::init(void) {
 	}
 	// Done - Loading text resources
 	//
-	// Initializing/Loading Subtitles' Fonts
+	// Initializing/Loading Subtitles Fonts
 	_subsFont = new Font(_vm);
 	// Use TAHOMA18.FON (is corrupted in places)
 	// 10PT or TAHOMA24 or KIA6PT  have all caps glyphs (and also are too big or too small) so they are not appropriate.
@@ -168,7 +167,7 @@ void Subtitles::init(void) {
 	//  debug("Max height %d", _subsFont->getTextHeight(""));
 	if (_subsFontsLoaded) {
 		for (int i = 0; i < kMaxNumOfSubtitlesLines; ++i) {
-			_subtitleLineScreenY[i] = 479 - ((kMaxNumOfSubtitlesLines - i) * (_subsFont->getTextHeight("") + 1));
+			_subtitleLineScreenY[i] = 479 - kSubtitlesBottomYOffsetPx - ((kMaxNumOfSubtitlesLines - i) * (_subsFont->getTextHeight("") + 1));
 		}
 	}
 }
@@ -257,10 +256,11 @@ const char *Subtitles::getOuttakeSubsText(const Common::String &outtakesName, in
 * Explicitly set the active subtitle text to be displayed
 * Used for debug purposes mainly.
 */
-void Subtitles::setGameSubsText(Common::String dbgQuote) {
+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
 	}
 }
 
@@ -309,14 +309,16 @@ bool Subtitles::isVisible() const {
 * Tick method specific for outtakes (VQA videos)
 */
 void Subtitles::tickOuttakes(Graphics::Surface &s) {
+	if (_subtitlesSystemInactive || !_vm->isSubtitlesEnabled()) {
+		return;
+	}
+
 	if (_currentSubtitleTextFull.empty()) {
 		_vm->_subtitles->hide();
 	} else {
 		_vm->_subtitles->show();
 	}
-	if (_subtitlesSystemInactive || !_vm->isSubtitlesEnabled()) {
-		return;
-	}
+
 	if (!_isVisible) { // keep it as a separate if
 		return;
 	}
@@ -327,12 +329,14 @@ void Subtitles::tickOuttakes(Graphics::Surface &s) {
 * Tick method for in-game subtitles -- Not for outtake cutscenes (VQA videos)
 */
 void Subtitles::tick(Graphics::Surface &s) {
-	if (!_vm->_audioSpeech->isPlaying()) {
-		_vm->_subtitles->hide(); // TODO might need a better system. Don't call it always.
-	}
 	if (_subtitlesSystemInactive || !_vm->isSubtitlesEnabled()) {
 		return;
 	}
+
+	if (!_vm->_audioSpeech->isPlaying() && !_forceShowWhenNoSpeech && _isVisible) {
+		_vm->_subtitles->hide(); // TODO might need a better system. Don't call it always.
+	}
+
 	if (!_isVisible)  { // keep it as a separate if
 		return;
 	}
@@ -351,8 +355,20 @@ void Subtitles::draw(Graphics::Surface &s) {
 		_subtitlesQuoteChanged = false;
 	}
 
-	for (int i = 0; i < _currentSubtitleLines; ++i) {
-		_subsFont->draw(_subtitleLineQuote[i], s, _subtitleLineScreenX[i], _subtitleLineScreenY[i]);
+	// 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;
+	}
+
+	for (int i = 0, j = startingLineFromTop; i < _currentSubtitleLines; ++i, ++j) {
+		_subsFont->draw(_subtitleLineQuote[i], s, _subtitleLineScreenX[i], _subtitleLineScreenY[j]);
 	}
 }
 
@@ -376,8 +392,8 @@ void Subtitles::draw(Graphics::Surface &s) {
 * 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 based on quote pixel width and not character count
+* 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() {
@@ -402,7 +418,10 @@ void Subtitles::calculatePosition() {
 
 	while (*textCharacters != 0) {
 		// check for new line explicit split case
-		if (_currentSubtitleLines < kMaxNumOfSubtitlesLines && *textCharacters == '\n' && tmpCharIndex != 0 && _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] == 0) {
+		if (_currentSubtitleLines < kMaxNumOfSubtitlesLines
+			&& *textCharacters == '\n'
+			&& tmpCharIndex != 0
+			&& _subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] == 0) {
 			_subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] = tmpCharIndex;
 			_currentSubtitleLines += 1;
 		}
@@ -410,14 +429,14 @@ void Subtitles::calculatePosition() {
 		textCharacters += 1;
 	}
 	_subtitleLineSplitAtCharIndex[_currentSubtitleLines - 1] = tmpCharIndex;
-	if (_currentSubtitleLines > 1) { // This means that split on new line characters is possible
+	if (_currentSubtitleLines > 1) { // This means that splitting on new line characters is possible
 		//
-		int j = 0;																// j iterates over subtitle lines.
-		textCharacters = (const uint8 *)_currentSubtitleTextFull.c_str();		// reset pointer to the start of subtitle quote
-		for (int i = 0; i < origQuoteNumOfChars ; ++i) {						// i iterates over line characters
+		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 at split point
+			} else { 															// i is now at a split point of the quote
 				_subtitleLineQuote[j] += '\0';
 				j += 1;															// start next line
 			}
@@ -432,9 +451,9 @@ void Subtitles::calculatePosition() {
 		}
 	} else {
 		// Here we initially have _currentSubtitleLines == 1
-		// Check quote for auto-splitting
+		// 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 threshold for width for auto-splitting quotes purposes
+		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
@@ -511,6 +530,7 @@ void Subtitles::calculatePosition() {
 */
 void Subtitles::clear() {
 	_isVisible = false;
+	_forceShowWhenNoSpeech = false;
 	_currentSubtitleTextFull = "";
 	for (int i = 0; i < kMaxNumOfSubtitlesLines; ++i) {
 		_subtitleLineQuote[i] = "";
diff --git a/engines/bladerunner/subtitles.h b/engines/bladerunner/subtitles.h
index 208a8f3..2947ab5 100644
--- a/engines/bladerunner/subtitles.h
+++ b/engines/bladerunner/subtitles.h
@@ -41,14 +41,16 @@ class TextResource;
 class Font;
 
 class Subtitles {
+	friend class Debugger;
 	//
 	// Subtitles could be in 6 possible languages are EN_ANY, DE_DEU, FR_FRA, IT_ITA, ES_ESP
 	//                   with corresponding _vm->_languageCode values: "E", "G", "F", "I", "R", "S"
-	// TODO Maybe support 1 + 6 * 26 entries to support multiple language subtitles? Would that be useful?
-	// TODO Or just support the current _vm->_languageCode ? [current implementation]
-	static const int kMaxNumOfSubtitlesLines = 3;
-	static const int kMaxWidthPerLineToAutoSplitThresholdPx = 610;
-	static const int kMaxTextResourceEntries = 1 + 25; // Support in-game subs (1) and all possible VQAs (25) with spoken dialogue or translatable text!
+
+	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 char *SUBTITLES_FILENAME_PREFIXES[kMaxTextResourceEntries];
 	static const char *SUBTITLES_FONT_FILENAME_EXTERNAL;
 
@@ -59,6 +61,7 @@ class Subtitles {
 	Font            *_subsFont;
 
 	bool				_isVisible;
+	bool				_forceShowWhenNoSpeech;
 	Common::String		_currentSubtitleTextFull;
 	Common::String		_subtitleLineQuote[kMaxNumOfSubtitlesLines];
 	int _subtitleLineScreenY[kMaxNumOfSubtitlesLines];
@@ -76,11 +79,11 @@ public:
 	~Subtitles();
 
 	void init();
-	void setSubtitlesSystemInactive(bool flag);                                    // disable subtitles system (possibly due to missing important resources like SUBTITLES.MIX file)
+	void setSubtitlesSystemInactive(bool flag);                     // disable subtitles system (possibly due to missing important resources like SUBTITLES.MIX file)
 	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 setGameSubsText(Common::String dbgQuote);                  // for debugging - explicit set subs text
+	void setGameSubsText(Common::String dbgQuote, bool force);                  // for debugging - explicit set subs text
 	bool show();
 	bool hide();
 	bool isVisible() const;
@@ -89,7 +92,6 @@ public:
 
 private:
 	void draw(Graphics::Surface &s);
-	// bool showAt(int x, int y);               // TODO maybe future use (?)
 	void calculatePosition();
 
 	int getIdxForSubsTreName(const Common::String &treName) const;





More information about the Scummvm-git-logs mailing list