From 66da4777d476c6a9fc2a13351e3b30afc748fd94 Mon Sep 17 00:00:00 2001 From: athrxx Date: Tue, 21 Feb 2012 21:14:28 +0100 Subject: KYRA: (EOB) - implement EGA mode (hi res dithering) for EOB II (also fix various thing connected to CGA/EGA modes) --- engines/kyra/chargen.cpp | 10 +- engines/kyra/darkmoon.cpp | 13 +- engines/kyra/eob.cpp | 2 +- engines/kyra/eobcommon.cpp | 6 +- engines/kyra/gui_eob.cpp | 28 +-- engines/kyra/gui_eob.h | 5 +- engines/kyra/kyra_hof.cpp | 2 +- engines/kyra/kyra_lok.cpp | 2 +- engines/kyra/kyra_mr.cpp | 2 +- engines/kyra/kyra_rpg.cpp | 17 +- engines/kyra/kyra_rpg.h | 5 + engines/kyra/kyra_v1.cpp | 9 +- engines/kyra/kyra_v1.h | 2 +- engines/kyra/lol.cpp | 2 +- engines/kyra/magic_eob.cpp | 2 +- engines/kyra/saveload_eob.cpp | 2 +- engines/kyra/scene_eob.cpp | 65 +++++-- engines/kyra/scene_rpg.cpp | 76 +++++---- engines/kyra/screen.cpp | 190 +++++++++++++-------- engines/kyra/screen.h | 24 ++- engines/kyra/screen_eob.cpp | 384 +++++++++++++++++++++++++++++++----------- engines/kyra/screen_eob.h | 14 +- 22 files changed, 591 insertions(+), 271 deletions(-) diff --git a/engines/kyra/chargen.cpp b/engines/kyra/chargen.cpp index 23274349e7..73f5fccb92 100644 --- a/engines/kyra/chargen.cpp +++ b/engines/kyra/chargen.cpp @@ -1496,7 +1496,7 @@ TransferPartyWiz::~TransferPartyWiz() { } bool TransferPartyWiz::start() { - _screen->copyPage(0, 12); + _screen->copyPage(0, (_screen->getPageScaleFactor(0) == 2) ? 1 : 12); if (!selectAndLoadTransferFile()) return false; @@ -1536,7 +1536,7 @@ bool TransferPartyWiz::start() { bool TransferPartyWiz::selectAndLoadTransferFile() { do { - _screen->copyPage(12, 0); + _screen->copyPage((_screen->getPageScaleFactor(0) == 2) ? 1 : 12, 0); if (transferFileDialogue(_vm->_savegameFilename)) break; } while (_vm->_gui->confirmDialogue2(15, 68, 1)); @@ -1566,7 +1566,7 @@ bool TransferPartyWiz::selectAndLoadTransferFile() { return false; Common::String target = _vm->_gui->transferTargetMenu(eobTargets); - _screen->copyPage(12, 0); + _screen->copyPage((_screen->getPageScaleFactor(0) == 2) ? 1 : 12, 0); if (target.empty()) return true; @@ -1579,10 +1579,10 @@ bool TransferPartyWiz::selectAndLoadTransferFile() { return true; } - _screen->copyPage(12, 0); + _screen->copyPage((_screen->getPageScaleFactor(0) == 2) ? 1 : 12, 0); bool result = _vm->_gui->transferFileMenu(target, dest); - _screen->copyPage(12, 0); + _screen->copyPage((_screen->getPageScaleFactor(0) == 2) ? 1 : 12, 0); return result; } diff --git a/engines/kyra/darkmoon.cpp b/engines/kyra/darkmoon.cpp index 918221e0dd..16bd3dad58 100644 --- a/engines/kyra/darkmoon.cpp +++ b/engines/kyra/darkmoon.cpp @@ -61,10 +61,11 @@ Common::Error DarkMoonEngine::init() { Palette pal(16); _screen->loadPalette(_egaDefaultPalette, pal, 16); _screen->setScreenPalette(pal); - } else { - _screen->loadPalette("palette.col", _screen->getPalette(0)); } + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); + _screen->setScreenPalette(_screen->getPalette(0)); + return Common::kNoError; } @@ -157,7 +158,9 @@ void DarkMoonEngine::generateMonsterPalettes(const char *file, int16 monsterInde int colx = 302 + 3 * i; for (int ii = 0; ii < 16; ii++) { - uint8 col = _screen->getPagePixel(_screen->_curPage, colx, 184 + ii); + // Don't use getPagePixel() here, since in EGA mode it will try to + // undither the pixel (although the shape bitmap is undithered already) + uint8 col = _screen->getCPagePtr(_screen->_curPage | 1)[(184 + ii) * Screen::SCREEN_W + colx]; int iii = 0; for (; iii < 16; iii++) { @@ -175,7 +178,9 @@ void DarkMoonEngine::generateMonsterPalettes(const char *file, int16 monsterInde memcpy(tmpPal, _monsterShapes[dci] + 4, 16); for (int iii = 0; iii < 16; iii++) { - uint8 col = _screen->getPagePixel(_screen->_curPage, colx + ii, 184 + iii); + // Don't use getPagePixel() here, since in EGA mode it will try to + // undither the pixel (although the shape bitmap is undithered already) + uint8 col = _screen->getCPagePtr(_screen->_curPage | 1)[(184 + iii) * Screen::SCREEN_W + colx + ii]; if (newPal[iii]) tmpPal[newPal[iii]] = col; } diff --git a/engines/kyra/eob.cpp b/engines/kyra/eob.cpp index 9e58affded..a7bde9f1ee 100644 --- a/engines/kyra/eob.cpp +++ b/engines/kyra/eob.cpp @@ -69,7 +69,7 @@ Common::Error EoBEngine::init() { _screen->loadPalette(_egaDefaultPalette, pal, 16); _screen->setScreenPalette(pal); } else { - _screen->loadPalette("palette.col", _screen->getPalette(0)); + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); } return Common::kNoError; diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp index 9bec256ec7..ff53ba8b0a 100644 --- a/engines/kyra/eobcommon.cpp +++ b/engines/kyra/eobcommon.cpp @@ -371,7 +371,7 @@ Common::Error EoBCoreEngine::init() { _screen = new Screen_EoB(this, _system); assert(_screen); - _screen->setResolution(); + _screen->setResolution(_flags.useHiResOverlay || (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA)); //MidiDriverType midiDriver = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB); _sound = new SoundAdLibPC(this, _mixer); @@ -1738,7 +1738,7 @@ void EoBCoreEngine::seq_portal() { bool EoBCoreEngine::checkPassword() { char answ[20]; Screen::FontId of = _screen->setFont(Screen::FID_8_FNT); - _screen->copyPage(0, 10); + _screen->copyPage(0, (_screen->getPageScaleFactor(0) == 2) ? 4 : 10); _screen->setScreenDim(13); gui_drawBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, guiSettings()->colors.frame1, guiSettings()->colors.frame2, -1); @@ -1765,7 +1765,7 @@ bool EoBCoreEngine::checkPassword() { _screen->modifyScreenDim(13, _screen->_curDim->sx - 1, _screen->_curDim->sy - 2, _screen->_curDim->w + 2, _screen->_curDim->h + 16); _screen->setFont(of); - _screen->copyPage(10, 0); + _screen->copyPage((_screen->getPageScaleFactor(0) == 2) ? 4 : 10, 0); return true; } diff --git a/engines/kyra/gui_eob.cpp b/engines/kyra/gui_eob.cpp index 39cc4692c4..eadfd10d1e 100644 --- a/engines/kyra/gui_eob.cpp +++ b/engines/kyra/gui_eob.cpp @@ -777,11 +777,11 @@ int EoBCoreEngine::clickedCamp(Button *button) { } _screen->copyPage(0, 7); - _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, 12, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, (_screen->getPageScaleFactor(0) == 2) ? 1 : 12, Screen::CR_NO_P_CHECK); _gui->runCampMenu(); - _screen->copyRegion(0, 0, 0, 120, 176, 24, 12, 2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 0, 0, 120, 176, 24, (_screen->getPageScaleFactor(0) == 2) ? 1 : 12, 2, Screen::CR_NO_P_CHECK); _screen->setScreenDim(cd); drawScene(0); @@ -1170,7 +1170,7 @@ int EoBCoreEngine::clickedSceneSpecial(Button *button) { int EoBCoreEngine::clickedSpellbookAbort(Button *button) { _updateFlags = 0; - _screen->copyRegion(0, 0, 64, 121, 112, 56, 10, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 0, 64, 121, 112, 56, (_screen->getPageScaleFactor(0) == 2) ? 4 : 10, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); gui_drawCompass(true); gui_toggleButtons(); @@ -1392,9 +1392,11 @@ GUI_EoB::GUI_EoB(EoBCoreEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) { _charSelectRedraw = false; + _highLightColorTable = (_vm->game() == GI_EOB1 && (_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA)) ? _highlightColorTableEGA : _highlightColorTableVGA; _updateBoxIndex = -1; _highLightBoxTimer = 0; _updateBoxColorIndex = 0; + _needRest = false; } @@ -2170,7 +2172,7 @@ void GUI_EoB::runCampMenu() { if (cnt > 4) { _vm->dropCharacter(selectCharacterDialogue(53)); _vm->gui_drawPlayField(false); - _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, 12, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, (_screen->getPageScaleFactor(0) == 2) ? 1 : 12, Screen::CR_NO_P_CHECK); _screen->setFont(Screen::FID_6_FNT); _vm->gui_drawAllCharPortraitsWithStats(); _screen->setFont(Screen::FID_8_FNT); @@ -2411,8 +2413,6 @@ void GUI_EoB::messageDialogue2(int dim, int id, int buttonTextCol) { } void GUI_EoB::updateBoxFrameHighLight(int box) { - static const uint8 colorTable[] = { 0x0F, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0x0C, 0xBC, 0xBA, 0xB8, 0xB6, 0xB4, 0xB2, 0xB0, 0x00 }; - if (_updateBoxIndex == box) { if (_updateBoxIndex == -1) return; @@ -2420,18 +2420,18 @@ void GUI_EoB::updateBoxFrameHighLight(int box) { if (_vm->_system->getMillis() <= _highLightBoxTimer) return; - if (!colorTable[_updateBoxColorIndex]) + if (!_highLightColorTable[_updateBoxColorIndex]) _updateBoxColorIndex = 0; - const EoBRect16 *r = &_updateBoxFrameHighLights[_updateBoxIndex]; - _screen->drawBox(r->x1, r->y1, r->x2, r->y2, colorTable[_updateBoxColorIndex++]); + const EoBRect16 *r = &_highlightFrames[_updateBoxIndex]; + _screen->drawBox(r->x1, r->y1, r->x2, r->y2, _highLightColorTable[_updateBoxColorIndex++]); _screen->updateScreen(); _highLightBoxTimer = _vm->_system->getMillis() + _vm->_tickLength; } else { if (_updateBoxIndex != -1) { - const EoBRect16 *r = &_updateBoxFrameHighLights[_updateBoxIndex]; + const EoBRect16 *r = &_highlightFrames[_updateBoxIndex]; _screen->drawBox(r->x1, r->y1, r->x2, r->y2, 12); _screen->updateScreen(); } @@ -2607,7 +2607,7 @@ Common::String GUI_EoB::transferTargetMenu(Common::Array &target break; } while (_saveSlotIdTemp[slot] == -1); - _screen->copyRegion(72, 14, 72, 14, 176, 144, 12, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(72, 14, 72, 14, 176, 144, (_screen->getPageScaleFactor(0) == 2) ? 7 : 12, 0, Screen::CR_NO_P_CHECK); _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h); return (slot < 6) ? _savegameList[_savegameOffset + slot] : Common::String(); @@ -4054,7 +4054,7 @@ void GUI_EoB::restParty_updateRestTime(int hours, bool init) { _screen->setFont(of); } -const EoBRect16 GUI_EoB::_updateBoxFrameHighLights[] = { +const EoBRect16 GUI_EoB::_highlightFrames[] = { { 0x00B7, 0x0001, 0x00F7, 0x0034 }, { 0x00FF, 0x0001, 0x013F, 0x0034 }, { 0x00B7, 0x0035, 0x00F7, 0x0068 }, @@ -4077,6 +4077,10 @@ const EoBRect16 GUI_EoB::_updateBoxFrameHighLights[] = { { 0x00A3, 0x0068, 0x00C3, 0x0089 } }; +const uint8 GUI_EoB::_highlightColorTableVGA[] = { 0x0F, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0x0C, 0xBC, 0xBA, 0xB8, 0xB6, 0xB4, 0xB2, 0xB0, 0x00 }; + +const uint8 GUI_EoB::_highlightColorTableEGA[] = { 0x0C, 0x0D, 0x0E, 0x0F, 0x0E, 0x0D, 0x00 }; + } // End of namespace Kyra #endif // ENABLE_EOB diff --git a/engines/kyra/gui_eob.h b/engines/kyra/gui_eob.h index 759ed641ce..f6be18ffbb 100644 --- a/engines/kyra/gui_eob.h +++ b/engines/kyra/gui_eob.h @@ -148,9 +148,12 @@ private: int _updateBoxIndex; int _updateBoxColorIndex; + const uint8 *_highLightColorTable; uint32 _highLightBoxTimer; - static const EoBRect16 _updateBoxFrameHighLights[]; + static const EoBRect16 _highlightFrames[]; + static const uint8 _highlightColorTableVGA[]; + static const uint8 _highlightColorTableEGA[]; }; } // End of namespace Kyra diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0ba173d9d0..b07e3a4965 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -221,7 +221,7 @@ void KyraEngine_HoF::pauseEngineIntern(bool pause) { Common::Error KyraEngine_HoF::init() { _screen = new Screen_HoF(this, _system); assert(_screen); - _screen->setResolution(); + _screen->setResolution(_flags.useHiResOverlay); _debugger = new Debugger_HoF(this); assert(_debugger); diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index d7e79575ec..e8a2c02e6e 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -172,7 +172,7 @@ Common::Error KyraEngine_LoK::init() { else _screen = new Screen_LoK(this, _system); assert(_screen); - _screen->setResolution(); + _screen->setResolution(_flags.useHiResOverlay); _debugger = new Debugger_LoK(this); assert(_debugger); diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 39ed0d038a..38f473a619 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -203,7 +203,7 @@ KyraEngine_MR::~KyraEngine_MR() { Common::Error KyraEngine_MR::init() { _screen = new Screen_MR(this, _system); assert(_screen); - _screen->setResolution(); + _screen->setResolution(_flags.useHiResOverlay); _debugger = new Debugger_v2(this); assert(_debugger); diff --git a/engines/kyra/kyra_rpg.cpp b/engines/kyra/kyra_rpg.cpp index 1e3890b124..121731e394 100644 --- a/engines/kyra/kyra_rpg.cpp +++ b/engines/kyra/kyra_rpg.cpp @@ -41,13 +41,17 @@ KyraRpgEngine::KyraRpgEngine(OSystem *system, const GameFlags &flags) : KyraEngi _currentLevel = 0; - _vmpPtr = 0; _vcnBlocks = 0; _vcfBlocks = 0; _vcnTransitionMask = 0; _vcnShift = 0; _vcnColTable = 0; + _vcnBlockWidth = 4; + _vcnBlockHeight = 8; + _vcnFlip0 = 0; + _vcnFlip1 = 1; _vmpPtr = 0; + _vmpSize = 0; _blockBrightness = _wllVcnOffset = 0; _blockDrawingBuffer = 0; _sceneWindowBuffer = 0; @@ -167,10 +171,17 @@ Common::Error KyraRpgEngine::init() { _wllWallFlags = new uint8[256]; memset(_wllWallFlags, 0, 256); + if (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA) { + _vcnBlockWidth <<= 1; + _vcnBlockHeight <<= 1; + SWAP(_vcnFlip0, _vcnFlip1); + } + _blockDrawingBuffer = new uint16[1320]; memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16)); - _sceneWindowBuffer = new uint8[21120]; - memset(_sceneWindowBuffer, 0, 21120); + uint32 swbSize = 22 * _vcnBlockWidth * 2 * 15 * _vcnBlockHeight; + _sceneWindowBuffer = new uint8[swbSize]; + memset(_sceneWindowBuffer, 0, swbSize); _lvlShapeTop = new int16[18]; memset(_lvlShapeTop, 0, 18 * sizeof(int16)); diff --git a/engines/kyra/kyra_rpg.h b/engines/kyra/kyra_rpg.h index f4678e302a..50a4c9bdc1 100644 --- a/engines/kyra/kyra_rpg.h +++ b/engines/kyra/kyra_rpg.h @@ -222,6 +222,7 @@ protected: uint16 _decorationCount; int16 _mappedDecorationsCount; uint16 *_vmpPtr; + uint16 _vmpSize; uint8 *_vcnBlocks; uint8 *_vcfBlocks; uint8 *_vcnTransitionMask; @@ -231,6 +232,10 @@ protected: uint8 *_sceneWindowBuffer; uint8 _blockBrightness; uint8 _wllVcnOffset; + uint8 _vcnBlockWidth; + uint8 _vcnBlockHeight; + uint8 _vcnFlip0; + uint8 _vcnFlip1; uint8 **_doorShapes; diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 0f7da7673b..7c67af2f13 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -230,7 +230,7 @@ KyraEngine_v1::~KyraEngine_v1() { delete _debugger; } -Common::Point KyraEngine_v1::getMousePos() const { +Common::Point KyraEngine_v1::getMousePos() { Common::Point mouse = _eventMan->getMousePos(); if (_flags.useHiResOverlay) { @@ -238,6 +238,9 @@ Common::Point KyraEngine_v1::getMousePos() const { mouse.y >>= 1; } + mouse.x /= screen()->getPageScaleFactor(0); + mouse.y /= screen()->getPageScaleFactor(0); + return mouse; } @@ -313,6 +316,8 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag) _mouseX >>= 1; _mouseY >>= 1; } + _mouseX /= screen()->getPageScaleFactor(0); + _mouseY /= screen()->getPageScaleFactor(0); keys = (event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800)); breakLoop = true; } break; @@ -325,6 +330,8 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag) _mouseX >>= 1; _mouseY >>= 1; } + _mouseX /= screen()->getPageScaleFactor(0); + _mouseY /= screen()->getPageScaleFactor(0); keys = (event.type == Common::EVENT_RBUTTONDOWN ? 201 : (202 | 0x800)); breakLoop = true; } break; diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 2c2901a753..95d58d4ab2 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -210,7 +210,7 @@ public: // input void setMousePos(int x, int y); - Common::Point getMousePos() const; + Common::Point getMousePos(); // config specific bool speechEnabled(); diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 38e9d33259..022a878e0a 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -364,7 +364,7 @@ GUI *LoLEngine::gui() const { Common::Error LoLEngine::init() { _screen = new Screen_LoL(this, _system); assert(_screen); - _screen->setResolution(); + _screen->setResolution(_flags.useHiResOverlay); _debugger = new Debugger_LoL(this); assert(_debugger); diff --git a/engines/kyra/magic_eob.cpp b/engines/kyra/magic_eob.cpp index fbddd620d1..b2949ce1d5 100644 --- a/engines/kyra/magic_eob.cpp +++ b/engines/kyra/magic_eob.cpp @@ -60,7 +60,7 @@ void EoBCoreEngine::useMagicBookOrSymbol(int charIndex, int type) { } if (!_updateFlags) - _screen->copyRegion(64, 121, 0, 0, 112, 56, 0, 10, Screen::CR_NO_P_CHECK); + _screen->copyRegion(64, 121, 0, 0, 112, 56, 0, (_screen->getPageScaleFactor(0) == 2) ? 4 : 10, Screen::CR_NO_P_CHECK); _updateFlags = 1; gui_setPlayFieldButtons(); gui_drawSpellbook(); diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp index 7f20c124ff..4a446aa3f3 100644 --- a/engines/kyra/saveload_eob.cpp +++ b/engines/kyra/saveload_eob.cpp @@ -298,7 +298,7 @@ Common::Error EoBCoreEngine::loadGameState(int slot) { useMagicBookOrSymbol(_openBookChar, _openBookType); } - _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, 12, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, (_screen->getPageScaleFactor(0) == 2) ? 1 : 12, Screen::CR_NO_P_CHECK); gui_toggleButtons(); setHandItem(_itemInHand); diff --git a/engines/kyra/scene_eob.cpp b/engines/kyra/scene_eob.cpp index 5a06fe7977..3db055db90 100644 --- a/engines/kyra/scene_eob.cpp +++ b/engines/kyra/scene_eob.cpp @@ -144,10 +144,10 @@ Common::String EoBCoreEngine::initLevelData(int sub) { const char *vmpPattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.EMP" : "%s.VMP"; Common::SeekableReadStream *s = _res->createReadStream(Common::String::format(vmpPattern, (const char *)pos)); - uint16 size = s->readUint16LE(); + _vmpSize = s->readUint16LE(); delete[] _vmpPtr; - _vmpPtr = new uint16[size]; - for (int i = 0; i < size; i++) + _vmpPtr = new uint16[_vmpSize]; + for (int i = 0; i < _vmpSize; i++) _vmpPtr[i] = s->readUint16LE(); delete s; @@ -185,6 +185,8 @@ Common::String EoBCoreEngine::initLevelData(int sub) { _screen->getPalette(0).copy(backupPal, 224, 32, 224); _screen->createFadeTable(src, _screen->getFadeTable(4), 12, 85); // grey (shadow) _screen->setFadeTableIndex(4); + if (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA) + _screen->setScreenPalette(_screen->getPalette(0)); } } @@ -280,25 +282,64 @@ void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { const char *filePattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.ECN" : "%s.VCN"; _screen->loadBitmap(Common::String::format(filePattern, _lastBlockDataFile).c_str(), 3, 3, 0); const uint8 *pos = _screen->getCPagePtr(3); - uint32 tlen = READ_LE_UINT16(pos) << 5; + + uint32 vcnSize = READ_LE_UINT16(pos) * _vcnBlockWidth * _vcnBlockHeight; pos += 2; - if (!(_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA))) - memcpy(_vcnColTable, pos, 32); + + const uint8 *colMap = pos; pos += 32; + delete[] _vcnBlocks; - _vcnBlocks = new uint8[tlen]; + _vcnBlocks = new uint8[vcnSize]; - if (_configRenderMode == Common::kRenderCGA) { + if (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA) { + const uint8 *egaTable = _screen->getEGADitheringTable(); + assert(_vmpPtr); + assert(egaTable); + + delete[] _vcnTransitionMask; + _vcnTransitionMask = new uint8[vcnSize]; + + for (int i = 0; i < _vmpSize; i++) { + uint16 vcnOffs = _vmpPtr[i] & 0x3FFF; + const uint8 *src = &pos[vcnOffs << 5]; + uint8 *dst1 = &_vcnBlocks[vcnOffs << 7]; + uint8 *dst3 = &_vcnTransitionMask[vcnOffs << 7]; + int palOffset = (i < 330) ? 0 : _wllVcnOffset; + + for (int y = 0; y < 8; y++) { + uint8 *dst2 = dst1 + 8; + uint8 *dst4 = dst3 + 8; + + for (int x = 0; x < 4; x++) { + uint8 in = *src++; + + dst1[0] = dst2[0] = egaTable[colMap[(in >> 4) + palOffset]]; + dst1[1] = dst2[1] = egaTable[colMap[(in & 0x0f) + palOffset]]; + dst3[0] = dst4[0] = (in & 0xf0) ? 0 : 0xff; + dst3[1] = dst4[1] = (in & 0x0f) ? 0 : 0xff; + + dst1 += 2; + dst2 += 2; + dst3 += 2; + dst4 += 2; + } + + dst1 += 8; + dst3 += 8; + } + } + } else if (_configRenderMode == Common::kRenderCGA) { uint8 *tmp = _screen->encodeShape(0, 0, 1, 8, false, cgaMapping); delete[] tmp; delete[] _vcnTransitionMask; - _vcnTransitionMask = new uint8[tlen]; + _vcnTransitionMask = new uint8[vcnSize]; uint8 tblSwitch = 0; uint8 *dst = _vcnBlocks; uint8 *dst2 = _vcnTransitionMask; - while (dst < _vcnBlocks + tlen) { + while (dst < _vcnBlocks + vcnSize) { const uint16 *table = _screen->getCGADitheringTable((tblSwitch++) & 1); for (int ii = 0; ii < 2; ii++) { *dst++ = ((table[pos[0]] & 0x000f) << 4) | ((table[pos[0]] & 0x0f00) >> 8); @@ -322,7 +363,9 @@ void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { } } } else { - memcpy(_vcnBlocks, pos, tlen); + if (_configRenderMode != Common::kRenderEGA) + memcpy(_vcnColTable, colMap, 32); + memcpy(_vcnBlocks, pos, vcnSize); } } diff --git a/engines/kyra/scene_rpg.cpp b/engines/kyra/scene_rpg.cpp index da7c9fdb90..b015b10cd9 100644 --- a/engines/kyra/scene_rpg.cpp +++ b/engines/kyra/scene_rpg.cpp @@ -348,6 +348,9 @@ bool KyraRpgEngine::checkSceneUpdateNeed(int block) { void KyraRpgEngine::drawVcnBlocks() { uint8 *d = _sceneWindowBuffer; uint16 *bdb = _blockDrawingBuffer; + uint16 pitch = 22 * _vcnBlockWidth * 2; + uint8 pxl[2]; + pxl[0] = pxl[1] = 0; for (int y = 0; y < 15; y++) { for (int x = 0; x < 22; x++) { @@ -371,7 +374,7 @@ void KyraRpgEngine::drawVcnBlocks() { uint8 *src = 0; if (vcnOffset) { - src = &_vcnBlocks[vcnOffset << 5]; + src = &_vcnBlocks[vcnOffset * _vcnBlockWidth * _vcnBlockHeight]; wllVcnOffset = _wllVcnOffset; } else { // floor/ceiling blocks @@ -381,36 +384,37 @@ void KyraRpgEngine::drawVcnBlocks() { vcnOffset &= 0x3fff; } - src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << 5); + src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset * _vcnBlockWidth * _vcnBlockHeight); } uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness; if (horizontalFlip) { - for (int blockY = 0; blockY < 8; blockY++) { - src += 3; - for (int blockX = 0; blockX < 4; blockX++) { + for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) { + src += (_vcnBlockWidth - 1); + for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) { uint8 bl = *src--; - *d++ = _vcnColTable[((bl & 0x0f) + wllVcnOffset) | shift]; - *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; + d[_vcnFlip0] = _vcnColTable[((bl & 0x0f) + wllVcnOffset) | shift]; + d[_vcnFlip1] = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; + d += 2; } - src += 5; - d += 168; + src += (_vcnBlockWidth + 1); + d += (pitch - 2 * _vcnBlockWidth); } } else { - for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4; blockX++) { + for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) { + for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) { uint8 bl = *src++; *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; *d++ = _vcnColTable[((bl & 0x0f) + wllVcnOffset) | shift]; } - d += 168; + d += (pitch - 2 * _vcnBlockWidth); } } - d -= 1400; + d -= (pitch * _vcnBlockHeight - 2 * _vcnBlockWidth); if (vcnExtraOffsetWll) { - d -= 8; + d -= (2 * _vcnBlockWidth); horizontalFlip = false; if (vcnExtraOffsetWll & 0x4000) { @@ -419,38 +423,38 @@ void KyraRpgEngine::drawVcnBlocks() { } shift = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness; - src = &_vcnBlocks[vcnExtraOffsetWll << 5]; - uint8 *maskTable = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll << 5] : 0; + src = &_vcnBlocks[vcnExtraOffsetWll * _vcnBlockWidth * _vcnBlockHeight]; + uint8 *maskTable = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll * _vcnBlockWidth * _vcnBlockHeight] : 0; if (horizontalFlip) { - for (int blockY = 0; blockY < 8; blockY++) { - src += 3; - maskTable += 3; - for (int blockX = 0; blockX < 4; blockX++) { + for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) { + src += (_vcnBlockWidth - 1); + maskTable += (_vcnBlockWidth - 1); + for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) { uint8 bl = *src--; uint8 mask = _vcnTransitionMask ? *maskTable-- : 0; - uint8 h = _vcnColTable[((bl & 0x0f) + wllVcnRmdOffset) | shift]; - uint8 l = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; + pxl[_vcnFlip0] = _vcnColTable[((bl & 0x0f) + wllVcnRmdOffset) | shift]; + pxl[_vcnFlip1] = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; if (_vcnTransitionMask) - *d = (*d & (mask & 0x0f)) | h; - else if (h) - *d = h; + *d = (*d & (mask & 0x0f)) | pxl[0]; + else if (pxl[0]) + *d = pxl[0]; d++; if (_vcnTransitionMask) - *d = (*d & (mask >> 4)) | l; - else if (l) - *d = l; + *d = (*d & (mask >> 4)) | pxl[1]; + else if (pxl[1]) + *d = pxl[1]; d++; } - src += 5; - maskTable += 5; - d += 168; + src += (_vcnBlockWidth + 1); + maskTable += (_vcnBlockWidth + 1); + d += (pitch - 2 * _vcnBlockWidth); } } else { - for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4; blockX++) { + for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) { + for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) { uint8 bl = *src++; uint8 mask = _vcnTransitionMask ? *maskTable++ : 0; uint8 h = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; @@ -468,13 +472,13 @@ void KyraRpgEngine::drawVcnBlocks() { *d = l; d++; } - d += 168; + d += (pitch - 2 * _vcnBlockWidth); } } - d -= 1400; + d -= (pitch * _vcnBlockHeight - 2 * _vcnBlockWidth); } } - d += 1232; + d += (pitch * (_vcnBlockHeight - 1)); } screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 3087a8a027..ef6333b350 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -39,7 +39,7 @@ namespace Kyra { Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize) : _system(system), _vm(vm), _sjisInvisibleColor(0), _dimTable(dimTable), _dimTableCount(dimTableSize), - _cursorColorKey((vm->game() == GI_KYRA1) ? 0xFF : 0x00) { + _cursorColorKey((vm->game() == GI_KYRA1 || vm->game() == GI_EOB1 || vm->game() == GI_EOB2) ? 0xFF : 0) { _debugEnabled = false; _maskMinY = _maskMaxY = -1; @@ -50,8 +50,14 @@ Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, co memset(_fonts, 0, sizeof(_fonts)); + memset(_pagePtrs, 0, sizeof(_pagePtrs)); + // Set scale factor to 1 (no scaling) for all pages + memset(_pageScaleFactor, 1, sizeof(_pageScaleFactor)); + // In VGA mode the odd and even page pointers point to the same buffers. + for (int i = 0; i < SCREEN_PAGE_NUM; i++) + _pageMapping[i] = i & ~1; + _renderMode = Common::kRenderDefault; - _cgaDrawCharDitheringTable = 0; _currentFont = FID_8_FNT; _paletteChanged = true; @@ -92,6 +98,12 @@ bool Screen::init() { if (ConfMan.hasKey("render_mode")) _renderMode = Common::parseRenderMode(ConfMan.get("render_mode")); + // CGA and EGA modes use additional pages to do the CGA/EGA specific graphics conversions. + if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) { + for (int i = 0; i < 8; i++) + _pageMapping[i] = i; + } + memset(_fonts, 0, sizeof(_fonts)); if (_vm->gameFlags().useHiResOverlay) { @@ -119,25 +131,28 @@ bool Screen::init() { _curPage = 0; - int numPages = SCREEN_PAGE_NUM / 2; - // CGA and EGA modes use additional pages to do the CGA/EGA specific graphics conversions. - if (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA) - numPages += 4; - - uint8 *pagePtr = new uint8[numPages * SCREEN_PAGE_SIZE]; - memset(pagePtr, 0, numPages * SCREEN_PAGE_SIZE); - - if (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA) { - // Unlike VGA mode the odd and even page numbers do not always point to the same buffers. - // Instead, the odd pages are used for CGA/EGA specific graphics conversions. - int pageNum = 0; - for (; pageNum < 8; pageNum++) - _pagePtrs[pageNum] = pagePtr + pageNum * SCREEN_PAGE_SIZE; - for (; pageNum < SCREEN_PAGE_NUM; pageNum += 2) - _pagePtrs[pageNum] = _pagePtrs[pageNum + 1] = pagePtr + (pageNum / 2) * SCREEN_PAGE_SIZE; - } else { - for (int pageNum = 0; pageNum < SCREEN_PAGE_NUM; pageNum += 2) - _pagePtrs[pageNum] = _pagePtrs[pageNum + 1] = pagePtr + (pageNum / 2) * SCREEN_PAGE_SIZE; + Common::Array realPages; + for (int i = 0; i < SCREEN_PAGE_NUM; i++) { + if (Common::find(realPages.begin(), realPages.end(), _pageMapping[i]) == realPages.end()) + realPages.push_back(_pageMapping[i]); + } + + int numPages = realPages.size(); + uint32 bufferSize = 0; + for (int i = 0; i < numPages; i++) + bufferSize += (SCREEN_PAGE_SIZE * _pageScaleFactor[realPages[i]] * _pageScaleFactor[realPages[i]]); + + uint8 *pagePtr = new uint8[bufferSize]; + memset(pagePtr, 0, bufferSize); + + memset(_pagePtrs, 0, sizeof(_pagePtrs)); + for (int i = 0; i < SCREEN_PAGE_NUM; i++) { + if (_pagePtrs[_pageMapping[i]]) { + _pagePtrs[i] = _pagePtrs[_pageMapping[i]]; + } else { + _pagePtrs[i] = pagePtr; + pagePtr += (SCREEN_PAGE_SIZE * _pageScaleFactor[i] * _pageScaleFactor[i]); + } } memset(_shapePages, 0, sizeof(_shapePages)); @@ -211,7 +226,7 @@ bool Screen::enableScreenDebug(bool enable) { if (_debugEnabled != enable) { _debugEnabled = enable; - setResolution(); + setResolution(_vm->gameFlags().useHiResOverlay); _forceFullUpdate = true; updateScreen(); } @@ -219,14 +234,14 @@ bool Screen::enableScreenDebug(bool enable) { return temp; } -void Screen::setResolution() { +void Screen::setResolution(bool hiRes) { byte palette[3*256]; _system->getPaletteManager()->grabPalette(palette, 0, 256); int width = 320, height = 200; bool defaultTo1xScaler = false; - if (_vm->gameFlags().useHiResOverlay) { + if (hiRes) { defaultTo1xScaler = true; height = 400; @@ -261,7 +276,7 @@ void Screen::updateScreen() { needRealUpdate = true; if (!_useOverlays) - _system->copyRectToScreen(getPagePtr(2), SCREEN_W, 320, 0, SCREEN_W, SCREEN_H); + _system->copyRectToScreen(getPagePtr(2), SCREEN_W, 320, 0, SCREEN_W * _pageScaleFactor[2], SCREEN_H * _pageScaleFactor[2]); else _system->copyRectToScreen(getPagePtr(2), SCREEN_W, 640, 0, SCREEN_W, SCREEN_H); } @@ -272,12 +287,12 @@ void Screen::updateScreen() { void Screen::updateDirtyRects() { if (_forceFullUpdate) { - _system->copyRectToScreen(getCPagePtr(0), SCREEN_W, 0, 0, SCREEN_W, SCREEN_H); + _system->copyRectToScreen(getCPagePtr(0), SCREEN_W * _pageScaleFactor[0], 0, 0, SCREEN_W * _pageScaleFactor[0], SCREEN_H * _pageScaleFactor[0]); } else { const byte *page0 = getCPagePtr(0); Common::List::iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { - _system->copyRectToScreen(page0 + it->top * SCREEN_W + it->left, SCREEN_W, it->left, it->top, it->width(), it->height()); + _system->copyRectToScreen(page0 + it->top * SCREEN_W * _pageScaleFactor[0] + it->left, SCREEN_W * _pageScaleFactor[0], it->left, it->top, it->width(), it->height()); } } _forceFullUpdate = false; @@ -451,6 +466,11 @@ const uint8 *Screen::getCPagePtr(int pageNum) const { return _pagePtrs[pageNum]; } +int Screen::getPageScaleFactor(int pageNum) { + assert(pageNum < SCREEN_PAGE_NUM); + return _pageScaleFactor[pageNum]; +} + uint8 *Screen::getPageRect(int pageNum, int x, int y, int w, int h) { assert(pageNum < SCREEN_PAGE_NUM); if (pageNum == 0 || pageNum == 1) @@ -462,7 +482,7 @@ void Screen::clearPage(int pageNum) { assert(pageNum < SCREEN_PAGE_NUM); if (pageNum == 0 || pageNum == 1) _forceFullUpdate = true; - memset(getPagePtr(pageNum), 0, SCREEN_PAGE_SIZE); + memset(getPagePtr(pageNum), 0, SCREEN_PAGE_SIZE * _pageScaleFactor[_curPage] * _pageScaleFactor[_curPage]); clearOverlayPage(pageNum); } @@ -476,7 +496,7 @@ int Screen::setCurPage(int pageNum) { void Screen::clearCurPage() { if (_curPage == 0 || _curPage == 1) _forceFullUpdate = true; - memset(getPagePtr(_curPage), 0, SCREEN_PAGE_SIZE); + memset(getPagePtr(_curPage), 0, SCREEN_PAGE_SIZE * _pageScaleFactor[_curPage] * _pageScaleFactor[_curPage]); clearOverlayPage(_curPage); } @@ -632,12 +652,17 @@ uint8 Screen::getPagePixel(int pageNum, int x, int y) { void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) { assert(pageNum < SCREEN_PAGE_NUM); assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H); + if (pageNum == 0 || pageNum == 1) addDirtyRect(x, y, 1, 1); if (_use16ColorMode) { color &= 0x0F; color |= (color << 4); + } else if (_renderMode == Common::kRenderCGA) { + color &= 0x03; + } else if (_renderMode == Common::kRenderEGA) { + color &= 0x0F; } _pagePtrs[pageNum][y * SCREEN_W + x] = color; @@ -845,16 +870,26 @@ void Screen::copyToPage0(int y, int h, uint8 page, uint8 *seqBuf) { } void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags) { + // Since we don't (need to) do any actual scaling, we check for compatible pages here + assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]); + + x1 *= _pageScaleFactor[srcPage]; + y1 *= _pageScaleFactor[srcPage]; + x2 *= _pageScaleFactor[dstPage]; + y2 *= _pageScaleFactor[dstPage]; + w *= _pageScaleFactor[srcPage]; + h *= _pageScaleFactor[srcPage]; + if (x2 < 0) { if (x2 <= -w) return; w += x2; x1 -= x2; x2 = 0; - } else if (x2 + w >= SCREEN_W) { - if (x2 > SCREEN_W) + } else if (x2 + w >= SCREEN_W * _pageScaleFactor[dstPage]) { + if (x2 > SCREEN_W * _pageScaleFactor[dstPage]) return; - w = SCREEN_W - x2; + w = SCREEN_W * _pageScaleFactor[srcPage] - x2; } if (y2 < 0) { @@ -863,14 +898,14 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag h += y2; y1 -= y2; y2 = 0; - } else if (y2 + h >= SCREEN_H) { - if (y2 > SCREEN_H) + } else if (y2 + h >= SCREEN_H * _pageScaleFactor[dstPage]) { + if (y2 > SCREEN_H * _pageScaleFactor[dstPage]) return; - h = SCREEN_H - y2; + h = SCREEN_H * _pageScaleFactor[srcPage] - y2; } - const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W + x1; - uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W + x2; + const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W * _pageScaleFactor[srcPage] + x1; + uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W * _pageScaleFactor[dstPage] + x2; if (src == dst) return; @@ -883,8 +918,8 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag if (flags & CR_NO_P_CHECK) { while (h--) { memmove(dst, src, w); - src += SCREEN_W; - dst += SCREEN_W; + src += SCREEN_W * _pageScaleFactor[srcPage]; + dst += SCREEN_W * _pageScaleFactor[dstPage]; } } else { while (h--) { @@ -892,19 +927,24 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag if (src[i]) dst[i] = src[i]; } - src += SCREEN_W; - dst += SCREEN_W; + src += SCREEN_W * _pageScaleFactor[srcPage]; + dst += SCREEN_W * _pageScaleFactor[dstPage]; } } } void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *dest) { + x *= _pageScaleFactor[pageNum]; + y *= _pageScaleFactor[pageNum]; + w *= _pageScaleFactor[pageNum]; + h *= _pageScaleFactor[pageNum]; + if (y < 0) { dest += (-y) * w; h += y; y = 0; } else if (y + h > SCREEN_H) { - h = SCREEN_H - y; + h = SCREEN_H * _pageScaleFactor[pageNum] - y; } if (x < 0) { @@ -912,7 +952,7 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 * w += x; x = 0; } else if (x + w > SCREEN_W) { - w = SCREEN_W - x; + w = SCREEN_W * _pageScaleFactor[pageNum] - x; } if (w < 0 || h < 0) @@ -921,14 +961,17 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 * uint8 *pagePtr = getPagePtr(pageNum); for (int i = y; i < y + h; ++i) - memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W + x, w); + memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W * _pageScaleFactor[pageNum] + x, w); } void Screen::copyPage(uint8 srcPage, uint8 dstPage) { + // Since we don't (need to) do any actual scaling, we check for compatible pages here + assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]); + uint8 *src = getPagePtr(srcPage); uint8 *dst = getPagePtr(dstPage); if (src != dst) - memcpy(dst, src, SCREEN_W * SCREEN_H); + memcpy(dst, src, SCREEN_W * _pageScaleFactor[srcPage] * SCREEN_H * _pageScaleFactor[srcPage]); copyOverlayRegion(0, 0, 0, 0, SCREEN_W, SCREEN_H, srcPage, dstPage); if (dstPage == 0 || dstPage == 1) @@ -955,7 +998,12 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint if (w < 0 || h < 0) return; - uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W + x; + x *= _pageScaleFactor[pageNum]; + y *= _pageScaleFactor[pageNum]; + w *= _pageScaleFactor[pageNum]; + h *= _pageScaleFactor[pageNum]; + + uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W * _pageScaleFactor[pageNum] + x; if (pageNum == 0 || pageNum == 1) addDirtyRect(x, y, w, h); @@ -964,7 +1012,7 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint while (h--) { memcpy(dst, src, w); - dst += SCREEN_W; + dst += SCREEN_W * _pageScaleFactor[pageNum]; src += w; } } @@ -1132,7 +1180,7 @@ void Screen::drawLine(bool vertical, int x, int y, int length, int color) { int currLine = 0; while (currLine < length) { *ptr = color; - ptr += SCREEN_W; + ptr += SCREEN_W * _pageScaleFactor[_curPage]; currLine++; } } else { @@ -1178,7 +1226,7 @@ bool Screen::loadFont(FontId fontId, const char *filename) { fnt = new AMIGAFont(); #ifdef ENABLE_EOB else if (_vm->game() == GI_EOB1 || _vm->game() == GI_EOB2) - fnt = new OldDOSFont(_renderMode, _cgaDrawCharDitheringTable); + fnt = new OldDOSFont(_renderMode, (_vm->game() == GI_EOB2) && (_renderMode == Common::kRenderEGA)); #endif // ENABLE_EOB else fnt = new DOSFont(); @@ -1265,12 +1313,12 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 break; } else if (c == '\r') { x = x_start; - y += charHeightFnt + _charOffset; + y += (charHeightFnt + _charOffset); } else { int charWidth = getCharWidth(c); if (x + charWidth > SCREEN_W) { x = x_start; - y += charHeightFnt + _charOffset; + y += (charHeightFnt + _charOffset); if (y >= SCREEN_H) break; } @@ -1307,6 +1355,9 @@ void Screen::drawChar(uint16 c, int x, int y) { if (x + charWidth > SCREEN_W || y + charHeight > SCREEN_H) return; + x *= _pageScaleFactor[_curPage]; + y *= _pageScaleFactor[_curPage]; + if (useOverlay) { uint8 *destPage = getOverlayPtr(_curPage); if (!destPage) { @@ -1318,11 +1369,11 @@ void Screen::drawChar(uint16 c, int x, int y) { fnt->drawChar(c, destPage, 640); } else { - fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W + x, SCREEN_W); + fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W * _pageScaleFactor[_curPage] + x, SCREEN_W * _pageScaleFactor[_curPage]); } if (_curPage == 0 || _curPage == 1) - addDirtyRect(x, y, charWidth, charHeight); + addDirtyRect(x, y, charWidth * _pageScaleFactor[_curPage], charHeight * _pageScaleFactor[_curPage]); } void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) { @@ -3084,16 +3135,11 @@ bool Screen::loadPalette(const char *filename, Palette &pal) { numCols = stream->size() / Palette::kPC98BytesPerColor; pal.loadPC98Palette(*stream, 0, MIN(maxCols, numCols)); } else if (_renderMode == Common::kRenderEGA) { - // EOB II checks the number of palette bytes to distinguish between real EGA palettes - // and normal palettes (which are used to generate a color map). - if (stream->size() == 16) { - numCols = 16; - pal.loadEGAPalette(*stream, 0, 16); - } else { - numCols = stream->size() / Palette::kVGABytesPerColor; - pal.loadVGAPalette(*stream, 0, numCols); - } - + numCols = stream->size(); + // There aren't any 16 color EGA palette files. So this shouldn't ever get triggered. + assert (numCols != 16); + numCols /= Palette::kVGABytesPerColor; + pal.loadVGAPalette(*stream, 0, numCols); } else { numCols = stream->size() / Palette::kVGABytesPerColor; pal.loadVGAPalette(*stream, 0, MIN(maxCols, numCols)); @@ -3163,7 +3209,7 @@ void Screen::addDirtyRect(int x, int y, int w, int h) { Common::Rect r(x, y, x + w, y + h); // Clip rectangle - r.clip(SCREEN_W, SCREEN_H); + r.clip(SCREEN_W * _pageScaleFactor[0], SCREEN_H * _pageScaleFactor[0]); // If it is empty after clipping, we are done if (r.isEmpty()) @@ -3270,6 +3316,8 @@ void Screen::crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int s if (srcPage > 13 || dstPage > 13) error("Screen::crossFadeRegion(): attempting to use temp page as source or dest page."); + assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]); + hideMouse(); uint16 *wB = (uint16 *)_pagePtrs[14]; @@ -3287,23 +3335,19 @@ void Screen::crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int s for (int i = 0; i < h; i++) SWAP(hB[_vm->_rnd.getRandomNumberRng(0, h - 1)], hB[i]); - uint8 *s = _pagePtrs[srcPage]; - uint8 *d = _pagePtrs[dstPage]; - for (int i = 0; i < h; i++) { int iH = i; uint32 end = _system->getMillis() + 3; for (int ii = 0; ii < w; ii++) { - int sX = x1 + wB[ii]; - int sY = y1 + hB[iH]; - int dX = x2 + wB[ii]; - int dY = y2 + hB[iH]; + int sX = (x1 + wB[ii]); + int sY = (y1 + hB[iH]); + int dX = (x2 + wB[ii]); + int dY = (y2 + hB[iH]); if (++iH >= h) iH = 0; - d[dY * 320 + dX] = s[sY * 320 + sX]; - addDirtyRect(dX, dY, 1, 1); + setPagePixel(dstPage, dX, dY, getPagePixel(srcPage, sX, sY)); } // This tries to speed things up, to get similiar speeds as in DOSBox etc. diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index fcb5ef2be4..18c0aa90f7 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -145,7 +145,7 @@ private: */ class OldDOSFont : public Font { public: - OldDOSFont(Common::RenderMode mode, const uint16 *cgaDitheringTable); + OldDOSFont(Common::RenderMode mode, bool useHiResEGADithering); ~OldDOSFont(); bool load(Common::SeekableReadStream &file); @@ -167,7 +167,10 @@ private: int _numGlyphs; Common::RenderMode _renderMode; - const uint16 *_cgaDitheringTable; + bool _useHiResEGADithering; + + static uint16 *_cgaDitheringTable; + static int _numRef; }; #endif // ENABLE_EOB @@ -395,7 +398,7 @@ public: // init virtual bool init(); - virtual void setResolution(); + virtual void setResolution(bool hiRes = false); void updateScreen(); @@ -422,14 +425,16 @@ public: void copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint8 *src); void shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPage, int ticks, bool transparent); - void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false); + virtual void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false); void clearPage(int pageNum); - uint8 getPagePixel(int pageNum, int x, int y); - void setPagePixel(int pageNum, int x, int y, uint8 color); + virtual uint8 getPagePixel(int pageNum, int x, int y); + virtual void setPagePixel(int pageNum, int x, int y, uint8 color); const uint8 *getCPagePtr(int pageNum) const; + int getPageScaleFactor(int pageNum); + uint8 *getPageRect(int pageNum, int x, int y, int w, int h); // palette handling @@ -453,7 +458,7 @@ public: void copyPalette(const int dst, const int src); // gui specific (processing on _curPage) - void drawLine(bool vertical, int x, int y, int length, int color); + virtual void drawLine(bool vertical, int x, int y, int length, int color); void drawClippedLine(int x1, int y1, int x2, int y2, int color); virtual void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2); void drawBox(int x1, int y1, int x2, int y2, int color); @@ -468,7 +473,7 @@ public: int getCharWidth(uint16 c) const; int getTextWidth(const char *str) const; - void printText(const char *str, int x, int y, uint8 color1, uint8 color2); + virtual void printText(const char *str, int x, int y, uint8 color1, uint8 color2); virtual void setTextColorMap(const uint8 *cmap) = 0; void setTextColor(const uint8 *cmap, int a, int b); @@ -569,13 +574,14 @@ protected: uint8 *_pagePtrs[16]; uint8 *_sjisOverlayPtrs[SCREEN_OVLS_NUM]; + uint8 _pageScaleFactor[SCREEN_PAGE_NUM]; + uint8 _pageMapping[SCREEN_PAGE_NUM]; bool _useOverlays; bool _useSJIS; bool _use16ColorMode; bool _isAmiga; Common::RenderMode _renderMode; - uint16 *_cgaDrawCharDitheringTable; uint8 _sjisInvisibleColor; diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp index 51665a00b1..38521d757c 100644 --- a/engines/kyra/screen_eob.cpp +++ b/engines/kyra/screen_eob.cpp @@ -51,7 +51,7 @@ Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _dsScaleTrans = 0; _cgaScaleTable = 0; _gfxMaxY = 0; - _egaColorMap = 0; + _egaDitheringTable = 0; _egaPixelValueTable = 0; _cgaMappingDefault = 0; _cgaDitheringTables[0] = _cgaDitheringTables[1] = 0; @@ -62,11 +62,10 @@ Screen_EoB::~Screen_EoB() { delete[] _fadeData; delete[] _dsTempPage; delete[] _cgaScaleTable; - delete[] _egaColorMap; + delete[] _egaDitheringTable; delete[] _egaPixelValueTable; delete[] _cgaDitheringTables[0]; delete[] _cgaDitheringTables[1]; - delete[] _cgaDrawCharDitheringTable; } bool Screen_EoB::init() { @@ -74,6 +73,12 @@ bool Screen_EoB::init() { } bool Screen_EoB::init(bool useHiResEGADithering) { + // Define hi-res pages for EGA mode in EOB II + if (useHiResEGADithering) { + for (int i = 0; i < 8; i++) + _pageScaleFactor[i] = 2; + } + if (Screen::init()) { int temp; _gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp); @@ -96,10 +101,10 @@ bool Screen_EoB::init(bool useHiResEGADithering) { if (_renderMode == Common::kRenderEGA) { _useHiResEGADithering = useHiResEGADithering; - _egaColorMap = new uint8[256]; + _egaDitheringTable = new uint8[256]; _egaPixelValueTable = new uint8[256]; for (int i = 0; i < 256; i++) { - _egaColorMap[i] = i & 0x0f; + _egaDitheringTable[i] = i & 0x0f; _egaPixelValueTable[i] = i & 0x0f; } @@ -110,12 +115,6 @@ bool Screen_EoB::init(bool useHiResEGADithering) { _cgaDitheringTables[1] = new uint16[256]; memset(_cgaDitheringTables[1], 0, 256 * sizeof(uint16)); - _cgaDrawCharDitheringTable = new uint16[256]; - memset(_cgaDrawCharDitheringTable, 0, 256 * sizeof(uint16)); - static const uint bits[] = { 0, 3, 12, 15 }; - for (int i = 0; i < 256; i++) - _cgaDrawCharDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4); - _cgaScaleTable = new uint8[256]; memset(_cgaScaleTable, 0, 256 * sizeof(uint8)); for (int i = 0; i < 256; i++) @@ -143,13 +142,19 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape) { void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl) { if (!shape) return; - int mouseW = shape[2] << 3; - int mouseH = shape[3]; - uint8 *cursor = new uint8[mouseW * mouseH]; - fillRect(0, 0, mouseW, mouseH, _cursorColorKey, 8); - drawShape(8, shape, 0, 0, 0, 2, ovl); + + int mouseW = (shape[2] << 3); + int mouseH = (shape[3]); + int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : _cursorColorKey; + + uint8 *cursor = new uint8[mouseW * _pageScaleFactor[6] * mouseH * _pageScaleFactor[6]]; + // We use memset and copyBlockToPage instead of fillRect to make sure that the + // color key 0xFF doesn't get converted into EGA color + memset (cursor, colorKey, mouseW * _pageScaleFactor[6] * mouseH * _pageScaleFactor[6]); + copyBlockToPage(6, 0, 0, mouseW, mouseH, cursor); + drawShape(6, shape, 0, 0, 0, 2, ovl); CursorMan.showMouse(false); - copyRegionToBuffer(8, 0, 0, mouseW, mouseH, cursor); + copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor); // Mouse cursor post processing for CGA mode. Unlike the original (which uses drawShape for the mouse cursor) // the cursor manager cannot know whether a pixel value of 0 is supposed to be black or transparent. Thus, we @@ -174,7 +179,7 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ov } } - CursorMan.replaceCursor(cursor, mouseW, mouseH, x, y, _cursorColorKey); + CursorMan.replaceCursor(cursor, mouseW * _pageScaleFactor[6], mouseH * _pageScaleFactor[6], x, y, colorKey); if (isMouseVisible()) CursorMan.showMouse(true); delete[] cursor; @@ -190,6 +195,19 @@ void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, s->read(_pagePtrs[pageNum], size); } +void Screen_EoB::printText(const char *str, int x, int y, uint8 color1, uint8 color2) { + if (_useHiResEGADithering) { + // This is sort of an abuse of the text color map. But since EOB doesn't use it anyway + // and the font drawing code needs access to both the original color values and the + // EGA dithering colors we pass them on like this. + uint8 cmap[2]; + cmap[0] = _egaDitheringTable[color2]; + cmap[1] = _egaDitheringTable[color1]; + setTextColor(cmap, 2, 3); + } + Screen::printText(str, x, y, color1, color2); +} + void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2) { printText(string, x - 1, y, 12, col2); printText(string, x, y + 1, 12, 0); @@ -256,87 +274,153 @@ void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) if (_renderMode == Common::kRenderCGA) { if (cgaMapping) generateCGADitheringTables(cgaMapping); + uint16 *d = (uint16*)dst; uint8 tblSwitch = 0; for (int height = SCREEN_H; height; height--) { const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1]; for (int width = SCREEN_W / 2; width; width--) { - *d++ = table[((src[1] & 0x0f) << 4) | (src[0] & 0x0f)]; + WRITE_LE_UINT16(d++, table[((src[1] & 0x0f) << 4) | (src[0] & 0x0f)]); src += 2; } } - if (dstPage == 0 || dstPage == 1) - _forceFullUpdate = true; + } else if (_useHiResEGADithering) { + for (int height = SCREEN_H; height; height--) { + uint8 *dst2 = dst + SCREEN_W * 2; + for (int width = SCREEN_W; width; width--) { + uint8 in = _egaDitheringTable[*src++]; + *dst++ = *dst2++ = in >> 4; + *dst++ = *dst2++ = in & 0x0f; + } + dst += (SCREEN_W * 2); + } } else if (_renderMode == Common::kRenderEGA) { uint32 len = SCREEN_W * SCREEN_H; - if (_useHiResEGADithering) { - while (len--) { - uint8 col = _egaColorMap[*src++] & 0x0f; - *dst++ = col; + while (len--) + *dst++ = *src++ & 0x0f; + + } else { + copyPage(srcPage, dstPage); + } - /*for (int i = 4; i; i--) { - uint8 col = _egaColorMap[*src++]; + if (dstPage == 0 || dstPage == 1) + _forceFullUpdate = true; +} - }*/ - } - } else { - while (len--) - *dst++ = *src++ & 0x0f; +void Screen_EoB::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum, bool xored) { + if (!_useHiResEGADithering) { + Screen::fillRect(x1, y1, x2, y2, color, pageNum, xored); + return; + } + + assert(x2 < SCREEN_W && y2 < SCREEN_H); + if (pageNum == -1) + pageNum = _curPage; + + uint16 pitch = (SCREEN_W - (x2 - x1 + 1)) * _pageScaleFactor[pageNum]; + uint8 col1 = (_egaDitheringTable[color] >> 4); + uint8 col2 = (_egaDitheringTable[color] & 0x0f); + + x1 *= _pageScaleFactor[pageNum]; + y1 *= _pageScaleFactor[pageNum]; + x2 *= _pageScaleFactor[pageNum]; + y2 *= _pageScaleFactor[pageNum]; + uint16 w = x2 - x1 + _pageScaleFactor[pageNum]; + uint16 h = y2 - y1 + _pageScaleFactor[pageNum]; + + uint8 *dst = getPagePtr(pageNum) + y1 * SCREEN_W * _pageScaleFactor[pageNum] + x1; + if (pageNum == 0 || pageNum == 1) + addDirtyRect(x1, y1, w, h); + + while (h--) { + for (uint16 w1 = w; w1; w1 -= 2) { + *dst++ = col1; + *dst++ = col2; } + dst += pitch; + } +} - if (dstPage == 0 || dstPage == 1) - _forceFullUpdate = true; +void Screen_EoB::drawLine(bool vertical, int x, int y, int length, int color) { + if (!_useHiResEGADithering) { + Screen::drawLine(vertical, x, y, length, color); + return; + } + + uint16 pitch = (SCREEN_W - 1) * _pageScaleFactor[_curPage]; + uint8 col1 = (_egaDitheringTable[color] >> 4); + uint8 col2 = (_egaDitheringTable[color] & 0x0f); + + x *= _pageScaleFactor[_curPage]; + y *= _pageScaleFactor[_curPage]; + length *= _pageScaleFactor[_curPage]; + uint8 *ptr = getPagePtr(_curPage) + y * SCREEN_W * _pageScaleFactor[_curPage] + x; + uint8 *ptr2 = ptr + SCREEN_W * _pageScaleFactor[_curPage]; + + if (vertical) { + assert((y + length) <= SCREEN_H * _pageScaleFactor[_curPage]); + int currLine = 0; + while (currLine < length) { + *ptr++ = col1; + *ptr++ = col2; + ptr += pitch; + currLine++; + } } else { - copyPage(srcPage, dstPage); + assert((x + length) <= SCREEN_W * _pageScaleFactor[_curPage]); + int currLine = 0; + while (currLine < length) { + *ptr++ = *ptr2++ = col1; + *ptr++ = *ptr2++ = col2; + currLine += 2; + } } + + if (_curPage == 0 || _curPage == 1) + addDirtyRect(x, y, (vertical) ? _pageScaleFactor[_curPage] : length, (vertical) ? length : _pageScaleFactor[_curPage]); } -void Screen_EoB::setScreenPalette(const Palette &pal) { - if (_renderMode == Common::kRenderEGA && _egaColorMap && pal.getNumColors() != 16) { - const uint8 *src = pal.getData(); - uint8 *dst = _egaColorMap; - - for (int i = 256; i; i--) { - uint8 r = *src++; - uint8 g = *src++; - uint8 b = *src++; - - uint8 col = 0; - uint16 min = 11907; - - for (int ii = 256; ii; ii--) { - const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3; - if (*palEntry == 0xff) - continue; - - int e_r = palEntry[0]; - e_r -= r; - int e_g = palEntry[1]; - e_g -= g; - int e_b = palEntry[2]; - e_b -= b; - - int s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b); - - if (s < min) { - min = s; - col = ii - 1; - } - } - *dst++ = col; - } +uint8 Screen_EoB::getPagePixel(int pageNum, int x, int y) { + if (!_useHiResEGADithering) + return Screen::getPagePixel(pageNum, x, y); - memset(_egaPixelValueTable, 0, 256); - for (int i = 0; i < 256; i++) - _egaPixelValueTable[_egaColorMap[i]] = i; + x *= _pageScaleFactor[_curPage]; + y *= _pageScaleFactor[_curPage]; + uint8 *pos = &_pagePtrs[pageNum][y * SCREEN_W * _pageScaleFactor[_curPage] + x]; - } else if (_renderMode == Common::kRenderEGA) { + return _egaPixelValueTable[(pos[0] << 4) | (pos[1] & 0x0f)]; +} + +void Screen_EoB::setPagePixel(int pageNum, int x, int y, uint8 color) { + if (!_useHiResEGADithering) { + Screen::setPagePixel(pageNum, x, y, color); + return; + } + + assert(pageNum < SCREEN_PAGE_NUM); + assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H); + + x *= _pageScaleFactor[_curPage]; + y *= _pageScaleFactor[_curPage]; + + if (pageNum == 0 || pageNum == 1) + addDirtyRect(x, y, _pageScaleFactor[pageNum], _pageScaleFactor[pageNum]); + + uint8 *pos = &_pagePtrs[pageNum][y * SCREEN_W * _pageScaleFactor[_curPage] + x]; + uint8 *pos2 = pos + SCREEN_W * _pageScaleFactor[_curPage]; + pos[0] = pos2[0] = _egaDitheringTable[color] >> 4; + pos[1] = pos2[1] = _egaDitheringTable[color] & 0x0f; +} + +void Screen_EoB::setScreenPalette(const Palette &pal) { + if (_useHiResEGADithering && pal.getNumColors() != 16) { + generateEGADitheringTable(pal); + } else if (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16) { _screenPalette->copy(pal); _system->getPaletteManager()->setPalette(_screenPalette->getData(), 0, _screenPalette->getNumColors()); - - } else if (_renderMode != Common::kRenderCGA) { + } else if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) { Screen::setScreenPalette(pal); } } @@ -457,7 +541,7 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco uint8 nib = 0, col = 0; uint8 *colorMap = 0; - if (_renderMode != Common::kRenderEGA) { + if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) { colorMap = new uint8[0x100]; memset(colorMap, 0xff, 0x100); } @@ -472,7 +556,7 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco *dst++ = (w & 0xff); *dst++ = (h & 0xff); - if (_renderMode == Common::kRenderEGA) { + if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) { for (int i = 0; i < 16; i++) dst[i] = i; } else { @@ -536,7 +620,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, y += _dsY1; } - dst += (_dsX1 << 3); + dst += (_dsX1 << 3) * _pageScaleFactor[pageNum]; int16 dX = x - (_dsX1 << 3); int16 dY = y; int16 dW = _dsX2 - _dsX1; @@ -608,11 +692,11 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, marginRight = w2 - marginLeft - width; } - dst += (dY * 320 + dX); + dst += (dY * SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum] + dX * _pageScaleFactor[pageNum]); uint8 *dstL = dst; if (pageNum == 0 || pageNum == 1) - addDirtyRect(rX, rY, rW, rH); + addDirtyRect(rX * _pageScaleFactor[pageNum], rY * _pageScaleFactor[pageNum], rW * _pageScaleFactor[pageNum], rH * _pageScaleFactor[pageNum]); while (dH--) { int16 xpos = (int16) marginLeft; @@ -647,7 +731,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, } while (xpos > 0); } - dst -= xpos; + dst -= (xpos * _pageScaleFactor[pageNum]); xpos += width; while (xpos > 0) { @@ -656,11 +740,12 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, src += pixelStep; if (m) { - drawShapeSetPixel(dst++, c); + drawShapeSetPixel(dst, c, SCREEN_W * _pageScaleFactor[pageNum]); + dst += _pageScaleFactor[pageNum]; xpos--; } else { uint8 len = (flags & 1) ? src[1] : src[0]; - dst += len; + dst += (len * _pageScaleFactor[pageNum]); xpos -= len; src += pixelStep; } @@ -686,7 +771,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, } while (xpos > 0); } - dstL += 320; + dstL += SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum]; dst = dstL; if (flags & 1) src = src2 + 1; @@ -754,12 +839,12 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, if (d < width) width = d; - dst += (dY * 320 + dX); + dst += (dY * _pageScaleFactor[pageNum] * SCREEN_W * _pageScaleFactor[pageNum] + dX * _pageScaleFactor[pageNum]); if (pageNum == 0 || pageNum == 1) - addDirtyRect(rX, rY, rW, rH); + addDirtyRect(rX * _pageScaleFactor[pageNum], rY * _pageScaleFactor[pageNum], rW * _pageScaleFactor[pageNum], rH * _pageScaleFactor[pageNum]); - int pitch = 320 - width; + int pitch = SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum] - width * _pageScaleFactor[pageNum]; int16 lineSrcStep = (w2 - width) / pixelsPerByte; uint8 lineSrcStepRemainder = (w2 - width) % pixelsPerByte; @@ -802,9 +887,9 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, } uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask]; if (col || pixelsPerByte == 4) - drawShapeSetPixel(dst, col); - dst++; - shift = (shift - (pixelStep * pixelPacking) & 7); + drawShapeSetPixel(dst, col, SCREEN_W * _pageScaleFactor[pageNum]); + dst += _pageScaleFactor[pageNum]; + shift = ((shift - (pixelStep * pixelPacking)) & 7); } src += lineSrcStep; dst += pitch; @@ -1266,25 +1351,36 @@ const uint16 *Screen_EoB::getCGADitheringTable(int index) { return !(index & ~1) ? _cgaDitheringTables[index] : 0; } -void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 c) { +const uint8 *Screen_EoB::getEGADitheringTable() { + return _egaDitheringTable; +} + +void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col, uint16 pitch) { if ((_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering) { if (_shapeFadeMode[0]) { if (_shapeFadeMode[1]) { - c = *dst; + col = _useHiResEGADithering ? _egaPixelValueTable[(dst[0] << 4) | (dst[1] & 0x0f)] : *dst; } else { _shapeFadeInternal &= 7; - c = *(dst + _shapeFadeInternal++); + col = _useHiResEGADithering ? _egaPixelValueTable[(dst[_shapeFadeInternal] << 4) | (dst[_shapeFadeInternal + 1] & 0x0f)] : dst[_shapeFadeInternal]; + _shapeFadeInternal++; } } if (_shapeFadeMode[1]) { uint8 cnt = _shapeFadeMode[1]; while (cnt--) - c = _fadeData[_fadeDataIndex + c]; + col = _fadeData[_fadeDataIndex + col]; } } - *dst = c; + if (_useHiResEGADithering) { + col = _egaDitheringTable[col]; + dst[0] = dst[pitch] = col >> 4; + dst[1] = dst[pitch + 1] = col & 0x0f; + } else { + *dst = col; + } } void Screen_EoB::scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc) { @@ -1340,6 +1436,43 @@ bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y return true; } +void Screen_EoB::generateEGADitheringTable(const Palette &pal) { + assert(_egaDitheringTable); + const uint8 *src = pal.getData(); + uint8 *dst = _egaDitheringTable; + + for (int i = 256; i; i--) { + int r = *src++; + int g = *src++; + int b = *src++; + + uint8 col = 0; + uint16 min = 0x2E83; + + for (int ii = 256; ii; ii--) { + const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3; + if (*palEntry == 0xff) + continue; + + int e_r = palEntry[0] - r; + int e_g = palEntry[1] - g; + int e_b = palEntry[2] - b; + + uint16 s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b); + + if (s <= min) { + min = s; + col = ii - 1; + } + } + *dst++ = col; + } + + memset(_egaPixelValueTable, 0, 256); + for (int i = 0; i < 256; i++) + _egaPixelValueTable[_egaDitheringTable[i]] = i; +} + void Screen_EoB::generateCGADitheringTables(const uint8 *mappingData) { for (int i = 0; i < 256; i++) { _cgaDitheringTables[0][i] = (mappingData[(i >> 4) + 16] << 8) | mappingData[i & 0x0f]; @@ -1398,14 +1531,34 @@ const uint8 Screen_EoB::_egaMatchTable[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F }; -OldDOSFont::OldDOSFont(Common::RenderMode mode, const uint16 *cgaDitheringTable) : _renderMode(mode), _cgaDitheringTable(cgaDitheringTable) { +uint16 *OldDOSFont::_cgaDitheringTable = 0; +int OldDOSFont::_numRef = 0; + +OldDOSFont::OldDOSFont(Common::RenderMode mode, bool useHiResEGADithering) : _renderMode(mode), _useHiResEGADithering(useHiResEGADithering) { _data = 0; _width = _height = _numGlyphs = 0; _bitmapOffsets = 0; + + _numRef++; + if (!_cgaDitheringTable && _numRef == 1) { + _cgaDitheringTable = new uint16[256]; + memset(_cgaDitheringTable, 0, 256 * sizeof(uint16)); + static const uint bits[] = { 0, 3, 12, 15 }; + for (int i = 0; i < 256; i++) + _cgaDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4); + } } OldDOSFont::~OldDOSFont() { unload(); + + if (_numRef) + --_numRef; + + if (_cgaDitheringTable && !_numRef) { + delete[] _cgaDitheringTable; + _cgaDitheringTable = 0; + } } bool OldDOSFont::load(Common::SeekableReadStream &file) { @@ -1491,18 +1644,27 @@ void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { } const uint8 *src = &_data[_bitmapOffsets[c]]; + uint8 *dst2 = dst + pitch; int w = (_width - 1) >> 3; pitch -= _width; + if (_useHiResEGADithering) + pitch *= 2; + uint8 color1 = _colorMap[1]; uint8 color2 = _colorMap[0]; + uint8 colEGA11 = _colorMap[3] >> 4; + uint8 colEGA12 = _colorMap[3] & 0x0f; + uint8 colEGA21 = _colorMap[2] >> 4; + uint8 colEGA22 = _colorMap[2] & 0x0f; + static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF }; uint16 cgaMask1 = cgaColorMask[color1 & 3]; uint16 cgaMask2 = cgaColorMask[color2 & 3]; - if (_renderMode == Common::kRenderCGA) { + if (_renderMode == Common::kRenderCGA || (_renderMode == Common::kRenderEGA && !_useHiResEGADithering)) { color1 &= 0x0f; color2 &= 0x0f; } @@ -1559,13 +1721,27 @@ void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { break; } - if (s & i) { - if (color1) - *dst = color1; - } else if (color2) { - *dst = color2; + if (_useHiResEGADithering) { + if (s & i) { + if (color1) { + dst[0] = dst2[0] = colEGA11; + dst[1] = dst2[1] = colEGA12; + } + } else if (color2) { + dst[0] = dst2[0] = colEGA21; + dst[1] = dst2[1] = colEGA22; + } + dst += 2; + dst2 += 2; + } else { + if (s & i) { + if (color1) + *dst = color1; + } else if (color2) { + *dst = color2; + } + dst++; } - dst++; } if (cW) @@ -1574,7 +1750,9 @@ void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const { runWidthLoop = false; } } + dst += pitch; + dst2 += pitch; } } diff --git a/engines/kyra/screen_eob.h b/engines/kyra/screen_eob.h index cf8f86953d..2bcfbd8f60 100644 --- a/engines/kyra/screen_eob.h +++ b/engines/kyra/screen_eob.h @@ -46,12 +46,19 @@ public: void loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size); + void printText(const char *str, int x, int y, uint8 color1, uint8 color2); void printShadedText(const char *string, int x, int y, int col1, int col2); + void loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage); void loadShapeSetBitmap(const char *file, int tempPage, int destPage); void convertPage(int srcPage, int dstPage, const uint8 *cgaMapping); + void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false); + void drawLine(bool vertical, int x, int y, int length, int color); + uint8 getPagePixel(int pageNum, int x, int y); + void setPagePixel(int pageNum, int x, int y, uint8 color); + void setScreenPalette(const Palette &pal); uint8 *encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit = false, const uint8 *cgaMapping = 0); @@ -76,14 +83,17 @@ public: void setFadeTableIndex(int index); void createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight); uint8 *getFadeTable(int index); + const uint16 *getCGADitheringTable(int index); + const uint8 *getEGADitheringTable(); private: - void drawShapeSetPixel(uint8 *dst, uint8 c); + void drawShapeSetPixel(uint8 *dst, uint8 col, uint16 pitch); void scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc); void scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src); bool posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2); + void generateEGADitheringTable(const Palette &pal); void generateCGADitheringTables(const uint8 *mappingData); int _dsDiv, _dsRem, _dsScaleTrans; @@ -104,7 +114,7 @@ private: uint16 *_cgaDitheringTables[2]; const uint8 *_cgaMappingDefault; - uint8 *_egaColorMap; + uint8 *_egaDitheringTable; uint8 *_egaPixelValueTable; bool _useHiResEGADithering; -- cgit v1.2.3