[Scummvm-git-logs] scummvm branch-2-2 -> a890b9e35106422f39f257a626912b463a87d9a4
athrxx
athrxx at scummvm.org
Fri Oct 30 21:32:10 UTC 2020
This automated email contains information about 12 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
a97a11efe9 SCUMM: (DIG/CJK) - fix 2byte font glyph shadows
c002bfebb9 SCUMM: (DIG/CJK) - fix 'invalid escape code' error in Chinese intro
cab2d71fff SCUMM: (DIG/CJK) - fix blast text rendering and positioning
43bbe659ed SCUMM: (DIG/CJK) - fix CJK Smush font drawing
8e5d73e661 SCUMM: (SMUSH) - fix text flags
57c4f2373a SCUMM: (DIG/CJK) - fix regression in text positioning
d4b6473a7d SCUMM: (DIG/CJK) - add specific text positioning fix from disasm
e3bd302b5b SCUMM: (DIG/CJK) - fix bug in charset rendering
06cb2345aa SCUMM: (COMI/CJK) - fix smush font glyph shadows
d3b63bc735 SCUMM: whitespace
60e507b7da SCUMM: (COMI/CJK) - fix blast text shading and positioning
a890b9e351 SCUMM: (SMUSH) - fix text coordinates and wrapping
Commit: a97a11efe98fb806959edf9ddfd62e1f4864483d
https://github.com/scummvm/scummvm/commit/a97a11efe98fb806959edf9ddfd62e1f4864483d
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:11+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix 2byte font glyph shadows
All CJK versions use the same shading. The original code hardly ever diverges for the different languages (mostly for accessing the character bitmap data from the font files).
Changed paths:
engines/scumm/charset.cpp
engines/scumm/smush/smush_font.cpp
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index b89ce446c2..60d36597b4 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -313,7 +313,7 @@ int CharsetRendererCommon::getFontHeight() {
int CharsetRendererClassic::getCharWidth(uint16 chr) {
int spacing = 0;
- if (_vm->_useCJKMode && chr >= 0x80)
+ if (_vm->_useCJKMode && chr >= 0x80)
return _vm->_2byteWidth / 2;
int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
@@ -523,7 +523,7 @@ void CharsetRendererPC::enableShadow(bool enable) {
_shadowColor = 0;
_enableShadow = enable;
- if (_vm->_game.version >= 7 && _vm->_language == Common::KO_KOR)
+ if (_vm->_game.version >= 7 && _vm->_useCJKMode)
_shadowType = kHorizontalShadowType;
else
_shadowType = kNormalShadowType;
@@ -909,7 +909,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
bool CharsetRendererClassic::prepareDraw(uint16 chr) {
bool is2byte = (chr >= 256 && _vm->_useCJKMode);
if (is2byte) {
- if (_vm->_language == Common::KO_KOR)
+ if (_vm->_game.version >= 7)
enableShadow(true);
_charPtr = _vm->get2byteCharPtr(chr);
@@ -923,6 +923,8 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) {
}
return true;
+ } else {
+ enableShadow(false);
}
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
@@ -1405,7 +1407,7 @@ CharsetRendererTownsClassic::CharsetRendererTownsClassic(ScummEngine *vm) : Char
int CharsetRendererTownsClassic::getCharWidth(uint16 chr) {
int spacing = 0;
- if (_vm->_useCJKMode) {
+ if (_vm->_useCJKMode) {
if ((chr & 0xff00) == 0xfd00) {
chr &= 0xff;
} else if (chr >= 256) {
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 46a2722715..12722cfc34 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -130,27 +130,31 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
enum ShadowMode {
kNone,
kNormalShadowMode,
- kKoreanV7ShadowMode,
+ kCJKv7ShadowMode,
kKoreanV8ShadowMode
};
ShadowMode shadowMode = kNone;
- if (_vm->_language == Common::KO_KOR) {
- if (_vm->_game.version == 8)
+ if (_vm->_useCJKMode) {
+ // TODO: Check Chinese and Japanese COMI
+ // For now the kKoreanV8ShadowMode is limited to Korean, because it isn't known yet
+ // how Chinese and Japanese COMI is supposed to look like (I suspect that this gets
+ // rendered the same way, just as it is done in DIG).
+ if (_vm->_game.version == 8 && _vm->_language == Common::KO_KOR)
shadowMode = kKoreanV8ShadowMode;
- else
- shadowMode = kKoreanV7ShadowMode;
+ else if (_vm->_game.version != 8)
+ shadowMode = kCJKv7ShadowMode;
}
- int shadowOffsetXTable[4] = {-1, 0, 1, 0};
- int shadowOffsetYTable[4] = {0, 1, 0, 0};
- int shadowOffsetColorTable[4] = {0, 0, 0, color};
+ int shadowOffsetXTable[4] = { -1, 0, 1, 0 };
+ int shadowOffsetYTable[4] = { 0, 1, 0, 0 };
+ int shadowOffsetColorTable[4] = { 0, 0, 0, color };
int shadowIdx = 3;
if (shadowMode == kKoreanV8ShadowMode)
shadowIdx = 0;
- else if (shadowMode == kKoreanV7ShadowMode)
+ else if (shadowMode == kCJKv7ShadowMode)
shadowIdx = 2;
const byte *origSrc = src;
Commit: c002bfebb914c80e284757f3d542e4939fb5c8ea
https://github.com/scummvm/scummvm/commit/c002bfebb914c80e284757f3d542e4939fb5c8ea
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:11+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix 'invalid escape code' error in Chinese intro
(the '^' char could occasionally appear as the second byte in a 2byte character)
Changed paths:
engines/scumm/charset.h
engines/scumm/smush/smush_font.h
engines/scumm/smush/smush_player.cpp
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 5c4baced8b..c5cf001a28 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -41,7 +41,6 @@ static inline bool checkSJISCode(byte c) {
return false;
}
-
class CharsetRenderer {
public:
diff --git a/engines/scumm/smush/smush_font.h b/engines/scumm/smush/smush_font.h
index 9cfea5a26d..e81600ca98 100644
--- a/engines/scumm/smush/smush_font.h
+++ b/engines/scumm/smush/smush_font.h
@@ -47,6 +47,16 @@ public:
void setColor(byte c) { _color = c; }
void drawString (const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, bool center);
void drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center);
+
+ static inline bool is2ByteCharacter(Common::Language lang, byte c) {
+ if (lang == Common::JA_JPN)
+ return (c >= 0x80 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFD);
+ else if (lang == Common::KO_KOR)
+ return (c >= 0xB0 && c <= 0xD0);
+ else if (lang == Common::ZH_TWN || lang == Common::ZH_CNA)
+ return (c >= 0x80);
+ return false;
+ }
};
} // End of namespace Scumm
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index da558aad9c..5b8e01ecca 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -613,6 +613,8 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
error("invalid escape code in text string");
}
} else {
+ if (SmushFont::is2ByteCharacter(_vm->_language, *sptr))
+ *sptr2++ = *sptr++;
*sptr2++ = *sptr++;
}
}
Commit: cab2d71fff061fe73f4fa9414e0dc8610e295a07
https://github.com/scummvm/scummvm/commit/cab2d71fff061fe73f4fa9414e0dc8610e295a07
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix blast text rendering and positioning
- fix getStringWidth()
- fix string translation
- skip special newline character when drawing text
Changed paths:
engines/scumm/charset.cpp
engines/scumm/charset.h
engines/scumm/string.cpp
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 60d36597b4..96699bba45 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -331,8 +331,11 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
int code = (_vm->_game.heversion >= 80) ? 127 : 64;
while ((chr = text[pos++]) != 0) {
- if (chr == '\n' || chr == '\r' || chr == _vm->_newLineCharacter)
+ if (_vm->_game.version == 7 && chr == _vm->_newLineCharacter)
+ continue;
+ else if (chr == '\n' || chr == '\r' || chr == _vm->_newLineCharacter)
break;
+
if (_vm->_game.heversion >= 72) {
if (chr == code) {
chr = text[pos++];
@@ -488,7 +491,7 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) {
curw++;
}
- } else {
+ } else if (chr != _vm->_newLineCharacter) {
curw += getCharWidth(chr);
}
} else {
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index c5cf001a28..2c52f81924 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -41,6 +41,16 @@ static inline bool checkSJISCode(byte c) {
return false;
}
+static inline bool is2ByteCharacter(Common::Language lang, byte c) {
+ if (lang == Common::JA_JPN)
+ return (c >= 0x80 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFD);
+ else if (lang == Common::KO_KOR)
+ return (c >= 0xB0 && c <= 0xD0);
+ else if (lang == Common::ZH_TWN || lang == Common::ZH_CNA)
+ return (c >= 0x80);
+ return false;
+}
+
class CharsetRenderer {
public:
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 0735546446..c96ef3a8fc 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -180,7 +180,7 @@ void ScummEngine_v6::drawBlastTexts() {
// Some localizations may override colors
// See credits in Chinese COMI
- if (_game.id == GID_CMI && _language == Common::ZH_TWN &&
+ if (_game.id == GID_CMI && _language == Common::ZH_TWN &&
c == '^' && (buf == _blastTextQueue[i].text + 1)) {
if (*buf == 'c') {
int color = buf[3] - '0' + 10 *(buf[2] - '0');
@@ -191,7 +191,7 @@ void ScummEngine_v6::drawBlastTexts() {
}
}
- if (c != 0 && c != 0xFF && c != '\n') {
+ if (c != 0 && c != 0xFF && c != '\n' && c != _newLineCharacter) {
if (c & 0x80 && _useCJKMode) {
if (_language == Common::JA_JPN && !checkSJISCode(c)) {
c = 0x20; //not in S-JIS
@@ -1302,7 +1302,7 @@ int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize)
num += (_game.version == 8) ? 4 : 2;
}
} else {
- if ((chr != '@') || (_game.id == GID_CMI && _language == Common::ZH_TWN) ||
+ if ((chr != '@') || (_game.version >= 7 && is2ByteCharacter(_language, lastChr)) ||
(_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) ||
(_game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN && checkSJISCode(lastChr))) {
*dst++ = chr;
Commit: 43bbe659eda4479fd93df110866d2bcc35274fc3
https://github.com/scummvm/scummvm/commit/43bbe659eda4479fd93df110866d2bcc35274fc3
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix CJK Smush font drawing
- fix character spacing, vertical placement, clipping etc.
- in particular I rewrote SmushFont::drawStringWrap() and modified getStringWidth() and getStringHeight() to match COMI disasm (fully compatible with DIG, but a bit nicer)
- this actually also fixes some slightly misplaced English (or other standard font language) strings
Changed paths:
engines/scumm/nut_renderer.cpp
engines/scumm/nut_renderer.h
engines/scumm/smush/smush_font.cpp
engines/scumm/smush/smush_font.h
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index d8672c473c..3a53f2726e 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -32,6 +32,7 @@ NutRenderer::NutRenderer(ScummEngine *vm, const char *filename) :
_vm(vm),
_numChars(0),
_maxCharSize(0),
+ _fontHeight(0),
_charBuffer(0),
_decodedData(0) {
memset(_chars, 0, sizeof(_chars));
@@ -125,8 +126,8 @@ void NutRenderer::loadFont(const char *filename) {
for (l = 0; l < _numChars; l++) {
offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
int width = READ_LE_UINT16(dataSrc + offset + 14);
- int height = READ_LE_UINT16(dataSrc + offset + 16);
- int size = width * height;
+ _fontHeight = READ_LE_UINT16(dataSrc + offset + 16);
+ int size = width * _fontHeight;
decodedLength += size;
if (size > _maxCharSize)
_maxCharSize = size;
diff --git a/engines/scumm/nut_renderer.h b/engines/scumm/nut_renderer.h
index 47458b9f77..a85f99403f 100644
--- a/engines/scumm/nut_renderer.h
+++ b/engines/scumm/nut_renderer.h
@@ -41,6 +41,7 @@ protected:
ScummEngine *_vm;
int _numChars;
int _maxCharSize;
+ int _fontHeight;
byte *_charBuffer;
byte *_decodedData;
byte *_paletteMap;
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 12722cfc34..f26727cce9 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -37,30 +37,58 @@ SmushFont::SmushFont(ScummEngine *vm, const char *filename, bool use_original_co
_original(use_original_colors) {
}
-int SmushFont::getStringWidth(const char *str) {
+int SmushFont::getStringWidth(const char *str, uint numBytesMax) {
assert(str);
-
+ int maxWidth = 0;
int width = 0;
- while (*str) {
- if (*str & 0x80 && _vm->_useCJKMode) {
- width += _vm->_2byteWidth + 1;
- str += 2;
- } else
- width += getCharWidth(*str++);
+
+ if (!numBytesMax)
+ return 0;
+
+ while (*str && numBytesMax) {
+ // No treatment of the ^ commands here, since they're handled/removed in handleTextResource().
+ if (is2ByteCharacter(_vm->_language, *str)) {
+ width += _vm->_2byteWidth + (_vm->_language != Common::JA_JPN ? 1 : 0);
+ ++str;
+ --numBytesMax;
+ } else if (*str == '\n') {
+ maxWidth = MAX<int>(width, maxWidth);
+ width = 0;
+ } else if (*str != '\r' && *str != _vm->_newLineCharacter) {
+ width += getCharWidth(*str);
+ }
+ ++str;
+ --numBytesMax;
}
- return width;
+
+ return MAX<int>(width, maxWidth);
}
-int SmushFont::getStringHeight(const char *str) {
+int SmushFont::getStringHeight(const char *str, uint numBytesMax) {
assert(str);
-
- int height = 0;
- while (*str) {
- int charHeight = getCharHeight(*str++);
- if (height < charHeight)
- height = charHeight;
+ int totalHeight = 0;
+ int lineHeight = 0;
+
+ if (!numBytesMax)
+ return 0;
+
+ while (*str && numBytesMax) {
+ // No treatment of the ^ commands here, since they're handled/removed in handleTextResource().
+ if (*str == '\n') {
+ totalHeight += (lineHeight ? lineHeight : _fontHeight) + 1;
+ lineHeight = 0;
+ } else if (*str != '\r' || *str != _vm->_newLineCharacter) {
+ lineHeight = MAX<int>(lineHeight, getCharHeight(*str));
+ if (is2ByteCharacter(_vm->_language, *str)) {
+ ++str;
+ --numBytesMax;
+ }
+ }
+ ++str;
+ --numBytesMax;
}
- return height;
+
+ return totalHeight + (lineHeight ? lineHeight : _fontHeight) + 1;
}
int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
@@ -189,7 +217,7 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
return w + 1;
}
-void SmushFont::drawSubstring(const char *str, byte *buffer, int dst_width, int x, int y) {
+void SmushFont::drawSubstring(const char *str, uint numBytesMax, byte *buffer, int dst_width, int x, int y) {
// This happens in the Full Throttle intro. I don't know if our
// text-drawing functions are buggy, or if this function is supposed
// to have to check for it.
@@ -197,125 +225,164 @@ void SmushFont::drawSubstring(const char *str, byte *buffer, int dst_width, int
x = 0;
if (_vm->_language == Common::HE_ISR) {
- for (int i = strlen(str); i >= 0; i--) {
+ for (int i = strlen(str); i >= 0 && numBytesMax; i--) {
x += drawChar(buffer, dst_width, x, y, str[i]);
+ --numBytesMax;
}
} else {
- for (int i = 0; str[i] != 0; i++) {
- if ((byte)str[i] >= 0x80 && _vm->_useCJKMode) {
- x += draw2byte(buffer, dst_width, x, y, (byte)str[i] + 256 * (byte)str[i+1]);
- i++;
- } else
+ for (int i = 0; str[i] != 0 && numBytesMax; ++i) {
+ if (is2ByteCharacter(_vm->_language, str[i])) {
+ x += draw2byte(buffer, dst_width, x, y, (byte)str[i] + 256 * (byte)str[i + 1]);
+ ++i;
+ --numBytesMax;
+ } else if (str[i] != '\n' && str[i] != _vm->_newLineCharacter) {
x += drawChar(buffer, dst_width, x, y, str[i]);
+ }
+ --numBytesMax;
}
}
}
-#define MAX_WORDS 60
+#define MAX_STRINGS 80
void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, bool center) {
debugC(DEBUG_SMUSH, "SmushFont::drawString(%s, %d, %d, %d)", str, x, y, center);
- while (str) {
- char line[256];
- char separators[] = "\n ";
+ int totalLen = (int)strlen(str);
+ int lineStart = 0;
- if (_vm->_language == Common::ZH_TWN)
- separators[1] = '!';
- else
- separators[1] = '\0';
+ // This can be found i COMI. No idea whether it is actually used. We currently don't handle these flags.
+ /*if (_vm->_game.id == GID_CMI && (flags & 0x40))
+ y -= (getStringHeight(str, totalLen) / 2);*/
- const char *pos = strpbrk(str, separators);
- if (pos) {
- memcpy(line, str, pos - str - 1);
- line[pos - str - 1] = 0;
- str = pos + 1;
- } else {
- strcpy(line, str);
- str = 0;
+ for (int pos = 0; pos <= totalLen; ++pos) {
+ if (str[pos] != '\0' && str[pos] != '\n')
+ continue;
+
+ int len = pos - lineStart;
+ int height = getStringHeight(str + lineStart, len);
+ if (y < dst_height) {
+ drawSubstring(str + lineStart, len, buffer, dst_width, center ? (x - getStringWidth(str + lineStart, len) / 2) : x, y);
+ y += height;
}
- drawSubstring(line, buffer, dst_width, center ? (x - getStringWidth(line) / 2) : x, y);
- y += getStringHeight(line);
+
+ lineStart = pos + 1;
}
}
void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center) {
debugC(DEBUG_SMUSH, "SmushFont::drawStringWrap(%s, %d, %d, %d, %d, %d)", str, x, y, left, right, center);
+ // This implementation is from COMI. Things are done a bit differently than in the older implementations.
+ // In particular, the older version would insert '\0' chars into the string to cut off the sub strings
+ // before calling getStringWidth(), getStringHeight() or drawSubstring() and replace these chars with the
+ // original values afterwards. COMI allows a byte length limitation in all the functions so that the sub
+ // string length can be passed and no cut off '\0' chars are needed.
const int width = right - left;
- Common::String s(str);
- char *words[MAX_WORDS];
- int word_count = 0;
- char separators[] = " \t\r\n ";
-
- if (_vm->_language == Common::ZH_TWN)
- separators[4] = '!';
- else
- separators[4] = '\0';
-
- Common::String::iterator tmp = s.begin();
- while (tmp) {
- assert(word_count < MAX_WORDS);
- words[word_count++] = tmp;
- tmp = strpbrk(tmp, separators);
- if (tmp == 0)
- break;
- *tmp++ = 0;
- }
-
- int i = 0, max_width = 0, height = 0, line_count = 0;
+ int len = (int)strlen(str);
+ Common::String spaceSeparators(Common::String::format(" %c", (char)_vm->_newLineCharacter));
+ Common::String breakSeparators(Common::String::format(" \n%c", (char)_vm->_newLineCharacter));
+
+ int16 substrByteLength[MAX_STRINGS];
+ memset(substrByteLength, 0, sizeof(substrByteLength));
+ int16 substrWidths[MAX_STRINGS];
+ memset(substrWidths, 0, sizeof(substrWidths));
+ int16 substrStart[MAX_STRINGS];
+ memset(substrStart, 0, sizeof(substrStart));
+
+ int16 numSubstrings = 0;
+ int height = 0;
+ int lastSubstrHeight = 0;
+ int maxWidth = 0;
+ int curWidth = 0;
+ int curPos = -1;
- char *substrings[MAX_WORDS];
- int substr_widths[MAX_WORDS];
- const int space_width = getCharWidth(' ');
+ while (curPos < len) {
+ int textStart = curPos + 1;
+ while (str[textStart] && spaceSeparators.contains(str[textStart]))
+ ++textStart;
- i = 0;
- while (i < word_count) {
- char *substr = words[i++];
- int substr_width = getStringWidth(substr);
+ int separatorWidth = curPos > 0 ? getStringWidth(str + curPos, textStart - curPos) : 0;
- while (i < word_count) {
- int word_width = getStringWidth(words[i]);
- if ((substr_width + space_width + word_width) >= width)
+ int nextSeparatorPos = textStart;
+ while (!breakSeparators.contains(str[nextSeparatorPos])) {
+ if (++nextSeparatorPos == len)
break;
- substr_width += word_width + space_width;
- *(words[i]-1) = ' '; // Convert 0 byte back to space
- i++;
}
- substrings[line_count] = substr;
- substr_widths[line_count++] = substr_width;
- if (max_width < substr_width)
- max_width = substr_width;
- height += getStringHeight(substr);
+ int wordWidth = getStringWidth(str + textStart, nextSeparatorPos - textStart);
+ int newWidth = curWidth + separatorWidth + wordWidth;
+
+ if (newWidth > width) {
+ if (numSubstrings < MAX_STRINGS) {
+ substrWidths[numSubstrings] = curWidth;
+ substrByteLength[numSubstrings] = curPos - substrStart[numSubstrings];
+ numSubstrings++;
+ }
+ newWidth = wordWidth;
+ substrStart[numSubstrings] = textStart;
+ }
+ curWidth = newWidth;
+
+ curPos = nextSeparatorPos;
+ if (!spaceSeparators.contains(str[nextSeparatorPos])) {
+ // This one is only triggered by '\n' (which frequently happens in COMI/English).
+ if (numSubstrings < MAX_STRINGS) {
+ substrWidths[numSubstrings] = curWidth;
+ substrByteLength[numSubstrings] = nextSeparatorPos - substrStart[numSubstrings];
+ numSubstrings++;
+ substrStart[numSubstrings] = nextSeparatorPos + 1;
+ }
+ curWidth = 0;
+ }
+ }
+
+ if (curWidth && numSubstrings < MAX_STRINGS) {
+ substrWidths[numSubstrings] = curWidth;
+ substrByteLength[numSubstrings] = curPos - substrStart[numSubstrings];
+ numSubstrings++;
}
- if (y > dst_height - height) {
- y = dst_height - height;
+ for (int i = 0; i < numSubstrings; ++i) {
+ maxWidth = MAX<int>(maxWidth, substrWidths[i]);
+ lastSubstrHeight = substrByteLength[i] > 0 ? getStringHeight(str + substrStart[i], substrByteLength[i]) : 0;
+ height += lastSubstrHeight;
}
+ // I have verified this for DIG and COMI (English and Chinese), so I limit this fix to that. In
+ // COMI this is actually more complicated, since there seem to be more text flags which we don't
+ // support. E. g. for a flag of 0x40 we'd substract another (lastHeight / 2) from y here (without
+ // any condition). And for flag 0x100 we'd actually skip this step. No idea yet whether the flags
+ // are relevant (they can't be too relevant or someone would have implemented them, but I'll check).
+ int clipHeight = height;
+ if (_vm->_game.id == GID_DIG || (_vm->_game.id == GID_CMI))
+ clipHeight += (lastSubstrHeight / 2);
+
+ /*if (_vm->_game.id == GID_CMI && (flags & 0x40))
+ y -= (lastSubstrHeight / 2);*/
+
+ if (y > dst_height - clipHeight /*&& !(_vm->_game.id == GID_CMI && (flags & 0x100))*/)
+ y = dst_height - clipHeight;
+
if (center) {
- max_width = (max_width + 1) / 2;
+ maxWidth = (maxWidth + 1) / 2;
x = left + width / 2;
- if (x < left + max_width)
- x = left + max_width;
- if (x > right - max_width)
- x = right - max_width;
-
- for (i = 0; i < line_count; i++) {
- drawSubstring(substrings[i], buffer, dst_width, x - substr_widths[i] / 2, y);
- y += getStringHeight(substrings[i]);
- }
+ if (x < left + maxWidth)
+ x = left + maxWidth;
+ if (x > right - maxWidth)
+ x = right - maxWidth;
} else {
- if (x > dst_width - max_width)
- x = dst_width - max_width;
+ if (x > dst_width - maxWidth)
+ x = dst_width - maxWidth;
+ }
- for (i = 0; i < line_count; i++) {
- drawSubstring(substrings[i], buffer, dst_width, x, y);
- y += getStringHeight(substrings[i]);
- }
+ for (int i = 0; i < numSubstrings; i++) {
+ int xpos = center ? x - substrWidths[i] / 2 : x;
+ len = substrByteLength[i] > 0 ? substrByteLength[i] : 0;
+ drawSubstring(str + substrStart[i], len, buffer, dst_width, xpos, y);
+ y += getStringHeight(str + substrStart[i], len);
}
}
diff --git a/engines/scumm/smush/smush_font.h b/engines/scumm/smush/smush_font.h
index e81600ca98..e731fd109d 100644
--- a/engines/scumm/smush/smush_font.h
+++ b/engines/scumm/smush/smush_font.h
@@ -35,11 +35,11 @@ protected:
bool _original;
- int getStringWidth(const char *str);
- int getStringHeight(const char *str);
+ int getStringWidth(const char *str, uint numBytesMax);
+ int getStringHeight(const char *str, uint numBytesMax);
int draw2byte(byte *buffer, int dst_width, int x, int y, int idx);
int drawChar(byte *buffer, int dst_width, int x, int y, byte chr);
- void drawSubstring(const char *str, byte *buffer, int dst_width, int x, int y);
+ void drawSubstring(const char *str, uint numBytesMax, byte *buffer, int dst_width, int x, int y);
public:
SmushFont(ScummEngine *vm, const char *filename, bool use_original_colors, bool new_colors);
Commit: 8e5d73e661fb6d1313243fa97857e466215ea720
https://github.com/scummvm/scummvm/commit/8e5d73e661fb6d1313243fa97857e466215ea720
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (SMUSH) - fix text flags
- Flag 8 is just for the subtitles. This is actually handled correctly in line 538/539.
- Flag 4 is for the wrapping. Most cases I have seen set both 4 and 8, so the visible changes are subtle.
Changed paths:
engines/scumm/smush/smush_player.cpp
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 5b8e01ecca..570ff73998 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -630,18 +630,23 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
}
// flags:
- // bit 0 - center 1
- // bit 1 - not used 2
- // bit 2 - ??? 4
- // bit 3 - wrap around 8
- switch (flags & 9) {
+ // bit 0 - center 0x01
+ // bit 1 - not used (align right) 0x02
+ // bit 2 - word wrap 0x04
+ // bit 3 - switchable 0x08
+ // bit 4 - fill background 0x10
+ // bit 5 - outline/shadow 0x20 (apparently only set by the text renderer itself, not from the smush data)
+ // bit 6 - vertical fix (COMI) 0x40
+ // bit 7 - skip ^ codes (COMI) 0x80
+ // bit 8 - no vertical fix (COMI) 0x100
+ switch (flags & 5) {
case 0:
sf->drawString(str, _dst, _width, _height, pos_x, pos_y, false);
break;
case 1:
sf->drawString(str, _dst, _width, _height, pos_x, MAX(pos_y, top), true);
break;
- case 8:
+ case 4:
// FIXME: Is 'right' the maximum line width here, just
// as it is in the next case? It's used several times
// in The Dig's intro, where 'left' and 'right' are
@@ -649,7 +654,7 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
// handle that correctly.
sf->drawStringWrap(str, _dst, _width, _height, pos_x, MAX(pos_y, top), left, right, false);
break;
- case 9:
+ case 5:
// In this case, the 'right' parameter is actually the
// maximum line width. This explains why it's sometimes
// smaller than 'left'.
Commit: 57c4f2373ae132a5c92148bdd9b7848b851d6f98
https://github.com/scummvm/scummvm/commit/57c4f2373ae132a5c92148bdd9b7848b851d6f98
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix regression in text positioning
CJK text in DIG was 2 pixels off vertically due to 4b13c33b.
COMI actually has a y-offset of 2 (not 7) for CJK fonts, but it is applied at a different location.
Changed paths:
engines/scumm/smush/smush_font.cpp
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index f26727cce9..5c94f708f2 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -193,8 +193,7 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
byte drawColor = shadowOffsetColorTable[shadowIdx];
src = origSrc;
-
- byte *dst = buffer + dst_width * (offY + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + offX;
+ byte *dst = buffer + dst_width * offY + offX;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
@@ -252,9 +251,14 @@ void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst
int totalLen = (int)strlen(str);
int lineStart = 0;
- // This can be found i COMI. No idea whether it is actually used. We currently don't handle these flags.
- /*if (_vm->_game.id == GID_CMI && (flags & 0x40))
- y -= (getStringHeight(str, totalLen) / 2);*/
+ // COMI always does this for CJK strings (before any other possible yPos fixes).
+ if (_vm->_game.id == GID_CMI) {
+ if (_vm->_useCJKMode)
+ y += 2;
+ // No idea whether it is actually used. We currently don't handle this flag.
+ /*if (flags & 0x40)
+ y -= (getStringHeight(str, totalLen) / 2);*/
+ }
for (int pos = 0; pos <= totalLen; ++pos) {
if (str[pos] != '\0' && str[pos] != '\n')
@@ -298,6 +302,10 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int
int curWidth = 0;
int curPos = -1;
+ // COMI does this for CJK strings (before any other possible yPos fixes, see lines 348 - 356).
+ if (_vm->_game.id == GID_CMI && _vm->_useCJKMode)
+ y += 2;
+
while (curPos < len) {
int textStart = curPos + 1;
while (str[textStart] && spaceSeparators.contains(str[textStart]))
Commit: d4b6473a7daf9b8d81f389660b81d596f9b2eb73
https://github.com/scummvm/scummvm/commit/d4b6473a7daf9b8d81f389660b81d596f9b2eb73
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (DIG/CJK) - add specific text positioning fix from disasm
This is basically a hack, but the original does it just like that. It ensures that certain CJK message strings at the bottom of the screen won't get cut off.
Changed paths:
engines/scumm/string.cpp
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index c96ef3a8fc..a9b377831f 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -129,6 +129,14 @@ void ScummEngine_v6::enqueueText(const byte *text, int x, int y, byte color, byt
BlastText &bt = _blastTextQueue[_blastTextQueuePos++];
assert(_blastTextQueuePos <= ARRAYSIZE(_blastTextQueue));
+ if (_useCJKMode) {
+ // The Dig expressly checks for x == 160 && y == 189 && charset == 3. Usually, if the game wants to print CJK text at the bottom
+ // of the screen it will use y = 183. So maybe this is a hack to fix some script texts that weren forgotten in the CJK converting
+ // process. COMI doesn't have anything like that.
+ if (_game.id == GID_DIG && x == 160 && y == 189 && charset == 3)
+ y -= 6;
+ }
+
convertMessageToString(text, bt.text, sizeof(bt.text));
bt.xpos = x;
bt.ypos = y;
Commit: e3bd302b5b2d4fa64fd6c042d7afa54a9143a1e8
https://github.com/scummvm/scummvm/commit/e3bd302b5b2d4fa64fd6c042d7afa54a9143a1e8
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (DIG/CJK) - fix bug in charset rendering
This fixes the bug shown in the fourth row of screenshots in ticket no. 11656 (DIG Asteroid scene). That bug could basically appear in any other scene which uses the xstart offset.
Changed paths:
engines/scumm/charset.cpp
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 96699bba45..9a3d21bc93 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -868,7 +868,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
}
if (is2byte && _vm->_game.platform != Common::kPlatformFMTowns)
- drawBits1(dstSurface, _left, drawTop, charPtr, drawTop, origWidth, origHeight);
+ drawBits1(dstSurface, _left + vs->xstart, drawTop, charPtr, drawTop, origWidth, origHeight);
else
drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
Commit: 06cb2345aab1be01bd3a609ebfdf0d14c50c7533
https://github.com/scummvm/scummvm/commit/06cb2345aab1be01bd3a609ebfdf0d14c50c7533
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:12+01:00
Commit Message:
SCUMM: (COMI/CJK) - fix smush font glyph shadows
I have confirmed that this type of shadow (one shadow pixel to the left, one to the right and one to the bottom) is drawn for all CJK characters in COMI.
Changed paths:
engines/scumm/smush/smush_font.cpp
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 5c94f708f2..5e46699c51 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -159,35 +159,17 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
kNone,
kNormalShadowMode,
kCJKv7ShadowMode,
- kKoreanV8ShadowMode
+ kCJKv8ShadowMode
};
- ShadowMode shadowMode = kNone;
-
- if (_vm->_useCJKMode) {
- // TODO: Check Chinese and Japanese COMI
- // For now the kKoreanV8ShadowMode is limited to Korean, because it isn't known yet
- // how Chinese and Japanese COMI is supposed to look like (I suspect that this gets
- // rendered the same way, just as it is done in DIG).
- if (_vm->_game.version == 8 && _vm->_language == Common::KO_KOR)
- shadowMode = kKoreanV8ShadowMode;
- else if (_vm->_game.version != 8)
- shadowMode = kCJKv7ShadowMode;
- }
+ ShadowMode shadowMode = _vm->_useCJKMode ? (_vm->_game.version == 8 ? kCJKv8ShadowMode : kCJKv7ShadowMode) : kNone;
int shadowOffsetXTable[4] = { -1, 0, 1, 0 };
int shadowOffsetYTable[4] = { 0, 1, 0, 0 };
int shadowOffsetColorTable[4] = { 0, 0, 0, color };
- int shadowIdx = 3;
- if (shadowMode == kKoreanV8ShadowMode)
- shadowIdx = 0;
- else if (shadowMode == kCJKv7ShadowMode)
- shadowIdx = 2;
-
const byte *origSrc = src;
-
- for (; shadowIdx < 4; shadowIdx++) {
+ for (int shadowIdx = (shadowMode == kCJKv8ShadowMode) ? 0 : (shadowMode == kCJKv7ShadowMode ? 2 : 3); shadowIdx < 4; shadowIdx++) {
int offX = x + shadowOffsetXTable[shadowIdx];
int offY = y + shadowOffsetYTable[shadowIdx];
byte drawColor = shadowOffsetColorTable[shadowIdx];
Commit: d3b63bc735544ab40447e85be7c548bb0776f12b
https://github.com/scummvm/scummvm/commit/d3b63bc735544ab40447e85be7c548bb0776f12b
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:13+01:00
Commit Message:
SCUMM: whitespace
Changed paths:
engines/scumm/actor.cpp
engines/scumm/charset.cpp
engines/scumm/gfx.cpp
engines/scumm/imuse/drivers/amiga.cpp
engines/scumm/imuse/drivers/amiga.h
engines/scumm/imuse/imuse.cpp
engines/scumm/imuse/imuse_part.cpp
engines/scumm/object.cpp
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 18b3251fbb..cb951d5071 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -755,9 +755,9 @@ void Actor::startWalkActor(int destX, int destY, int dir) {
} else if (_vm->_game.version <= 2) {
_moving = (_moving & ~(MF_LAST_LEG | MF_IN_LEG)) | MF_NEW_LEG;
- } else {
- _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
- }
+ } else {
+ _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
+ }
}
@@ -1071,8 +1071,8 @@ UpdateActorDirection:;
directionUpdate();
animateActor(newDirToOldDir(_facing));
- // FIXME: During the hands-free-demo in the library (room 5), Purple Tentacle gets stuck following Sandy due to the corner of the stairs,
- // This is due to distance, and walkbox gap/layout. This works fine with the original engine, because it 'brute forces'
+ // FIXME: During the hands-free-demo in the library (room 5), Purple Tentacle gets stuck following Sandy due to the corner of the stairs,
+ // This is due to distance, and walkbox gap/layout. This works fine with the original engine, because it 'brute forces'
// another pixel move in the walk direction before giving up, allowing us to move enough pixels to hit the next walkbox.
// Why this fails with the return is because script-10 is executing a 'walkActorToActor' every cycle, which restarts the movement process
// As a work around, we implement the original engine behaviour only for Purple Tentacle in the Demo. Doing this for other actors
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 9a3d21bc93..5869cff2e2 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -335,7 +335,7 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
continue;
else if (chr == '\n' || chr == '\r' || chr == _vm->_newLineCharacter)
break;
-
+
if (_vm->_game.heversion >= 72) {
if (chr == code) {
chr = text[pos++];
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 35d6a1e276..a8478aacce 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1023,7 +1023,7 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
VirtScreen *vs;
byte *screenBuf;
- if (rect.top < 0)
+ if (rect.top < 0)
rect.top = 0;
if (rect.left >= rect.right || rect.top >= rect.bottom)
return;
diff --git a/engines/scumm/imuse/drivers/amiga.cpp b/engines/scumm/imuse/drivers/amiga.cpp
index 9407f78a92..d4b8bc547f 100644
--- a/engines/scumm/imuse/drivers/amiga.cpp
+++ b/engines/scumm/imuse/drivers/amiga.cpp
@@ -175,7 +175,7 @@ private:
IMuseDriver_Amiga *_driver;
};
-SoundChannel_Amiga::SoundChannel_Amiga(IMuseDriver_Amiga *driver, int id, Instrument_Amiga *instruments) : _driver(driver), _id(id), _instruments(instruments),
+SoundChannel_Amiga::SoundChannel_Amiga(IMuseDriver_Amiga *driver, int id, Instrument_Amiga *instruments) : _driver(driver), _id(id), _instruments(instruments),
_assign(0), _next(0), _prev(0), _sustain(false), _note(0) {
assert(id > -1 && id < 4);
_channels[id] = this;
@@ -194,7 +194,7 @@ SoundChannel_Amiga::~SoundChannel_Amiga() {
delete[] _volTable;
_volTable = 0;
}
-
+
SoundChannel_Amiga *SoundChannel_Amiga::allocate(int prio) {
SoundChannel_Amiga *res = 0;
@@ -276,10 +276,10 @@ void SoundChannel_Amiga::noteOn(byte note, byte volume, byte program, int8 trans
_driver->disableChannel(_id);
setVelocity(0, 0);
setVolume(volume);
-
+
if (s->type > 1)
return;
-
+
uint16 period = calculatePeriod(pitchBend + ((_note + transpose) << 7), s->baseNote, s->rate);
if (s->type == 1) {
@@ -412,7 +412,7 @@ void SoundChannel_Amiga::setVelocity(uint8 velo, int delay) {
} else {
_driver->setChannelVolume(_id, _volTable[(_ioUnit.volume << 5) + velo]);
_ioUnit.currentLevel = _ioUnit.fadeTargetLevel = velo;
- _ioUnit.fadeLevelMod = 0;
+ _ioUnit.fadeLevelMod = 0;
}
}
@@ -751,7 +751,7 @@ void IMuseDriver_Amiga::interrupt() {
if (!_isOpen)
return;
- for (_ticker += _internalTempo; _ticker >= _baseTempo; _ticker -= _baseTempo) {
+ for (_ticker += _internalTempo; _ticker >= _baseTempo; _ticker -= _baseTempo) {
updateParser();
updateSounds();
}
@@ -831,12 +831,12 @@ void IMuseDriver_Amiga::loadInstrument(int program) {
if (size <= 0)
break;
-
+
size -= 38;
Instrument_Amiga::Samples *s = &_instruments[program].samples[block];
ims.seek(594 + offset + header[block], SEEK_SET);
int8 *buf = new int8[size];
-
+
s->rate = ims.readUint16BE();
s->baseNote = ims.readUint16BE();
s->noteRangeMin = ims.readSint16BE();
diff --git a/engines/scumm/imuse/drivers/amiga.h b/engines/scumm/imuse/drivers/amiga.h
index 29dc5d4e07..f76a27178d 100644
--- a/engines/scumm/imuse/drivers/amiga.h
+++ b/engines/scumm/imuse/drivers/amiga.h
@@ -68,7 +68,7 @@ private:
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
-
+
int32 _ticker;
bool _isOpen;
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index af91a77c23..61d24b67f7 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -697,7 +697,7 @@ bool IMuseInternal::startSound_internal(int sound, int offset) {
//
// Tunes involved
// 100 - Captain Dread's map
- // 113 - Guard Kiosk / Mardi Grass
+ // 113 - Guard Kiosk / Mardi Grass
// 115 - Map of Booty Island / Ville de la Booty
// 118 - Ville de la Booty
//
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 1614076ee0..1495e869a7 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -145,7 +145,7 @@ void Part::set_pan(int8 pan) {
void Part::set_transpose(int8 transpose) {
_transpose = transpose;
-
+
if (_se->_isAmiga) {
// The Amiga version does a check like this. While this is probably a bug (a signed int8 can never be 128),
// the playback depends on this being implemented exactly like in the original driver. I found this bug with
@@ -155,7 +155,7 @@ void Part::set_transpose(int8 transpose) {
} else {
_transpose_eff = (_transpose == -128) ? 0 : transpose_clamp(_transpose + _player->getTranspose(), -24, 24);
sendPitchBend();
- }
+ }
}
void Part::sustain(bool value) {
@@ -368,9 +368,9 @@ void Part::sendPitchBend() {
// so we'll do the scaling ourselves.
if (_player->_se->isNativeMT32())
bend = bend * _pitchbend_factor / 12;
-
+
// We send the transpose value separately for Amiga (which is more like the original handles this).
- // Some rhythm instruments depend on this.
+ // Some rhythm instruments depend on this.
int8 transpose = _se->_isAmiga ? 0 : _transpose_eff;
_mc->pitchBend(clamp(bend + (_detune_eff * 64 / 12) + (transpose * 8192 / 12), -8192, 8191));
}
@@ -384,7 +384,7 @@ void Part::sendTranspose() {
// such functions.
if (!_se->_isAmiga)
return;
-
+
_mc->transpose(_transpose_eff);
}
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index 1581eb32a9..b373a0a9f4 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -113,7 +113,7 @@ void ScummEngine::setOwnerOf(int obj, int owner) {
return;
// WORKAROUND for bug #6802: assert() was triggered in freddi2.
- // Bug is in room 39. Problem is script 10, in the localvar2==78 case;
+ // Bug is in room 39. Problem is script 10, in the localvar2==78 case;
// this only sets the obj id if var198 is non-zero, but in the asserting
// case, it is obj 0. That means two setOwnerOf calls are made with obj 0.
// The correct setOwnerOf calls are made afterwards, so just ignoring this
Commit: 60e507b7da95700daeac11d953e19046f78a703e
https://github.com/scummvm/scummvm/commit/60e507b7da95700daeac11d953e19046f78a703e
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:13+01:00
Commit Message:
SCUMM: (COMI/CJK) - fix blast text shading and positioning
- COMI adds a y-Offset of 2 in CJK mode.
- The shadowed glyphs are used for all CJK font drawing, not only Korean. Also, the char height has to be adjusted by one pixel for the shadow.
Changed paths:
engines/scumm/charset.cpp
engines/scumm/nut_renderer.cpp
engines/scumm/string.cpp
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 5869cff2e2..d914d7dedb 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -1280,8 +1280,11 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
int height = _current->getCharHeight(chr);
bool is2byte = chr >= 256 && _vm->_useCJKMode;
- if (is2byte)
+ if (is2byte) {
width = _vm->_2byteWidth;
+ if (_vm->_game.id == GID_CMI)
+ height++; // One extra pixel for the shadow
+ }
shadow.right = _left + width;
shadow.bottom = _top + height;
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index 3a53f2726e..9f6954ab84 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -405,24 +405,10 @@ void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byt
return;
}
- enum ShadowMode {
- kNone,
- kKoreanV8ShadowMode
- };
-
- ShadowMode shadowMode = kNone;
-
- if (_vm->_language == Common::KO_KOR && _vm->_game.version == 8) {
- shadowMode = kKoreanV8ShadowMode;
- }
-
int shadowOffsetXTable[4] = {-1, 0, 1, 0};
int shadowOffsetYTable[4] = {0, 1, 0, 0};
int shadowOffsetColorTable[4] = {0, 0, 0, color};
-
- int shadowIdx = 3;
- if (shadowMode == kKoreanV8ShadowMode)
- shadowIdx = 0;
+ int shadowIdx = (_vm->_useCJKMode && _vm->_game.id == GID_CMI) ? 0 : 3;
const byte *origSrc = src;
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index a9b377831f..d63a83915c 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -132,9 +132,12 @@ void ScummEngine_v6::enqueueText(const byte *text, int x, int y, byte color, byt
if (_useCJKMode) {
// The Dig expressly checks for x == 160 && y == 189 && charset == 3. Usually, if the game wants to print CJK text at the bottom
// of the screen it will use y = 183. So maybe this is a hack to fix some script texts that weren forgotten in the CJK converting
- // process. COMI doesn't have anything like that.
+ // process.
if (_game.id == GID_DIG && x == 160 && y == 189 && charset == 3)
y -= 6;
+ // COMI always adds a y-offset of 2 in CJK mode.
+ if (_game.id == GID_CMI)
+ y += 2;
}
convertMessageToString(text, bt.text, sizeof(bt.text));
Commit: a890b9e35106422f39f257a626912b463a87d9a4
https://github.com/scummvm/scummvm/commit/a890b9e35106422f39f257a626912b463a87d9a4
Author: athrxx (athrxx at scummvm.org)
Date: 2020-10-30T22:31:13+01:00
Commit Message:
SCUMM: (SMUSH) - fix text coordinates and wrapping
Some fixes from disasm to have the text look pixel-exact like the original.
Some lines in COMI are still off a bit by 2 pixels to the left or to the right. Whilst I doubt that anyone would notice it I'll try to fix that, too.
Changed paths:
engines/scumm/insane/insane.cpp
engines/scumm/smush/smush_font.cpp
engines/scumm/smush/smush_font.h
engines/scumm/smush/smush_player.cpp
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index c0ba9ea6c8..bcbf1331da 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -1262,10 +1262,8 @@ void Insane::smlayer_showStatusMsg(int32 arg_0, byte *renderBitmap, int32 codecp
int32 flags, const char *formatString, const char *strng) {
SmushFont *sf = _player->getFont(0);
int color = 1;
- int32 top = 0;
char *str = NULL, *string;
int len = strlen(formatString) + strlen(strng) + 16;
-
string = (char *)malloc(len);
str = string;
@@ -1299,23 +1297,20 @@ void Insane::smlayer_showStatusMsg(int32 arg_0, byte *renderBitmap, int32 codecp
sf->setColor(color);
// flags:
- // bit 0 - center 1
- // bit 1 - not used 2
- // bit 2 - ??? 4
- // bit 3 - wrap around 8
- switch (flags) {
- case 0:
- sf->drawString(str, renderBitmap, _player->_width, _player->_height, pos_x, pos_y, false);
- break;
- case 1:
- sf->drawString(str, renderBitmap, _player->_width, _player->_height, pos_x, MAX(pos_y, top), true);
- break;
- case 5:
- sf->drawStringWrap(str, renderBitmap, _player->_width, _player->_height, pos_x, pos_y, 10, 300, true);
- break;
- default:
- error("Insane::smlayer_showStatusMsg. Not handled flags: %d", flags);
+ // bit 0 - center 0x01
+ // bit 1 - not used (align right) 0x02
+ // bit 2 - word wrap 0x04
+ // bit 3 - switchable 0x08
+ // bit 4 - fill background 0x10
+ if (flags & 4) {
+ Common::Rect clipRect(0, 0, _player->_width, _player->_height);
+ sf->drawStringWrap(str, renderBitmap, clipRect, pos_x, pos_y, flags & 1);
+ } else {
+ Common::Rect clipRect(10, 0, 310, _player->_height);
+ sf->drawString(str, renderBitmap, clipRect, pos_x, pos_y, flags & 1);
}
+
+
free (string);
}
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 5e46699c51..f63e8b66ae 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -77,7 +77,7 @@ int SmushFont::getStringHeight(const char *str, uint numBytesMax) {
if (*str == '\n') {
totalHeight += (lineHeight ? lineHeight : _fontHeight) + 1;
lineHeight = 0;
- } else if (*str != '\r' || *str != _vm->_newLineCharacter) {
+ } else if (*str != '\r' && *str != _vm->_newLineCharacter) {
lineHeight = MAX<int>(lineHeight, getCharHeight(*str));
if (is2ByteCharacter(_vm->_language, *str)) {
++str;
@@ -227,8 +227,8 @@ void SmushFont::drawSubstring(const char *str, uint numBytesMax, byte *buffer, i
#define MAX_STRINGS 80
-void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, bool center) {
- debugC(DEBUG_SMUSH, "SmushFont::drawString(%s, %d, %d, %d)", str, x, y, center);
+void SmushFont::drawString(const char *str, byte *buffer, Common::Rect &clipRect, int x, int y, bool center) {
+ debugC(DEBUG_SMUSH, "SmushFont::drawString(str: '%s', x: %d, y: %d, clipRect: (%d, %d, %d, %d), center: %d)", str, x, y, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, center);
int totalLen = (int)strlen(str);
int lineStart = 0;
@@ -248,8 +248,8 @@ void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst
int len = pos - lineStart;
int height = getStringHeight(str + lineStart, len);
- if (y < dst_height) {
- drawSubstring(str + lineStart, len, buffer, dst_width, center ? (x - getStringWidth(str + lineStart, len) / 2) : x, y);
+ if (y < clipRect.bottom) {
+ drawSubstring(str + lineStart, len, buffer, _vm->_screenWidth, center ? (x - getStringWidth(str + lineStart, len) / 2) : x, y);
y += height;
}
@@ -257,15 +257,14 @@ void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst
}
}
-void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center) {
- debugC(DEBUG_SMUSH, "SmushFont::drawStringWrap(%s, %d, %d, %d, %d, %d)", str, x, y, left, right, center);
-
+void SmushFont::drawStringWrap(const char *str, byte *buffer, Common::Rect &clipRect, int x, int y, bool center) {
+ debugC(DEBUG_SMUSH, "SmushFont::drawStringWrap(str: '%s', x: %d, y: %d, clipRect: (%d, %d, %d, %d), center: %d)", str, x, y, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, center);
// This implementation is from COMI. Things are done a bit differently than in the older implementations.
// In particular, the older version would insert '\0' chars into the string to cut off the sub strings
// before calling getStringWidth(), getStringHeight() or drawSubstring() and replace these chars with the
// original values afterwards. COMI allows a byte length limitation in all the functions so that the sub
// string length can be passed and no cut off '\0' chars are needed.
- const int width = right - left;
+
int len = (int)strlen(str);
Common::String spaceSeparators(Common::String::format(" %c", (char)_vm->_newLineCharacter));
Common::String breakSeparators(Common::String::format(" \n%c", (char)_vm->_newLineCharacter));
@@ -284,7 +283,7 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int
int curWidth = 0;
int curPos = -1;
- // COMI does this for CJK strings (before any other possible yPos fixes, see lines 348 - 356).
+ // COMI does this for CJK strings (before any other possible yPos fixes, see lines 343 - 355).
if (_vm->_game.id == GID_CMI && _vm->_useCJKMode)
y += 2;
@@ -304,7 +303,7 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int
int wordWidth = getStringWidth(str + textStart, nextSeparatorPos - textStart);
int newWidth = curWidth + separatorWidth + wordWidth;
- if (newWidth > width) {
+ if (curWidth && newWidth > clipRect.width()) {
if (numSubstrings < MAX_STRINGS) {
substrWidths[numSubstrings] = curWidth;
substrByteLength[numSubstrings] = curPos - substrStart[numSubstrings];
@@ -316,13 +315,13 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int
curWidth = newWidth;
curPos = nextSeparatorPos;
- if (!spaceSeparators.contains(str[nextSeparatorPos])) {
+ if (!spaceSeparators.contains(str[curPos])) {
// This one is only triggered by '\n' (which frequently happens in COMI/English).
if (numSubstrings < MAX_STRINGS) {
substrWidths[numSubstrings] = curWidth;
- substrByteLength[numSubstrings] = nextSeparatorPos - substrStart[numSubstrings];
+ substrByteLength[numSubstrings] = curPos - substrStart[numSubstrings];
numSubstrings++;
- substrStart[numSubstrings] = nextSeparatorPos + 1;
+ substrStart[numSubstrings] = curPos + 1;
}
curWidth = 0;
}
@@ -340,38 +339,34 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int
height += lastSubstrHeight;
}
- // I have verified this for DIG and COMI (English and Chinese), so I limit this fix to that. In
- // COMI this is actually more complicated, since there seem to be more text flags which we don't
- // support. E. g. for a flag of 0x40 we'd substract another (lastHeight / 2) from y here (without
- // any condition). And for flag 0x100 we'd actually skip this step. No idea yet whether the flags
- // are relevant (they can't be too relevant or someone would have implemented them, but I'll check).
- int clipHeight = height;
- if (_vm->_game.id == GID_DIG || (_vm->_game.id == GID_CMI))
- clipHeight += (lastSubstrHeight / 2);
+ // I have verified these y-corrections for DIG (English and Chinese), COMI (English and Chinese) and FT (English).
+ // In COMI there seem to be more text flags which we don't support and for which I haven't seen use cases yet. I
+ // put some commented-out code in here as a reminder...
+ int clipHeight = height + lastSubstrHeight / 2;
/*if (_vm->_game.id == GID_CMI && (flags & 0x40))
y -= (lastSubstrHeight / 2);*/
- if (y > dst_height - clipHeight /*&& !(_vm->_game.id == GID_CMI && (flags & 0x100))*/)
- y = dst_height - clipHeight;
+ if (y > clipRect.bottom - clipHeight /*&& !(_vm->_game.id == GID_CMI && (flags & 0x100))*/)
+ y = clipRect.bottom - clipHeight;
- if (center) {
- maxWidth = (maxWidth + 1) / 2;
- x = left + width / 2;
+ if (y < clipRect.top)
+ y = clipRect.top;
- if (x < left + maxWidth)
- x = left + maxWidth;
- if (x > right - maxWidth)
- x = right - maxWidth;
+ if (center) {
+ if (x + (maxWidth >> 1) > clipRect.right)
+ x = clipRect.right - (maxWidth >> 1);
+ if (x - (maxWidth >> 1) < clipRect.left)
+ x = clipRect.left + (maxWidth >> 1);
} else {
- if (x > dst_width - maxWidth)
- x = dst_width - maxWidth;
+ if (x > clipRect.right - maxWidth)
+ x = clipRect.right - maxWidth;
}
for (int i = 0; i < numSubstrings; i++) {
int xpos = center ? x - substrWidths[i] / 2 : x;
len = substrByteLength[i] > 0 ? substrByteLength[i] : 0;
- drawSubstring(str + substrStart[i], len, buffer, dst_width, xpos, y);
+ drawSubstring(str + substrStart[i], len, buffer, _vm->_screenWidth, xpos, y);
y += getStringHeight(str + substrStart[i], len);
}
}
diff --git a/engines/scumm/smush/smush_font.h b/engines/scumm/smush/smush_font.h
index e731fd109d..c870424ec2 100644
--- a/engines/scumm/smush/smush_font.h
+++ b/engines/scumm/smush/smush_font.h
@@ -45,8 +45,8 @@ public:
SmushFont(ScummEngine *vm, const char *filename, bool use_original_colors, bool new_colors);
void setColor(byte c) { _color = c; }
- void drawString (const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, bool center);
- void drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center);
+ void drawString (const char *str, byte *buffer, Common::Rect &clipRect, int x, int y, bool center);
+ void drawStringWrap(const char *str, byte *buffer, Common::Rect &clipRect, int x, int y, bool center);
static inline bool is2ByteCharacter(Common::Language lang, byte c) {
if (lang == Common::JA_JPN)
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 570ff73998..2858066687 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -24,6 +24,7 @@
#include "common/file.h"
#include "common/system.h"
#include "common/util.h"
+#include "common/rect.h"
#include "audio/mixer.h"
@@ -513,8 +514,8 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
int flags = b.readSint16LE();
int left = b.readSint16LE();
int top = b.readSint16LE();
- int right = b.readSint16LE();
- /*int32 height =*/ b.readSint16LE();
+ int width = b.readSint16LE();
+ int height = b.readSint16LE();
/*int32 unk2 =*/ b.readUint16LE();
const char *str;
@@ -561,18 +562,18 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
while (str[0] == '^') {
switch (str[1]) {
case 'f':
- {
- int id = str[3] - '0';
- str += 4;
- sf = getFont(id);
- }
- break;
+ {
+ int id = str[3] - '0';
+ str += 4;
+ sf = getFont(id);
+ }
+ break;
case 'c':
- {
- color = str[4] - '0' + 10 *(str[3] - '0');
- str += 5;
- }
- break;
+ {
+ color = str[4] - '0' + 10 *(str[3] - '0');
+ str += 5;
+ }
+ break;
default:
error("invalid escape code in text string");
}
@@ -636,35 +637,27 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
// bit 3 - switchable 0x08
// bit 4 - fill background 0x10
// bit 5 - outline/shadow 0x20 (apparently only set by the text renderer itself, not from the smush data)
- // bit 6 - vertical fix (COMI) 0x40
- // bit 7 - skip ^ codes (COMI) 0x80
- // bit 8 - no vertical fix (COMI) 0x100
- switch (flags & 5) {
- case 0:
- sf->drawString(str, _dst, _width, _height, pos_x, pos_y, false);
- break;
- case 1:
- sf->drawString(str, _dst, _width, _height, pos_x, MAX(pos_y, top), true);
- break;
- case 4:
- // FIXME: Is 'right' the maximum line width here, just
- // as it is in the next case? It's used several times
- // in The Dig's intro, where 'left' and 'right' are
- // always 0 and 321 respectively, and apparently we
- // handle that correctly.
- sf->drawStringWrap(str, _dst, _width, _height, pos_x, MAX(pos_y, top), left, right, false);
- break;
- case 5:
- // In this case, the 'right' parameter is actually the
- // maximum line width. This explains why it's sometimes
- // smaller than 'left'.
- //
- // Note that in The Dig's "Spacetime Six" movie it's
- // 621. I have no idea what that means.
- sf->drawStringWrap(str, _dst, _width, _height, pos_x, MAX(pos_y, top), left, MIN(left + right, _width), true);
- break;
- default:
- error("SmushPlayer::handleTextResource. Not handled flags: %d", flags);
+ // bit 6 - vertical fix (COMI) 0x40 (COMI handles this in the printing method, but I haven't seen a case where it is used)
+ // bit 7 - skip ^ codes (COMI) 0x80 (should be irrelevant for Smush, we strip these commands anyway)
+ // bit 8 - no vertical fix (COMI) 0x100 (COMI handles this in the printing method, but I haven't seen a case where it is used)
+
+ if (flags & 4) {
+ // COMI has to do it all a bit different, of course. SCUMM7 games immediately render the text from here and actually use the clipping data
+ // provided by the text resource. COMI does not render directly, but enqueues a blast string (which is then drawn through the usual main
+ // loop routines). During that process the rect data will get dumped and replaced with the following default values. It's hard to tell
+ // whether this is on purpose or not (the text looks not necessarily better or worse, just different), so we follow the original...
+ if (_vm->_game.id == GID_CMI) {
+ left = top = 10;
+ width = _width - 20;
+ height = _height - 20;
+ }
+ Common::Rect clipRect(MAX<int>(0, left), MAX<int>(0, top), MIN<int>(left + width, _width), MIN<int>(top + height, _height));
+ sf->drawStringWrap(str, _dst, clipRect, pos_x, pos_y, flags & 1);
+ } else {
+ // Similiar to the wrapped text, COMI will pass on rect coords here, which will later be lost. Unlike with the wrapped text, it will
+ // finally use the full screen dimenstions. SCUMM7 renders directly from here (see comment above), but also with the full screen.
+ Common::Rect clipRect(0, 0, _width, _height);
+ sf->drawString(str, _dst, clipRect, pos_x, pos_y, flags & 1);
}
free(string);
More information about the Scummvm-git-logs
mailing list