[Scummvm-git-logs] scummvm master -> 23e31dd2cfd578bdd04ccab1c62f861ce4bfc22f

mgerhardy noreply at scummvm.org
Thu May 11 20:00:36 UTC 2023


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:
23e31dd2cf TWINE: Support rendering Japanese strings in LBA1-PC


Commit: 23e31dd2cfd578bdd04ccab1c62f861ce4bfc22f
    https://github.com/scummvm/scummvm/commit/23e31dd2cfd578bdd04ccab1c62f861ce4bfc22f
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-05-11T22:00:31+02:00

Commit Message:
TWINE: Support rendering Japanese strings in LBA1-PC

Changed paths:
    engines/twine/resources/resources.cpp
    engines/twine/resources/resources.h
    engines/twine/text.cpp
    engines/twine/text.h


diff --git a/engines/twine/resources/resources.cpp b/engines/twine/resources/resources.cpp
index aeac2fa4d26..53d03b81c01 100644
--- a/engines/twine/resources/resources.cpp
+++ b/engines/twine/resources/resources.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "twine/resources/resources.h"
+#include "common/file.h"
 #include "common/tokenizer.h"
 #include "common/util.h"
 #include "twine/audio/sound.h"
@@ -40,6 +41,7 @@ Resources::~Resources() {
 		free(_samplesTable[i]);
 	}
 	free(_fontPtr);
+	free(_sjisFontPtr);
 }
 
 void Resources::initPalettes() {
@@ -140,6 +142,15 @@ void Resources::initResources() {
 		error("Failed to load font");
 	}
 
+	const int kMinSjisSize = 11072 * 24 * 3;
+	Common::File f24;
+	if (f24.open("FNT24.DAT") && f24.size() >= kMinSjisSize) {
+		// Rest is garbage
+		_sjisFontPtr = (byte *)malloc(kMinSjisSize);
+		assert(_sjisFontPtr);
+		f24.read(_sjisFontPtr, kMinSjisSize);
+	}
+
 	_engine->_text->setFontParameters(2, 8);
 	_engine->_text->setFontColor(COLOR_14);
 	_engine->_text->setTextCrossColor(136, 143, 2);
diff --git a/engines/twine/resources/resources.h b/engines/twine/resources/resources.h
index b5d681cafbf..93e412fed5a 100644
--- a/engines/twine/resources/resources.h
+++ b/engines/twine/resources/resources.h
@@ -174,6 +174,7 @@ public:
 	/** Font buffer pointer */
 	int32 _fontBufSize = 0;
 	uint8 *_fontPtr = nullptr;
+	uint8 *_sjisFontPtr = nullptr;
 
 	SpriteData _spriteShadowPtr;
 	SpriteBoundingBoxData _spriteBoundingBox;
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 2c1316b39bd..8eb1b879a9f 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -48,9 +48,12 @@ namespace TwinE {
 #define VOX_EXT ".vox"
 
 static const int32 PADDING = 8;
+static const int kLBASJISCharWidth = 24;
+static const int kLBASJISCharHeight = 24;
 
 Text::Text(TwinEEngine *engine) : _engine(engine) {
 	Common::fill(&_currMenuTextBuffer[0], &_currMenuTextBuffer[256], 0);
+	_isShiftJIS = _engine->getGameLang() == Common::Language::JA_JPN;
 }
 
 Text::~Text() {
@@ -172,7 +175,45 @@ void Text::initSceneTextBank() {
 	initDial((TextBankId)((int)_engine->_scene->_sceneTextBank + (int)TextBankId::Citadel_Island));
 }
 
-void Text::drawCharacter(int32 x, int32 y, uint8 character) {
+void Text::drawCharacter(int32 x, int32 y, uint16 character) {
+	const uint8 usedColor = _dialTextColor;
+
+	if (_isShiftJIS && character > 0x100 && _engine->_resources->_sjisFontPtr) {
+		int index = 0;
+		if (character >= 0x8140 && character <= 0x9fff)
+			index = character - 0x8140;
+		else if (character >= 0xe040 && character <= 0xeaff)
+			index = character - 0xe040 + 8320;
+		else {
+			drawCharacter(x, y, '?');
+			return;
+		}
+
+		byte *glyphPtr = _engine->_resources->_sjisFontPtr + index * (kLBASJISCharHeight * kLBASJISCharWidth / 8);
+
+		for (uint8 fontY = 0; fontY < kLBASJISCharHeight; ++fontY) {
+			byte bits = 0;
+			int remBits = 0;
+			for (uint8 fontX = 0; fontX < kLBASJISCharWidth; ++fontX) {
+				if (remBits == 0) {
+					remBits = 8;
+					bits = *glyphPtr++;
+				}
+				int32 tempX = x + fontX;
+				int32 tempY = y + fontY;
+				if ((bits & 0x80) && tempX >= 0 && tempX < (_engine->width() - 1) && tempY >= 0 && tempY < (_engine->height() - 1)) {
+					_engine->_frontVideoBuffer.setPixel(tempX, tempY, usedColor);
+				}
+
+				remBits--;
+				bits <<= 1;
+			}
+		}
+		return;
+	}
+
+	if (character > 0x100)
+		character = '?';
 	Common::MemoryReadStream stream(_engine->_resources->_fontPtr, _engine->_resources->_fontBufSize);
 	stream.seek(character * 4);
 	stream.seek(stream.readSint16LE());
@@ -181,8 +222,6 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) {
 	x += stream.readByte();
 	y += stream.readByte();
 
-	const uint8 usedColor = _dialTextColor;
-
 	int32 tempX = x;
 	int32 tempY = y;
 
@@ -216,7 +255,7 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) {
 	}
 }
 
-void Text::drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color, Common::Rect &dirtyRect) {
+void Text::drawCharacterShadow(int32 x, int32 y, uint16 character, int32 color, Common::Rect &dirtyRect) {
 	if (character == ' ') {
 		return;
 	}
@@ -237,6 +276,14 @@ void Text::drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color, C
 	}
 }
 
+uint16 Text::getNextChar(const char *&dialogue) {
+	uint16 currChar = *dialogue++ & 0xff;
+	if (_isShiftJIS && ((currChar >= 0x81 && currChar <= 0x9f)
+			    || (currChar >= 0xe0 && currChar <= 0xea)) && ((*dialogue & 0xff) >= 0x40))
+		currChar = (currChar << 8) | (*dialogue++ & 0xff);
+	return currChar;
+}
+
 void Text::drawText(int32 x, int32 y, const char *dialogue, bool shadow) {
 	// if the font is not defined
 	if (_engine->_resources->_fontPtr == nullptr) {
@@ -244,7 +291,7 @@ void Text::drawText(int32 x, int32 y, const char *dialogue, bool shadow) {
 	}
 
 	do {
-		const uint8 currChar = (uint8)*dialogue++; // read the next char from the string
+		const uint16 currChar = getNextChar(dialogue); // read the next char from the string
 		if (currChar == '\0') {
 			break;
 		}
@@ -271,7 +318,7 @@ int32 Text::getTextSize(const char *dialogue) {
 	int32 dialTextSize = 0;
 
 	do {
-		const uint8 currChar = (uint8) * (dialogue++);
+		const uint16 currChar = getNextChar(dialogue);
 		if (currChar == '\0') {
 			break;
 		}
@@ -517,14 +564,22 @@ void Text::fadeInCharacters(int32 counter, int32 fontColor) {
 	_engine->copyBlockPhys(dirtyRect);
 }
 
-int32 Text::getCharWidth(uint8 chr) const {
+int32 Text::getCharWidth(uint16 chr) const {
+	if (_isShiftJIS && (chr > 0x100))
+		return kLBASJISCharWidth;
+	if (chr > 0x100)
+		chr = '?';
 	Common::MemoryReadStream stream(_engine->_resources->_fontPtr, _engine->_resources->_fontBufSize);
 	stream.seek(chr * 4);
 	stream.seek(stream.readSint16LE());
 	return stream.readByte();
 }
 
-int32 Text::getCharHeight(uint8 chr) const {
+int32 Text::getCharHeight(uint16 chr) const {
+	if (_isShiftJIS && (chr > 0x100))
+		return kLBASJISCharHeight;
+	if (chr > 0x100)
+		chr = '?';
 	Common::MemoryReadStream stream(_engine->_resources->_fontPtr, _engine->_resources->_fontBufSize);
 	stream.seek(chr * 4);
 	stream.seek(stream.readSint16LE() + 1);
@@ -551,7 +606,7 @@ ProgressiveTextState Text::updateProgressiveText() { // NextDialCar
 		_dialTextXPos = _dialTextBox.left + PADDING;
 		_dialTextYPos = _dialTextBox.top + PADDING;
 	}
-	const char currentChar = *_progressiveTextBufferPtr;
+	const uint16 currentChar = getNextChar(_progressiveTextBufferPtr);
 	assert(currentChar != '\0');
 	fillFadeInBuffer(_dialTextXPos, _dialTextYPos, currentChar);
 	fadeInCharacters(_fadeInCharactersPos, _dialTextStartColor);
@@ -563,9 +618,6 @@ ProgressiveTextState Text::updateProgressiveText() { // NextDialCar
 		_dialTextXPos += charWidth + 2;
 	}
 
-	// next character
-	_progressiveTextBufferPtr++;
-
 	// reaching 0-byte means a new line - as we are fading in per line
 	if (*_progressiveTextBufferPtr != '\0') {
 		return ProgressiveTextState::ContinueRunning;
diff --git a/engines/twine/text.h b/engines/twine/text.h
index 4c427514c06..c877167242c 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -51,7 +51,7 @@ private:
 	 * @param y Y coordinate in screen
 	 * @param character ascii character to display
 	 */
-	void drawCharacter(int32 x, int32 y, uint8 character);
+	void drawCharacter(int32 x, int32 y, uint16 character);
 	/**
 	 * Draw character with shadow
 	 * @param x X coordinate in screen
@@ -59,13 +59,14 @@ private:
 	 * @param character ascii character to display
 	 * @param color character color
 	 */
-	void drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color, Common::Rect& dirtyRect);
+	void drawCharacterShadow(int32 x, int32 y, uint16 character, int32 color, Common::Rect& dirtyRect);
 	void initProgressiveTextBuffer();
 	struct WordSize {
 		int32 inChar = 0;
 		int32 inPixel = 0;
 	};
 	WordSize getWordSize(const char *completeText, char *wordBuf, int32 wordBufSize);
+	uint16 getNextChar(const char *&dialogue);
 	void processTextLine();
 	// draw next page arrow polygon
 	void renderContinueReadingTriangle();
@@ -90,7 +91,7 @@ private:
 	int32 _dialTextYPos = 0;
 
 	/** Current position of in the buffer of characters that are currently faded in */
-	char *_progressiveTextBufferPtr = nullptr;
+	const char *_progressiveTextBufferPtr = nullptr;
 
 	int32 _dialTextBoxCurrentLine = 0;
 	struct BlendInCharacter {
@@ -135,6 +136,8 @@ private:
 	int32 _dialTextBoxLines = 0; // dialogueBoxParam1
 	int32 _dialTextBoxMaxX = 0; // dialogueBoxParam2
 
+	bool _isShiftJIS = false;
+
 	bool displayText(TextId index, bool showText, bool playVox, bool loop);
 public:
 	Text(TwinEEngine *engine);
@@ -183,8 +186,8 @@ public:
 	 * @param dialogue ascii text to display
 	 */
 	int32 getTextSize(const char *dialogue);
-	int32 getCharWidth(uint8 chr) const;
-	int32 getCharHeight(uint8 chr) const;
+	int32 getCharWidth(uint16 chr) const;
+	int32 getCharHeight(uint16 chr) const;
 
 	void initDialogueBox();
 	void initInventoryDialogueBox();




More information about the Scummvm-git-logs mailing list