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

phcoder noreply at scummvm.org
Wed May 10 11:19:02 UTC 2023


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

Summary:
f9b6669241 COMMON: Add DBCS-oriented variant of String
e2c1cae56a GRIM: Add detection entry for Chinese monkey4
7e0d5f1c6f GRIM: Support localize file in UTF-16LE
bf4b5db9ed GRIM: Prefer unpacked files over ones in archives
87a4fe7831 GRIM: Support DBCS and Unicode word-wrapping
385d6e5115 GRIM: Mark ZH_TWN as requiring font rendering
98c337f1da GRIM: Support override font
c93486dfe2 GRIM: Support Chinese TGA font
cb3ee1411a GRIM: Use TGA font for Chinese monkey4


Commit: f9b666924149bd529f37dc94dc459f351e551761
    https://github.com/scummvm/scummvm/commit/f9b666924149bd529f37dc94dc459f351e551761
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
COMMON: Add DBCS-oriented variant of String

Changed paths:
  A common/dbcs-str.cpp
  A common/dbcs-str.h
    common/module.mk
    common/str-base.cpp


diff --git a/common/dbcs-str.cpp b/common/dbcs-str.cpp
new file mode 100644
index 00000000000..c286872947e
--- /dev/null
+++ b/common/dbcs-str.cpp
@@ -0,0 +1,230 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/dbcs-str.h"
+#include "common/str.h"
+#include "common/memorypool.h"
+#include "common/util.h"
+
+namespace Common {
+
+void DBCSString::decodeDBCS(const char *str, uint32 len) {
+	for (uint i = 0; i < len; ) {
+		if ((str[i] & 0x80) && i + 1 < len) {
+			operator+=((str[i] << 8) | (str[i+1] & 0xff));
+			i += 2;
+		} else if (str[i] & 0x80) {
+			operator+=(str[i] << 8);
+			i++;
+		} else {
+			operator+=(str[i]);
+			i++;
+		}
+	}
+}
+
+DBCSString::DBCSString(const char *str) : BaseString<uint16>() {
+	if (str == nullptr) {
+		_storage[0] = 0;
+		_size = 0;
+	} else {
+		decodeDBCS(str, strlen(str));
+	}
+}
+
+DBCSString::DBCSString(const char *str, uint32 len) : BaseString<uint16>() {
+	decodeDBCS(str, len);
+}
+
+DBCSString::DBCSString(const char *beginP, const char *endP) : BaseString<uint16>() {
+	assert(endP >= beginP);
+	decodeDBCS(beginP, endP - beginP);
+}
+
+DBCSString::DBCSString(const String &str) : BaseString<uint16>() {
+	decodeDBCS(str.c_str(), str.size());
+}
+
+DBCSString::DBCSString(uint16 c) : BaseString<uint16>() {
+	_storage[0] = c;
+	_storage[1] = 0;
+
+	_size = (c == 0) ? 0 : 1;
+}
+
+DBCSString &DBCSString::operator=(const DBCSString &str) {
+	assign(str);
+	return *this;
+}
+
+DBCSString &DBCSString::operator=(DBCSString &&str) {
+	assign(static_cast<DBCSString &&>(str));
+	return *this;
+}
+
+DBCSString &DBCSString::operator=(const String &str) {
+	clear();
+	decodeDBCS(str.c_str(), str.size());
+	return *this;
+}
+
+DBCSString &DBCSString::operator=(const value_type *str) {
+	return DBCSString::operator=(DBCSString(str));
+}
+
+DBCSString &DBCSString::operator=(const char *str) {
+	clear();
+	decodeDBCS(str, strlen(str));
+	return *this;
+}
+
+DBCSString &DBCSString::operator+=(const DBCSString &str) {
+	if (&str == this) {
+		return operator+=(DBCSString(str));
+	}
+
+	int len = str._size;
+	if (len > 0) {
+		ensureCapacity(_size + len, true);
+
+		memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type));
+		_size += len;
+	}
+	return *this;
+}
+
+DBCSString &DBCSString::operator+=(value_type c) {
+	ensureCapacity(_size + 1, true);
+
+	_str[_size++] = c;
+	_str[_size] = 0;
+
+	return *this;
+}
+
+bool DBCSString::operator==(const String &x) const {
+	return equalsC(x.c_str());
+}
+
+bool DBCSString::operator==(const char *x) const {
+	return equalsC(x);
+}
+
+bool DBCSString::operator!=(const String &x) const {
+	return !equalsC(x.c_str());
+}
+
+bool DBCSString::operator!=(const char *x) const {
+	return !equalsC(x);
+}
+
+DBCSString operator+(const DBCSString &x, const DBCSString &y) {
+	DBCSString temp(x);
+	temp += y;
+	return temp;
+}
+
+DBCSString operator+(const DBCSString &x, const DBCSString::value_type y) {
+	DBCSString temp(x);
+	temp += y;
+	return temp;
+}
+
+DBCSString DBCSString::substr(size_t pos, size_t len) const {
+	if (pos >= _size)
+		return DBCSString();
+	else if (len == npos)
+		return DBCSString(_str + pos);
+	else
+		return DBCSString(_str + pos, MIN((size_t)_size - pos, len));
+}
+
+void DBCSString::insertString(const char *s, uint32 p) {
+	insertString(DBCSString(s), p);
+}
+
+void DBCSString::insertString(const String &s, uint32 p) {
+	insertString(DBCSString(s), p);
+}
+
+void DBCSString::replace(uint32 pos, uint32 count, const DBCSString &str) {
+	replace(pos, count, str, 0, str._size);
+}
+
+void DBCSString::replace(iterator begin_, iterator end_, const DBCSString &str) {
+	replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
+}
+
+void DBCSString::replace(uint32 posOri, uint32 countOri, const DBCSString &str,
+					 uint32 posDest, uint32 countDest) {
+	replace(posOri, countOri, str._str, posDest, countDest);
+}
+
+void DBCSString::replace(uint32 posOri, uint32 countOri, const uint16 *str,
+					 uint32 posDest, uint32 countDest) {
+
+	// Prepare string for the replaced text.
+	if (countOri < countDest) {
+		uint32 offset = countDest - countOri; ///< Offset to copy the characters
+		uint32 newSize = _size + offset;
+
+		ensureCapacity(newSize, true);
+
+		_size = newSize;
+
+		// Push the old characters to the end of the string
+		for (uint32 i = _size; i >= posOri + countDest; i--)
+			_str[i] = _str[i - offset];
+
+	} else if (countOri > countDest) {
+		uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
+
+		makeUnique();
+
+		// Pull the remainder string back
+		for (uint32 i = posOri + countDest; i + offset <= _size; i++)
+			_str[i] = _str[i + offset];
+
+		_size -= offset;
+	} else {
+		makeUnique();
+	}
+
+	// Copy the replaced part of the string
+	for (uint32 i = 0; i < countDest; i++)
+		_str[posOri + i] = str[posDest + i];
+
+}
+
+String DBCSString::convertToString() const {
+	Common::String r;
+	for (uint i = 0; i < size(); i++) {
+		if (_str[i] >= 0x100) {
+			r += _str[i] >> 8;
+			r += _str[i] & 0xff;
+		} else
+			r += _str[i];
+			
+	}
+	return r;
+}
+
+} // End of namespace Common
diff --git a/common/dbcs-str.h b/common/dbcs-str.h
new file mode 100644
index 00000000000..dc66d555953
--- /dev/null
+++ b/common/dbcs-str.h
@@ -0,0 +1,172 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef COMMON_DBCS_STR_H
+#define COMMON_DBCS_STR_H
+
+#include "common/scummsys.h"
+#include "common/util.h"
+#include "common/str-enc.h"
+#include "common/str-base.h"
+
+namespace Common {
+
+class String;
+
+/**
+ * A simple string class for DBCS strings in ScummVM.
+ *
+ * The presence of \0 characters in the string will cause undefined
+ * behavior in some operations.
+ */
+
+class DBCSString : public BaseString<uint16> {
+public:
+	typedef uint32 unsigned_type; /*!< Unsigned version of the underlying type. */
+public:
+	/** Construct a new empty string. */
+	constexpr DBCSString() : BaseString<uint16>() {}
+
+	/** Construct a new string from the given null-terminated C string. */
+	explicit DBCSString(const value_type *str) : BaseString<uint16>(str) {}
+
+	/** Construct a new string containing exactly @p len characters read from address @p str. */
+	DBCSString(const value_type *str, uint32 len) : BaseString<uint16>(str, len) {}
+
+	explicit DBCSString(const uint32 *str) : BaseString<uint16>((const value_type *) str) {}
+	DBCSString(const uint32 *str, uint32 len) : BaseString<uint16>((const value_type *) str, len) {}
+	DBCSString(const uint32 *beginP, const uint32 *endP) : BaseString<uint16>((const value_type *) beginP, (const value_type *) endP) {}
+
+	/** Construct a new string containing the characters between @p beginP (including) and @p endP (excluding). */
+	DBCSString(const value_type *beginP, const value_type *endP) : BaseString<uint16>(beginP, endP) {}
+
+	/** Construct a copy of the given string. */
+	DBCSString(const DBCSString &str) : BaseString<uint16>(str) {}
+
+	/** Construct a string by moving an existing string. */
+	DBCSString(DBCSString &&str) : BaseString<uint16>(static_cast<BaseString<uint16> &&>(str)) {}
+
+	/** Construct a new string from the given null-terminated C string that uses the given @p page encoding. */
+	explicit DBCSString(const char *str);
+
+	/** Construct a new string containing exactly @p len characters read from address @p str. */
+	DBCSString(const char *str, uint32 len);
+
+	/** Construct a new string containing the characters between @p beginP (including) and @p endP (excluding). */
+	DBCSString(const char *beginP, const char *endP);
+
+	/** Construct a copy of the given string. */
+	explicit DBCSString(const String &str);
+
+	/** Construct a string consisting of the given character. */
+	explicit DBCSString(value_type c);
+
+	/** Assign a given string to this string. */
+	DBCSString &operator=(const DBCSString &str);
+
+	/** Move a given string to this string. */
+	DBCSString &operator=(DBCSString &&str);
+
+	/** @overload */
+	DBCSString &operator=(const String &str);
+
+	/** @overload */
+	DBCSString &operator=(const value_type *str);
+
+	/** @overload */
+	DBCSString &operator=(const char *str);
+
+	/** Append the given string to this string. */
+	DBCSString &operator+=(const DBCSString &str);
+
+	/** @overload */
+	DBCSString &operator+=(value_type c);
+
+	using BaseString<value_type>::operator==;
+	using BaseString<value_type>::operator!=;
+
+	/** Check whether this string is identical to string @p x. */
+	bool operator==(const String &x) const;
+
+	/** @overload */
+	bool operator==(const char *x) const;
+
+	/** Check whether this string is different than string @p x. */
+	bool operator!=(const String &x) const;
+
+	/** @overload */
+	bool operator!=(const char *x) const;
+
+	/** Convert the string to the standard String represantation. */
+	String convertToString() const;
+
+	using BaseString<value_type>::insertString;
+	void insertString(const char *s, uint32 p);   /*!< Insert string @p s into this string at position @p p. */
+	void insertString(const String &s, uint32 p); /*!< @overload */
+
+	/** Return a substring of this string */
+	DBCSString substr(size_t pos = 0, size_t len = npos) const;
+
+	/**@{
+	 * Functions to replace some amount of chars with chars from some other string.
+	 *
+	 * @note The implementation follows that of the STL's std::string:
+	 *       http://www.cplusplus.com/reference/string/string/replace/
+	 *
+	 * @param pos Starting position for the replace in the original string.
+	 * @param count Number of chars to replace from the original string.
+	 * @param str Source of the new chars.
+	 * @param posOri Same as pos
+	 * @param countOri Same as count
+	 * @param posDest Initial position to read str from.
+	 * @param countDest Number of chars to read from str. npos by default.
+	 */
+	// Replace 'count' bytes, starting from 'pos' with str.
+	void replace(uint32 pos, uint32 count, const DBCSString &str);
+	// Replace the characters in [begin, end) with str._str.
+	void replace(iterator begin, iterator end, const DBCSString &str);
+	// Replace _str[posOri, posOri + countOri) with
+	// str._str[posDest, posDest + countDest)
+	void replace(uint32 posOri, uint32 countOri, const DBCSString &str,
+					uint32 posDest, uint32 countDest);
+	// Replace _str[posOri, posOri + countOri) with
+	// str[posDest, posDest + countDest)
+	void replace(uint32 posOri, uint32 countOri, const uint16 *str,
+					uint32 posDest, uint32 countDest);
+	/**@}*/
+
+private:
+	void decodeDBCS(const char *str, uint32 len);
+
+	friend class String;
+};
+
+/** Concatenate strings @p x and @p y. */
+DBCSString operator+(const DBCSString &x, const DBCSString &y);
+
+/** Append the given @p y character to the given @p x string. */
+DBCSString operator+(const DBCSString &x, DBCSString::value_type y);
+
+/** @} */
+
+} // End of namespace Common
+
+#endif
diff --git a/common/module.mk b/common/module.mk
index 0f5f40f0b09..6cc1f16ade7 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS := \
 	concatstream.o \
 	config-manager.o \
 	coroutines.o \
+	dbcs-str.o \
 	debug.o \
 	error.o \
 	events.o \
diff --git a/common/str-base.cpp b/common/str-base.cpp
index 1b8b36f7339..c38f33b5192 100644
--- a/common/str-base.cpp
+++ b/common/str-base.cpp
@@ -837,6 +837,7 @@ TEMPLATE uint BASESTRING::hash() const {
 }
 
 template class BaseString<char>;
+template class BaseString<uint16>;
 template class BaseString<u32char_type_t>;
 
 }


Commit: e2c1cae56a398507cce94059ad29658366c01ad6
    https://github.com/scummvm/scummvm/commit/e2c1cae56a398507cce94059ad29658366c01ad6
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Add detection entry for Chinese monkey4

Changed paths:
    engines/grim/detection.cpp


diff --git a/engines/grim/detection.cpp b/engines/grim/detection.cpp
index e8296e4a4ce..2020e7cd958 100644
--- a/engines/grim/detection.cpp
+++ b/engines/grim/detection.cpp
@@ -419,6 +419,20 @@ static const GrimGameDescription gameDescriptions[] = {
 		},
 		GType_MONKEY4
 	},
+	{
+		// Escape from Monkey Island Chinese
+		{
+			"monkey4",
+			"",
+			AD_ENTRY2s("artAll.m4b", "61959da91d864bf5f4588daa4a5a3019", 18515664,
+				   "Script.tab", "ee08a95b6820f7b876940f6cd41dbae7", 618346),
+			Common::ZH_TWN,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE,
+			GUI_OPTIONS_GRIME
+		},
+		GType_MONKEY4
+	},
 	{
 		// Escape from Monkey Island German
 		{


Commit: 7e0d5f1c6ff32dc1af6de53755a8b0b6393c0738
    https://github.com/scummvm/scummvm/commit/7e0d5f1c6ff32dc1af6de53755a8b0b6393c0738
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Support localize file in UTF-16LE

Changed paths:
    engines/grim/grim.h
    engines/grim/localize.cpp


diff --git a/engines/grim/grim.h b/engines/grim/grim.h
index c9f6f3fe9b8..c3c06fa2acc 100644
--- a/engines/grim/grim.h
+++ b/engines/grim/grim.h
@@ -288,6 +288,7 @@ protected:
 public:
 	int _cursorX = 0;
 	int _cursorY = 0;
+	bool _isUtf8 = false;
 };
 
 extern GrimEngine *g_grim;
diff --git a/engines/grim/localize.cpp b/engines/grim/localize.cpp
index 5c3bf570e31..1eac0a1b751 100644
--- a/engines/grim/localize.cpp
+++ b/engines/grim/localize.cpp
@@ -102,6 +102,15 @@ Localizer::Localizer() {
 		case MKTAG('I', 'N', 'T', 'T'):
 		case MKTAG('6', '6', '6', 'I'):
 			break;
+		case 0xfffe4600: {
+			Common::String n = Common::U32String::decodeUTF16LE((const uint16 *) (data + 2), (filesize - 2) / 2).encode();
+			delete[] data;
+			data = new char[n.size() + 1];
+			memcpy(data, n.c_str(), n.size() + 1);
+			filesize = n.size();
+			g_grim->_isUtf8 = true;
+			break;
+		}
 		default:
 			error("Invalid magic reading %s: %08x (%s)", filename.c_str(), READ_BE_UINT32(data), tag2str(READ_BE_UINT32(data)));
 		}


Commit: bf4b5db9ed7483b33fedb0fa41113329e48acb22
    https://github.com/scummvm/scummvm/commit/bf4b5db9ed7483b33fedb0fa41113329e48acb22
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Prefer unpacked files over ones in archives

Changed paths:
    engines/grim/resource.cpp


diff --git a/engines/grim/resource.cpp b/engines/grim/resource.cpp
index 2ebd8fda8cc..1920e3d80e8 100644
--- a/engines/grim/resource.cpp
+++ b/engines/grim/resource.cpp
@@ -197,7 +197,7 @@ ResourceLoader::ResourceLoader() {
 		error("%s", "Cannot find game data - check configuration file");
 
 	// Load labs
-	int priority = files.size();
+	int priority = -1;
 	for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
 		Common::String filename = (*x)->getName();
 		filename.toLowercase();


Commit: 87a4fe7831f196f8e3bbfdef596c24ab0b409a91
    https://github.com/scummvm/scummvm/commit/87a4fe7831f196f8e3bbfdef596c24ab0b409a91
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Support DBCS and Unicode word-wrapping

Changed paths:
    engines/grim/textobject.cpp
    engines/grim/textobject.h


diff --git a/engines/grim/textobject.cpp b/engines/grim/textobject.cpp
index 99d03287410..ba6b087f7ce 100644
--- a/engines/grim/textobject.cpp
+++ b/engines/grim/textobject.cpp
@@ -21,6 +21,8 @@
 
 #include "common/unicode-bidi.h"
 
+#include "common/dbcs-str.h"
+
 #include "engines/grim/debug.h"
 #include "engines/grim/grim.h"
 #include "engines/grim/textobject.h"
@@ -161,9 +163,9 @@ void TextObject::destroy() {
 	}
 }
 
-void TextObject::setupText() {
-	Common::String msg = LuaBase::instance()->parseMsgText(_textID.c_str(), nullptr);
-	Common::String message;
+template <typename S>
+void TextObject::setupTextReal(S msg, Common::String (*convert)(const S &s)) {
+	S message;
 
 	// remove spaces (NULL_TEXT) from the end of the string,
 	// while this helps make the string unique it screws up
@@ -209,7 +211,7 @@ void TextObject::setupText() {
 	}
 
 	// We break the message to lines not longer than maxWidth
-	Common::String currLine;
+	S currLine;
 	_numberLines = 1;
 	int lineWidth = 0;
 	for (uint i = 0; i < msg.size(); i++) {
@@ -226,14 +228,16 @@ void TextObject::setupText() {
 					--i;
 				}
 			} else { // if it is a unique word
-				int dashWidth = _font->getCharKernedWidth('-');
+				bool useDash = !(g_grim->getGameLanguage() == Common::Language::ZH_CHN || g_grim->getGameLanguage() == Common::Language::ZH_TWN);
+				int dashWidth = useDash ? _font->getCharKernedWidth('-') : 0;
 				while (lineWidth + dashWidth > maxWidth && currLine.size() > 1) {
 					lineWidth -= _font->getCharKernedWidth(currLine.lastChar());
 					message.deleteLastChar();
 					currLine.deleteLastChar();
 					--i;
 				}
-				message += '-';
+				if (useDash)
+					message += '-';
 			}
 			message += '\n';
 			currLine.clear();
@@ -263,27 +267,54 @@ void TextObject::setupText() {
 
 	for (int j = 0; j < _numberLines; j++) {
 		int nextLinePos, cutLen;
-		const char *breakPos = strchr(message.c_str(), '\n');
-		if (breakPos) {
+		const typename S::value_type *breakPos = message.c_str();
+		while (*breakPos && *breakPos != '\n')
+			breakPos++;
+		if (*breakPos == '\n') {
 			nextLinePos = breakPos - message.c_str();
 			cutLen = nextLinePos + 1;
 		} else {
 			nextLinePos = message.size();
 			cutLen = nextLinePos;
 		}
-		Common::String currentLine(message.c_str(), message.c_str() + nextLinePos);
+		S currentLine(message.c_str(), message.c_str() + nextLinePos);
+		Common::String currentLineConvert = convert(currentLine);
 
 		// Reverse the line for the Hebrew translation
 		if (g_grim->getGameLanguage() == Common::HE_ISR)
-			currentLine = Common::convertBiDiString(currentLine, Common::kWindows1255);
+			currentLineConvert = Common::convertBiDiString(currentLineConvert, Common::kWindows1255);
 
-		_lines[j] = currentLine;
-		int width = _font->getKernedStringLength(currentLine);
+		_lines[j] = currentLineConvert;
+		int width = _font->getKernedStringLength(currentLineConvert);
 		if (width > _maxLineWidth)
 			_maxLineWidth = width;
 		for (int count = 0; count < cutLen; count++)
 			message.deleteChar(0);
 	}
+}
+
+static Common::String sConvert(const Common::String &s) {
+	return s;
+}
+
+static Common::String usConvert(const Common::U32String &us) {
+	return us.encode(Common::CodePage::kUtf8);
+}
+
+static Common::String dbcsConvert(const Common::DBCSString &ds) {
+	return ds.convertToString();
+}
+
+void TextObject::setupText() {
+	Common::String msg = LuaBase::instance()->parseMsgText(_textID.c_str(), nullptr);
+
+	if (g_grim->_isUtf8)
+		setupTextReal<Common::U32String>(msg.decode(Common::CodePage::kUtf8), usConvert);
+	else if (g_grim->getGameLanguage() == Common::Language::ZH_CHN || g_grim->getGameLanguage() == Common::Language::ZH_TWN)
+		setupTextReal<Common::DBCSString>(Common::DBCSString(msg), dbcsConvert);
+	else
+		setupTextReal<Common::String>(msg, sConvert);
+
 	_elapsedTime = 0;
 }
 
diff --git a/engines/grim/textobject.h b/engines/grim/textobject.h
index 3c0adac5c93..ce37cc91054 100644
--- a/engines/grim/textobject.h
+++ b/engines/grim/textobject.h
@@ -147,6 +147,10 @@ protected:
 	bool _created;
 
 	int _stackLevel;
+
+private:
+	template <typename S>
+	void setupTextReal(S msg, Common::String (*convert)(const S &s));
 };
 
 } // end of namespace Grim


Commit: 385d6e51156aeb7645c6b32dfefe2084db849383
    https://github.com/scummvm/scummvm/commit/385d6e51156aeb7645c6b32dfefe2084db849383
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Mark ZH_TWN as requiring font rendering

Changed paths:
    engines/grim/grim.cpp


diff --git a/engines/grim/grim.cpp b/engines/grim/grim.cpp
index 9267f2962e9..a87f3d1ae7e 100644
--- a/engines/grim/grim.cpp
+++ b/engines/grim/grim.cpp
@@ -282,7 +282,8 @@ GfxBase *GrimEngine::createRenderer(int screenW, int screenH) {
 	}
 
 	// Not supported yet.
-	if (getLanguage() == Common::Language::ZH_CHN)
+	if (getLanguage() == Common::Language::ZH_CHN || getLanguage() == Common::Language::ZH_TWN
+		|| getGameLanguage() == Common::Language::ZH_CHN || getGameLanguage() == Common::Language::ZH_TWN)
 		availableRendererTypes &= ~Graphics::kRendererTypeOpenGLShaders;
 
 	Graphics::RendererType matchingRendererType = Graphics::Renderer::getBestMatchingType(desiredRendererType, availableRendererTypes);


Commit: 98c337f1dadf00dbc6f80c8e3f4a4d556951ae2b
    https://github.com/scummvm/scummvm/commit/98c337f1dadf00dbc6f80c8e3f4a4d556951ae2b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Support override font

In Chinese Monkey4 we need to use chinese font instead of normal font.

Changed paths:
    engines/grim/grim.h
    engines/grim/resource.cpp


diff --git a/engines/grim/grim.h b/engines/grim/grim.h
index c3c06fa2acc..701f1657f1c 100644
--- a/engines/grim/grim.h
+++ b/engines/grim/grim.h
@@ -289,6 +289,7 @@ public:
 	int _cursorX = 0;
 	int _cursorY = 0;
 	bool _isUtf8 = false;
+	Font *_overrideFont = nullptr;
 };
 
 extern GrimEngine *g_grim;
diff --git a/engines/grim/resource.cpp b/engines/grim/resource.cpp
index 1920e3d80e8..2300cc63adf 100644
--- a/engines/grim/resource.cpp
+++ b/engines/grim/resource.cpp
@@ -368,6 +368,9 @@ Costume *ResourceLoader::loadCostume(const Common::String &filename, Actor *owne
 Font *ResourceLoader::loadFont(const Common::String &filename) {
 	Common::SeekableReadStream *stream;
 
+	if (g_grim->_overrideFont)
+		return g_grim->_overrideFont;
+
 	if (g_grim->getGameType() == GType_GRIM && g_grim->isRemastered()) {
 		Common::String name = "FontsHD/" + filename + ".txt";
 		stream = openNewStreamFile(name, true);


Commit: c93486dfe2d60ed726f0d900ce566190f61a5a5d
    https://github.com/scummvm/scummvm/commit/c93486dfe2d60ed726f0d900ce566190f61a5a5d
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Support Chinese TGA font

Changed paths:
    engines/grim/font.cpp
    engines/grim/font.h


diff --git a/engines/grim/font.cpp b/engines/grim/font.cpp
index 58733c680c5..e7e0802c28e 100644
--- a/engines/grim/font.cpp
+++ b/engines/grim/font.cpp
@@ -25,6 +25,8 @@
 #include "graphics/font.h"
 #include "graphics/surface.h"
 
+#include "image/tga.h"
+
 #include "engines/grim/debug.h"
 #include "engines/grim/grim.h"
 #include "engines/grim/savegame.h"
@@ -85,14 +87,14 @@ Font *Font::getFirstFont() {
 }
 
 bool BitmapFont::is8Bit() const {
-	return !_isDBCS;
+	return !_isDBCS && !_isUnicode;
 }
 
 BitmapFont::BitmapFont() :
 		_userData(nullptr),
 		_fontData(nullptr), _charHeaders(nullptr),
 		_numChars(0), _dataSize(0), _kernedHeight(0), _baseOffsetY(0),
-		_firstChar(0), _lastChar(0) {
+		_firstChar(0), _lastChar(0), _isUnicode(false), _isDBCS(false) {
 }
 
 BitmapFont::~BitmapFont() {
@@ -164,7 +166,7 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 		_charHeaders[i].startingLine = data->readSByte();
 		data->seek(1, SEEK_CUR);
 		// Character bitmap size
-		_charHeaders[i].bitmapWidth = data->readUint32LE();
+		_charHeaders[i].bitmapPitch = _charHeaders[i].bitmapWidth = data->readUint32LE();
 		_charHeaders[i].bitmapHeight = data->readUint32LE();
 	}
 	// Read font data
@@ -175,7 +177,57 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 	g_driver->createFont(this);
 }
 
-uint16 BitmapFont::getCharIndex(uint16 c) const {
+void BitmapFont::loadTGA(const Common::String &filename, Common::SeekableReadStream *index, Common::SeekableReadStream *image) {
+  	Image::TGADecoder dec;
+	bool success = dec.loadStream(*image);
+
+	if (!success)
+		return;
+
+	const Graphics::Surface *surf = dec.getSurface();
+
+	const int MAX_16BIT_CHARACTER = 0xffff;
+	const int INDEX_ENTRY_SIZE = 10;
+
+	_filename = filename;
+	_numChars = index->size() / INDEX_ENTRY_SIZE;
+	_dataSize = surf->w * surf->h;
+	_kernedHeight = 16;
+	_baseOffsetY = 0;
+	_firstChar = 0;
+	_lastChar = MAX_16BIT_CHARACTER;
+
+	_isDBCS = false;
+	_isUnicode = true;
+
+	// Read character headers
+	_charHeaders = new CharHeader[_numChars];
+
+	_fwdCharIndex.resize(MAX_16BIT_CHARACTER + 1, -1);
+	for (uint i = 0; i < _numChars; ++i) {
+		uint16 point = index->readUint16LE();
+		uint32 x = index->readUint32LE();
+		uint32 y = index->readUint32LE();
+		_fwdCharIndex[point] = i;
+		_charHeaders[i].offset = x + y * surf->w;
+		_charHeaders[i].kernedWidth = 16;
+		_charHeaders[i].startingCol = 0;
+		_charHeaders[i].startingLine = 0;
+		_charHeaders[i].bitmapWidth = 16;
+		_charHeaders[i].bitmapHeight = 16;
+		_charHeaders[i].bitmapPitch = surf->w;
+	}
+	// Read font data
+	_fontData = new byte[_dataSize];
+
+	for (int y = 0; y < surf->h; y++)
+		for (int x = 0; x < surf->w; x++)
+			_fontData[y * surf->w + x] = surf->getPixel(x, y) ? 0 : 0xff;
+
+	g_driver->createFont(this);
+}
+
+uint16 BitmapFont::getCharIndex(uint32 c) const {
 	int res = c < _fwdCharIndex.size() ? _fwdCharIndex[c] : -1;
 	if (res >= 0)
 		return res;
@@ -186,25 +238,70 @@ uint16 BitmapFont::getCharIndex(uint16 c) const {
 	return 0;
 }
 
+uint32 BitmapFont::getNextChar(const Common::String &text, uint32 &i) const {
+	if (_isUnicode) {
+		uint32 chr = 0;
+		uint num = 1;
+
+		if ((text[i] & 0xF8) == 0xF0) {
+			num = 4;
+		} else if ((text[i] & 0xF0) == 0xE0) {
+			num = 3;
+		} else if ((text[i] & 0xE0) == 0xC0) {
+			num = 2;
+		}
+
+		if (text.size() - i < num) {
+			i = text.size();
+			return '?';
+		}
+
+		switch (num) {
+		case 4:
+			chr |= (text[i++] & 0x07) << 18;
+			chr |= (text[i++] & 0x3F) << 12;
+			chr |= (text[i++] & 0x3F) << 6;
+			chr |= (text[i++] & 0x3F);
+			break;
+
+		case 3:
+			chr |= (text[i++] & 0x0F) << 12;
+			chr |= (text[i++] & 0x3F) << 6;
+			chr |= (text[i++] & 0x3F);
+			break;
+
+		case 2:
+			chr |= (text[i++] & 0x1F) << 6;
+			chr |= (text[i++] & 0x3F);
+			break;
+
+		default:
+			chr = (text[i++] & 0x7F);
+			break;
+		}
+
+		return chr;
+	}
+	uint16 ch = uint8(text[i]);
+	if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
+		ch = (ch << 8) | (text[++i] & 0xff);
+	}
+	i++;
+	return ch;
+}
+
 int BitmapFont::getKernedStringLength(const Common::String &text) const {
 	int result = 0;
-	for (uint32 i = 0; i < text.size(); ++i) {
-		uint16 ch = uint8(text[i]);
-		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
-			ch = (ch << 8) | (text[++i] & 0xff);
-		}
-		result += getCharKernedWidth(ch);
+	for (uint32 i = 0; i < text.size(); ) {
+		result += getCharKernedWidth(getNextChar(text, i));
 	}
 	return result;
 }
 
 int BitmapFont::getBitmapStringLength(const Common::String &text) const {
 	int result = 0;
-	for (uint32 i = 0; i < text.size(); ++i) {
-		uint16 ch = uint8(text[i]);
-		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
-			ch = (ch << 8) | (text[++i] & 0xff);
-		}
+	for (uint32 i = 0; i < text.size(); ) {
+		uint32 ch = getNextChar(text, i);
 		result += getCharKernedWidth(ch) + getCharStartingCol(ch);
 	}
 	return result;
@@ -212,11 +309,8 @@ int BitmapFont::getBitmapStringLength(const Common::String &text) const {
 
 int BitmapFont::getStringHeight(const Common::String &text) const {
 	int result = 0;
-	for (uint32 i = 0; i < text.size(); ++i) {
-		uint16 ch = uint8(text[i]);
-		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
-			ch = (ch << 8) | (text[++i] & 0xff);
-		}
+	for (uint32 i = 0; i < text.size(); ) {
+		uint32 ch = getNextChar(text, i);
 
 		int verticalOffset = getCharStartingLine(ch) + getBaseOffsetY();
 		int charHeight = verticalOffset + getCharBitmapHeight(ch);
@@ -274,12 +368,10 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 	buf.create(width, height, pixelFormat);
 	buf.fillRect(Common::Rect(0, 0, width, height), colorKey);
 
-	for (unsigned int d = 0; d < currentLine.size(); d++) {
-		uint16 ch = uint8(currentLine[d]);
-		if (_isDBCS && (ch & 0x80) &&  d + 1 < currentLine.size()) {
-			ch = (ch << 8) | (currentLine[++d] & 0xff);
-		}
+	for (uint32 d = 0; d < currentLine.size(); ) {
+		uint32 ch = getNextChar(currentLine, d);
 		int32 charBitmapWidth = getCharBitmapWidth(ch);
+		int32 charBitmapPitch = getCharBitmapPitch(ch);
 		int32 charBitmapHeight = getCharBitmapHeight(ch);
 		int8 fontRow = getCharStartingLine(ch) + getBaseOffsetY();
 		int8 fontCol = getCharStartingCol(ch);
@@ -287,7 +379,7 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 		for (int line = 0; line < charBitmapHeight; line++) {
 			int lineOffset = (fontRow + line);
 			int columnOffset = startColumn + fontCol;
-			int fontOffset = (charBitmapWidth * line);
+			int fontOffset = (charBitmapPitch * line);
 			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++, columnOffset++, fontOffset++) {
 				byte pixel = getCharData(ch)[fontOffset];
 				if (pixel == 0x80) {
diff --git a/engines/grim/font.h b/engines/grim/font.h
index f8b9cde5eb4..76c0027ba98 100644
--- a/engines/grim/font.h
+++ b/engines/grim/font.h
@@ -44,7 +44,7 @@ public:
 	virtual int getKernedStringLength(const Common::String &text) const = 0;
 	virtual int32 getBaseOffsetY() const = 0;
 	virtual void render(Graphics::Surface &buf, const Common::String &currentLine, const Graphics::PixelFormat &pixelFormat, uint32 blackColor, uint32 color, uint32 colorKey) const = 0;
-	virtual int32 getCharKernedWidth(uint16 c) const = 0;
+	virtual int32 getCharKernedWidth(uint32 c) const = 0;
 	virtual int getPoolId() const = 0;
 	virtual int32 getPoolTag() const = 0;
 	virtual bool is8Bit() const = 0;
@@ -69,20 +69,21 @@ public:
 	int32 getPoolTag() const override { return getStaticTag(); }
 
 	void load(const Common::String &filename, Common::SeekableReadStream *data);
-
+	void loadTGA(const Common::String &filename, Common::SeekableReadStream *index, Common::SeekableReadStream *image);
 
 	const Common::String &getFilename() const { return _filename; }
 	int32 getKernedHeight() const override { return _kernedHeight; }
 	int32 getFontWidth() const override { return getCharKernedWidth('w'); }
 	int32 getBaseOffsetY() const override { return _baseOffsetY; }
 	void render(Graphics::Surface &buf, const Common::String &currentLine, const Graphics::PixelFormat &pixelFormat, uint32 blackColor, uint32 color, uint32 colorKey) const override;
-	int32 getCharBitmapWidth(uint16 c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
-	int32 getCharBitmapHeight(uint16 c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
-	int32 getCharKernedWidth(uint16 c) const override { return _charHeaders[getCharIndex(c)].kernedWidth; }
-	int32 getCharStartingCol(uint16 c) const { return _charHeaders[getCharIndex(c)].startingCol; }
-	int32 getCharStartingLine(uint16 c) const { return _charHeaders[getCharIndex(c)].startingLine; }
-	int32 getCharOffset(uint16 c) const { return _charHeaders[getCharIndex(c)].offset; }
-	const byte *getCharData(uint16 c) const { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
+	int32 getCharBitmapWidth(uint32 c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
+	int32 getCharBitmapPitch(uint32 c) const { return _charHeaders[getCharIndex(c)].bitmapPitch; }
+	int32 getCharBitmapHeight(uint32 c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
+	int32 getCharKernedWidth(uint32 c) const override { return _charHeaders[getCharIndex(c)].kernedWidth; }
+	int32 getCharStartingCol(uint32 c) const { return _charHeaders[getCharIndex(c)].startingCol; }
+	int32 getCharStartingLine(uint32 c) const { return _charHeaders[getCharIndex(c)].startingLine; }
+	int32 getCharOffset(uint32 c) const { return _charHeaders[getCharIndex(c)].offset; }
+	const byte *getCharData(uint32 c) const { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
 
 	const byte *getFontData() const { return _fontData; }
 	uint32 getDataSize() const { return _dataSize; }
@@ -100,14 +101,15 @@ public:
 
 	static const uint8 emerFont[][13];
 private:
-
-	uint16 getCharIndex(uint16 c) const;
+	uint32 getNextChar(const Common::String &text, uint32 &i) const;
+	uint16 getCharIndex(uint32 c) const;
 	struct CharHeader {
 		int32 offset;
 		int8  kernedWidth;
-		int8  startingCol;
-		int8  startingLine;
+		int32 startingCol;
+		int32 startingLine;
 		int32 bitmapWidth;
+		int32 bitmapPitch;
 		int32 bitmapHeight;
 	};
 
@@ -119,7 +121,7 @@ private:
 	CharHeader *_charHeaders;
 	byte *_fontData;
 	void *_userData;
-	bool _isDBCS;
+	bool _isDBCS, _isUnicode;
 };
 
 class FontTTF : public Font, public PoolObject<FontTTF> {
@@ -132,7 +134,7 @@ public:
 
 	int32 getKernedHeight() const override { return _font->getFontHeight(); }
 	int32 getBaseOffsetY() const override { return 0; }
-	int32 getCharKernedWidth(uint16 c) const override { return _font->getCharWidth(c); }
+	int32 getCharKernedWidth(uint32 c) const override { return _font->getCharWidth(c); }
 	int32 getFontWidth() const override { return getCharKernedWidth('w'); }
 
 	int getKernedStringLength(const Common::String &text) const override { return _font->getStringWidth(text); }


Commit: cb3ee1411affe1fd852a66230dc3010df1e23966
    https://github.com/scummvm/scummvm/commit/cb3ee1411affe1fd852a66230dc3010df1e23966
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-10T13:18:54+02:00

Commit Message:
GRIM: Use TGA font for Chinese monkey4

Changed paths:
    engines/grim/grim.cpp


diff --git a/engines/grim/grim.cpp b/engines/grim/grim.cpp
index a87f3d1ae7e..420f5e612ff 100644
--- a/engines/grim/grim.cpp
+++ b/engines/grim/grim.cpp
@@ -396,6 +396,15 @@ Common::Error GrimEngine::run() {
 		g_driver = createRenderer(640, 480);
 	}
 
+	if (getGameType() == GType_MONKEY4 && getGameLanguage() == Common::Language::ZH_TWN) {
+		Common::File img, imgmap;
+		if (img.open("font.tga") && imgmap.open("map.bin")) {
+			BitmapFont *f = new BitmapFont();
+			f->loadTGA("font.tga", &imgmap, &img);
+			_overrideFont = f;
+		}
+	}
+
 	if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) {
 		// Play EMI Mac Aspyr logo
 		playAspyrLogo();




More information about the Scummvm-git-logs mailing list