From 946597d3b293fa75d7f0a39f345ad07a36052bd1 Mon Sep 17 00:00:00 2001 From: athrxx Date: Sat, 16 Feb 2019 00:51:42 +0100 Subject: KYRA: (EOB1/Amiga) - fix level graphics --- engines/kyra/engine/kyra_rpg.cpp | 19 ++- engines/kyra/engine/kyra_rpg.h | 37 ++++- engines/kyra/engine/scene_eob.cpp | 27 ++-- engines/kyra/engine/scene_rpg.cpp | 288 +++++++++++++++++++++++--------------- 4 files changed, 247 insertions(+), 124 deletions(-) diff --git a/engines/kyra/engine/kyra_rpg.cpp b/engines/kyra/engine/kyra_rpg.cpp index 3d7a4df208..46fef3fcff 100644 --- a/engines/kyra/engine/kyra_rpg.cpp +++ b/engines/kyra/engine/kyra_rpg.cpp @@ -43,12 +43,16 @@ KyraRpgEngine::KyraRpgEngine(OSystem *system, const GameFlags &flags) : KyraEngi _vcnBlocks = 0; _vcfBlocks = 0; - _vcnTransitionMask = 0; + _vcnTransitionMask = _vcnMaskTbl = 0; _vcnShift = 0; _vcnColTable = 0; + _vcnShiftVal = 0; _vcnBpp = flags.useHiColorMode ? 2 : 1; + _vcnSrcBitsPerPixel = (flags.platform == Common::kPlatformAmiga) ? 5 : (_vcnBpp == 2 ? 8 : 4); + _vcnDrawLine = 0; + _vmpPtr = 0; - _blockBrightness = _wllVcnOffset = 0; + _blockBrightness = _wllVcnOffset = _wllVcnOffset2 = _wllVcnRmdOffset = 0; _blockDrawingBuffer = 0; _sceneWindowBuffer = 0; _monsterShapes = _monsterPalettes = 0; @@ -135,6 +139,7 @@ KyraRpgEngine::~KyraRpgEngine() { delete[] _vcnShift; delete[] _blockDrawingBuffer; delete[] _sceneWindowBuffer; + delete _vcnDrawLine; delete[] _lvlShapeTop; delete[] _lvlShapeBottom; @@ -184,6 +189,16 @@ Common::Error KyraRpgEngine::init() { for (int i = 0; i < 128; i++) _vcnColTable[i] = i & 0x0F; + if (_vcnBpp == 2) + _vcnDrawLine = new VcnLineDrawingMethods(new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_hiCol), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_hiCol), + new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_trans_hiCol), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_trans_hiCol)); + else if (_flags.platform == Common::kPlatformAmiga) + _vcnDrawLine = new VcnLineDrawingMethods(new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_Amiga), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_Amiga), + new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_trans_Amiga), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_trans_Amiga)); + else + _vcnDrawLine = new VcnLineDrawingMethods(new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_4bit), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_4bit), + new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_fw_trans_4bit), new VcnDrawProc(this, &KyraRpgEngine::vcnDraw_bw_trans_4bit)); + _doorShapes = new uint8*[6]; memset(_doorShapes, 0, 6 * sizeof(uint8 *)); diff --git a/engines/kyra/engine/kyra_rpg.h b/engines/kyra/engine/kyra_rpg.h index 0e04c77f46..dbdd2560e2 100644 --- a/engines/kyra/engine/kyra_rpg.h +++ b/engines/kyra/engine/kyra_rpg.h @@ -198,9 +198,39 @@ protected: bool hasWall(int index); void assignVisibleBlocks(int block, int direction); bool checkSceneUpdateNeed(int block); - void drawVcnBlocks(); uint16 calcNewBlockPosition(uint16 curBlock, uint16 direction); + void drawVcnBlocks(); + void vcnDraw_fw_4bit(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_4bit(uint8 *&dst, const uint8 *&src); + void vcnDraw_fw_trans_4bit(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_trans_4bit(uint8 *&dst, const uint8 *&src); + void vcnDraw_fw_hiCol(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_hiCol(uint8 *&dst, const uint8 *&src); + void vcnDraw_fw_trans_hiCol(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_trans_hiCol(uint8 *&dst, const uint8 *&src); + void vcnDraw_fw_Amiga(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_Amiga(uint8 *&dst, const uint8 *&src); + void vcnDraw_fw_trans_Amiga(uint8 *&dst, const uint8 *&src); + void vcnDraw_bw_trans_Amiga(uint8 *&dst, const uint8 *&src); + + typedef Common::Functor2Mem VcnDrawProc; + struct VcnLineDrawingMethods { + VcnLineDrawingMethods(VcnDrawProc *fw, VcnDrawProc *bw, VcnDrawProc *fw_t, VcnDrawProc *bw_t) : forward(fw), backwards(bw), forward_trans(fw_t), backwards_trans(bw_t) {} + ~VcnLineDrawingMethods() { + delete forward; + delete backwards; + delete forward_trans; + delete backwards_trans; + } + + VcnDrawProc *forward; + VcnDrawProc *backwards; + VcnDrawProc *forward_trans; + VcnDrawProc *backwards_trans; + }; + VcnLineDrawingMethods *_vcnDrawLine; + virtual int clickedDoorSwitch(uint16 block, uint16 direction) = 0; int clickedWallShape(uint16 block, uint16 direction); int clickedLeverOn(uint16 block, uint16 direction); @@ -232,13 +262,18 @@ protected: uint8 *_vcnBlocks; uint8 *_vcfBlocks; uint8 *_vcnTransitionMask; + uint8 *_vcnMaskTbl; uint8 *_vcnShift; + uint8 _vcnShiftVal; uint8 *_vcnColTable; + uint8 _vcnSrcBitsPerPixel; uint8 _vcnBpp; uint16 *_blockDrawingBuffer; uint8 *_sceneWindowBuffer; uint8 _blockBrightness; uint8 _wllVcnOffset; + uint8 _wllVcnOffset2; + uint8 _wllVcnRmdOffset; uint8 **_doorShapes; diff --git a/engines/kyra/engine/scene_eob.cpp b/engines/kyra/engine/scene_eob.cpp index 539d81da6c..0bd4ca9072 100644 --- a/engines/kyra/engine/scene_eob.cpp +++ b/engines/kyra/engine/scene_eob.cpp @@ -30,7 +30,6 @@ #include "common/system.h" - namespace Kyra { void EoBCoreEngine::loadLevel(int level, int sub) { @@ -298,14 +297,15 @@ void EoBCoreEngine::addLevelItems() { } } -void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { +void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { if (file) strcpy(_lastBlockDataFile, file); + delete[] _vcnBlocks; + uint32 vcnSize = 0; + if (_flags.platform == Common::kPlatformFMTowns) { - uint32 size; - delete[] _vcnBlocks; - _vcnBlocks = _res->fileData(Common::String::format("%s.VCC", _lastBlockDataFile).c_str(), &size); + _vcnBlocks = _res->fileData(Common::String::format("%s.VCC", _lastBlockDataFile).c_str(), &vcnSize); return; } @@ -314,22 +314,24 @@ void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { if (_flags.platform == Common::kPlatformAmiga) { Common::SeekableReadStream *in = _res->createReadStream(fn); - uint16 size = in->readUint16LE() << 5; - in->seek(0, SEEK_SET); - _screen->loadFileDataToPage(in, 3, size + 34); + vcnSize = in->readUint16LE() * (_vcnSrcBitsPerPixel << 3); + _vcnBlocks = new uint8[vcnSize]; + _screen->getPalette(0).loadAmigaPalette(*in, 1, 5); + in->seek(22, SEEK_CUR); + in->read(_vcnBlocks, vcnSize); delete in; - } else { - _screen->loadBitmap(fn.c_str(), 3, 3, 0, true); + return; } + _screen->loadBitmap(fn.c_str(), 3, 3, 0, true); + const uint8 *pos = _screen->getCPagePtr(3); - uint16 vcnSize = READ_LE_UINT16(pos) << 5; + vcnSize = READ_LE_UINT16(pos) * (_vcnSrcBitsPerPixel << 3); pos += 2; const uint8 *colMap = pos; pos += 32; - delete[] _vcnBlocks; _vcnBlocks = new uint8[vcnSize]; if (_configRenderMode == Common::kRenderCGA) { @@ -355,6 +357,7 @@ void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { } else { if (!(_flags.gameID == GI_EOB1 && _configRenderMode == Common::kRenderEGA)) memcpy(_vcnColTable, colMap, 32); + memcpy(_vcnBlocks, pos, vcnSize); } } diff --git a/engines/kyra/engine/scene_rpg.cpp b/engines/kyra/engine/scene_rpg.cpp index 0528df6db1..4c0a97e7c7 100644 --- a/engines/kyra/engine/scene_rpg.cpp +++ b/engines/kyra/engine/scene_rpg.cpp @@ -344,24 +344,28 @@ bool KyraRpgEngine::checkSceneUpdateNeed(int block) { return false; } +uint16 KyraRpgEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) { + static const int16 blockPosTable[] = { -32, 1, 32, -1 }; + return (curBlock + blockPosTable[direction]) & 0x3FF; +} + void KyraRpgEngine::drawVcnBlocks() { uint8 *d = _sceneWindowBuffer; uint16 *bdb = _blockDrawingBuffer; - uint16 *hiColorPal = screen()->get16bitPalette(); - + for (int y = 0; y < 15; y++) { for (int x = 0; x < 22; x++) { bool horizontalFlip = false; uint16 vcnOffset = *bdb++; uint16 vcnExtraOffsetWll = 0; - int wllVcnOffset = 0; - int wllVcnRmdOffset = 0; + _wllVcnOffset2 = 0; + _wllVcnRmdOffset = 0; if (vcnOffset & 0x8000) { // this renders a wall block over the transparent pixels of a floor/ceiling block vcnExtraOffsetWll = vcnOffset - 0x8000; vcnOffset = 0; - wllVcnRmdOffset = _wllVcnOffset; + _wllVcnRmdOffset = _wllVcnOffset; } if (vcnOffset & 0x4000) { @@ -371,8 +375,8 @@ void KyraRpgEngine::drawVcnBlocks() { const uint8 *src = 0; if (vcnOffset) { - src = &_vcnBlocks[vcnOffset << (4 + _vcnBpp)]; - wllVcnOffset = _wllVcnOffset; + src = &_vcnBlocks[vcnOffset * (_vcnSrcBitsPerPixel << 3)]; + _wllVcnOffset2 = _wllVcnOffset; } else { // floor/ceiling blocks vcnOffset = bdb[329]; @@ -381,46 +385,22 @@ void KyraRpgEngine::drawVcnBlocks() { vcnOffset &= 0x3FFF; } - src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << (4 + _vcnBpp)); + src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset * (_vcnSrcBitsPerPixel << 3)); } - uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness; + _vcnShiftVal = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness; - if (horizontalFlip) { - for (int blockY = 0; blockY < 8; blockY++) { - src += ((_vcnBpp << 2) - 1); - for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { - if (_vcnBpp == 2) { - *(uint16*)d = hiColorPal[*src--]; - d += 2; - } else { - uint8 bl = *src--; - *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; - *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; - } - } - src += ((_vcnBpp << 2) + 1); - d += 168 * _vcnBpp; - } - } else { - for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { - if (_vcnBpp == 2) { - *(uint16*)d = hiColorPal[*src++]; - d += 2; - } else { - uint8 bl = *src++; - *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; - *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; - } - } - d += 168 * _vcnBpp; - } + for (int blockY = 0; blockY < 8; blockY++) { + if (horizontalFlip) + (*_vcnDrawLine->backwards)(d, src); + else + (*_vcnDrawLine->forward)(d, src); + d += 168 * _vcnBpp; } d -= 1400 * _vcnBpp; if (vcnExtraOffsetWll) { - d -= 8 * _vcnBpp; + d -= (8 * _vcnBpp); horizontalFlip = false; if (vcnExtraOffsetWll & 0x4000) { @@ -428,72 +408,16 @@ void KyraRpgEngine::drawVcnBlocks() { horizontalFlip = true; } - shift = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness; - src = &_vcnBlocks[vcnExtraOffsetWll << (4 + _vcnBpp)]; - uint8 *maskTable = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll << 5] : 0; - - if (horizontalFlip) { - for (int blockY = 0; blockY < 8; blockY++) { - src += ((_vcnBpp << 2) - 1); - maskTable += 3; - for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { - if (_vcnBpp == 2) { - uint8 bl = *src--; - if (bl) - *(uint16*)d = hiColorPal[bl]; - d += 2; - } else { - uint8 bl = *src--; - uint8 mask = _vcnTransitionMask ? *maskTable-- : 0; - uint8 h = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; - uint8 l = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; - - if (_vcnTransitionMask) - *d = (*d & (mask & 0x0F)) | h; - else if (h) - *d = h; - d++; - - if (_vcnTransitionMask) - *d = (*d & (mask >> 4)) | l; - else if (l) - *d = l; - d++; - } - } - src += ((_vcnBpp << 2) + 1); - maskTable += 5; - d += 168 * _vcnBpp; - } - } else { - for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { - if (_vcnBpp == 2) { - uint8 bl = *src++; - if (bl) - *(uint16*)d = hiColorPal[bl]; - d += 2; - } else { - uint8 bl = *src++; - uint8 mask = _vcnTransitionMask ? *maskTable++ : 0; - uint8 h = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; - uint8 l = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; - - if (_vcnTransitionMask) - *d = (*d & (mask >> 4)) | h; - else if (h) - *d = h; - d++; - - if (_vcnTransitionMask) - *d = (*d & (mask & 0x0F)) | l; - else if (l) - *d = l; - d++; - } - } - d += 168 * _vcnBpp; - } + _vcnShiftVal = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness; + src = &_vcnBlocks[vcnExtraOffsetWll * (_vcnSrcBitsPerPixel << 3)]; + _vcnMaskTbl = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll * (_vcnSrcBitsPerPixel << 3)] : 0; + + for (int blockY = 0; blockY < 8; blockY++) { + if (horizontalFlip) + (*_vcnDrawLine->backwards_trans)(d, src); + else + (*_vcnDrawLine->forward_trans)(d, src); + d += 168 * _vcnBpp; } d -= 1400 * _vcnBpp; } @@ -504,11 +428,157 @@ void KyraRpgEngine::drawVcnBlocks() { screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer); } -uint16 KyraRpgEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) { - static const int16 blockPosTable[] = { -32, 1, 32, -1 }; - return (curBlock + blockPosTable[direction]) & 0x3FF; +void KyraRpgEngine::vcnDraw_fw_4bit(uint8 *&dst, const uint8 *&src) { + for (int blockX = 0; blockX < 4; blockX++) { + uint8 bl = *src++; + *dst++ = _vcnColTable[((bl >> 4) + _wllVcnOffset2) | _vcnShiftVal]; + *dst++ = _vcnColTable[((bl & 0x0F) + _wllVcnOffset2) | _vcnShiftVal]; + } +} + +void KyraRpgEngine::vcnDraw_bw_4bit(uint8 *&dst, const uint8 *&src) { + src += 3; + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + uint8 bl = *src--; + *dst++ = _vcnColTable[((bl & 0x0F) + _wllVcnOffset2) | _vcnShiftVal]; + *dst++ = _vcnColTable[((bl >> 4) + _wllVcnOffset2) | _vcnShiftVal]; + } + src += 5; +} + +void KyraRpgEngine::vcnDraw_fw_trans_4bit(uint8 *&dst, const uint8 *&src) { + for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) { + uint8 bl = *src++; + uint8 mask = _vcnTransitionMask ? *_vcnMaskTbl++ : 0; + uint8 h = _vcnColTable[((bl >> 4) + _wllVcnRmdOffset) | _vcnShiftVal]; + uint8 l = _vcnColTable[((bl & 0x0F) + _wllVcnRmdOffset) | _vcnShiftVal]; + + if (_vcnTransitionMask) + *dst = (*dst & (mask >> 4)) | h; + else if (h) + *dst = h; + dst++; + + if (_vcnTransitionMask) + *dst = (*dst & (mask & 0x0F)) | l; + else if (l) + *dst = l; + dst++; + } +} + +void KyraRpgEngine::vcnDraw_bw_trans_4bit(uint8 *&dst, const uint8 *&src) { + src += 3; + _vcnMaskTbl += 3; + for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) { + uint8 bl = *src--; + uint8 mask = _vcnTransitionMask ? *_vcnMaskTbl-- : 0; + uint8 h = _vcnColTable[((bl & 0x0F) + _wllVcnRmdOffset) | _vcnShiftVal]; + uint8 l = _vcnColTable[((bl >> 4) + _wllVcnRmdOffset) | _vcnShiftVal]; + + if (_vcnTransitionMask) + *dst = (*dst & (mask & 0x0F)) | h; + else if (h) + *dst = h; + dst++; + + if (_vcnTransitionMask) + *dst = (*dst & (mask >> 4)) | l; + else if (l) + *dst = l; + dst++; + } + src += 5; + _vcnMaskTbl += 5; } +void KyraRpgEngine::vcnDraw_fw_hiCol(uint8 *&dst, const uint8 *&src) { + const uint16 *hiColorPal = screen()->get16bitPalette(); + for (int blockX = 0; blockX < 8; blockX++) { + *(uint16*)dst = hiColorPal[*src++]; + dst += 2; + } +} + +void KyraRpgEngine::vcnDraw_bw_hiCol(uint8 *&dst, const uint8 *&src) { + src += 7; + const uint16 *hiColorPal = screen()->get16bitPalette(); + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + *(uint16*)dst = hiColorPal[*src--]; + dst += 2; + } + src += 9; +} + +void KyraRpgEngine::vcnDraw_fw_trans_hiCol(uint8 *&dst, const uint8 *&src) { + const uint16 *hiColorPal = screen()->get16bitPalette(); + for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) { + uint8 bl = *src++; + if (bl) + *(uint16*)dst = hiColorPal[bl]; + dst += 2; + } +} + +void KyraRpgEngine::vcnDraw_bw_trans_hiCol(uint8 *&dst, const uint8 *&src) { + src += 7; + const uint16 *hiColorPal = screen()->get16bitPalette(); + for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) { + uint8 bl = *src--; + if (bl) + *(uint16*)dst = hiColorPal[bl]; + dst += 2; + } + src += 9; +} + +void KyraRpgEngine::vcnDraw_fw_Amiga(uint8 *&dst, const uint8 *&src) { + for (int blockX = 0; blockX < 8; blockX++) { + *dst = 0; + for (int i = 0; i < 5; ++i) + *dst |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i); + dst++; + } + src += 5; +} + +void KyraRpgEngine::vcnDraw_bw_Amiga(uint8 *&dst, const uint8 *&src) { + for (int blockX = 7; blockX >= 0; blockX--) { + *dst = 0; + for (int i = 0; i < 5; ++i) + *dst |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i); + dst++; + } + src += 5; +} + +void KyraRpgEngine::vcnDraw_fw_trans_Amiga(uint8 *&dst, const uint8 *&src) { + for (int blockX = 0; blockX < 8; blockX++) { + uint8 col = 0; + for (int i = 0; i < 5; ++i) + col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i); + + if (col) + *dst = col; + dst++; + } + src += 5; +} + +void KyraRpgEngine::vcnDraw_bw_trans_Amiga(uint8 *&dst, const uint8 *&src) { + for (int blockX = 7; blockX >= 0; blockX--) { + uint8 col = 0; + for (int i = 0; i < 5; ++i) + col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i); + + if (col) + *dst = col; + dst++; + } + src += 5; +} + + int KyraRpgEngine::clickedWallShape(uint16 block, uint16 direction) { uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]]; if (!clickedShape(v)) -- cgit v1.2.3