aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/charset.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/charset.cpp')
-rw-r--r--engines/scumm/charset.cpp537
1 files changed, 364 insertions, 173 deletions
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index fa4804ce7d..e75a45212e 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -52,20 +52,15 @@ void ScummEngine::loadCJKFont() {
_newLineCharacter = 0;
if (_game.version <= 5 && _game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN) { // FM-TOWNS v3 / v5 Kanji
- int numChar = 256 * 32;
- _2byteWidth = 16;
- _2byteHeight = 16;
- // use FM-TOWNS font rom, since game files don't have kanji font resources
- if (!fp.open("fmt_fnt.rom")) {
- error("SCUMM::Font: Couldn't open fmt_fnt.rom");
- } else {
- _useCJKMode = true;
- debug(2, "Loading FM-TOWNS Kanji rom");
- _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar];
- fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar);
- fp.close();
- }
+#ifdef DISABLE_TOWNS_DUAL_LAYER_MODE
+ error("FM-Towns Kanji font drawing requires dual graphics layer support which is disabled in this build");
+#endif
+ // use FM-TOWNS font rom, since game files don't have kanji font resources
+ _cjkFont = Graphics::FontSJIS::createFont(Common::kPlatformFMTowns);
+ if (!_cjkFont)
+ error("SCUMM::Font: Couldn't open file 'FMT_FNT.ROM'");
_textSurfaceMultiplier = 2;
+ _useCJKMode = true;
} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) {
int numChar = 3418;
_2byteWidth = 12;
@@ -167,90 +162,6 @@ void ScummEngine::loadCJKFont() {
}
}
-static int SJIStoFMTChunk(int f, int s) { //converts sjis code to fmt font offset
- enum {
- KANA = 0,
- KANJI = 1,
- EKANJI = 2
- };
- int base = s - ((s + 1) % 32);
- int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;
-
- if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
- if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
- if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;
-
- if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
- c = 48; //correction
- p = -8; //correction
- }
-
- if (kanjiType == KANA) {//Kana
- chunk_f = (f - 0x81) * 2;
- } else if (kanjiType == KANJI) {//Standard Kanji
- p += f - 0x88;
- chunk_f = c + 2 * p;
- } else if (kanjiType == EKANJI) {//Enhanced Kanji
- p += f - 0xe0;
- chunk_f = c + 2 * p;
- }
-
- // Base corrections
- if (base == 0x7f && s == 0x7f)
- base -= 0x20;
- if (base == 0x9f && s == 0xbe)
- base += 0x20;
- if (base == 0xbf && s == 0xde)
- base += 0x20;
- //if (base == 0x7f && s == 0x9e)
- // base += 0x20;
-
- switch (base) {
- case 0x3f:
- cr = 0; //3f
- if (kanjiType == KANA) chunk = 1;
- else if (kanjiType == KANJI) chunk = 31;
- else if (kanjiType == EKANJI) chunk = 111;
- break;
- case 0x5f:
- cr = 0; //5f
- if (kanjiType == KANA) chunk = 17;
- else if (kanjiType == KANJI) chunk = 47;
- else if (kanjiType == EKANJI) chunk = 127;
- break;
- case 0x7f:
- cr = -1; //80
- if (kanjiType == KANA) chunk = 9;
- else if (kanjiType == KANJI) chunk = 63;
- else if (kanjiType == EKANJI) chunk = 143;
- break;
- case 0x9f:
- cr = 1; //9e
- if (kanjiType == KANA) chunk = 2;
- else if (kanjiType == KANJI) chunk = 32;
- else if (kanjiType == EKANJI) chunk = 112;
- break;
- case 0xbf:
- cr = 1; //be
- if (kanjiType == KANA) chunk = 18;
- else if (kanjiType == KANJI) chunk = 48;
- else if (kanjiType == EKANJI) chunk = 128;
- break;
- case 0xdf:
- cr = 1; //de
- if (kanjiType == KANA) chunk = 10;
- else if (kanjiType == KANJI) chunk = 64;
- else if (kanjiType == EKANJI) chunk = 144;
- break;
- default:
- debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
- return 0;
- }
-
- debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
- return ((chunk_f + chunk) * 32 + (s - base)) + cr;
-}
-
static int SJIStoPCEChunk(int f, int s) { //converts sjis code to pce font offset
// rangeTbl maps SJIS char-codes to the PCE System Card font rom.
// Each pair {<upperBound>,<lowerBound>} in the array represents a SJIS range.
@@ -327,9 +238,8 @@ byte *ScummEngine::get2byteCharPtr(int idx) {
}
idx = (SWAP_CONSTANT_16(idx) & 0x7fff) - 1;
- } else {
- idx = SJIStoFMTChunk((idx % 256), (idx / 256));
}
+
break;
case Common::ZH_TWN:
{
@@ -453,30 +363,79 @@ void CharsetRendererV3::setCurID(int32 id) {
}
int CharsetRendererCommon::getFontHeight() {
- if (_vm->_useCJKMode)
- return MAX(_vm->_2byteHeight + 1, _fontHeight);
- else
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ static const uint8 sjisFontHeightM1[] = { 0, 8, 9, 8, 9, 8, 9, 0, 0, 0 };
+ static const uint8 sjisFontHeightM2[] = { 0, 8, 9, 9, 9, 8, 9, 9, 9, 8 };
+ static const uint8 sjisFontHeightI4[] = { 0, 8, 9, 9, 9, 8, 8, 8, 8, 8 };
+ const uint8 *htbl = (_vm->_game.id == GID_MONKEY) ? sjisFontHeightM1 : ((_vm->_game.id == GID_INDY4) ? sjisFontHeightI4 : sjisFontHeightM2);
+ return (_vm->_game.version == 3) ? 8 : htbl[_curId];
+ } else {
+ return MAX(_vm->_2byteHeight + 1, _fontHeight);
+ }
+ } else
return _fontHeight;
}
// do spacing for variable width old-style font
-int CharsetRendererClassic::getCharWidth(byte chr) {
- if (chr >= 0x80 && _vm->_useCJKMode)
- return _vm->_2byteWidth / 2;
+int CharsetRendererClassic::getCharWidth(uint16 chr) {
int spacing = 0;
- int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- if (offs) {
- spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2];
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if ((chr & 0xff00) == 0xfd00) {
+ chr &= 0xff;
+ } else if (chr >= 256) {
+ spacing = 8;
+ } else if (useTownsFontRomCharacter(chr)) {
+ spacing = 4;
+ }
+
+ if (spacing) {
+ if (_vm->_game.id == GID_MONKEY) {
+ spacing++;
+ if (_curId == 2)
+ spacing++;
+ } else if (_vm->_game.id != GID_INDY4 && _curId == 1) {
+ spacing++;
+ }
+ }
+
+ } else if (chr >= 0x80) {
+ return _vm->_2byteWidth / 2;
+ }
+ }
+
+ if (!spacing) {
+ int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
+ if (offs) {
+ spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2];
+ }
}
return spacing;
}
+bool CharsetRendererClassic::useTownsFontRomCharacter(uint16 chr) {
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_vm->_game.platform != Common::kPlatformFMTowns || !_vm->_useCJKMode)
+ return false;
+
+ if (chr < 128) {
+ if (((_vm->_game.id == GID_MONKEY2 && _curId != 0) || (_vm->_game.id == GID_INDY4 && _curId != 3)) && (chr > 31 && chr != 94 && chr != 95 && chr != 126 && chr != 127))
+ return true;
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
int CharsetRenderer::getStringWidth(int arg, const byte *text) {
int pos = 0;
int width = 1;
- byte chr;
+ int chr;
int oldID = getCurID();
int code = (_vm->_game.heversion >= 80) ? 127 : 64;
@@ -534,12 +493,20 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
}
}
}
- if ((chr & 0x80) && _vm->_useCJKMode) {
- pos++;
- width += _vm->_2byteWidth;
- } else {
- width += getCharWidth(chr);
+
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if (checkSJISCode(chr))
+ // This strange character conversion is the exact way the original does it here.
+ // This is the only way to get an accurate text formatting in the MI1 intro.
+ chr = (int8)text[pos++] | (chr << 8);
+ } else if (chr & 0x80) {
+ pos++;
+ width += _vm->_2byteWidth;
+ continue;
+ }
}
+ width += getCharWidth(chr);
}
setCurID(oldID);
@@ -550,7 +517,7 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
int lastspace = -1;
int curw = 1;
- byte chr;
+ int chr;
int oldID = getCurID();
int code = (_vm->_game.heversion >= 80) ? 127 : 64;
@@ -612,9 +579,17 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
if (chr == _vm->_newLineCharacter)
lastspace = pos - 1;
- if ((chr & 0x80) && _vm->_useCJKMode) {
- pos++;
- curw += _vm->_2byteWidth;
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if (checkSJISCode(chr))
+ // This strange character conversion is the exact way the original does it here.
+ // This is the only way to get an accurate text formatting in the MI1 intro.
+ chr = (int8)str[pos++] | (chr << 8);
+ curw += getCharWidth(chr);
+ } else if (chr & 0x80) {
+ pos++;
+ curw += _vm->_2byteWidth;
+ }
} else {
curw += getCharWidth(chr);
}
@@ -631,12 +606,22 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
setCurID(oldID);
}
-int CharsetRendererV3::getCharWidth(byte chr) {
- if (chr & 0x80 && _vm->_useCJKMode)
- return _vm->_2byteWidth / 2;
+int CharsetRendererV3::getCharWidth(uint16 chr) {
int spacing = 0;
- spacing = *(_widthTable + chr);
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if (chr >= 256)
+ spacing = 8;
+ else if (chr >= 128)
+ spacing = 4;
+ } else if (chr & 0x80) {
+ spacing = _vm->_2byteWidth / 2;
+ }
+ }
+
+ if (!spacing)
+ spacing = *(_widthTable + chr);
return spacing;
}
@@ -655,6 +640,14 @@ void CharsetRendererV3::setColor(byte color) {
} else
useShadow = false;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ _color = (_color & 0x0f) | ((_color & 0x0f) << 4);
+ if (_color == 0)
+ _color = 0x88;
+ }
+#endif
+
enableShadow(useShadow);
translateColor();
@@ -673,17 +666,37 @@ void CharsetRendererCommon::enableShadow(bool enable) {
if (enable) {
if (_vm->_game.platform == Common::kPlatformFMTowns) {
_shadowColor = 8;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ _shadowColor = _vm->_game.version == 5 ? _vm->_townsCharsetColorMap[0] : 0x88;
+ if (_vm->_cjkFont) {
+ if (_vm->_game.version == 5) {
+ if (((_vm->_game.id == GID_MONKEY) && (_curId == 2 || _curId == 4 || _curId == 6)) ||
+ ((_vm->_game.id == GID_MONKEY2) && (_curId != 1 && _curId != 5 && _curId != 9)) ||
+ ((_vm->_game.id == GID_INDY4) && (_curId == 2 || _curId == 3 || _curId == 4))) {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kOutlineMode);
+ } else {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
+ }
+ _vm->_cjkFont->toggleFlippedMode((_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) && _curId == 3);
+ } else {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kShadowMode);
+ }
+ }
+#endif
_shadowMode = kFMTOWNSShadowMode;
} else {
_shadowColor = 0;
_shadowMode = kNormalShadowMode;
}
} else {
+ if (_vm->_cjkFont) {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
+ _vm->_cjkFont->toggleFlippedMode(false);
+ }
_shadowMode = kNoShadowMode;
}
}
-
void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
// WORKAROUND for bug #1509509: Indy3 Mac does not show black
// characters (such as in the grail diary) if ignoreCharsetMask
@@ -696,7 +709,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
VirtScreen *vs;
const byte *charPtr;
byte *dst;
- int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
+ int is2byte = (chr >= 256 && _vm->_useCJKMode) ? 1 : 0;
assertRange(0, _curId, _vm->_numCharsets - 1, "charset");
@@ -706,10 +719,16 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (chr == '@')
return;
- if (is2byte) {
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_useCJKMode && chr > 127) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ charPtr = 0;
+ width = _vm->_cjkFont->getCharWidth(chr);
+ height = _vm->_cjkFont->getFontHeight();
+ } else {
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ charPtr = _vm->get2byteCharPtr(chr);
+ }
} else {
charPtr = _fontPtr + chr * 8;
width = getCharWidth(chr);
@@ -744,18 +763,31 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
_hasMask = true;
_textScreenID = vs->number;
}
- if ((ignoreCharsetMask || !vs->hasTwoBuffers) && !(_vm->_useCJKMode && _vm->_textSurfaceMultiplier == 2)) {
+
+ if (
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ (_vm->_game.platform != Common::kPlatformFMTowns) &&
+#endif
+ (ignoreCharsetMask || !vs->hasTwoBuffers)) {
dst = vs->getPixels(_left, drawTop);
- drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->bytesPerPixel);
+ if (charPtr)
+ drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->bytesPerPixel);
+ else if (_vm->_cjkFont)
+ _vm->_cjkFont->drawChar(dst, chr, vs->pitch, vs->bytesPerPixel, _color, _shadowColor);
} else {
dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier);
- drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.bytesPerPixel);
+ if (charPtr)
+ drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.bytesPerPixel, (_vm->_textSurfaceMultiplier == 2 && !is2byte));
+ else if (_vm->_cjkFont)
+ _vm->_cjkFont->drawChar(dst, chr, _vm->_textSurface.pitch, vs->bytesPerPixel, _color, _shadowColor);
+ if (is2byte)
+ origWidth /= _vm->_textSurfaceMultiplier;
}
if (_str.left > _left)
_str.left = _left;
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ _left += origWidth;
if (_str.right < _left) {
_str.right = _left;
@@ -773,9 +805,17 @@ void CharsetRendererV3::drawChar(int chr, const Graphics::Surface &s, int x, int
int width, height;
int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
if (is2byte) {
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ width = _vm->_cjkFont->getCharWidth(chr);
+ height = _vm->_cjkFont->getFontHeight();
+ dst = (byte *)s.pixels + y * s.pitch + x;
+ _vm->_cjkFont->drawChar(dst, chr, s.pitch, s.bytesPerPixel, _color, _shadowColor);
+ return;
+ } else {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ }
} else {
charPtr = _fontPtr + chr * 8;
// width = height = 8;
@@ -801,6 +841,29 @@ void CharsetRenderer::translateColor() {
}
}
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+void CharsetRenderer::processTownsCharsetColors(uint8 bytesPerPixel) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ for (int i = 0; i < (1 << bytesPerPixel); i++) {
+ uint8 c = _vm->_charsetColorMap[i];
+
+ if (c > 16) {
+ uint8 t = (_vm->_currentPalette[c * 3] < 32) ? 4 : 12;
+ t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 2 : 10);
+ t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 1 : 9);
+ c = t;
+ }
+
+ if (c == 0)
+ c = _vm->_townsOverrideShadowColor;
+
+ c = ((c & 0x0f) << 4) | (c & 0x0f);
+ _vm->_townsCharsetColorMap[i] = c;
+ }
+ }
+}
+#endif
+
void CharsetRenderer::saveLoadWithSerializer(Serializer *ser) {
static const SaveLoadEntry charsetRendererEntries[] = {
MKLINE_OLD(CharsetRenderer, _curId, sleByte, VER(73), VER(73)),
@@ -822,7 +885,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
int offsX, offsY;
VirtScreen *vs;
const byte *charPtr;
- bool is2byte = (chr >= 0x80 && _vm->_useCJKMode);
+ bool is2byte = (chr >= 256 && _vm->_useCJKMode);
assertRange(1, _curId, _vm->_numCharsets - 1, "charset");
@@ -836,12 +899,44 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_vm->_charsetColorMap[1] = _color;
- if (is2byte) {
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ processTownsCharsetColors(_bytesPerPixel);
+ bool noSjis = false;
+
+ if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_useCJKMode) {
+ if ((chr & 0x00ff) == 0x00fd) {
+ chr >>= 8;
+ noSjis = true;
+ }
+ }
+
+ if (useTownsFontRomCharacter(chr) && !noSjis) {
+ charPtr = 0;
+ _vm->_cjkChar = chr;
enableShadow(true);
+
+ width = getCharWidth(chr);
+ // For whatever reason MI1 uses a different font width
+ // for alignment calculation and for drawing when
+ // charset 2 is active. This fixes some subtle glitches.
+ if (_vm->_game.id == GID_MONKEY && _curId == 2)
+ width--;
+ origWidth = width;
+
+ origHeight = height = getFontHeight();
+ offsX = offsY = 0;
+ } else
+#endif
+ if (_vm->_useCJKMode && (chr >= 128) && !noSjis) {
+ enableShadow(true);
+ origWidth = width = _vm->_2byteWidth;
+ origHeight = height = _vm->_2byteHeight;
charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
offsX = offsY = 0;
+ if (_shadowMode != kNoShadowMode) {
+ width++;
+ height++;
+ }
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x14000);
@@ -849,8 +944,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
return;
charPtr = _fontPtr + charOffs;
- width = charPtr[0];
- height = charPtr[1];
+ width = origWidth = charPtr[0];
+ height = origHeight = charPtr[1];
if (_disableOffsX) {
offsX = 0;
@@ -862,13 +957,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
charPtr += 4; // Skip over char header
}
- origWidth = width;
- origHeight = height;
- if (_shadowMode != kNoShadowMode) {
- width++;
- height++;
- }
if (_firstChar) {
_str.left = 0;
_str.top = 0;
@@ -879,8 +968,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_top += offsY;
_left += offsX;
- if (_left + origWidth / _vm->_textSurfaceMultiplier > _right + 1 || _left < 0) {
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ if (_left + origWidth > _right + 1 || _left < 0) {
+ _left += origWidth;
_top -= offsY;
return;
}
@@ -905,23 +994,29 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);
- if (!ignoreCharsetMask) {
+ // This check for kPlatformFMTowns and kMainVirtScreen is at least required for the chat with
+ // the navigator's head in front of the ghost ship in Monkey Island 1
+ if (!ignoreCharsetMask
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ || (_vm->_game.platform == Common::kPlatformFMTowns && vs->number == kMainVirtScreen)
+#endif
+ ) {
_hasMask = true;
_textScreenID = vs->number;
}
printCharIntern(is2byte, charPtr, origWidth, origHeight, width, height, vs, ignoreCharsetMask);
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ _left += origWidth;
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode != kNoShadowMode)
+ if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode != kNoShadowMode)
_str.right++;
}
- if (_str.bottom < _top + height / _vm->_textSurfaceMultiplier)
- _str.bottom = _top + height / _vm->_textSurfaceMultiplier;
+ if (_str.bottom < _top + origHeight)
+ _str.bottom = _top + origHeight;
_top -= offsY;
}
@@ -961,7 +1056,11 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
} else {
Graphics::Surface dstSurface;
Graphics::Surface backSurface;
- if ((ignoreCharsetMask || !vs->hasTwoBuffers) && !(_vm->_useCJKMode && _vm->_textSurfaceMultiplier == 2)) {
+ if ((ignoreCharsetMask || !vs->hasTwoBuffers)
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ && (_vm->_game.platform != Common::kPlatformFMTowns)
+#endif
+ ) {
dstSurface = *vs;
dstPtr = vs->getPixels(_left, drawTop);
} else {
@@ -980,10 +1079,12 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
drawTop = _top - _vm->_screenTop;
}
- if (is2byte) {
+ if (!charPtr && _vm->_cjkFont)
+ _vm->_cjkFont->drawChar(dstPtr, _vm->_cjkChar, dstSurface.pitch, dstSurface.bytesPerPixel, _vm->_townsCharsetColorMap[1], _shadowColor);
+ else if (is2byte) {
drawBits1(dstSurface, dstPtr, charPtr, drawTop, origWidth, origHeight, dstSurface.bytesPerPixel);
} else {
- drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
+ drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight, _vm->_textSurfaceMultiplier == 2);
}
if (_blitAlso && vs->hasTwoBuffers) {
@@ -1031,9 +1132,17 @@ void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x
if (is2byte) {
enableShadow(true);
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ width = _vm->_cjkFont->getCharWidth(chr);
+ height = _vm->_cjkFont->getFontHeight();
+ dst = (byte *)s.pixels + y * s.pitch + x;
+ _vm->_cjkFont->drawChar(dst, chr, s.pitch, s.bytesPerPixel, _color, _shadowColor);
+ return;
+ } else {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ }
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x10000);
@@ -1056,23 +1165,55 @@ void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x
}
}
-void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
+void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height,
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ bool scale2x) {
+#else
+ bool) {
+#endif
+
int y, x;
int color;
byte numbits, bits;
+ byte *dst2 = dst;
+ int pitch = s.pitch - width;
+
assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
bits = *src++;
numbits = 8;
+ byte *cmap = _vm->_charsetColorMap;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_vm->_game.platform == Common::kPlatformFMTowns)
+ cmap = _vm->_townsCharsetColorMap;
+ if (scale2x) {
+ dst2 += s.pitch;
+ pitch <<= 1;
+ }
+#endif
for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) {
color = (bits >> (8 - bpp)) & 0xFF;
if (color && y + drawTop >= 0) {
- *dst = _vm->_charsetColorMap[color];
+ *dst = cmap[color];
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x)
+ dst[1] = dst2[0] = dst2[1] = dst[0];
+#endif
}
dst++;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst++;
+ dst2 += 2;
+ }
+#endif
+
bits <<= bpp;
numbits -= bpp;
if (numbits == 0) {
@@ -1080,13 +1221,37 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co
numbits = 8;
}
}
- dst += s.pitch - width;
+ dst += pitch;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ dst2 += pitch;
+#endif
}
}
-void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth,
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ bool scale2x) {
+#else
+ bool) {
+#endif
+
int y, x;
byte bits = 0;
+ uint8 col = _color;
+ int pitch = s.pitch - width * bitDepth;
+ byte *dst2 = dst + s.pitch;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ byte *dst3 = dst2;
+ byte *dst4 = dst2;
+ if (scale2x) {
+ dst3 = dst2 + s.pitch;
+ dst4 = dst3 + s.pitch;
+ pitch <<= 1;
+ }
+ if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_game.version == 5)
+ col = _vm->_townsCharsetColorMap[1];
+#endif
for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) {
@@ -1103,23 +1268,49 @@ void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, con
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
if (_shadowMode != kNoShadowMode) {
- *(dst + 1) = _shadowColor;
- *(dst + s.pitch) = _shadowColor;
- if (_shadowMode != kFMTOWNSShadowMode)
- *(dst + s.pitch + 1) = _shadowColor;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor;
+ dst3[0] = dst4[0] = dst3[1] = dst4[1] = _shadowColor;
+ } else
+#endif
+ {
+ dst[1] = dst2[0] = _shadowColor;
+ if (_shadowMode != kFMTOWNSShadowMode)
+ dst2[1] = _shadowColor;
+ }
}
- *dst = _color;
+ dst[0] = col;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x)
+ dst[1] = dst2[0] = dst2[1] = col;
+#endif
}
}
dst += bitDepth;
+ dst2 += bitDepth;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst++;
+ dst2++;
+ dst3 += 2;
+ dst4 += 2;
+ }
+#endif
}
- dst += s.pitch - width * bitDepth;
+ dst += pitch;
+ dst2 += pitch;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ dst3 += pitch;
+ dst4 += pitch;
+#endif
}
}
#ifdef USE_RGB_COLOR
-void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) {
int y, x;
int bitCount = 0;
byte bits = 0;
@@ -1191,7 +1382,7 @@ int CharsetRendererNut::getCharHeight(byte chr) {
return _current->getCharHeight(chr);
}
-int CharsetRendererNut::getCharWidth(byte chr) {
+int CharsetRendererNut::getCharWidth(uint16 chr) {
assert(_current);
return _current->getCharWidth(chr);
}
@@ -1349,7 +1540,7 @@ void CharsetRendererNES::drawChar(int chr, const Graphics::Surface &s, int x, in
drawBits1(s, dst, charPtr, y, width, height, s.bytesPerPixel);
}
-void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) {
for (int i = 0; i < 8; i++) {
byte c0 = src[i];
byte c1 = src[i + 8];