[Scummvm-git-logs] scummvm master -> 60141a62acd69255fd8fa6fb284f7930d59a4364

sev- noreply at scummvm.org
Sun Mar 5 21:39:34 UTC 2023


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

Summary:
95b83f8d3d GRIM: Add entries for Chinese version
34db914a09 GRIM: Support "ssIN" magic for GRIM.TAB
829eab2f72 GRIM: Split TTF fonts from bitmap fonts and add a drawing interface
3e1075c2b0 GRIM: Small optimisation in bitmap font renderer
dc86f8731c GRIM: Support Chinese font
dfcccd3246 GRIM: Fix rendering bug
349c515089 GRIM: Disable shaders renderer with Chinese
60141a62ac GRIM: Double the size of Chinese font


Commit: 95b83f8d3d7b66fa4c39c99ac21905cc0ec25b0c
    https://github.com/scummvm/scummvm/commit/95b83f8d3d7b66fa4c39c99ac21905cc0ec25b0c
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Add entries for Chinese version

Changed paths:
    engines/grim/detection.cpp
    engines/grim/md5check.cpp


diff --git a/engines/grim/detection.cpp b/engines/grim/detection.cpp
index a26c75ceb22..2274485f334 100644
--- a/engines/grim/detection.cpp
+++ b/engines/grim/detection.cpp
@@ -82,6 +82,21 @@ static const GrimGameDescription gameDescriptions[] = {
 		},
 		GType_GRIM
 	},
+	{
+		// Grim Fandango English version (unpatched) + Chinese Fan translation
+		{
+			"grim",
+			"",
+			AD_ENTRY2s("VOX0001.LAB", "8b12ed530195c6c577436df27df62ecb", 58011176,
+				   "GRIM.TAB", "613d5c80480229837a14829cbc1e1d22", 273523),
+			Common::ZH_CHN,
+			Common::kPlatformWindows,
+			ADGF_NO_FLAGS,
+			GUI_OPTIONS_GRIME
+		},
+		GType_GRIM
+	},
+
 	{
 		// Grim Fandango French version (un/patched ???)
 		{
diff --git a/engines/grim/md5check.cpp b/engines/grim/md5check.cpp
index 8e9416c9a09..b80ef1fd9e5 100644
--- a/engines/grim/md5check.cpp
+++ b/engines/grim/md5check.cpp
@@ -127,6 +127,9 @@ const char *movie01[] = {
 const char *movie00[] = {
 	"0c6b8e4fa74024c4afdf7758f8d8b1a0" //english unpatched
 };
+const char *data005[] = {
+	"84738c0783093b1e515eb98918d2a405" //Chinese unpatched
+};
 const char *data004[] = {
 	"2cdb79d3606965a9a0a3378507488dd7" //english unpatched
 };
@@ -142,7 +145,8 @@ const char *data001[] = {
 };
 const char *data000[] = {
 	"2069b8bf113119910df8219e787e7e94", //english pre-patched
-	"08e2505a6a7fd90d3920131b1297c60f" //english unpatched
+	"08e2505a6a7fd90d3920131b1297c60f", //english unpatched
+	"7c9886667636aa77fe1ab9bada257595"  //Chinese unpatched
 };
 const char *credits[] = {
 	"6dcecad8f01657184f8576aab8fb3f00", //english unpatched
@@ -150,7 +154,8 @@ const char *credits[] = {
 	"2e6319c2ec5772ced5dc9f8b41eb5de7", //german unpatched
 	"cd71ca4e600198277f22e944988f7516", //french unpatched
 	"836a2081d5e57ed6ef5eaade7f770b0e", //spanish unpatched
-	"368baa2f319a72278035095e4f4a4466"  //brasilian-portuguese
+	"368baa2f319a72278035095e4f4a4466", //brasilian-portuguese
+	"6589646e7a61eff352b2e1d1c08963eb"  //Chinese unpatched
 };
 const char *local[] = {
 	"6142624ce13ea3c9079aa80918010c4a", //italian unpatched
@@ -447,9 +452,12 @@ void MD5Check::init() {
 			MD5SUM("data001.lab", data001)
 			MD5SUM("data000.lab", data000)
 			MD5SUM("credits.lab", credits)
-			if (g_grim->getGameLanguage() != Common::EN_ANY) {
+			if (g_grim->getGameLanguage() != Common::EN_ANY && g_grim->getGameLanguage() != Common::ZH_CHN) {
 				MD5SUM("local.lab", local)
 			}
+			if (g_grim->getGameLanguage() == Common::ZH_CHN) {
+				MD5SUM("data005.lab", data005)
+			}
 		}
 	} else {
 		if (g_grim->getGameFlags() & ADGF_DEMO) {


Commit: 34db914a095514555bd63a11e845b9e1422fc935
    https://github.com/scummvm/scummvm/commit/34db914a095514555bd63a11e845b9e1422fc935
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Support "ssIN" magic for GRIM.TAB

Changed paths:
    engines/grim/localize.cpp


diff --git a/engines/grim/localize.cpp b/engines/grim/localize.cpp
index dadacec7c9f..984e0dce3ba 100644
--- a/engines/grim/localize.cpp
+++ b/engines/grim/localize.cpp
@@ -98,6 +98,7 @@ Localizer::Localizer() {
 			}
 		case MKTAG('D', 'O', 'E', 'L'):
 		case MKTAG('a', 'r', 't', 'p'):
+		case MKTAG('s', 's', 'I', 'N'):
 			break;
 		default:
 			error("Invalid magic reading %s: %08x (%s)", filename.c_str(), READ_BE_UINT32(data), tag2str(READ_BE_UINT32(data)));


Commit: 829eab2f72ad23c9950fc53b599d4300ecbfa5a5
    https://github.com/scummvm/scummvm/commit/829eab2f72ad23c9950fc53b599d4300ecbfa5a5
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Split TTF fonts from bitmap fonts and add a drawing interface

This cleans up the code and allows adding double-byte charsets easier

Changed paths:
    engines/grim/emi/lua_v2.cpp
    engines/grim/font.cpp
    engines/grim/font.h
    engines/grim/gfx_opengl.cpp
    engines/grim/gfx_opengl_shaders.cpp
    engines/grim/gfx_tinygl.cpp
    engines/grim/grim.cpp
    engines/grim/lua.cpp
    engines/grim/lua_v1.cpp
    engines/grim/remastered/lua_remastered.cpp
    engines/grim/resource.cpp
    engines/grim/savegame.cpp
    engines/grim/textobject.cpp


diff --git a/engines/grim/emi/lua_v2.cpp b/engines/grim/emi/lua_v2.cpp
index c733d2893fb..51b245e04f2 100644
--- a/engines/grim/emi/lua_v2.cpp
+++ b/engines/grim/emi/lua_v2.cpp
@@ -219,18 +219,13 @@ void Lua_V2::GetFontDimensions() {
 
 	const char *fontName = lua_getstring(fontObj);
 
-	Font *font = nullptr;
-	for (Font *f : Font::getPool()) {
-		if (f->getFilename() == fontName) {
-			font = f;
-		}
-	}
+	Font *font = Font::getByFileName(fontName);
 	if (!font) {
 		font = g_resourceloader->loadFont(fontName);
 	}
 	if (font) {
 		int32 h = font->getBaseOffsetY();
-		int32 w = font->getCharKernedWidth('w');
+		int32 w = font->getFontWidth();
 		lua_pushnumber(w);
 		lua_pushnumber(h);
 	} else {
diff --git a/engines/grim/font.cpp b/engines/grim/font.cpp
index 7e14351bd15..5bc26ca4e92 100644
--- a/engines/grim/font.cpp
+++ b/engines/grim/font.cpp
@@ -23,6 +23,7 @@
 
 #include "graphics/fonts/ttf.h"
 #include "graphics/font.h"
+#include "graphics/surface.h"
 
 #include "engines/grim/debug.h"
 #include "engines/grim/grim.h"
@@ -33,21 +34,71 @@
 
 namespace Grim {
 
-Font::Font() :
+void Font::save(const Font *font, SaveGame *state) {
+	const FontTTF *ttf = dynamic_cast<const FontTTF *>(font);
+	if (ttf) {
+		state->writeLESint32(-2);
+		state->writeLESint32(ttf->getId());
+		return;
+	}
+	const BitmapFont *bitmapFont = dynamic_cast<const BitmapFont *>(font);
+	if (bitmapFont) {
+		state->writeLESint32(bitmapFont->getId());
+		return;
+	}
+	state->writeLESint32(-1);
+}
+
+Font *Font::load(SaveGame *state) {
+	int32 fontId = state->readLESint32();
+	if (fontId == -1) {
+		return nullptr;
+	}
+	if (fontId == -2) {
+		fontId = state->readLESint32();
+		return FontTTF::getPool().getObject(fontId);
+	}
+
+	return BitmapFont::getPool().getObject(fontId);
+}
+
+Font *Font::getByFileName(const Common::String& fontName) {
+	for (Font *f : BitmapFont::getPool()) {
+		if (f->getFilename() == fontName) {
+			return f;
+		}
+	}
+	for (Font *f : FontTTF::getPool()) {
+		if (f->getFilename() == fontName) {
+			return f;
+		}
+	}
+	return nullptr;
+}
+
+Font *Font::getFirstFont() {
+	if (BitmapFont::getPool().begin() != BitmapFont::getPool().end())
+		return *BitmapFont::getPool().begin();
+	if (FontTTF::getPool().begin() != FontTTF::getPool().end())
+		return *FontTTF::getPool().begin();
+	return nullptr;
+}
+
+BitmapFont::BitmapFont() :
 		_userData(nullptr),
 		_fontData(nullptr), _charHeaders(nullptr), _charIndex(nullptr),
 		_numChars(0), _dataSize(0), _kernedHeight(0), _baseOffsetY(0),
 		_firstChar(0), _lastChar(0) {
 }
 
-Font::~Font() {
+BitmapFont::~BitmapFont() {
 	delete[] _charIndex;
 	delete[] _charHeaders;
 	delete[] _fontData;
 	g_driver->destroyFont(this);
 }
 
-void Font::load(const Common::String &filename, Common::SeekableReadStream *data) {
+void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream *data) {
 	_filename = filename;
 	_numChars = data->readUint32LE();
 	_dataSize = data->readUint32LE();
@@ -83,7 +134,7 @@ void Font::load(const Common::String &filename, Common::SeekableReadStream *data
 	g_driver->createFont(this);
 }
 
-uint16 Font::getCharIndex(unsigned char c) const {
+uint16 BitmapFont::getCharIndex(unsigned char c) const {
 	uint16 c2 = uint16(c);
 
 	// In order to ensure the correct character codes for
@@ -113,7 +164,7 @@ uint16 Font::getCharIndex(unsigned char c) const {
 	return 0;
 }
 
-int Font::getKernedStringLength(const Common::String &text) const {
+int BitmapFont::getKernedStringLength(const Common::String &text) const {
 	int result = 0;
 	for (uint32 i = 0; i < text.size(); ++i) {
 		result += getCharKernedWidth(text[i]);
@@ -121,7 +172,7 @@ int Font::getKernedStringLength(const Common::String &text) const {
 	return result;
 }
 
-int Font::getBitmapStringLength(const Common::String &text) const {
+int BitmapFont::getBitmapStringLength(const Common::String &text) const {
 	int result = 0;
 	for (uint32 i = 0; i < text.size(); ++i) {
 		result += getCharKernedWidth(text[i]) + getCharStartingCol(text[i]);
@@ -129,7 +180,7 @@ int Font::getBitmapStringLength(const Common::String &text) const {
 	return result;
 }
 
-int Font::getStringHeight(const Common::String &text) const {
+int BitmapFont::getStringHeight(const Common::String &text) const {
 	int result = 0;
 	for (uint32 i = 0; i < text.size(); ++i) {
 		int verticalOffset = getCharStartingLine(text[i]) + getBaseOffsetY();
@@ -140,11 +191,11 @@ int Font::getStringHeight(const Common::String &text) const {
 	return result;
 }
 
-void Font::saveState(SaveGame *state) const {
+void BitmapFont::saveState(SaveGame *state) const {
 	state->writeString(getFilename());
 }
 
-void Font::restoreState(SaveGame *state) {
+void BitmapFont::restoreState(SaveGame *state) {
 	Common::String fname = state->readString();
 	Common::SeekableReadStream *stream;
 
@@ -161,7 +212,73 @@ void Font::restoreState(SaveGame *state) {
 	delete stream;
 }
 
+void FontTTF::saveState(SaveGame *state) const {
+	state->writeString(getFilename());
+	state->writeLESint32(_size);
+}
+
+void FontTTF::restoreState(SaveGame *state) {
+	Common::String fname = state->readString();
+	int size = state->readLESint32();
+	Common::SeekableReadStream *stream;
+
+	g_driver->destroyFont(this);
+	delete _font;
+
+	stream = g_resourceloader->openNewStreamFile(fname.c_str(), true);
+	loadTTF(fname, stream, size);
+	delete stream;
+}
+
+void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLine,
+			const Graphics::PixelFormat &pixelFormat, uint32 blackColor, uint32 color, uint32 colorKey) const {
+	int width = getBitmapStringLength(currentLine) + 1;
+	int height = getStringHeight(currentLine) + 1;
+
+	uint8 *_textBitmap = new uint8[height * width]();
+
+	int startColumn = 0;
+	for (unsigned int d = 0; d < currentLine.size(); d++) {
+		int ch = currentLine[d];
+		int32 charBitmapWidth = getCharBitmapWidth(ch);
+		int8 fontRow = getCharStartingLine(ch) + getBaseOffsetY();
+		int8 fontCol = getCharStartingCol(ch);
+
+		for (int line = 0; line < getCharBitmapHeight(ch); line++) {
+			int lineOffset = ((fontRow + line) * width);
+			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++) {
+				int columnOffset = startColumn + fontCol + bitmapCol;
+				int fontOffset = (charBitmapWidth * line) + bitmapCol;
+				int8 pixel = getCharData(ch)[fontOffset];
+				assert(lineOffset + columnOffset < width*height);
+				if (pixel != 0)
+					_textBitmap[lineOffset + columnOffset] = pixel;
+			}
+		}
+		startColumn += getCharKernedWidth(ch);
+	}
+
+	buf.create(width, height, pixelFormat);
+	uint8 *bitmapData = _textBitmap;
+	for (int iy = 0; iy < height; iy++) {
+		for (int ix = 0; ix < width; ix++, bitmapData++) {
+			byte pixel = *bitmapData;
+			if (pixel == 0x00) {
+				buf.setPixel(ix, iy, colorKey);
+			} else if (pixel == 0x80) {
+				buf.setPixel(ix, iy, blackColor);
+			} else if (pixel == 0xFF) {
+				buf.setPixel(ix, iy, color);
+			}
+		}
+	}
+
+	delete[] _textBitmap;
+}
+
 void FontTTF::loadTTF(const Common::String &filename, Common::SeekableReadStream *data, int size) {
+	_filename = filename;
+	_size = size;
 #ifdef USE_FREETYPE2
 	_font = Graphics::loadTTFFont(*data, size);
 #else
@@ -169,8 +286,17 @@ void FontTTF::loadTTF(const Common::String &filename, Common::SeekableReadStream
 #endif
 }
 
+void FontTTF::render(Graphics::Surface &surface, const Common::String &currentLine, const Graphics::PixelFormat &pixelFormat, uint32 blackColor, uint32 color, uint32 colorKey) const {
+#ifdef USE_FREETYPE2
+	Common::Rect bbox = _font->getBoundingBox(currentLine);
+	surface.create(bbox.right, bbox.bottom, pixelFormat);
+	surface.fillRect(Common::Rect(0, 0, bbox.right, bbox.bottom), colorKey);
+	_font->drawString(&surface, currentLine, 0, 0, bbox.right, 0xFFFFFFFF);
+#endif
+}
+
 // Hardcoded default font for FPS, GUI, etc
-const uint8 Font::emerFont[][13] = {
+const uint8 BitmapFont::emerFont[][13] = {
 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
diff --git a/engines/grim/font.h b/engines/grim/font.h
index 24dff72fcb0..b8e229fc959 100644
--- a/engines/grim/font.h
+++ b/engines/grim/font.h
@@ -25,6 +25,7 @@
 #include "engines/grim/pool.h"
 
 #include "graphics/font.h"
+#include "graphics/pixelformat.h"
 
 namespace Common {
 class SeekableReadStream;
@@ -34,22 +35,50 @@ namespace Grim {
 
 class SaveGame;
 
-class Font : public PoolObject<Font> {
+class Font {
 public:
-	Font();
-	~Font();
+	virtual ~Font() {}
+
+	virtual int32 getKernedHeight() const = 0;
+	virtual int32 getFontWidth() const = 0;
+	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(unsigned char c) const = 0;
+	virtual int getPoolId() const = 0;
+	virtual int32 getPoolTag() const = 0;
+	virtual bool is8Bit() const = 0;
+	const Common::String &getFilename() const { return _filename; }
+
+	static Font *getByFileName(const Common::String& fileName);
+	static Font *getFirstFont();
+	static void save(const Font *font, SaveGame *state);
+	static Font *load(SaveGame *state);
+
+protected:
+	Common::String _filename;
+};
+
+class BitmapFont : public Font, public PoolObject<BitmapFont> {
+public:
+	BitmapFont();
+	~BitmapFont();
 
 	static int32 getStaticTag() { return MKTAG('F', 'O', 'N', 'T'); }
+	int getPoolId() const override { return getId(); }
+	int32 getPoolTag() const override { return getStaticTag(); }
 
 	void load(const Common::String &filename, Common::SeekableReadStream *data);
 
 
 	const Common::String &getFilename() const { return _filename; }
-	virtual int32 getKernedHeight() const { return _kernedHeight; }
-	virtual int32 getBaseOffsetY() const { return _baseOffsetY; }
+	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;
 	virtual int32 getCharBitmapWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
 	virtual int32 getCharBitmapHeight(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
-	virtual int32 getCharKernedWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].kernedWidth; }
+	int32 getCharKernedWidth(unsigned char c) const override { return _charHeaders[getCharIndex(c)].kernedWidth; }
 	virtual int32 getCharStartingCol(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingCol; }
 	virtual int32 getCharStartingLine(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingLine; }
 	virtual int32 getCharOffset(unsigned char c) const { return _charHeaders[getCharIndex(c)].offset; }
@@ -57,6 +86,7 @@ public:
 
 	const byte *getFontData() const { return _fontData; }
 	uint32 getDataSize() const { return _dataSize; }
+	bool is8Bit() const override { return true; }
 
 	virtual int getKernedStringLength(const Common::String &text) const;
 	virtual int getBitmapStringLength(const Common::String &text) const;
@@ -88,21 +118,32 @@ private:
 	uint16 *_charIndex;
 	CharHeader *_charHeaders;
 	byte *_fontData;
-	Common::String _filename;
 	void *_userData;
 };
 
-class FontTTF : public Font {
+class FontTTF : public Font, public PoolObject<FontTTF> {
 public:
 	void loadTTF(const Common::String &filename, Common::SeekableReadStream *data, int size);
 
+	static int32 getStaticTag() { return MKTAG('T', 'T', 'F', ' '); }
+	int getPoolId() const override { return getId(); }
+	int32 getPoolTag() const override { return getStaticTag(); }
+
 	int32 getKernedHeight() const override { return _font->getFontHeight(); }
 	int32 getBaseOffsetY() const override { return 0; }
 	int32 getCharKernedWidth(unsigned char 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); }
+	void render(Graphics::Surface &buf, const Common::String &currentLine, const Graphics::PixelFormat &pixelFormat, uint32 blackColor, uint32 color, uint32 colorKey) const override;
+	bool is8Bit() const override { return false; }
+
+	void saveState(SaveGame *state) const;
+	void restoreState(SaveGame *state);
 
+private:
 	Graphics::Font *_font;
+	int _size;
 };
 
 } // end of namespace Grim
diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp
index 752f3380d40..f62561d60ba 100644
--- a/engines/grim/gfx_opengl.cpp
+++ b/engines/grim/gfx_opengl.cpp
@@ -1286,7 +1286,10 @@ struct FontUserData {
 	GLuint texture;
 };
 
-void GfxOpenGL::createFont(Font *font) {
+void GfxOpenGL::createFont(Font *f) {
+	if (!f->is8Bit())
+		return;
+	BitmapFont *font = static_cast<BitmapFont *>(f);
 	const byte *bitmapData = font->getFontData();
 	uint dataSize = font->getDataSize();
 
@@ -1372,10 +1375,12 @@ void GfxOpenGL::createFont(Font *font) {
 }
 
 void GfxOpenGL::destroyFont(Font *font) {
-	const FontUserData *data = (const FontUserData *)font->getUserData();
-	if (data) {
-		glDeleteTextures(1, &(data->texture));
-		delete data;
+	if (font->is8Bit()) {
+		const FontUserData *data = static_cast<const FontUserData *>(static_cast<const BitmapFont *>(font)->getUserData());
+		if (data) {
+			glDeleteTextures(1, &(data->texture));
+			delete data;
+		}
 	}
 }
 
@@ -1384,14 +1389,12 @@ struct TextObjectUserData {
 };
 
 void GfxOpenGL::createTextObject(TextObject *text) {
-	if (g_grim->getGameType() != GType_GRIM || !g_grim->isRemastered())
-		return;
-
-#ifdef USE_FREETYPE2
 	//error("Could not get font userdata");
 	const Font *font = text->getFont();
-	const FontTTF *f = static_cast<const FontTTF *>(font);
-	Graphics::Font *gf = f->_font;
+
+	if (font->is8Bit())
+		return;
+
 	int numLines = text->getNumLines();
 	GLuint *texids = new GLuint[numLines];
 	glGenTextures(numLines, texids);
@@ -1399,10 +1402,8 @@ void GfxOpenGL::createTextObject(TextObject *text) {
 	for (int i = 0; i < numLines; i++) {
 		Graphics::Surface surface;
 
-		int width = gf->getStringWidth(text->getLines()[i]);
-		int height = width;
-		surface.create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
-		gf->drawString(&surface, text->getLines()[i], 0, 0, width, 0xFFFFFFFF);
+		font->render(surface, text->getLines()[i], Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24),
+			     0xFF000000, 0xFFFFFFFF, 0x00000000);
 
 		byte *bitmap = (byte *)surface.getPixels();
 
@@ -1411,7 +1412,7 @@ void GfxOpenGL::createTextObject(TextObject *text) {
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface.w, surface.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
 
 		surface.free();
 	}
@@ -1419,7 +1420,6 @@ void GfxOpenGL::createTextObject(TextObject *text) {
 
 	ud->_texids = texids;
 	text->setUserData(ud);
-#endif
 }
 
 void GfxOpenGL::drawTextObject(const TextObject *text) {
@@ -1442,23 +1442,15 @@ void GfxOpenGL::drawTextObject(const TextObject *text) {
 	glDepthMask(GL_FALSE);
 
 	const Color &color = text->getFGColor();
-	const Font *font = text->getFont();
+	const Font *f = text->getFont();
 
 	glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
-	const FontUserData *userData = (const FontUserData *)font->getUserData();
-	if (!userData) {
-		if (g_grim->getGameType() != GType_GRIM || !g_grim->isRemastered())
-			error("Could not get font userdata");
-#ifdef USE_FREETYPE2
-		const FontTTF *f = static_cast<const FontTTF *>(font);
-		Graphics::Font *gf = f->_font;
-
-
+	if (!f->is8Bit()) {
 		const TextObjectUserData *ud = (const TextObjectUserData *)text->getUserData();
 
 		int numLines = text->getNumLines();
 		for (int i = 0; i < numLines; ++i) {
-			float width = gf->getStringWidth(text->getLines()[i]);
+			float width = f->getKernedStringLength(text->getLines()[i]);
 			float height = width;
 			float x = text->getLineX(i);
 
@@ -1498,10 +1490,13 @@ void GfxOpenGL::drawTextObject(const TextObject *text) {
 		glEnable(GL_DEPTH_TEST);
 		glEnable(GL_LIGHTING);
 		glDepthMask(GL_TRUE);
-#endif
 		return;
 	}
 
+	const BitmapFont *font = static_cast<const BitmapFont *>(f);
+	const FontUserData *userData = (const FontUserData *)font->getUserData();
+	if (!userData)
+		error("Could not get font userdata");
 	float sizeW = userData->size * _scaleW;
 	float sizeH = userData->size * _scaleH;
 	GLuint texture = userData->texture;
@@ -1821,7 +1816,7 @@ void GfxOpenGL::loadEmergFont() {
 	_emergFont = glGenLists(128);
 	for (int i = 32; i < 128; i++) {
 		glNewList(_emergFont + i, GL_COMPILE);
-		glBitmap(8, 13, 0, 2, 10, 0, Font::emerFont[i - 32]);
+		glBitmap(8, 13, 0, 2, 10, 0, BitmapFont::emerFont[i - 32]);
 		glEndList();
 	}
 }
diff --git a/engines/grim/gfx_opengl_shaders.cpp b/engines/grim/gfx_opengl_shaders.cpp
index 2edc7aa5a18..d8151121e86 100644
--- a/engines/grim/gfx_opengl_shaders.cpp
+++ b/engines/grim/gfx_opengl_shaders.cpp
@@ -1519,7 +1519,10 @@ void GfxOpenGLS::destroyBitmap(BitmapData *bitmap) {
 	}
 }
 
-void GfxOpenGLS::createFont(Font *font) {
+void GfxOpenGLS::createFont(Font *f) {
+	if (!f->is8Bit())
+		error("non-8bit fonts are not supported in GL shaders renderer");
+	BitmapFont *font = static_cast<BitmapFont *>(f);
 	const byte *bitmapData = font->getFontData();
 	uint dataSize = font->getDataSize();
 
@@ -1604,16 +1607,21 @@ void GfxOpenGLS::createFont(Font *font) {
 }
 
 void GfxOpenGLS::destroyFont(Font *font) {
-	const FontUserData *data = (const FontUserData *)font->getUserData();
-	if (data) {
-		glDeleteTextures(1, &(data->texture));
-		delete data;
+	if (font->is8Bit()) {
+		const FontUserData *data = static_cast<const FontUserData *>(static_cast<const BitmapFont *>(font)->getUserData());
+		if (data) {
+			glDeleteTextures(1, &(data->texture));
+			delete data;
+		}
 	}
 }
 
 void GfxOpenGLS::createTextObject(TextObject *text) {
 	const Color &color = text->getFGColor();
-	const Font *font = text->getFont();
+	const Font *f = text->getFont();
+	if (!f->is8Bit())
+		error("non-8bit fonts are not supported in GL shaders renderer");
+	const BitmapFont *font = static_cast<const BitmapFont *>(f);
 
 	const FontUserData *userData = (const FontUserData *)font->getUserData();
 	if (!userData)
@@ -1860,7 +1868,7 @@ void GfxOpenGLS::loadEmergFont() {
 		int blockcol = c & 0xf;
 		for (int row = 0; row < 13; ++row) {
 			int base = 128 * (16 * blockrow + row) + 8 * blockcol;
-			uint8 val = Font::emerFont[c - 32][row];
+			uint8 val = BitmapFont::emerFont[c - 32][row];
 			atlas[base + 0] = (val & 0x80) ? 255 : 0;
 			atlas[base + 1] = (val & 0x40) ? 255 : 0;
 			atlas[base + 2] = (val & 0x20) ? 255 : 0;
diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp
index 552aaacd5ee..263df3d7460 100644
--- a/engines/grim/gfx_tinygl.cpp
+++ b/engines/grim/gfx_tinygl.cpp
@@ -1055,52 +1055,12 @@ void GfxTinyGL::createTextObject(TextObject *text) {
 	}
 	for (int j = 0; j < numLines; j++) {
 		const Common::String &currentLine = lines[j];
-
-		int width = font->getBitmapStringLength(currentLine) + 1;
-		int height = font->getStringHeight(currentLine) + 1;
-
-		uint8 *_textBitmap = new uint8[height * width]();
-
-		int startColumn = 0;
-		for (unsigned int d = 0; d < currentLine.size(); d++) {
-			int ch = currentLine[d];
-			int32 charBitmapWidth = font->getCharBitmapWidth(ch);
-			int8 fontRow = font->getCharStartingLine(ch) + font->getBaseOffsetY();
-			int8 fontCol = font->getCharStartingCol(ch);
-
-			for (int line = 0; line < font->getCharBitmapHeight(ch); line++) {
-				int lineOffset = ((fontRow + line) * width);
-				for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++) {
-					int columnOffset = startColumn + fontCol + bitmapCol;
-					int fontOffset = (charBitmapWidth * line) + bitmapCol;
-					int8 pixel = font->getCharData(ch)[fontOffset];
-					assert(lineOffset + columnOffset < width*height);
-					if (pixel != 0)
-						_textBitmap[lineOffset + columnOffset] = pixel;
-				}
-			}
-			startColumn += font->getCharKernedWidth(ch);
-		}
-
 		Graphics::Surface buf;
-		buf.create(width, height, _pixelFormat);
-
-		uint8 *bitmapData = _textBitmap;
-		for (int iy = 0; iy < height; iy++) {
-			for (int ix = 0; ix < width; ix++, bitmapData++) {
-				byte pixel = *bitmapData;
-				if (pixel == 0x00) {
-					buf.setPixel(ix, iy, kKitmapColorkey);
-				} else if (pixel == 0x80) {
-					buf.setPixel(ix, iy, blackColor);
-				} else if (pixel == 0xFF) {
-					buf.setPixel(ix, iy, color);
-				}
-			}
-		}
 
-		userData[j].width = width;
-		userData[j].height = height;
+		font->render(buf, currentLine, _pixelFormat, blackColor, color, kKitmapColorkey);
+
+		userData[j].width = buf.w;
+		userData[j].height = buf.h;
 		userData[j].image = tglGenBlitImage();
 		tglUploadBlitImage(userData[j].image, buf, kKitmapColorkey, true);
 		userData[j].x = text->getLineX(j);
@@ -1113,7 +1073,6 @@ void GfxTinyGL::createTextObject(TextObject *text) {
 		}
 
 		buf.free();
-		delete[] _textBitmap;
 	}
 }
 
@@ -1227,7 +1186,7 @@ void GfxTinyGL::loadEmergFont() {
 	uint32 colorTransparent = textureFormat.ARGBToColor(0, 255, 255, 255);
 	for (int i = 0; i < 96; i++) {
 		_emergFont[i] = tglGenBlitImage();
-		const uint8 *ptr = Font::emerFont[i];
+		const uint8 *ptr = BitmapFont::emerFont[i];
 		for (int py = 0; py < 13; py++) {
 				int line = ptr[12 - py];
 				for (int px = 0; px < 8; px++) {
diff --git a/engines/grim/grim.cpp b/engines/grim/grim.cpp
index 209080c21dc..688175186e5 100644
--- a/engines/grim/grim.cpp
+++ b/engines/grim/grim.cpp
@@ -242,7 +242,8 @@ void GrimEngine::clearPools() {
 	PrimitiveObject::getPool().deleteObjects();
 	TextObject::getPool().deleteObjects();
 	Bitmap::getPool().deleteObjects();
-	Font::getPool().deleteObjects();
+	BitmapFont::getPool().deleteObjects();
+	FontTTF::getPool().deleteObjects();
 	ObjectState::getPool().deleteObjects();
 
 	_currSet = nullptr;
@@ -1187,7 +1188,10 @@ void GrimEngine::savegameRestore() {
 	Bitmap::getPool().restoreObjects(_savedState);
 	Debug::debug(Debug::Engine, "Bitmaps restored successfully.");
 
-	Font::getPool().restoreObjects(_savedState);
+	BitmapFont::getPool().restoreObjects(_savedState);
+	if (_savedState->saveMinorVersion() >= 28) {
+		FontTTF::getPool().restoreObjects(_savedState);
+	}
 	Debug::debug(Debug::Engine, "Fonts restored successfully.");
 
 	ObjectState::getPool().restoreObjects(_savedState);
@@ -1270,7 +1274,7 @@ void GrimEngine::restoreGRIM() {
 
 	//TextObject stuff
 	_sayLineDefaults.setFGColor(_savedState->readColor());
-	_sayLineDefaults.setFont(Font::getPool().getObject(_savedState->readLESint32()));
+	_sayLineDefaults.setFont(Font::load(_savedState));
 	_sayLineDefaults.setHeight(_savedState->readLESint32());
 	_sayLineDefaults.setJustify(_savedState->readLESint32());
 	_sayLineDefaults.setWidth(_savedState->readLESint32());
@@ -1359,7 +1363,8 @@ void GrimEngine::savegameSave() {
 	Bitmap::getPool().saveObjects(_savedState);
 	Debug::debug(Debug::Engine, "Bitmaps saved successfully.");
 
-	Font::getPool().saveObjects(_savedState);
+	BitmapFont::getPool().saveObjects(_savedState);
+	FontTTF::getPool().saveObjects(_savedState);
 	Debug::debug(Debug::Engine, "Fonts saved successfully.");
 
 	ObjectState::getPool().saveObjects(_savedState);
@@ -1428,7 +1433,7 @@ void GrimEngine::saveGRIM() {
 
 	//TextObject stuff
 	_savedState->writeColor(_sayLineDefaults.getFGColor());
-	_savedState->writeLESint32(_sayLineDefaults.getFont()->getId());
+	Font::save(_sayLineDefaults.getFont(), _savedState);
 	_savedState->writeLESint32(_sayLineDefaults.getHeight());
 	_savedState->writeLESint32(_sayLineDefaults.getJustify());
 	_savedState->writeLESint32(_sayLineDefaults.getWidth());
diff --git a/engines/grim/lua.cpp b/engines/grim/lua.cpp
index 184dd3ca831..21113aee064 100644
--- a/engines/grim/lua.cpp
+++ b/engines/grim/lua.cpp
@@ -373,8 +373,12 @@ TextObject *LuaBase::gettextobject(lua_Object obj) {
 	return TextObject::getPool().getObject(lua_getuserdata(obj));
 }
 
-Font *LuaBase::getfont(lua_Object obj) {
-	return Font::getPool().getObject(lua_getuserdata(obj));
+Font *LuaBase::getfont(lua_Object fontObj) {
+	if (lua_tag(fontObj) == BitmapFont::getStaticTag())
+		return BitmapFont::getPool().getObject(lua_getuserdata(fontObj));
+	if (lua_tag(fontObj) == FontTTF::getStaticTag())
+		return FontTTF::getPool().getObject(lua_getuserdata(fontObj));
+	return nullptr;
 }
 
 Color LuaBase::getcolor(lua_Object obj) {
@@ -511,23 +515,18 @@ void LuaBase::setTextObjectParams(TextObjectCommon *textObject, lua_Object table
 	if (keyObj) {
 		if (g_grim->getGameType() == GType_MONKEY4 && lua_isstring(keyObj)) {
 			const char *str = lua_getstring(keyObj);
-			Font *font = nullptr;
-			for (Font *f : Font::getPool()) {
-				if (f->getFilename() == str) {
-					font = f;
-				}
-			}
+			Font *font = Font::getByFileName(str);
 			if (!font) {
 				font = g_resourceloader->loadFont(str);
 			}
 
 			textObject->setFont(font);
-		} else if (lua_isuserdata(keyObj) && lua_tag(keyObj) == MKTAG('F','O','N','T')) {
+		} else if (lua_isuserdata(keyObj) && (lua_tag(keyObj) == BitmapFont::getStaticTag() || lua_tag(keyObj) == FontTTF::getStaticTag())) {
 			textObject->setFont(getfont(keyObj));
 		} else if (g_grim->getGameType() == GType_MONKEY4 && !textObject->getFont() && g_grim->getGamePlatform() == Common::kPlatformPS2) {
 			// HACK:
 			warning("HACK: No default font set for PS2-version, just picking one for now");
-			textObject->setFont(*Font::getPool().begin());
+			textObject->setFont(Font::getFirstFont());
 		}
 	}
 
diff --git a/engines/grim/lua_v1.cpp b/engines/grim/lua_v1.cpp
index 6bba8405d7f..a24bfaf5fa6 100644
--- a/engines/grim/lua_v1.cpp
+++ b/engines/grim/lua_v1.cpp
@@ -724,7 +724,7 @@ void Lua_V1::LockFont() {
 		const char *fontName = lua_getstring(param1);
 		Font *result = g_resourceloader->loadFont(fontName);
 		if (result) {
-			lua_pushusertag(result->getId(), MKTAG('F','O','N','T'));
+			lua_pushusertag(result->getPoolId(), result->getPoolTag());
 			return;
 		}
 	}
diff --git a/engines/grim/remastered/lua_remastered.cpp b/engines/grim/remastered/lua_remastered.cpp
index 199fd044730..ca3852b67bc 100644
--- a/engines/grim/remastered/lua_remastered.cpp
+++ b/engines/grim/remastered/lua_remastered.cpp
@@ -44,14 +44,14 @@ void Lua_Remastered::WidescreenCorrectionFactor() {
 void Lua_Remastered::GetFontDimensions() {
 	// Taken from Lua_v2 and modified
 	lua_Object fontObj = lua_getparam(1);
-	if (!lua_isuserdata(fontObj) || lua_tag(fontObj) != Font::getStaticTag())
+	if (!lua_isuserdata(fontObj))
 		return;
 
-	Font *font = Font::getPool().getObject(lua_getuserdata(fontObj));
+	Font *font = getfont(fontObj);
 
 	if (font) {
 		int32 h = font->getKernedHeight();
-		int32 w = font->getCharKernedWidth('w');
+		int32 w = font->getFontWidth();
 		lua_pushnumber(w);
 		lua_pushnumber(h);
 	} else {
diff --git a/engines/grim/resource.cpp b/engines/grim/resource.cpp
index 29cdf4f963f..b16f9d3b8c9 100644
--- a/engines/grim/resource.cpp
+++ b/engines/grim/resource.cpp
@@ -394,7 +394,7 @@ Font *ResourceLoader::loadFont(const Common::String &filename) {
 	if (!stream)
 		error("Could not find font file %s", filename.c_str());
 
-	Font *result = new Font();
+	BitmapFont *result = new BitmapFont();
 	result->load(filename, stream);
 	delete stream;
 
diff --git a/engines/grim/savegame.cpp b/engines/grim/savegame.cpp
index b606e5da464..6182ecd5d1a 100644
--- a/engines/grim/savegame.cpp
+++ b/engines/grim/savegame.cpp
@@ -34,7 +34,7 @@ namespace Grim {
 #define SAVEGAME_FOOTERTAG  'ESAV'
 
 uint SaveGame::SAVEGAME_MAJOR_VERSION = 22;
-uint SaveGame::SAVEGAME_MINOR_VERSION = 27;
+uint SaveGame::SAVEGAME_MINOR_VERSION = 28;
 
 SaveGame *SaveGame::openForLoading(const Common::String &filename) {
 	Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename);
diff --git a/engines/grim/textobject.cpp b/engines/grim/textobject.cpp
index 9eb5b1b767e..8ec3b8c1ae5 100644
--- a/engines/grim/textobject.cpp
+++ b/engines/grim/textobject.cpp
@@ -87,11 +87,7 @@ void TextObject::saveState(SaveGame *state) const {
 	state->writeBool(_isSpeech);
 	state->writeLESint32(_elapsedTime);
 
-	if (_font) {
-		state->writeLESint32(_font->getId());
-	} else {
-		state->writeLESint32(-1);
-	}
+	Font::save(_font, state);
 
 	state->writeString(_textID);
 
@@ -116,12 +112,7 @@ bool TextObject::restoreState(SaveGame *state) {
 	_isSpeech     = state->readBool();
 	_elapsedTime  = state->readLESint32();
 
-	int32 fontId = state->readLESint32();
-	if (fontId == -1) {
-		_font = nullptr;
-	} else {
-		_font = Font::getPool().getObject(fontId);
-	}
+	_font = Font::load(state);
 
 	_textID = state->readString();
 


Commit: 3e1075c2b0970b5aae685aab56faa7ae5b0ed0f2
    https://github.com/scummvm/scummvm/commit/3e1075c2b0970b5aae685aab56faa7ae5b0ed0f2
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Small optimisation in bitmap font renderer

Changed paths:
    engines/grim/font.cpp


diff --git a/engines/grim/font.cpp b/engines/grim/font.cpp
index 5bc26ca4e92..69360077285 100644
--- a/engines/grim/font.cpp
+++ b/engines/grim/font.cpp
@@ -235,9 +235,11 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 	int width = getBitmapStringLength(currentLine) + 1;
 	int height = getStringHeight(currentLine) + 1;
 
-	uint8 *_textBitmap = new uint8[height * width]();
-
 	int startColumn = 0;
+
+	buf.create(width, height, pixelFormat);
+	buf.fillRect(Common::Rect(0, 0, width, height), colorKey);
+
 	for (unsigned int d = 0; d < currentLine.size(); d++) {
 		int ch = currentLine[d];
 		int32 charBitmapWidth = getCharBitmapWidth(ch);
@@ -245,35 +247,19 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 		int8 fontCol = getCharStartingCol(ch);
 
 		for (int line = 0; line < getCharBitmapHeight(ch); line++) {
-			int lineOffset = ((fontRow + line) * width);
-			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++) {
-				int columnOffset = startColumn + fontCol + bitmapCol;
-				int fontOffset = (charBitmapWidth * line) + bitmapCol;
-				int8 pixel = getCharData(ch)[fontOffset];
-				assert(lineOffset + columnOffset < width*height);
-				if (pixel != 0)
-					_textBitmap[lineOffset + columnOffset] = pixel;
+			int lineOffset = (fontRow + line);
+			int columnOffset = startColumn + fontCol;
+			int fontOffset = (charBitmapWidth * line);
+			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++, columnOffset++, fontOffset++) {
+				byte pixel = getCharData(ch)[fontOffset];
+				if (pixel == 0x80)
+					buf.setPixel(columnOffset, lineOffset, blackColor);
+				else if (pixel == 0xFF)
+					buf.setPixel(columnOffset, lineOffset, color);
 			}
 		}
 		startColumn += getCharKernedWidth(ch);
 	}
-
-	buf.create(width, height, pixelFormat);
-	uint8 *bitmapData = _textBitmap;
-	for (int iy = 0; iy < height; iy++) {
-		for (int ix = 0; ix < width; ix++, bitmapData++) {
-			byte pixel = *bitmapData;
-			if (pixel == 0x00) {
-				buf.setPixel(ix, iy, colorKey);
-			} else if (pixel == 0x80) {
-				buf.setPixel(ix, iy, blackColor);
-			} else if (pixel == 0xFF) {
-				buf.setPixel(ix, iy, color);
-			}
-		}
-	}
-
-	delete[] _textBitmap;
 }
 
 void FontTTF::loadTTF(const Common::String &filename, Common::SeekableReadStream *data, int size) {


Commit: dc86f8731ca1017eea8ef618b9fbefbf08d1da3a
    https://github.com/scummvm/scummvm/commit/dc86f8731ca1017eea8ef618b9fbefbf08d1da3a
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Support Chinese font

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


diff --git a/engines/grim/font.cpp b/engines/grim/font.cpp
index 69360077285..4ee88a2c259 100644
--- a/engines/grim/font.cpp
+++ b/engines/grim/font.cpp
@@ -84,15 +84,19 @@ Font *Font::getFirstFont() {
 	return nullptr;
 }
 
+bool BitmapFont::is8Bit() const {
+	return !_isDBCS;
+}
+
 BitmapFont::BitmapFont() :
 		_userData(nullptr),
-		_fontData(nullptr), _charHeaders(nullptr), _charIndex(nullptr),
+		_fontData(nullptr), _charHeaders(nullptr),
 		_numChars(0), _dataSize(0), _kernedHeight(0), _baseOffsetY(0),
 		_firstChar(0), _lastChar(0) {
 }
 
 BitmapFont::~BitmapFont() {
-	delete[] _charIndex;
+	_fwdCharIndex.clear();
 	delete[] _charHeaders;
 	delete[] _fontData;
 	g_driver->destroyFont(this);
@@ -108,10 +112,47 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 	_firstChar = data->readUint32LE();
 	_lastChar = data->readUint32LE();
 
-	// Read character indexes - are the key/value reversed?
-	_charIndex = new uint16[_numChars];
-	for (uint i = 0; i < _numChars; ++i)
-		_charIndex[i] = data->readUint16LE();
+	_isDBCS = g_grim->getGameLanguage() == Common::ZH_CHN && _numChars > 0xff;
+
+	if (_isDBCS) {
+		// Read character indexes - are the key/value reversed?
+		_fwdCharIndex.resize(_numChars);
+		for (uint i = 0; i < _numChars; ++i) {
+			uint16 point = data->readUint16LE();
+			_fwdCharIndex[i] = point ? point : -1;
+		}
+	} else {
+		// Read character indexes - are the key/value reversed?
+		Common::Array<uint16> revCharIndex;
+		revCharIndex.resize(_numChars);
+		uint16 maxPoint = 0;
+		for (uint i = 0; i < _numChars; ++i) {
+			uint16 point = data->readUint16LE();
+			revCharIndex[i] = point;
+			if (point > maxPoint)
+				maxPoint = point;
+		}
+		_fwdCharIndex.resize(maxPoint + 1, -1);
+		for (uint i = 0; i < _numChars; ++i) {
+			_fwdCharIndex[revCharIndex[i]] = i;
+		}
+
+		// In order to ensure the correct character codes for
+		// accented characters it is necessary to check the
+		// requested code against the index of characters for
+		// the font.  Previously, signed characters were
+		// causing the problem but it might be possible for
+		// an invalid character to be called for other reasons.
+		//
+		// Example: Without this fix when Manny greets Eva
+		// for the first time and he says "Buenos Días" the
+		// 'í' character will either show up as a different
+		// character or it crashes the game.
+		for (uint i = 0; i < _numChars; ++i) {
+			if (revCharIndex[i] == i)
+				_fwdCharIndex[revCharIndex[i]] = i;
+		}
+	}
 
 	// Read character headers
 	_charHeaders = new CharHeader[_numChars];
@@ -134,30 +175,11 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 	g_driver->createFont(this);
 }
 
-uint16 BitmapFont::getCharIndex(unsigned char c) const {
-	uint16 c2 = uint16(c);
-
-	// In order to ensure the correct character codes for
-	// accented characters it is necessary to check the
-	// requested code against the index of characters for
-	// the font.  Previously, signed characters were
-	// causing the problem but it might be possible for
-	// an invalid character to be called for other reasons.
-	//
-	// Example: Without this fix when Manny greets Eva
-	// for the first time and he says "Buenos Días" the
-	// 'í' character will either show up as a different
-	// character or it crashes the game.
-
-	if (_charIndex[c2] == c2) {
-		return c2;
-	}
-
-	for (uint i = 0; i < _numChars; ++i) {
-		if (_charIndex[i] == c2)
-			return i;
-	}
-	Debug::warning(Debug::Fonts, "The requested character (code 0x%x) does not correspond to anything in the font data!", c2);
+uint16 BitmapFont::getCharIndex(uint16 c) const {
+	int res = c < _fwdCharIndex.size() ? _fwdCharIndex[c] : -1;
+	if (res >= 0)
+		return res;
+	Debug::warning(Debug::Fonts, "The requested character (code 0x%x) does not correspond to anything in the font data!", c);
 	// If we couldn't find the character then default to
 	// the first character in the font so that something
 	// gets loaded to prevent the game from crashing
@@ -167,7 +189,11 @@ uint16 BitmapFont::getCharIndex(unsigned char c) const {
 int BitmapFont::getKernedStringLength(const Common::String &text) const {
 	int result = 0;
 	for (uint32 i = 0; i < text.size(); ++i) {
-		result += getCharKernedWidth(text[i]);
+		uint16 ch = uint8(text[i]);
+		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
+			ch = (ch << 8) | (text[++i] & 0xff);
+		}
+		result += getCharKernedWidth(ch);
 	}
 	return result;
 }
@@ -175,7 +201,11 @@ int BitmapFont::getKernedStringLength(const Common::String &text) const {
 int BitmapFont::getBitmapStringLength(const Common::String &text) const {
 	int result = 0;
 	for (uint32 i = 0; i < text.size(); ++i) {
-		result += getCharKernedWidth(text[i]) + getCharStartingCol(text[i]);
+		uint16 ch = uint8(text[i]);
+		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
+			ch = (ch << 8) | (text[++i] & 0xff);
+		}
+		result += getCharKernedWidth(ch) + getCharStartingCol(ch);
 	}
 	return result;
 }
@@ -183,8 +213,13 @@ 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) {
-		int verticalOffset = getCharStartingLine(text[i]) + getBaseOffsetY();
-		int charHeight = verticalOffset + getCharBitmapHeight(text[i]);
+		uint16 ch = uint8(text[i]);
+		if (_isDBCS && i + 1 < text.size() && (ch & 0x80)) {
+			ch = (ch << 8) | (text[++i] & 0xff);
+		}
+
+		int verticalOffset = getCharStartingLine(ch) + getBaseOffsetY();
+		int charHeight = verticalOffset + getCharBitmapHeight(ch);
 		if (charHeight > result)
 			result = charHeight;
 	}
@@ -202,8 +237,7 @@ void BitmapFont::restoreState(SaveGame *state) {
 	g_driver->destroyFont(this);
 	delete[] _fontData;
 	_fontData = nullptr;
-	delete[] _charIndex;
-	_charIndex = nullptr;
+	_fwdCharIndex.clear();
 	delete[] _charHeaders;
 	_charHeaders = nullptr;
 
@@ -241,7 +275,10 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 	buf.fillRect(Common::Rect(0, 0, width, height), colorKey);
 
 	for (unsigned int d = 0; d < currentLine.size(); d++) {
-		int ch = currentLine[d];
+		uint16 ch = uint8(currentLine[d]);
+		if (_isDBCS && d + 1 < currentLine.size()) {
+			ch = (ch << 8) | (currentLine[++d] & 0xff);
+		}
 		int32 charBitmapWidth = getCharBitmapWidth(ch);
 		int8 fontRow = getCharStartingLine(ch) + getBaseOffsetY();
 		int8 fontCol = getCharStartingCol(ch);
diff --git a/engines/grim/font.h b/engines/grim/font.h
index b8e229fc959..88356b1dbb7 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(unsigned char c) const = 0;
+	virtual int32 getCharKernedWidth(uint16 c) const = 0;
 	virtual int getPoolId() const = 0;
 	virtual int32 getPoolTag() const = 0;
 	virtual bool is8Bit() const = 0;
@@ -76,21 +76,21 @@ public:
 	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;
-	virtual int32 getCharBitmapWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
-	virtual int32 getCharBitmapHeight(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
-	int32 getCharKernedWidth(unsigned char c) const override { return _charHeaders[getCharIndex(c)].kernedWidth; }
-	virtual int32 getCharStartingCol(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingCol; }
-	virtual int32 getCharStartingLine(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingLine; }
-	virtual int32 getCharOffset(unsigned char c) const { return _charHeaders[getCharIndex(c)].offset; }
-	const byte *getCharData(unsigned char c) const { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
+	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); }
 
 	const byte *getFontData() const { return _fontData; }
 	uint32 getDataSize() const { return _dataSize; }
-	bool is8Bit() const override { return true; }
+	bool is8Bit() const override;
 
-	virtual int getKernedStringLength(const Common::String &text) const;
-	virtual int getBitmapStringLength(const Common::String &text) const;
-	virtual int getStringHeight(const Common::String &text) const;
+	int getKernedStringLength(const Common::String &text) const;
+	int getBitmapStringLength(const Common::String &text) const;
+	int getStringHeight(const Common::String &text) const;
 
 	const void *getUserData() const { return _userData; }
 	void setUserData(void *data) { _userData = data; }
@@ -101,7 +101,7 @@ public:
 	static const uint8 emerFont[][13];
 private:
 
-	uint16 getCharIndex(unsigned char c) const;
+	uint16 getCharIndex(uint16 c) const;
 	struct CharHeader {
 		int32 offset;
 		int8  kernedWidth;
@@ -115,10 +115,11 @@ private:
 	uint32 _dataSize;
 	uint32 _kernedHeight, _baseOffsetY;
 	uint32 _firstChar, _lastChar;
-	uint16 *_charIndex;
+	Common::Array<int> _fwdCharIndex;
 	CharHeader *_charHeaders;
 	byte *_fontData;
 	void *_userData;
+	bool _isDBCS;
 };
 
 class FontTTF : public Font, public PoolObject<FontTTF> {
@@ -131,7 +132,7 @@ public:
 
 	int32 getKernedHeight() const override { return _font->getFontHeight(); }
 	int32 getBaseOffsetY() const override { return 0; }
-	int32 getCharKernedWidth(unsigned char c) const override { return _font->getCharWidth(c); }
+	int32 getCharKernedWidth(uint16 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: dfcccd32463bd13328bc9d11f755c681cd8438fe
    https://github.com/scummvm/scummvm/commit/dfcccd32463bd13328bc9d11f755c681cd8438fe
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Fix rendering bug

Changed paths:
    engines/grim/gfx_opengl.cpp


diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp
index f62561d60ba..9712e50c07e 100644
--- a/engines/grim/gfx_opengl.cpp
+++ b/engines/grim/gfx_opengl.cpp
@@ -1451,7 +1451,7 @@ void GfxOpenGL::drawTextObject(const TextObject *text) {
 		int numLines = text->getNumLines();
 		for (int i = 0; i < numLines; ++i) {
 			float width = f->getKernedStringLength(text->getLines()[i]);
-			float height = width;
+			float height = f->getKernedHeight();
 			float x = text->getLineX(i);
 
 			float y = text->getLineY(i);


Commit: 349c51508983cae75501178b0ddf2a18d74035ba
    https://github.com/scummvm/scummvm/commit/349c51508983cae75501178b0ddf2a18d74035ba
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Disable shaders renderer with Chinese

Changed paths:
    engines/grim/grim.cpp


diff --git a/engines/grim/grim.cpp b/engines/grim/grim.cpp
index 688175186e5..9267f2962e9 100644
--- a/engines/grim/grim.cpp
+++ b/engines/grim/grim.cpp
@@ -281,6 +281,10 @@ GfxBase *GrimEngine::createRenderer(int screenW, int screenH) {
 		availableRendererTypes &= ~Graphics::kRendererTypeOpenGLShaders;
 	}
 
+	// Not supported yet.
+	if (getLanguage() == Common::Language::ZH_CHN)
+		availableRendererTypes &= ~Graphics::kRendererTypeOpenGLShaders;
+
 	Graphics::RendererType matchingRendererType = Graphics::Renderer::getBestMatchingType(desiredRendererType, availableRendererTypes);
 
 	_softRenderer = matchingRendererType == Graphics::kRendererTypeTinyGL;


Commit: 60141a62acd69255fd8fa6fb284f7930d59a4364
    https://github.com/scummvm/scummvm/commit/60141a62acd69255fd8fa6fb284f7930d59a4364
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2023-03-05T22:39:27+01:00

Commit Message:
GRIM: Double the size of Chinese font

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


diff --git a/engines/grim/font.cpp b/engines/grim/font.cpp
index 4ee88a2c259..703aec49351 100644
--- a/engines/grim/font.cpp
+++ b/engines/grim/font.cpp
@@ -121,6 +121,7 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 			uint16 point = data->readUint16LE();
 			_fwdCharIndex[i] = point ? point : -1;
 		}
+		_scale = 2;
 	} else {
 		// Read character indexes - are the key/value reversed?
 		Common::Array<uint16> revCharIndex;
@@ -152,6 +153,7 @@ void BitmapFont::load(const Common::String &filename, Common::SeekableReadStream
 			if (revCharIndex[i] == i)
 				_fwdCharIndex[revCharIndex[i]] = i;
 		}
+		_scale = 1;
 	}
 
 	// Read character headers
@@ -280,19 +282,25 @@ void BitmapFont::render(Graphics::Surface &buf, const Common::String &currentLin
 			ch = (ch << 8) | (currentLine[++d] & 0xff);
 		}
 		int32 charBitmapWidth = getCharBitmapWidth(ch);
+		int32 charBitmapHeight = getCharBitmapHeight(ch);
 		int8 fontRow = getCharStartingLine(ch) + getBaseOffsetY();
 		int8 fontCol = getCharStartingCol(ch);
 
-		for (int line = 0; line < getCharBitmapHeight(ch); line++) {
-			int lineOffset = (fontRow + line);
+		for (int line = 0; line < charBitmapHeight; line++) {
+			int lineOffset = (fontRow + line * _scale);
 			int columnOffset = startColumn + fontCol;
 			int fontOffset = (charBitmapWidth * line);
-			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++, columnOffset++, fontOffset++) {
+			for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++, columnOffset += _scale, fontOffset++) {
 				byte pixel = getCharData(ch)[fontOffset];
-				if (pixel == 0x80)
-					buf.setPixel(columnOffset, lineOffset, blackColor);
-				else if (pixel == 0xFF)
-					buf.setPixel(columnOffset, lineOffset, color);
+				if (pixel == 0x80) {
+					for (uint i = 0; i < _scale; i++)
+						for (uint j = 0; j < _scale; j++)
+							buf.setPixel(columnOffset + i, lineOffset + j, blackColor);
+				} else if (pixel == 0xFF) {
+					for (uint i = 0; i < _scale; i++)
+						for (uint j = 0; j < _scale; j++)
+							buf.setPixel(columnOffset + i, lineOffset + j, color);
+				}
 			}
 		}
 		startColumn += getCharKernedWidth(ch);
diff --git a/engines/grim/font.h b/engines/grim/font.h
index 88356b1dbb7..edd292c5266 100644
--- a/engines/grim/font.h
+++ b/engines/grim/font.h
@@ -72,15 +72,15 @@ public:
 
 
 	const Common::String &getFilename() const { return _filename; }
-	int32 getKernedHeight() const override { return _kernedHeight; }
+	int32 getKernedHeight() const override { return _kernedHeight * _scale; }
 	int32 getFontWidth() const override { return getCharKernedWidth('w'); }
-	int32 getBaseOffsetY() const override { return _baseOffsetY; }
+	int32 getBaseOffsetY() const override { return _baseOffsetY * _scale; }
 	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 getCharKernedWidth(uint16 c) const override { return _charHeaders[getCharIndex(c)].kernedWidth * _scale; }
+	int32 getCharStartingCol(uint16 c) const { return _charHeaders[getCharIndex(c)].startingCol * _scale; }
+	int32 getCharStartingLine(uint16 c) const { return _charHeaders[getCharIndex(c)].startingLine * _scale; }
 	int32 getCharOffset(uint16 c) const { return _charHeaders[getCharIndex(c)].offset; }
 	const byte *getCharData(uint16 c) const { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
 
@@ -120,6 +120,7 @@ private:
 	byte *_fontData;
 	void *_userData;
 	bool _isDBCS;
+	uint _scale;
 };
 
 class FontTTF : public Font, public PoolObject<FontTTF> {




More information about the Scummvm-git-logs mailing list