From 1db83059b0a33f910c1d2f78630dccde2dd167b9 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Tue, 10 Jul 2007 00:39:12 +0000 Subject: Preliminary (and buggy) Kanji support. svn-id: r27998 --- engines/scumm/charset.cpp | 32 ++++++----- engines/scumm/gfx.cpp | 135 ++++++++++++++++++++++++++++++++++++++-------- engines/scumm/input.cpp | 5 +- engines/scumm/scumm.cpp | 20 +++++-- engines/scumm/scumm.h | 3 ++ 5 files changed, 153 insertions(+), 42 deletions(-) (limited to 'engines/scumm') diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 40637ec4b3..86b48c3690 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -48,6 +48,8 @@ better separation of the various modules. void ScummEngine::loadCJKFont() { Common::File fp; _useCJKMode = false; + _textSurfaceMultiplier = 1; + if (_language == Common::JA_JPN && _game.version <= 5) { // FM-TOWNS v3 / v5 Kanji int numChar = 256 * 32; _2byteWidth = 16; @@ -60,6 +62,7 @@ void ScummEngine::loadCJKFont() { fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar); fp.close(); } + _textSurfaceMultiplier = 2; } else if (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN) { int numChar = 0; const char *fontFile = NULL; @@ -85,6 +88,7 @@ void ScummEngine::loadCJKFont() { if (fontFile && fp.open(fontFile)) { debug(2, "Loading CJK Font"); _useCJKMode = true; + _textSurfaceMultiplier = 1; // No multiplication here fp.seek(2, SEEK_CUR); _2byteWidth = fp.readByte(); _2byteHeight = fp.readByte(); @@ -276,7 +280,7 @@ int CharsetRendererCommon::getFontHeight() { // do spacing for variable width old-style font int CharsetRendererClassic::getCharWidth(byte chr) { if (chr >= 0x80 && _vm->_useCJKMode) - return _vm->_2byteWidth / 2; + return _vm->_2byteWidth; int spacing = 0; int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); @@ -1160,7 +1164,7 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) int CharsetRendererV3::getCharWidth(byte chr) { if (chr & 0x80 && _vm->_useCJKMode) - return _vm->_2byteWidth / 2; + return _vm->_2byteWidth; int spacing = 0; spacing = *(_widthTable + chr); @@ -1257,18 +1261,18 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { _hasMask = true; _textScreenID = vs->number; } - if (ignoreCharsetMask || !vs->hasTwoBuffers) { + if ((ignoreCharsetMask || !vs->hasTwoBuffers) && !(_vm->_useCJKMode && _vm->_textSurfaceMultiplier == 2)) { dst = vs->getPixels(_left, drawTop); drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight); } else { - dst = (byte *)_vm->_textSurface.getBasePtr(_left, _top); + dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier); drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight); } if (_str.left > _left) _str.left = _left; - _left += origWidth; + _left += origWidth / _vm->_textSurfaceMultiplier; if (_str.right < _left) { _str.right = _left; @@ -1276,8 +1280,8 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { _str.right++; } - if (_str.bottom < _top + height) - _str.bottom = _top + height; + if (_str.bottom < _top + height / _vm->_textSurfaceMultiplier) + _str.bottom = _top + height / _vm->_textSurfaceMultiplier; } void CharsetRendererV3::drawChar(int chr, const Graphics::Surface &s, int x, int y) { @@ -1391,8 +1395,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { _top += offsY; _left += offsX; - if (_left + origWidth > _right + 1 || _left < 0) { - _left += origWidth; + if (_left + origWidth / _vm->_textSurfaceMultiplier > _right + 1 || _left < 0) { + _left += origWidth / _vm->_textSurfaceMultiplier; _top -= offsY; return; } @@ -1424,7 +1428,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { printCharIntern(is2byte, charPtr, origWidth, origHeight, width, height, vs, ignoreCharsetMask); - _left += origWidth; + _left += origWidth / _vm->_textSurfaceMultiplier; if (_str.right < _left) { _str.right = _left; @@ -1432,8 +1436,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { _str.right++; } - if (_str.bottom < _top + height) - _str.bottom = _top + height; + if (_str.bottom < _top + height / _vm->_textSurfaceMultiplier) + _str.bottom = _top + height / _vm->_textSurfaceMultiplier; _top -= offsY; } @@ -1473,12 +1477,12 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, } else { Graphics::Surface dstSurface; Graphics::Surface backSurface; - if (ignoreCharsetMask || !vs->hasTwoBuffers) { + if ((ignoreCharsetMask || !vs->hasTwoBuffers) && !(_vm->_useCJKMode && _vm->_textSurfaceMultiplier == 2)) { dstSurface = *vs; dstPtr = vs->getPixels(_left, drawTop); } else { dstSurface = _vm->_textSurface; - dstPtr = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch + _left; + dstPtr = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch * _vm->_textSurfaceMultiplier + _left * _vm->_textSurfaceMultiplier; } if (_blitAlso && vs->hasTwoBuffers) { diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index c70a0e9351..3c6f57be1a 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -561,8 +561,25 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i return; const byte *src = vs->getPixels(x, top); + int m = _textSurfaceMultiplier; + byte *dst; + int vsPitch; int pitch = vs->pitch; + if (_useCJKMode && _textSurfaceMultiplier == 2) { + dst = _fmtownsBuf; + + scale2x(dst, _screenWidth * m, src, vs->pitch, width, height); + src = dst; + + vsPitch = _screenWidth * m - width * m; + + } else { + vsPitch = vs->pitch - width; + } + + dst = _compositeBuf; + if (_game.version < 7) { // For The Dig, FT and COMI, we just blit everything to the screen at once. // For older games, things are more complicated. First off, we need to @@ -572,7 +589,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i // Compute pointer to the text surface assert(_compositeBuf); - const byte *text = (byte *)_textSurface.getBasePtr(x, y); + const byte *text = (byte *)_textSurface.getBasePtr(x * m, y * m); // The values x, width, etc. are all multiples of 8 at this point, // so loop unrolloing might be a good idea... @@ -594,19 +611,18 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i // but also more complicated to implement, and incurs a bigger overhead when // writing to the text surface. #ifdef __DS__ - DS::asmDrawStripToScreen(height, width, text, src, _compositeBuf, vs->pitch, width, _textSurface.pitch); + DS::asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, width, _textSurface.pitch); #else - byte *dst = _compositeBuf; - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { + for (int h = 0; h < height * m; ++h) { + for (int w = 0; w < width * m; ++w) { byte tmp = *text++; if (tmp == CHARSET_MASK_TRANSPARENCY) tmp = *src; *dst++ = tmp; src++; } - src += vs->pitch - width; - text += _textSurface.pitch - width; + src += vsPitch; + text += _textSurface.pitch - width * m; } #endif @@ -621,6 +637,12 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i // center image on the screen x += (Common::kHercW - _screenWidth * 2) / 2; // (720 - 320*2)/2 = 40 + } else if (_useCJKMode && m == 2) { + pitch *= m; + x *= m; + y *= m; + width *= m; + height *= m; } else { if (_renderMode == Common::kRenderCGA) ditherCGA(_compositeBuf, width, x, y, width, height); @@ -721,6 +743,25 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid *height = dsty - *y; } +void ScummEngine::scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { + byte *dstL1 = dst; + byte *dstL2 = dst + dstPitch; + + int dstAdd = dstPitch * 2 - w * 2; + int srcAdd = srcPitch - w; + + while (h--) { + for (int x = 0; x < w; ++x, dstL1 += 2, dstL2 += 2) { + uint16 col = *src++; + col |= col << 8; + *(uint16*)(dstL1) = col; + *(uint16*)(dstL2) = col; + } + dstL1 += dstAdd; dstL2 += dstAdd; + src += srcAdd; + } +} + #pragma mark - #pragma mark --- Background buffers & charset mask --- @@ -1117,8 +1158,8 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) { error("can only copy bg to main window"); blit(backbuff, vs->pitch, bgbuff, vs->pitch, width, height); if (_charset->_hasMask) { - byte *mask = (byte *)_textSurface.getBasePtr(x, y - _screenTop); - fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width, height); + byte *mask = (byte *)_textSurface.getBasePtr(x * _textSurfaceMultiplier, (y - _screenTop) * _textSurfaceMultiplier); + fill(mask, _textSurface.pitch, CHARSET_MASK_TRANSPARENCY, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); } } else if (_game.heversion >= 71) { // Flags are used for different methods in HE games @@ -3362,7 +3403,17 @@ void ScummEngine::dissolveEffect(int width, int height) { for (i = 0; i < w * h; i++) { x = offsets[i] % vs->pitch; y = offsets[i] / vs->pitch; - _system->copyRectToScreen(vs->getPixels(x, y), vs->pitch, x, y + vs->topline, width, height); + + if (_useCJKMode && _textSurfaceMultiplier == 2) { + int m = _textSurfaceMultiplier; + byte *dst = _fmtownsBuf + x * m + y * m * _screenWidth * m; + scale2x(dst, _screenWidth * m, vs->getPixels(x, y), vs->pitch, width, height); + + _system->copyRectToScreen(dst, _screenWidth * m, x * m, (y + vs->topline) * m, width * m, height * m); + } else { + _system->copyRectToScreen(vs->getPixels(x, y), vs->pitch, x, y + vs->topline, width, height); + } + if (++blits >= blits_before_refresh) { blits = 0; @@ -3391,16 +3442,30 @@ void ScummEngine::scrollEffect(int dir) { step = (step * delay) / kScrolltime; + byte *src; + int m = _textSurfaceMultiplier; + int vsPitch = vs->pitch; + switch (dir) { case 0: //up y = 1 + step; while (y < vs->h) { moveScreen(0, -step, vs->h); - _system->copyRectToScreen(vs->getPixels(0, y - step), - vs->pitch, - 0, vs->h - step, - vs->w, step); + + src = vs->getPixels(0, y - step); + if (_useCJKMode && m == 2) { + int x1 = 0, y1 = vs->h - step; + byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m; + scale2x(dst, _screenWidth * m, src, vs->pitch, vs->w, step); + src = dst; + vsPitch = _screenWidth * 2; + } + + _system->copyRectToScreen(src, + vsPitch, + 0 * m, (vs->h - step) * m, + vs->w * m, step * m); _system->updateScreen(); waitForTimer(delay); @@ -3412,10 +3477,18 @@ void ScummEngine::scrollEffect(int dir) { y = 1 + step; while (y < vs->h) { moveScreen(0, step, vs->h); - _system->copyRectToScreen(vs->getPixels(0, vs->h - y), - vs->pitch, + src = vs->getPixels(0, vs->h - y); + if (_useCJKMode && m == 2) { + int x1 = 0, y1 = 0; + byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m; + scale2x(dst, _screenWidth * m, src, vs->pitch, vs->w, step); + src = dst; + vsPitch = _screenWidth * 2; + } + _system->copyRectToScreen(src, + vsPitch, 0, 0, - vs->w, step); + vs->w * m, step * m); _system->updateScreen(); waitForTimer(delay); @@ -3427,10 +3500,18 @@ void ScummEngine::scrollEffect(int dir) { x = 1 + step; while (x < vs->w) { moveScreen(-step, 0, vs->h); - _system->copyRectToScreen(vs->getPixels(x - step, 0), - vs->pitch, - vs->w - step, 0, - step, vs->h); + src = vs->getPixels(x - step, 0); + if (_useCJKMode && m == 2) { + int x1 = vs->w - step, y1 = 0; + byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m; + scale2x(dst, _screenWidth * m, src, vs->pitch, step, vs->h); + src = dst; + vsPitch = _screenWidth * 2; + } + _system->copyRectToScreen(src, + vsPitch, + (vs->w - step) * m, 0, + step * m, vs->h * m); _system->updateScreen(); waitForTimer(delay); @@ -3442,8 +3523,16 @@ void ScummEngine::scrollEffect(int dir) { x = 1 + step; while (x < vs->w) { moveScreen(step, 0, vs->h); - _system->copyRectToScreen(vs->getPixels(vs->w - x, 0), - vs->pitch, + src = vs->getPixels(vs->w - x, 0); + if (_useCJKMode && m == 2) { + int x1 = 0, y1 = 0; + byte *dst = _fmtownsBuf + x1 * m + y1 * m * _screenWidth * m; + scale2x(dst, _screenWidth * m, src, vs->pitch, step, vs->h); + src = dst; + vsPitch = _screenWidth * 2; + } + _system->copyRectToScreen(src, + vsPitch, 0, 0, step, vs->h); _system->updateScreen(); diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index ffcb7d03f2..6647e9fe8d 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -162,8 +162,11 @@ void ScummEngine::parseEvents() { if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) { _mouse.x -= (Common::kHercW - _screenWidth * 2) / 2; - _mouse.x /= 2; + _mouse.x >>= 1; _mouse.y = _mouse.y * 4 / 7; + } else if (_useCJKMode && _textSurfaceMultiplier == 2) { + _mouse.x >>= 1; + _mouse.y >>= 1; } break; case Common::EVENT_LBUTTONUP: diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index f29f1c7970..e54060c9e1 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -587,6 +587,7 @@ ScummEngine::~ScummEngine() { free(_compositeBuf); free(_herculesBuf); + free(_fmtownsBuf); delete _debugger; @@ -1078,12 +1079,19 @@ int ScummEngine::init() { _fileHandle = new ScummFile(); } + // Load CJK font, if present + // Load it earlier so _useCJKMode variable could be set + loadCJKFont(); + // Initialize backend _system->beginGFXTransaction(); bool defaultTo1XScaler = false; if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) { _system->initSize(Common::kHercW, Common::kHercH); defaultTo1XScaler = true; + } else if (_useCJKMode) { + _system->initSize(_screenWidth * _textSurfaceMultiplier, _screenHeight * _textSurfaceMultiplier); + defaultTo1XScaler = true; } else { _system->initSize(_screenWidth, _screenHeight); defaultTo1XScaler = (_screenWidth > 320); @@ -1135,14 +1143,11 @@ void ScummEngine::setupScumm() { // Load localization data, if present loadLanguageBundle(); - // Load CJK font, if present - loadCJKFont(); - // Create the charset renderer setupCharsetRenderer(); // Create and clear the text surface - _textSurface.create(_screenWidth, _screenHeight, 1); + _textSurface.create(_screenWidth * _textSurfaceMultiplier, _screenHeight * _textSurfaceMultiplier, 1); clearTextSurface(); // Create the costume renderer @@ -1210,6 +1215,13 @@ void ScummEngine::setupScumm() { #if (defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__)) Graphics::initfonts(); #endif + + _fmtownsBuf = 0; + if (_game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN) { + _fmtownsBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier); + } + + _compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier); } #ifndef DISABLE_SCUMM_7_8 diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 438797a018..18c2275029 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -1026,10 +1026,12 @@ protected: // Screen rendering byte *_compositeBuf; byte *_herculesBuf; + byte *_fmtownsBuf; virtual void drawDirtyScreenParts(); void updateDirtyScreen(VirtScreenNumber slot); void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b); void ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const; + void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); public: VirtScreen *findVirtScreen(int y); @@ -1151,6 +1153,7 @@ public: * drawStripToScreen() composits it over the game graphics. */ Graphics::Surface _textSurface; + int _textSurfaceMultiplier; protected: byte _charsetColor; -- cgit v1.2.3