[Scummvm-git-logs] scummvm master -> c868fe1365f11a7b029ba89c353386e7bb8cdbf9

elasota noreply at scummvm.org
Fri Aug 12 23:00:54 UTC 2022


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:
c868fe1365 MTROPOLIS: Update subtitle format


Commit: c868fe1365f11a7b029ba89c353386e7bb8cdbf9
    https://github.com/scummvm/scummvm/commit/c868fe1365f11a7b029ba89c353386e7bb8cdbf9
Author: elasota (ejlasota at gmail.com)
Date: 2022-08-12T19:00:31-04:00

Commit Message:
MTROPOLIS: Update subtitle format

Changed paths:
    engines/mtropolis/subtitles.cpp
    engines/mtropolis/subtitles.h


diff --git a/engines/mtropolis/subtitles.cpp b/engines/mtropolis/subtitles.cpp
index d3545de95b6..f1c4e657ea2 100644
--- a/engines/mtropolis/subtitles.cpp
+++ b/engines/mtropolis/subtitles.cpp
@@ -304,7 +304,7 @@ Common::ErrorCode SubtitleLineTable::load(const Common::String &filePath, const
 	if (!loader.readLine(strs))
 		return Common::kReadingFailed;
 
-	if (strs.size() != 7 || strs[0] != "subtitle_set_id" || strs[1] != "text" || strs[2] != "time" || strs[3] != "duration" || strs[4] != "location" || strs[5] != "speaker" || strs[6] != "is_gameplay")
+	if (strs.size() != 8 || strs[0] != "subtitle_set_id" || strs[1] != "text" || strs[2] != "time" || strs[3] != "duration" || strs[4] != "slot" || strs[5] != "speaker" || strs[6] != "class" || strs[7] != "position")
 		return Common::kReadingFailed;
 
 	uint currentLine = 0;
@@ -312,32 +312,37 @@ Common::ErrorCode SubtitleLineTable::load(const Common::String &filePath, const
 		if (strs.size() == 0)
 			break;
 
-		if (strs.size() != 7)
+		if (strs.size() != 8)
 			return Common::kReadingFailed;
 
 		double timestamp = 0;
 		double duration = 0;
-		uint location = 0;
-		uint isGameplay = 0;
+		double position = 0;
+		uint slot = 0;
+		LineClass lineClass = kLineClassDefault;
 		if (sscanf(strs[2].c_str(), "%lf", &timestamp) != 1)
 			timestamp = 0;
 
 		if (sscanf(strs[3].c_str(), "%lf", &duration) != 1)
 			duration = 0;
 
-		if (sscanf(strs[4].c_str(), "%u", &location) != 1)
-			location = 0;
+		if (sscanf(strs[4].c_str(), "%u", &slot) != 1)
+			slot = 0;
 
-		if (sscanf(strs[6].c_str(), "%u", &isGameplay) != 1)
-			isGameplay = 0;
+		if (strs[6] == "gameplay")
+			lineClass = kLineClassGameplay;
+
+		if (sscanf(strs[7].c_str(), "%lf", &position) != 1)
+			position = 0;
 
 		LineData lineData;
 		lineData.durationMSec = static_cast<uint32>(duration * 1000.0);
 		lineData.timeOffsetMSec = static_cast<uint32>(timestamp * 1000.0);
 		lineData.textUTF8 = strs[1];
-		lineData.location = location;
+		lineData.slot = slot;
 		lineData.speakerID = speakerTable.getSpeakerID(strs[5]);
-		lineData.isGameplay = isGameplay;
+		lineData.lineClass = lineClass;
+		lineData.position = position;
 
 		LineRange &range = _lineRanges[strs[0]];
 		if (range.numLines == 0)
@@ -361,7 +366,7 @@ SubtitleLineTable::LineRange::LineRange() : linesStart(0), numLines(0) {
 }
 
 
-SubtitleLineTable::LineData::LineData() : timeOffsetMSec(0), location(0), durationMSec(0), speakerID(0), isGameplay(false) {
+SubtitleLineTable::LineData::LineData() : timeOffsetMSec(0), slot(0), durationMSec(0), speakerID(0), lineClass(kLineClassDefault), position(0) {
 }
 
 const Common::Array<SubtitleLineTable::LineData> &SubtitleLineTable::getAllLines() const {
@@ -378,7 +383,8 @@ const SubtitleLineTable::LineRange *SubtitleLineTable::getLinesForSubtitleSetID(
 SubtitleRenderer::DisplayItem::DisplayItem() : expireTime(0) {
 }
 
-SubtitleDisplayItem::SubtitleDisplayItem(const Common::String &text, const Common::String &speaker, uint slot) : _slot(slot) {
+SubtitleDisplayItem::SubtitleDisplayItem(const Common::String &text, const Common::String &speaker, uint slot, double position)
+	: _slot(slot), _position(position) {
 	_text = text.decode(Common::kUtf8);
 	_speaker = speaker.decode(Common::kUtf8);
 }
@@ -395,14 +401,20 @@ uint SubtitleDisplayItem::getSlot() const {
 	return _slot;
 }
 
-SubtitleRenderer::SubtitleRenderer() : _nonImmediateDisappearTime(3500), _isDirty(true), _lastTime(0) {
+double SubtitleDisplayItem::getPosition() const {
+	return _position;
+}
+
+SubtitleRenderer::SubtitleRenderer() : _nonImmediateDisappearTime(3500), _isDirty(true), _lastTime(0), _fontHeight(0) {
 #ifdef USE_FREETYPE2
 	Common::File fontFile;
 	const char *fontPath = "LiberationSans-Bold.ttf";
 
 	_font.reset(Graphics::loadTTFFontFromArchive(fontPath, 14, Graphics::kTTFSizeModeCell));
 
-	if (!_font)
+	if (_font) {
+		_fontHeight = _font->getFontHeight();
+	} else
 		warning("Couldn't open '%s', subtitles will not work", fontPath);
 
 	// TODO: Maybe support subtitles some other way if FreeType isn't enabled
@@ -417,6 +429,7 @@ void SubtitleRenderer::addDisplayItem(const Common::SharedPtr<SubtitleDisplayIte
 	for (DisplayItem &existingItem : _displayItems) {
 		if (existingItem.item->getSlot() == item->getSlot()) {
 			existingItem.item = item;
+			existingItem.surface.reset();
 			if (duration > 0)
 				existingItem.expireTime = _lastTime + duration;
 			else
@@ -477,12 +490,14 @@ bool SubtitleRenderer::update(uint64 currentTime) {
 }
 
 void SubtitleRenderer::composite(Window &window) const {
-	if (_surface) {
-		Graphics::ManagedSurface *windowSurf = window.getSurface().get();
-		if (windowSurf) {
-			int x = (windowSurf->w - _surface->w) / 2;
-			int y = (windowSurf->h + 300) / 2 - _surface->h;
-			windowSurf->blitFrom(*_surface, Common::Point(x, y));
+	for (const DisplayItem& displayItem : _displayItems) {
+		if (displayItem.surface) {
+			Graphics::ManagedSurface *windowSurf = window.getSurface().get();
+			if (windowSurf) {
+				int x = (windowSurf->w - displayItem.surface->w) / 2;
+				int y = (windowSurf->h + 300) / 2 - displayItem.surface->h + static_cast<int>(_fontHeight * displayItem.item->getPosition());
+				windowSurf->blitFrom(*displayItem.surface, Common::Point(x, y));
+			}
 		}
 	}
 }
@@ -495,10 +510,13 @@ void SubtitleRenderer::render() {
 	if (!_font)
 		return;
 
-	uint widestLine = 0;
-	uint numLines = 0;
-	for (const DisplayItem &item : _displayItems) {
-		if (item.item) {
+	for (uint ri = _displayItems.size(); ri > 0; ri--) {
+		uint i = ri - 1;
+
+		DisplayItem &item = _displayItems[i];
+		if (!item.surface) {
+			uint widestLine = 0;
+
 			const SubtitleDisplayItem &dispItem = *item.item;
 			Common::Array<Common::U32String> lines;
 
@@ -521,56 +539,26 @@ void SubtitleRenderer::render() {
 					widestLine = speakerWidth;
 			}
 
-			if (itemLines > numLines)
-				numLines = itemLines;
-		}
-	}
-
-	_surface.reset();
-
-	if (numLines == 0 || widestLine == 0)
-		return;
-
-	int fontHeight = _font->getFontHeight();
-
-	const int borderWidth = 1;
-	const int verticalPadding = 5;
-	const int horizontalPadding = 20;
-
-	int surfaceWidth = static_cast<int>(widestLine) + borderWidth * 2 + horizontalPadding * 2;
-	int surfaceHeight = static_cast<int>(numLines) * fontHeight + borderWidth * 2 + verticalPadding * 2;
-
-	Graphics::PixelFormat fmt = Graphics::createPixelFormat<8888>();
-	_surface.reset(new Graphics::ManagedSurface(surfaceWidth, surfaceHeight, fmt));
-
-	_surface->fillRect(Common::Rect(0, 0, surfaceWidth, surfaceHeight), fmt.RGBToColor(0, 0, 0));
+			if (itemLines == 0 || widestLine == 0) {
+				// Nothing to render, remove the item
+				_displayItems.remove_at(i);
+				_isDirty = true;
+				continue;
+			}
 
-	for (int drawPass = 0; drawPass < 2; drawPass++) {
-		for (const DisplayItem &item : _displayItems) {
-			if (item.item) {
-				const SubtitleDisplayItem &dispItem = *item.item;
-				Common::Array<Common::U32String> lines;
+			const int borderWidth = 1;
+			const int verticalPadding = 5;
+			const int horizontalPadding = 20;
 
-				const Common::U32String &itemText = dispItem.getText();
+			int surfaceWidth = static_cast<int>(widestLine) + borderWidth * 2 + horizontalPadding * 2;
+			int surfaceHeight = static_cast<int>(itemLines) * _fontHeight + borderWidth * 2 + verticalPadding * 2;
 
-				int speakerLine = 0;
-				for (uint i = 0; i < itemText.size(); i++) {
-					if (itemText[i] == '\\')
-						speakerLine++;
-					else
-						break;
-				}
+			Graphics::PixelFormat fmt = Graphics::createPixelFormat<8888>();
+			Common::SharedPtr<Graphics::ManagedSurface> surface(new Graphics::ManagedSurface(surfaceWidth, surfaceHeight, fmt));
 
-				splitLines(itemText, lines);
-
-				for (const Common::U32String &str : lines) {
-					uint width = _font->getStringWidth(str);
-					if (width > widestLine)
-						widestLine = width;
-				}
-
-				const Common::U32String &speaker = item.item->getSpeaker();
+			surface->fillRect(Common::Rect(0, 0, surfaceWidth, surfaceHeight), fmt.RGBToColor(0, 0, 0));
 
+			for (int drawPass = 0; drawPass < 2; drawPass++) {
 				int textStartLine = 0;
 				if (speaker.size() > 0) {
 					textStartLine++;
@@ -585,7 +573,7 @@ void SubtitleRenderer::render() {
 					else
 						drawColor = fmt.RGBToColor(255, 255, 127);
 
-					_font->drawString(_surface.get(), speaker, startX, speakerLine * fontHeight + verticalPadding + borderWidth, speakerWidth, drawColor);
+					_font->drawString(surface.get(), speaker, startX, verticalPadding + borderWidth, speakerWidth, drawColor);
 				}
 
 				for (uint lineIndex = 0; lineIndex < lines.size(); lineIndex++) {
@@ -601,72 +589,75 @@ void SubtitleRenderer::render() {
 					else
 						drawColor = fmt.RGBToColor(255, 255, 255);
 
-					_font->drawString(_surface.get(), line, startX, (textStartLine + static_cast<int>(lineIndex)) * fontHeight + verticalPadding + borderWidth, lineWidth, drawColor);
+					_font->drawString(surface.get(), line, startX, (textStartLine + static_cast<int>(lineIndex)) * _fontHeight + verticalPadding + borderWidth, lineWidth, drawColor);
 				}
-			}
-		}
 
-		if (drawPass == 0) {
-			int w = _surface->w;
-			int h = _surface->h;
+				if (drawPass == 0) {
+					int w = surface->w;
+					int h = surface->h;
+
+					// Horizontal pass (max r -> g)
+					for (int y = borderWidth; y < h - borderWidth; y++) {
+						uint32 *rowPixels = static_cast<uint32 *>(surface->getBasePtr(0, y));
 
-			// Horizontal pass (max r -> g)
-			for (int y = borderWidth; y < h - borderWidth; y++) {
-				uint32 *rowPixels = static_cast<uint32 *>(_surface->getBasePtr(0, y));
+						for (int x = borderWidth; x < w - borderWidth; x++) {
+							uint8 r, g, b, a;
+							uint8 brightest = 0;
 
-				for (int x = borderWidth; x < w - borderWidth; x++) {
-					uint8 r, g, b, a;
-					uint8 brightest = 0;
+							for (int kxo = -borderWidth; kxo < borderWidth; kxo++) {
+								fmt.colorToARGB(rowPixels[x + kxo], a, r, g, b);
 
-					for (int kxo = -borderWidth; kxo < borderWidth; kxo++) {
-						fmt.colorToARGB(rowPixels[x + kxo], a, r, g, b);
+								if (r > brightest)
+									brightest = r;
+							}
 
-						if (r > brightest)
-							brightest = r;
+							fmt.colorToARGB(rowPixels[x], a, r, g, b);
+							rowPixels[x] = fmt.ARGBToColor(a, r, brightest, b);
+						}
 					}
 
-					fmt.colorToARGB(rowPixels[x], a, r, g, b);
-					rowPixels[x] = fmt.ARGBToColor(a, r, brightest, b);
-				}
-			}
+					// Vertical pass (max g -> b)
+					int pitch = surface->pitch;
+					for (int x = borderWidth; x < w - borderWidth; x++) {
+						char *basePixelPtr = static_cast<char *>(surface->getBasePtr(x, 0));
 
-			// Vertical pass (max g -> b)
-			int pitch = _surface->pitch;
-			for (int x = borderWidth; x < w - borderWidth; x++) {
-				char *basePixelPtr = static_cast<char *>(_surface->getBasePtr(x, 0));
+						for (int y = borderWidth; y < h - borderWidth; y++) {
+							uint8 r, g, b, a;
+							uint8 brightest = 0;
 
-				for (int y = borderWidth; y < h - borderWidth; y++) {
-					uint8 r, g, b, a;
-					uint8 brightest = 0;
+							for (int kyo = -borderWidth; kyo < borderWidth; kyo++) {
+								uint32 *offsetPxPtr = reinterpret_cast<uint32 *>(basePixelPtr + (y + kyo) * pitch);
+								fmt.colorToARGB(*offsetPxPtr, a, r, g, b);
 
-					for (int kyo = -borderWidth; kyo < borderWidth; kyo++) {
-						uint32 *offsetPxPtr = reinterpret_cast<uint32 *>(basePixelPtr + (y + kyo) * pitch);
-						fmt.colorToARGB(*offsetPxPtr, a, r, g, b);
+								if (g > brightest)
+									brightest = g;
+							}
 
-						if (g > brightest)
-							brightest = g;
+							uint32 *pxPtr = reinterpret_cast<uint32 *>(basePixelPtr + y * pitch);
+							fmt.colorToARGB(*pxPtr, a, r, g, b);
+							*pxPtr = fmt.ARGBToColor(a, r, g, brightest);
+						}
 					}
 
-					uint32 *pxPtr = reinterpret_cast<uint32 *>(basePixelPtr + y * pitch);
-					fmt.colorToARGB(*pxPtr, a, r, g, b);
-					*pxPtr = fmt.ARGBToColor(a, r, g, brightest);
-				}
-			}
-
-			// Shadow backdrop pass
-			for (int y = 0; y < h; y++) {
-				uint32 *rowPixels = static_cast<uint32 *>(_surface->getBasePtr(0, y));
+					// Shadow backdrop pass
+					for (int y = 0; y < h; y++) {
+						uint32 *rowPixels = static_cast<uint32 *>(surface->getBasePtr(0, y));
 
-				for (int x = 0; x < w; x++) {
-					uint8 a, r, g, b;
-					fmt.colorToARGB(rowPixels[x], a, r, g, b);
+						for (int x = 0; x < w; x++) {
+							uint8 a, r, g, b;
+							fmt.colorToARGB(rowPixels[x], a, r, g, b);
 
-					uint8 minGrayAlpha = 224;
-					uint8 grayAlpha = (((256 - minGrayAlpha) * b) >> 8) + minGrayAlpha;
+							uint8 minGrayAlpha = 224;
+							uint8 grayAlpha = (((256 - minGrayAlpha) * b) >> 8) + minGrayAlpha;
 
-					rowPixels[x] = fmt.ARGBToColor(grayAlpha, 0, 0, 0);
+							rowPixels[x] = fmt.ARGBToColor(grayAlpha, 0, 0, 0);
+						}
+					}
 				}
 			}
+
+			// Done drawing
+			item.surface = surface;
 		}
 	}
 }
@@ -728,9 +719,9 @@ void SubtitlePlayer::stop() {
 void SubtitlePlayer::triggerSubtitleLine(const SubtitleLineTable::LineData &line) {
 	SubtitleRenderer *renderer = _runtime->getSubtitleRenderer().get();
 	if (renderer) {
-		Common::SharedPtr<SubtitleDisplayItem> dispItem(new SubtitleDisplayItem(line.textUTF8, _speakers->getSpeakers()[line.speakerID], line.location));
+		Common::SharedPtr<SubtitleDisplayItem> dispItem(new SubtitleDisplayItem(line.textUTF8, _speakers->getSpeakers()[line.speakerID], line.slot, line.position));
 		for (uint i = 0; i < _items.size(); i++) {
-			if (_items[i]->getSlot() == line.location) {
+			if (_items[i]->getSlot() == line.slot) {
 				renderer->removeDisplayItem(_items[i].get(), true);
 				_items.remove_at(i);
 				break;
diff --git a/engines/mtropolis/subtitles.h b/engines/mtropolis/subtitles.h
index d226bb59fc6..e84391e154b 100644
--- a/engines/mtropolis/subtitles.h
+++ b/engines/mtropolis/subtitles.h
@@ -94,15 +94,21 @@ public:
 		uint numLines;
 	};
 
+	enum LineClass {
+		kLineClassDefault,
+		kLineClassGameplay,
+	};
+
 	struct LineData {
 		LineData();
 
 		uint32 timeOffsetMSec;
-		uint location;
+		uint slot;
 		uint durationMSec;
 		Common::String textUTF8;
 		uint speakerID;
-		bool isGameplay;
+		LineClass lineClass;
+		double position;
 	};
 
 	const Common::Array<LineData> &getAllLines() const;
@@ -123,16 +129,18 @@ struct SubtitleTables {
 
 class SubtitleDisplayItem {
 public:
-	SubtitleDisplayItem(const Common::String &text, const Common::String &speaker, uint slot);
+	SubtitleDisplayItem(const Common::String &text, const Common::String &speaker, uint slot, double position);
 
 	const Common::U32String &getText() const;
 	const Common::U32String &getSpeaker() const;
 	uint getSlot() const;
+	double getPosition() const;
 
 private:
 	Common::U32String _text;
 	Common::U32String _speaker;
 	uint _slot;
+	double _position;
 };
 
 class SubtitleRenderer {
@@ -152,6 +160,7 @@ private:
 		DisplayItem();
 
 		Common::SharedPtr<SubtitleDisplayItem> item;
+		Common::SharedPtr<Graphics::ManagedSurface> surface;
 		uint64 expireTime;
 	};
 
@@ -159,10 +168,11 @@ private:
 	static void splitLines(const Common::U32String &str, Common::Array<Common::U32String> &outLines);
 
 	Common::Array<DisplayItem> _displayItems;
-	Common::SharedPtr<Graphics::ManagedSurface> _surface;
+
 	Common::SharedPtr<Graphics::Font> _font;
 	uint64 _lastTime;
 	uint _nonImmediateDisappearTime;
+	int _fontHeight;
 	bool _isDirty;
 };
 




More information about the Scummvm-git-logs mailing list