aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorMax Horn2004-10-23 23:08:53 +0000
committerMax Horn2004-10-23 23:08:53 +0000
commitb60febe8a81120a21c2346bb8bc4255038b695e8 (patch)
tree57aa745c3b460152db976ecf1bf6d78ef6e03d14 /scumm
parente8811e71584ff4f4530b462e0b390281fadba88b (diff)
downloadscummvm-rg350-b60febe8a81120a21c2346bb8bc4255038b695e8.tar.gz
scummvm-rg350-b60febe8a81120a21c2346bb8bc4255038b695e8.tar.bz2
scummvm-rg350-b60febe8a81120a21c2346bb8bc4255038b695e8.zip
Patch #1048283 (Improved CJK / FM-TOWNS support & some documention)
svn-id: r15671
Diffstat (limited to 'scumm')
-rw-r--r--scumm/charset.cpp213
-rw-r--r--scumm/charset.h23
-rw-r--r--scumm/nut_renderer.cpp18
-rw-r--r--scumm/smush/smush_font.cpp17
-rw-r--r--scumm/string.cpp52
5 files changed, 227 insertions, 96 deletions
diff --git a/scumm/charset.cpp b/scumm/charset.cpp
index 257e7b332d..76128abc7f 100644
--- a/scumm/charset.cpp
+++ b/scumm/charset.cpp
@@ -26,20 +26,37 @@
namespace Scumm {
void ScummEngine::loadCJKFont() {
+ File fp;
_useCJKMode = false;
- if ((_gameId == GID_DIG || _gameId == GID_CMI) && (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN)) {
- File fp;
+ if (_language == Common::JA_JPN && _version <= 5) { // 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", File::kFileReadMode)) {
+ _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();
+ }
+ } else if (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN) {
+ int numChar = 0;
const char *fontFile = NULL;
+
switch (_language) {
case Common::KO_KOR:
fontFile = "korean.fnt";
+ numChar = 2350;
break;
case Common::JA_JPN:
fontFile = (_gameId == GID_DIG) ? "kanji16.fnt" : "japanese.fnt";
+ numChar = 1024; //FIXME
break;
case Common::ZH_TWN:
if (_gameId == GID_CMI) {
fontFile = "chinese.fnt";
+ numChar = 1; //FIXME
}
break;
default:
@@ -52,49 +69,23 @@ void ScummEngine::loadCJKFont() {
_2byteWidth = fp.readByte();
_2byteHeight = fp.readByte();
- int numChar = 0;
- switch (_language) {
- case Common::KO_KOR:
- numChar = 2350;
- break;
- case Common::JA_JPN:
- numChar = (_gameId == GID_DIG) ? 1024 : 2048; //FIXME
- break;
- case Common::ZH_TWN:
- numChar = 1; //FIXME
- break;
- default:
- break;
- }
- _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar];
- fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar);
- fp.close();
- }
- } else if (_language == Common::JA_JPN && _version == 5) { // FM-TOWNS Kanji
- File fp;
- 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")) {
- _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();
+ } else {
+ warning("Couldn't load any font");
}
}
}
-static int SJIStoFMTChunk(int f, int s) //convert sjis code to fmt font offset
-{
+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 % 32) - 1;
- int c = 0, p = 0, chunk_f = 0, chunk = 0, cr, kanjiType = KANA;
+ 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;
@@ -115,10 +106,15 @@ static int SJIStoFMTChunk(int f, int s) //convert sjis code to fmt font offset
chunk_f = c + 2 * p;
}
+ // Base corrections
if (base == 0x7f && s == 0x7f)
- base -= 0x20; //correction
- if ((base == 0x7f && s == 0x9e) || (base == 0x9f && s == 0xbe) || (base == 0xbf && s == 0xde))
- base += 0x20; //correction
+ 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:
@@ -158,9 +154,11 @@ static int SJIStoFMTChunk(int f, int s) //convert sjis code to fmt font offset
else if (kanjiType == EKANJI) chunk = 144;
break;
default:
+ warning("Invaild 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;
}
@@ -238,10 +236,24 @@ void CharsetRendererV3::setCurID(byte id) {
_fontPtr += _numChars;
}
+int CharsetRendererCommon::getFontHeight() {
+ if(_vm->_useCJKMode)
+ return MAX(_vm->_2byteHeight + 1, (int)_fontPtr[1]);
+ else
+ return _fontPtr[1];
+}
+
+int CharsetRendererV3::getFontHeight() {
+ if(_vm->_useCJKMode)
+ return MAX(_vm->_2byteHeight + 1, 8);
+ else
+ return 8;
+}
+
// do spacing for variable width old-style font
int CharsetRendererClassic::getCharWidth(byte chr) {
if (chr >= 0x80 && _vm->_useCJKMode)
- return 6;
+ return _vm->_2byteWidth / 2;
int spacing = 0;
int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
@@ -276,6 +288,10 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
if (chr == 0xD)
break;
if (chr == 254 || chr == 255) {
+ //process in LE
+ if(chr == 254 && checkKSCode(text[pos], chr) && _vm->_useCJKMode) {
+ goto loc_avoid_ks_fe;
+ }
chr = text[pos++];
if (chr == 3) // 'WAIT'
break;
@@ -299,7 +315,13 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
continue;
}
}
- width += getCharWidth(chr);
+loc_avoid_ks_fe:
+ if ((chr & 0x80) && _vm->_useCJKMode) {
+ pos++;
+ width += _vm->_2byteWidth;
+ } else {
+ width += getCharWidth(chr);
+ }
}
setCurID(oldID);
@@ -333,6 +355,10 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
} else if (chr == '@')
continue;
if (chr == 254 || chr == 255) {
+ //process in LE
+ if(chr == 254 && checkKSCode(str[pos], chr) && _vm->_useCJKMode) {
+ goto loc_avoid_ks_fe;
+ }
chr = str[pos++];
if (chr == 3) // 'Wait'
break;
@@ -366,7 +392,13 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
if (chr == ' ')
lastspace = pos - 1;
- curw += getCharWidth(chr);
+loc_avoid_ks_fe:
+ if ((chr & 0x80) && _vm->_useCJKMode) {
+ pos++;
+ curw += _vm->_2byteWidth;
+ } else {
+ curw += getCharWidth(chr);
+ }
if (lastspace == -1)
continue;
if (curw > maxwidth) {
@@ -1105,6 +1137,8 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
}
int CharsetRendererV3::getCharWidth(byte chr) {
+ if (chr & 0x80 && _vm->_useCJKMode)
+ return _vm->_2byteWidth / 2;
int spacing = 0;
spacing = *(_widthTable + chr);
@@ -1129,10 +1163,10 @@ void CharsetRendererV3::setColor(byte color)
void CharsetRendererV3::printChar(int chr) {
// Indy3 / Zak256 / Loom
+ int width, height, origWidth, origHeight;
VirtScreen *vs;
- byte *char_ptr, *dest_ptr;
- int width, height;
- int drawTop;
+ byte *charPtr, *dst;
+ int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
checkRange(_vm->_numCharsets - 1, 0, _curId, "Printing with bad charset %d");
@@ -1142,6 +1176,25 @@ void CharsetRendererV3::printChar(int chr) {
if (chr == '@')
return;
+ if (is2byte) {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ } else {
+ charPtr = _fontPtr + chr * 8;
+// width = height = 8;
+ width = getCharWidth(chr);
+ height = 8;
+ }
+
+ origWidth = width;
+ origHeight = height;
+
+ if (_dropShadow) {
+ width++;
+ height++;
+ }
+
if (_firstChar) {
_str.left = _left;
_str.top = _top;
@@ -1150,14 +1203,7 @@ void CharsetRendererV3::printChar(int chr) {
_firstChar = false;
}
- width = height = 8;
- if (_dropShadow) {
- width++;
- height++;
- }
-
- drawTop = _top - vs->topline;
- char_ptr = _fontPtr + chr * 8;
+ int drawTop = _top - vs->topline;
_vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);
@@ -1166,17 +1212,17 @@ void CharsetRendererV3::printChar(int chr) {
_textScreenID = vs->number;
}
if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
- dest_ptr = vs->getPixels(_left, drawTop);
- drawBits1(*vs, dest_ptr, char_ptr, drawTop, 8, 8);
+ dst = vs->getPixels(_left, drawTop);
+ drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight);
} else {
- dest_ptr = (byte *)_vm->gdi._textSurface.pixels + _top * _vm->gdi._textSurface.pitch + _left;
- drawBits1(_vm->gdi._textSurface, dest_ptr, char_ptr, drawTop, 8, 8);
+ dst = (byte *)_vm->gdi._textSurface.pixels + _top * _vm->gdi._textSurface.pitch + _left;
+ drawBits1(_vm->gdi._textSurface, dst, charPtr, drawTop, origWidth, origHeight);
}
if (_str.left > _left)
_str.left = _left;
- _left += getCharWidth(chr);
+ _left += origWidth;
if (_str.right < _left) {
_str.right = _left;
@@ -1189,10 +1235,21 @@ void CharsetRendererV3::printChar(int chr) {
}
void CharsetRendererV3::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
- byte *char_ptr, *dest_ptr;
- char_ptr = _fontPtr + chr * 8;
- dest_ptr = (byte *)s.pixels + y * s.pitch + x;
- drawBits1(s, dest_ptr, char_ptr, y, 8, 8);
+ byte *charPtr, *dst;
+ int width, height;
+ int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
+ if (is2byte) {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ } else {
+ charPtr = _fontPtr + chr * 8;
+// width = height = 8;
+ width = getCharWidth(chr);
+ height = 8;
+ }
+ dst = (byte *)s.pixels + y * s.pitch + x;
+ drawBits1(s, dst, charPtr, y, width, height);
}
@@ -1216,6 +1273,7 @@ void CharsetRendererClassic::printChar(int chr) {
int type = *_fontPtr;
if (is2byte) {
_dropShadow = true;
+ _shadowColor = (_vm->_features & GF_FMTOWNS) ? 8 : 0;
charPtr = _vm->get2byteCharPtr(chr);
width = _vm->_2byteWidth;
height = _vm->_2byteHeight;
@@ -1404,20 +1462,35 @@ void CharsetRendererClassic::printChar(int chr) {
void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
const byte *charPtr;
byte *dst;
+ int width, height;
+ int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
- uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- assert(charOffs < 0x10000);
- if (!charOffs)
- return;
- charPtr = _fontPtr + charOffs;
-
- int width = charPtr[0];
- int height = charPtr[1];
+ if (is2byte) {
+ _dropShadow = true;
+ _shadowColor = (_vm->_features & GF_FMTOWNS) ? 8 : 0;
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ } else {
+ uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
+ assert(charOffs < 0x10000);
+ if (!charOffs)
+ return;
+ charPtr = _fontPtr + charOffs;
+
+ width = charPtr[0];
+ height = charPtr[1];
- charPtr += 4; // Skip over char header
+ charPtr += 4; // Skip over char header
+ }
dst = (byte *)s.pixels + y * s.pitch + x;
- drawBitsN(s, dst, charPtr, *_fontPtr, y, width, height);
+
+ if (is2byte) {
+ drawBits1(s, dst, charPtr, y, width, height);
+ } else {
+ drawBitsN(s, dst, charPtr, *_fontPtr, y, width, height);
+ }
}
void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
@@ -1540,7 +1613,7 @@ void CharsetRendererNut::printChar(int chr) {
int height = _current->getCharHeight(chr);
if (chr >= 256 && _vm->_useCJKMode)
- width = 16;
+ width = _vm->_2byteWidth;
shadow.right = _left + width + 2;
shadow.bottom = _top + height + 2;
diff --git a/scumm/charset.h b/scumm/charset.h
index 66c506e73c..0e86f83470 100644
--- a/scumm/charset.h
+++ b/scumm/charset.h
@@ -31,6 +31,25 @@ class ScummEngine;
class NutRenderer;
struct VirtScreen;
+static inline bool checkKSCode(byte hi, byte lo) {
+ //hi : xx
+ //lo : yy
+ if ((0xA1 > lo) || (0xFE < lo)) {
+ return false;
+ }
+ if ((hi >= 0xB0) && (hi <= 0xC8)) {
+ return true;
+ }
+ return false;
+}
+
+static inline bool checkSJISCode(byte c) {
+ if ((c > 0x84 && c < 0x88) || (c > 0x9f && c < 0xe0) || (c > 0xea /* && c <= 0xff */))
+ return false;
+ return true;
+}
+
+
class CharsetRenderer {
public:
@@ -94,7 +113,7 @@ public:
void setCurID(byte id);
- int getFontHeight() { return _fontPtr[1]; }
+ int getFontHeight();
};
class CharsetRendererClassic : public CharsetRendererCommon {
@@ -122,7 +141,7 @@ public:
void drawChar(int chr, const Graphics::Surface &s, int x, int y);
void setCurID(byte id);
void setColor(byte color);
- int getFontHeight() { return 8; }
+ int getFontHeight();
int getCharWidth(byte chr);
};
diff --git a/scumm/nut_renderer.cpp b/scumm/nut_renderer.cpp
index 859578bb14..1b8c737248 100644
--- a/scumm/nut_renderer.cpp
+++ b/scumm/nut_renderer.cpp
@@ -204,13 +204,8 @@ int NutRenderer::getCharWidth(byte c) const {
return 0;
}
- if (c >= 0x80 && _vm->_useCJKMode) {
- if (_vm->_gameId == GID_CMI)
- return 8;
- if (_vm->_gameId == GID_DIG)
- return 6;
- return 0;
- }
+ if (c >= 0x80 && _vm->_useCJKMode)
+ return _vm->_2byteWidth / 2;
if (c >= _numChars)
error("invalid character in NutRenderer::getCharWidth : %d (%d)", c, _numChars);
@@ -225,13 +220,8 @@ int NutRenderer::getCharHeight(byte c) const {
return 0;
}
- if (c >= 0x80 && _vm->_useCJKMode) {
- if (_vm->_gameId == GID_CMI)
- return 16;
- if (_vm->_gameId == GID_DIG)
- return 10;
- return 0;
- }
+ if (c >= 0x80 && _vm->_useCJKMode)
+ return _vm->_2byteHeight;
if (c >= _numChars)
error("invalid character in NutRenderer::getCharHeight : %d (%d)", c, _numChars);
diff --git a/scumm/smush/smush_font.cpp b/scumm/smush/smush_font.cpp
index 188dfd6773..b830a78e82 100644
--- a/scumm/smush/smush_font.cpp
+++ b/scumm/smush/smush_font.cpp
@@ -43,7 +43,11 @@ int SmushFont::getStringWidth(const char *str) {
int width = 0;
while (*str) {
- width += getCharWidth(*str++);
+ if(*str & 0x80 && g_scumm->_useCJKMode) {
+ width += g_scumm->_2byteWidth + 1;
+ str += 2;
+ } else
+ width += getCharWidth(*str++);
}
return width;
}
@@ -118,18 +122,25 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
int h = _vm->_2byteHeight;
byte *src = _vm->get2byteCharPtr(idx);
- byte *dst = buffer + dst_width * (y + (_vm->_gameId == GID_CMI ? 7 : 2)) + x;
+ byte *dst = buffer + dst_width * (y + (_vm->_gameId == GID_CMI ? 7 : (_vm->_gameId == GID_DIG ? 2 : 0))) + x;
byte bits = 0;
char color = (_color != -1) ? _color : 1;
+
if (_new_colors)
- color = (char)0xff; //FIXME;
+ color = (char)0xff;
+
+ if (g_scumm->_gameId == GID_FT)
+ color = 1;
+
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
if ((i % 8) == 0)
bits = *src++;
if (bits & revBitMask[i % 8]) {
dst[i + 1] = 0;
+ dst[dst_width + i] = 0;
+ dst[dst_width + i + 1] = 0;
dst[i] = color;
}
}
diff --git a/scumm/string.cpp b/scumm/string.cpp
index 36f033fcdf..362864acff 100644
--- a/scumm/string.cpp
+++ b/scumm/string.cpp
@@ -103,6 +103,8 @@ void ScummEngine::CHARSET_1() {
int code = (_heversion >= 80) ? 127 : 64;
char value[32];
+ bool cmi_pos_hack = false;
+
if (!_haveMsg)
return;
@@ -283,6 +285,11 @@ void ScummEngine::CHARSET_1() {
warning("CHARSET_1: invalid code %d", c);
}
} else if (c == 0xFE || c == 0xFF) {
+ //WORKAROUND
+ //to avoid korean code 0xfe treated as charset message code.
+ if(c == 0xFE && checkKSCode(*(buffer + 1), c) && _useCJKMode) {
+ goto loc_avoid_ks_fe;
+ }
c = *buffer++;
switch (c) {
case 1:
@@ -343,13 +350,19 @@ void ScummEngine::CHARSET_1() {
warning("CHARSET_1: invalid code %d", c);
}
} else {
+loc_avoid_ks_fe:
_charset->_left = _charset->_nextLeft;
_charset->_top = _charset->_nextTop;
if (c & 0x80 && _useCJKMode)
- if (_language == 6 && ((c > 0x84 && c < 0x88) || (c > 0x9f && c < 0xe0) || (c > 0xea && c <= 0xff)))
+ if (_language == Common::JA_JPN && !checkSJISCode(c)) {
c = 0x20; //not in S-JIS
- else
- c += *buffer++ * 256;
+ } else {
+ c += *buffer++ * 256; //LE
+ if(_gameId == GID_CMI) { //HACK: This fixes korean text position in COMI (off by 6 pixel)
+ cmi_pos_hack = true;
+ _charset->_top += 6;
+ }
+ }
if (_version <= 3) {
_charset->printChar(c);
} else {
@@ -363,6 +376,10 @@ void ScummEngine::CHARSET_1() {
} else
_charset->printChar(c);
}
+ if(cmi_pos_hack) {
+ cmi_pos_hack = false;
+ _charset->_top -= 6;
+ }
_charset->_nextLeft = _charset->_left;
_charset->_nextTop = _charset->_top;
@@ -389,6 +406,8 @@ void ScummEngine::drawString(int a, const byte *msg) {
uint color;
int code = (_heversion >= 80) ? 127 : 64;
+ bool cmi_pos_hack = false;
+
addMessageToStack(msg, buf, sizeof(buf));
_charset->_top = _string[a].ypos + _screenTop;
@@ -491,10 +510,24 @@ void ScummEngine::drawString(int a, const byte *msg) {
_charset->_blitAlso = true;
}
}
- if (c >= 0x80 && _useCJKMode)
- c += buf[i++] * 256;
+ if (c & 0x80 && _useCJKMode) {
+ if (_language == Common::JA_JPN && !checkSJISCode(c)) {
+ c = 0x20; //not in S-JIS
+ } else {
+ c += buf[i++] * 256;
+ if(_gameId == GID_CMI) {
+ cmi_pos_hack = true;
+ _charset->_top += 6;
+ }
+ }
+ }
_charset->printChar(c);
_charset->_blitAlso = false;
+
+ if(cmi_pos_hack) {
+ cmi_pos_hack = false;
+ _charset->_top -= 6;
+ }
}
}
@@ -729,8 +762,13 @@ void ScummEngine::drawBlastTexts() {
do {
c = *buf++;
if (c != 0 && c != 0xFF) {
- if (c >= 0x80 && _useCJKMode)
- c += *buf++ * 256;
+ if (c & 0x80 && _useCJKMode) {
+ if (_language == Common::JA_JPN && !checkSJISCode(c)) {
+ c = 0x20; //not in S-JIS
+ } else {
+ c += *buf++ * 256;
+ }
+ }
_charset->printChar(c);
}
} while (c);