From 02000cfe371784fe5eb46e063a0391fa1ec2001f Mon Sep 17 00:00:00 2001 From: athrxx Date: Mon, 25 Mar 2019 21:46:18 +0100 Subject: KYRA: (EOB2/Amiga) - add special gfx decoder for localized version --- engines/kyra/engine/eobcommon.cpp | 36 +++++-- engines/kyra/engine/scene_eob.cpp | 7 +- engines/kyra/graphics/screen_eob.cpp | 144 ++++++++++++++++++++++++--- engines/kyra/graphics/screen_eob.h | 3 + engines/kyra/sequence/sequences_darkmoon.cpp | 6 +- 5 files changed, 167 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp index 792cf10008..1c75c78d70 100644 --- a/engines/kyra/engine/eobcommon.cpp +++ b/engines/kyra/engine/eobcommon.cpp @@ -1346,10 +1346,15 @@ void EoBCoreEngine::npcSequence(int npcIndex) { drawNpcScene(npcIndex); Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT"); - if (s) + if (s) { _screen->loadFileDataToPage(s, 5, 32000); - else - _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); + } else { + s = _res->createReadStream("TEXT.CPS"); + if (s->readSint32BE() + 12 == s->size()) + _screen->loadSpecialAmigaCPS("TEXT.CPS", 5, false); + else + _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); + } delete s; gui_drawBox(0, 121, 320, 79, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); @@ -1597,12 +1602,18 @@ void EoBCoreEngine::initDialogueSequence() { snd_stopSound(); Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT"); - if (s) + if (s) { _screen->loadFileDataToPage(s, 5, 32000); - else - _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); - _txt->setupField(9, 0); + } else { + s = _res->createReadStream("TEXT.CPS"); + if (s->readSint32BE() + 12 == s->size()) + _screen->loadSpecialAmigaCPS("TEXT.CPS", 5, false); + else + _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); + } delete s; + + _txt->setupField(9, 0); } void EoBCoreEngine::restoreAfterDialogueSequence() { @@ -1804,10 +1815,15 @@ void EoBCoreEngine::displayParchment(int id) { if (id >= 0) { // display text Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT"); - if (s) + if (s) { _screen->loadFileDataToPage(s, 5, 32000); - else - _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); + } else { + s = _res->createReadStream("TEXT.CPS"); + if (s->readSint32BE() + 12 == s->size()) + _screen->loadSpecialAmigaCPS("TEXT.CPS", 5, false); + else + _screen->loadBitmap("TEXT.CPS", 5, 5, 0, true); + } delete s; _screen->set16bitShadingLevel(4); gui_drawBox(0, 0, 176, 175, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); diff --git a/engines/kyra/engine/scene_eob.cpp b/engines/kyra/engine/scene_eob.cpp index f010069f63..9a2f4e2f93 100644 --- a/engines/kyra/engine/scene_eob.cpp +++ b/engines/kyra/engine/scene_eob.cpp @@ -132,7 +132,12 @@ void EoBCoreEngine::readLevelFileData(int level) { if (s) { s->seek(0); - _screen->loadFileDataToPage(s, 5, 15000); + if (s->readSint32BE() + 12 == s->size()) { + _screen->loadSpecialAmigaCPS(file.c_str(), 5, false); + } else { + s->seek(0); + _screen->loadFileDataToPage(s, 5, 15000); + } delete s; } } diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp index b3c0393e8a..2e2674d9dd 100644 --- a/engines/kyra/graphics/screen_eob.cpp +++ b/engines/kyra/graphics/screen_eob.cpp @@ -29,9 +29,11 @@ #include "kyra/engine/eobcommon.h" #include "kyra/resource/resource.h" +#include "kyra/engine/util.h" #include "common/system.h" #include "common/translation.h" +#include "common/memstream.h" #include "graphics/cursorman.h" #include "graphics/palette.h" @@ -267,9 +269,10 @@ void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int te if (s->size() == 0) { loadAlternative = true; - // This check is due to EOB II Amiga German.That version simply checks - // for certain file names which aren't actual CPS files. The files contain - // raw data. I check the header size info to identify these. + // This check is due to EOB II Amiga German. That version simply checks + // for certain file names which aren't actual CPS files. These files use + // a diffenrent format and compression type. I check the header size + // info to identify these. } else if (_vm->gameFlags().platform == Common::kPlatformAmiga) { // Tolerance for diffenrences up to 2 bytes is needed in some cases if ((((s->readUint16LE()) + 5) & ~3) != (((s->size()) + 3) & ~3)) @@ -291,18 +294,7 @@ void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int te loadBitmap(tmp.c_str(), tempPage, destPage, 0); } else if (_vm->gameFlags().platform == Common::kPlatformAmiga) { - s = _vm->resource()->createReadStream(tmp); - if (!s) - error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file); - - // See comment above. In addition to checking for certain file names which - // aren't real CPS files the EOB II Amiga German makes a specific check for CHARGEN.CPS - // which contains palette data at the beginning. For now I haven't come up - // with a way of avoiding this hack. - if (tmp.equals("CHARGEN.CPS")) - _palettes[0]->loadAmigaPalette(*s, 0, 32); - - loadFileDataToPage(s, destPage, 40000); + loadSpecialAmigaCPS(tmp.c_str(), destPage, true); } else { tmp.setChar('X', 0); @@ -1529,6 +1521,128 @@ void Screen_EoB::shadeRect(int x1, int y1, int x2, int y2, int shadingLevel) { _16bitShadingLevel = l; } +static uint32 _decodeFrameAmiga_x = 0; + +bool decodeFrameAmiga_readNextBit(const uint8 *&data, uint32 &code, uint32 &chk) { + _decodeFrameAmiga_x = code & 1; + code >>= 1; + if (code) + return _decodeFrameAmiga_x; + + data -= 4; + code = READ_BE_UINT32(data); + chk ^= code; + _decodeFrameAmiga_x = code & 1; + code = (code >> 1) | (1 << 31); + + return _decodeFrameAmiga_x; +} + +uint32 decodeFrameAmiga_readBits(const uint8 *&data, uint32 &code, uint32 &chk, int count) { + uint32 res = 0; + while (count--) { + decodeFrameAmiga_readNextBit(data, code, chk); + uint32 bt1 = _decodeFrameAmiga_x; + _decodeFrameAmiga_x = res >> 31; + res = (res << 1) | bt1; + } + return res; +} + +void Screen_EoB::loadSpecialAmigaCPS(const char *fileName, int destPage, bool isGraphics) { + uint32 fileSize = 0; + const uint8 *file = _vm->resource()->fileData(fileName, &fileSize); + + if (!file) + error("Screen_EoB::loadSpecialAmigaCPS(): Failed to load file '%s'", file); + + uint32 inSize = READ_BE_UINT32(file); + const uint8 *pos = file; + + // Check whether the file starts with the actual compression header. + // If this is not the case, there should a palette before the header. + // Unlike normal CPS files these files never have more than one palette. + if (((inSize + 15) & ~3) != ((fileSize + 3) & ~3)) { + Common::MemoryReadStream in(pos, 64); + _palettes[0]->loadAmigaPalette(in, 0, 32); + pos += 64; + } + + inSize = READ_BE_UINT32(pos); + uint32 outSize = READ_BE_UINT32(pos + 4); + uint32 chk = READ_BE_UINT32(pos + 8); + + pos = pos + 8 + inSize; + uint8 *dstStart = _pagePtrs[destPage]; + uint8 *dst = dstStart + outSize; + + uint32 val = READ_BE_UINT32(pos); + _decodeFrameAmiga_x = 0; + chk ^= val; + + while (dst > dstStart) { + int para = -1; + int para2 = 0; + + if (decodeFrameAmiga_readNextBit(pos, val, chk)) { + uint32 code = decodeFrameAmiga_readBits(pos, val, chk, 2); + + if (code == 3) { + para = para2 = 8; + } else { + int cnt = 0; + if (code < 2) { + cnt = 3 + code; + para2 = 9 + code; + } else { + cnt = decodeFrameAmiga_readBits(pos, val, chk, 8) + 1; + para2 = 12; + } + + code = decodeFrameAmiga_readBits(pos, val, chk, para2); + while (cnt--) { + dst--; + *dst = dst[code & 0xFFFF]; + } + } + } else { + if (decodeFrameAmiga_readNextBit(pos, val, chk)) { + uint32 code = decodeFrameAmiga_readBits(pos, val, chk, 8); + dst--; + *dst = dst[code & 0xFFFF]; + dst--; + *dst = dst[code & 0xFFFF]; + + } else { + para = 3; + } + } + + if (para > 0) { + uint32 code = decodeFrameAmiga_readBits(pos, val, chk, para); + uint32 cnt = (code & 0xFFFF) + para2 + 1; + + while (cnt--) { + for (int i = 0; i < 8; ++i) { + decodeFrameAmiga_readNextBit(pos, val, chk); + uint32 bt1 = _decodeFrameAmiga_x; + _decodeFrameAmiga_x = code >> 31; + code = (code << 1) | bt1; + } + *(--dst) = code & 0xFF; + } + } + } + + delete[] file; + + if (chk) + error("Screen_EoB::loadSpecialAmigaCPS(): Checksum error"); + + if (isGraphics) + convertAmigaGfx(_pagePtrs[destPage], 320, 200); +} + void Screen_EoB::updateDirtyRects() { if (!_useHiResEGADithering) { Screen::updateDirtyRects(); diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h index 42a03ca225..66efc25cc0 100644 --- a/engines/kyra/graphics/screen_eob.h +++ b/engines/kyra/graphics/screen_eob.h @@ -90,6 +90,9 @@ public: void convertToHiColor(int page); void shadeRect(int x1, int y1, int x2, int y2, int shadingLevel); + // Amiga specific + void loadSpecialAmigaCPS(const char *fileName, int destPage, bool isGraphics); + private: void updateDirtyRects(); void ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey = -1); diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp index 86e837ec51..b92eb74fde 100644 --- a/engines/kyra/sequence/sequences_darkmoon.cpp +++ b/engines/kyra/sequence/sequences_darkmoon.cpp @@ -131,7 +131,7 @@ int DarkMoonEngine::mainMenu() { while (menuChoice >= 0 && !shouldQuit()) { switch (menuChoice) { case 0: { - if (_flags.platform == Common::kPlatformFMTowns) { + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformAmiga) { _screen->loadPalette("MENU.PAL", _screen->getPalette(0)); _screen->setScreenPalette(_screen->getPalette(0)); _screen->loadEoBBitmap("MENU", 0, 3, 3, 2); @@ -1341,8 +1341,8 @@ void DarkmoonSequenceHelper::loadScene(int index, int pageNum, bool ignorePalett _screen->loadBitmap(_config->cpsFiles[index], pageNum | 1, pageNum | 1, ignorePalette ? 0 : _palettes[0]); } else if (s && _vm->gameFlags().platform == Common::kPlatformAmiga) { - _screen->loadFileDataToPage(s, 5, 64000); - _screen->decodeLocalizedAmigaPage(5, pageNum, true); + delete s; + _screen->loadSpecialAmigaCPS(_config->cpsFiles[index], pageNum | 1, true); } else { if (!s) { -- cgit v1.2.3