From 59576f461c9149ff8e396a7c0ba07df389ed3086 Mon Sep 17 00:00:00 2001 From: CommonLoon102 Date: Tue, 20 Apr 2021 10:40:50 +0200 Subject: [PATCH] fixed graphics glitches with PSX backgrounds --- game.cpp | 14 +++++++++----- game.h | 1 + level1_rock.cpp | 3 +++ level2_fort.cpp | 1 + level3_pwr1.cpp | 6 +++++- level4_isld.cpp | 2 ++ level5_lava.cpp | 1 + level7_lar1.cpp | 4 ++++ level8_lar2.cpp | 2 ++ mdec.cpp | 38 +++++++++++++++++++------------------- mdec.h | 2 +- video.cpp | 36 ++++++++++++++++++++++++------------ video.h | 4 +++- 13 files changed, 75 insertions(+), 39 deletions(-) diff --git a/game.cpp b/game.cpp index 9cb510e..8fbbd81 100644 --- a/game.cpp +++ b/game.cpp @@ -1274,6 +1274,7 @@ void Game::restartLevel() { preloadLevelScreenData(screenNum, kNoScreen); _andyObject->levelData0x2988 = _res->_resLevelData0x2988PtrTable[_andyObject->spriteNum]; memset(_video->_backgroundLayer, 0, Video::W * Video::H); + _video->clearYuvBackBuffer(); resetScreen(); if (_andyObject->screenNum != screenNum) { preloadLevelScreenData(_andyObject->screenNum, kNoScreen); @@ -1817,8 +1818,16 @@ void Game::drawPlasmaCannon() { _plasmaCannonObject = 0; } +void Game::updateBackgroundPsx(int num) { + if (_res->_isPsx) { + const LvlBackgroundData *lvl = &_res->_resLvlScreenBackgroundDataTable[_res->_currentScreenResourceNum]; + _video->decodeBackgroundPsx(lvl->backgroundBitmapTable[num] + 4, -1, Video::W, Video::H); + } +} + void Game::drawScreen() { memcpy(_video->_frontLayer, _video->_backgroundLayer, Video::W * Video::H); + _video->copyYuvBackBuffer(); // redraw background animation sprites LvlBackgroundData *dat = &_res->_resLvlScreenBackgroundDataTable[_res->_currentScreenResourceNum]; @@ -2718,11 +2727,6 @@ int Game::displayHintScreen(int num, int pause) { _video->_paletteChanged = true; } unmuteSound(); - if (isPsx) { // restore level screen bitmap - LvlBackgroundData *lvl = &_res->_resLvlScreenBackgroundDataTable[_res->_currentScreenResourceNum]; - const uint8_t *bmp = lvl->backgroundBitmapTable[lvl->currentBackgroundId]; - _video->decodeBackgroundPsx(bmp + 4, -1, Video::W, Video::H); - } return confirmQuit && quit == kQuitYes; } diff --git a/game.h b/game.h index 6b36d95..e3cd14e 100644 --- a/game.h +++ b/game.h @@ -307,6 +307,7 @@ struct Game { int restoreAndyCollidesLava(); int updateAndyLvlObject(); void drawPlasmaCannon(); + void updateBackgroundPsx(int num); void drawScreen(); void updateLvlObjectList(LvlObject **list); void updateLvlObjectLists(); diff --git a/level1_rock.cpp b/level1_rock.cpp index 137d6f6..f0b46e8 100644 --- a/level1_rock.cpp +++ b/level1_rock.cpp @@ -88,6 +88,7 @@ void Level_rock::postScreenUpdate_rock_screen0() { ++_screenCounterTable[0]; if (_screenCounterTable[0] > 25) { _res->_screensState[0].s0 = 1; + _g->updateBackgroundPsx(1); } if (_screenCounterTable[0] == 2) { _g->setShakeScreen(3, 12); @@ -129,6 +130,7 @@ void Level_rock::postScreenUpdate_rock_screen4() { _g->setupScreenMask(4); } else if (_screenCounterTable[4] > 46) { _res->_screensState[4].s0 = 1; + _g->updateBackgroundPsx(1); } if (_screenCounterTable[4] == 31) { _g->setShakeScreen(2, 12); @@ -168,6 +170,7 @@ void Level_rock::postScreenUpdate_rock_screen9() { _checkpoint = 5; } _res->_screensState[9].s0 = 1; + _g->updateBackgroundPsx(1); _g->setAndySprite(2); _andyObject->xPos = 105; _andyObject->yPos = 52; diff --git a/level2_fort.cpp b/level2_fort.cpp index cf3310e..7a22818 100644 --- a/level2_fort.cpp +++ b/level2_fort.cpp @@ -72,6 +72,7 @@ void Level_fort::postScreenUpdate_fort_screen1() { _g->setupScreenMask(1); } else if (_screenCounterTable[1] == 59) { _res->_screensState[1].s0 = 1; + _g->updateBackgroundPsx(1); _res->_resLvlScreenBackgroundDataTable[1].currentBackgroundId = 1; } } diff --git a/level3_pwr1.cpp b/level3_pwr1.cpp index 52d718a..04b2f50 100644 --- a/level3_pwr1.cpp +++ b/level3_pwr1.cpp @@ -122,6 +122,7 @@ void Level_pwr1::postScreenUpdate_pwr1_screen6() { _res->_screensState[6].s0 = 1; dat->currentMaskId = 1; dat->currentBackgroundId = 1; + _g->updateBackgroundPsx(1); if (_checkpoint == 0) { _checkpoint = 1; } @@ -131,7 +132,8 @@ void Level_pwr1::postScreenUpdate_pwr1_screen6() { ++_screenCounterTable[6]; if (_screenCounterTable[6] >= 54) { _res->_screensState[6].s0 = 2; - dat->currentBackgroundId = 1; + dat->currentBackgroundId = 2; + _g->updateBackgroundPsx(2); } break; default: { @@ -242,6 +244,7 @@ void Level_pwr1::postScreenUpdate_pwr1_screen23() { _res->_resLvlScreenBackgroundDataTable[23].currentMaskId = 1; _res->_resLvlScreenBackgroundDataTable[23].currentBackgroundId = 1; _g->setupScreenMask(23); + _g->updateBackgroundPsx(1); } break; case 0: @@ -267,6 +270,7 @@ void Level_pwr1::postScreenUpdate_pwr1_screen27() { ++_screenCounterTable[27]; if (_screenCounterTable[27] == 37) { _res->_screensState[27].s0 = 1; + _g->updateBackgroundPsx(1); _res->_resLvlScreenBackgroundDataTable[27].currentMaskId = 1; _res->_resLvlScreenBackgroundDataTable[27].currentBackgroundId = 1; _g->setupScreenMask(27); diff --git a/level4_isld.cpp b/level4_isld.cpp index 5acddf9..cfb3a58 100644 --- a/level4_isld.cpp +++ b/level4_isld.cpp @@ -79,6 +79,7 @@ void Level_isld::postScreenUpdate_isld_screen1() { ++_screenCounterTable[1]; if (_screenCounterTable[1] > 21) { _res->_screensState[1].s0 = 1; + _g->updateBackgroundPsx(1); _res->_resLvlScreenBackgroundDataTable[1].currentBackgroundId = 1; } } @@ -167,6 +168,7 @@ void Level_isld::postScreenUpdate_isld_screen15() { ++_screenCounterTable[15]; if (_screenCounterTable[15] >= 60) { _res->_screensState[15].s0 = 1; + _g->updateBackgroundPsx(1); } break; case 0: diff --git a/level5_lava.cpp b/level5_lava.cpp index 20d46cf..f688c8e 100644 --- a/level5_lava.cpp +++ b/level5_lava.cpp @@ -86,6 +86,7 @@ void Level_lava::postScreenUpdate_lava_screen0() { ++_screenCounterTable[0]; if (_screenCounterTable[0] >= 11) { _res->_screensState[0].s0 = 1; + _g->updateBackgroundPsx(1); } break; case 0: diff --git a/level7_lar1.cpp b/level7_lar1.cpp index a74869b..1f5ac9a 100644 --- a/level7_lar1.cpp +++ b/level7_lar1.cpp @@ -191,6 +191,7 @@ void Level_lar1::postScreenUpdate_lar1_screen0() { } else if (_screenCounterTable[0] >= 45) { _res->_screensState[0].s0 = 1; _res->_resLvlScreenBackgroundDataTable[0].currentBackgroundId = 1; + _g->updateBackgroundPsx(1); } else if (_screenCounterTable[0] == 11) { _g->setShakeScreen(3, 2); } else if (_screenCounterTable[0] == 13) { @@ -208,6 +209,7 @@ void Level_lar1::postScreenUpdate_lar1_screen0() { _res->_resLvlScreenBackgroundDataTable[0].currentMaskId = 2; _g->setupScreenMask(0); _res->_screensState[0].s0 = 2; + _g->updateBackgroundPsx(2); } break; } @@ -354,6 +356,7 @@ void Level_lar1::postScreenUpdate_lar1_screen14() { _g->setupScreenMask(14); } else if (_screenCounterTable[14] >= 20) { _res->_screensState[14].s0 = 1; + _g->updateBackgroundPsx(1); } else if (_screenCounterTable[14] == 7 || _screenCounterTable[14] == 9 || _screenCounterTable[14] == 11 || _screenCounterTable[14] == 13 || _screenCounterTable[14] == 15) { _g->setShakeScreen(3, 2); } @@ -441,6 +444,7 @@ void Level_lar1::postScreenUpdate_lar1_screen19() { } else if (_screenCounterTable[19] >= 14) { _res->_screensState[19].s0 = 1; _res->_resLvlScreenBackgroundDataTable[19].currentBackgroundId = 1; + _g->updateBackgroundPsx(1); } } } diff --git a/level8_lar2.cpp b/level8_lar2.cpp index cdada0c..3ebb29f 100644 --- a/level8_lar2.cpp +++ b/level8_lar2.cpp @@ -440,8 +440,10 @@ void Level_lar2::preScreenUpdate_lar2_screen7() { if (_res->_currentScreenResourceNum == 7) { if (_checkpoint >= 4 && _checkpoint < 7) { _res->_screensState[7].s0 = 1; + _g->updateBackgroundPsx(1); } else { _res->_screensState[7].s0 = 0; + _g->updateBackgroundPsx(0); } if (_checkpoint == 5) { if (!_paf->_skipCutscenes) { diff --git a/mdec.cpp b/mdec.cpp index d14775a..936bc7b 100644 --- a/mdec.cpp +++ b/mdec.cpp @@ -26,8 +26,8 @@ struct BitStream { // most significant 16 bits _len += 16; } assert(_len >= count); - const int value = (_bits >> (_len - count)) & ((1 << count) - 1); _len -= count; + const int value = (_bits >> _len) & ((1 << count) - 1); return value; } int getSignedBits(int len) { @@ -117,15 +117,15 @@ static void dequantizeBlock(int *coefficients, float *block, int scale) { } } -static const double _idct8x8[8][8] = { - { 0.353553390593274, 0.490392640201615, 0.461939766255643, 0.415734806151273, 0.353553390593274, 0.277785116509801, 0.191341716182545, 0.097545161008064 }, - { 0.353553390593274, 0.415734806151273, 0.191341716182545, -0.097545161008064, -0.353553390593274, -0.490392640201615, -0.461939766255643, -0.277785116509801 }, - { 0.353553390593274, 0.277785116509801, -0.191341716182545, -0.490392640201615, -0.353553390593274, 0.097545161008064, 0.461939766255643, 0.415734806151273 }, - { 0.353553390593274, 0.097545161008064, -0.461939766255643, -0.277785116509801, 0.353553390593274, 0.415734806151273, -0.191341716182545, -0.490392640201615 }, - { 0.353553390593274, -0.097545161008064, -0.461939766255643, 0.277785116509801, 0.353553390593274, -0.415734806151273, -0.191341716182545, 0.490392640201615 }, - { 0.353553390593274, -0.277785116509801, -0.191341716182545, 0.490392640201615, -0.353553390593273, -0.097545161008064, 0.461939766255643, -0.415734806151273 }, - { 0.353553390593274, -0.415734806151273, 0.191341716182545, 0.097545161008064, -0.353553390593274, 0.490392640201615, -0.461939766255643, 0.277785116509801 }, - { 0.353553390593274, -0.490392640201615, 0.461939766255643, -0.415734806151273, 0.353553390593273, -0.277785116509801, 0.191341716182545, -0.097545161008064 } +static const int16_t _idct8x8[8][8] = { + { 23170, 32138, 30273, 27245, 23170, 18204, 12539, 6392 }, + { 23170, 27245, 12539, -6393, -23171, -32139, -30274, -18205 }, + { 23170, 18204, -12540, -32139, -23171, 6392, 30273, 27245 }, + { 23170, 6392, -30274, -18205, 23170, 27245, -12540, -32139 }, + { 23170, -6393, -30274, 18204, 23170, -27246, -12540, 32138 }, + { 23170, -18205, -12540, 32138, -23171, -6393, 30273, -27246 }, + { 23170, -27246, 12539, 6392, -23171, 32138, -30274, 18204 }, + { 23170, -32139, 30273, -27246, 23170, -18205, 12539, -6393 } }; static void idct(float *dequantData, float *result) { @@ -135,7 +135,7 @@ static void idct(float *dequantData, float *result) { for (int x = 0; x < 8; x++) { float p = 0; for (int i = 0; i < 8; ++i) { - p += dequantData[i] * _idct8x8[x][i]; + p += dequantData[i] * _idct8x8[x][i] / 0x10000; } tmp[y + x * 8] = p; } @@ -147,7 +147,7 @@ static void idct(float *dequantData, float *result) { for (int y = 0; y < 8; y++) { float p = 0; for (int i = 0; i < 8; ++i) { - p += u[i] * _idct8x8[y][i]; + p += u[i] * _idct8x8[y][i] / 0x10000; } result[y * 8 + x] = p; } @@ -176,7 +176,7 @@ static void decodeBlock(BitStream *bs, int x8, int y8, uint8_t *dst, int dstPitc } } -int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, int w, int h, MdecOutput *out) { +int decodeMDEC(const uint8_t *src, int len, const uint8_t *mbOrder, int mbLength, int w, int h, MdecOutput *out) { BitStream bs(src, len); bs.getBits(16); const uint16_t vlc = bs.getBits(16); @@ -192,15 +192,15 @@ int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, i const int yPitch = out->planes[kOutputPlaneY].pitch; uint8_t *yPtr = out->planes[kOutputPlaneY].ptr + out->y * yPitch + out->x; const int cbPitch = out->planes[kOutputPlaneCb].pitch; - uint8_t *cbPtr = out->planes[kOutputPlaneCb].ptr + (out->y * cbPitch + out->x) / 2; + uint8_t *cbPtr = out->planes[kOutputPlaneCb].ptr + (out->y / 2) * cbPitch + (out->x / 2); const int crPitch = out->planes[kOutputPlaneCr].pitch; - uint8_t *crPtr = out->planes[kOutputPlaneCr].ptr + (out->y * crPitch + out->x) / 2; + uint8_t *crPtr = out->planes[kOutputPlaneCr].ptr + (out->y / 2) * crPitch + (out->x / 2); int z = 0; for (int x = 0, x2 = 0; x < blockW; ++x, x2 += 2) { for (int y = 0, y2 = 0; y < blockH; ++y, y2 += 2) { - if (z < mblen) { - const uint8_t xy = mborder[z]; + if (z < mbLength) { + const uint8_t xy = mbOrder[z]; if ((xy & 15) != x || (xy >> 4) != y) { continue; } @@ -212,13 +212,13 @@ int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, i decodeBlock(&bs, x2 + 1, y2, yPtr, yPitch, qscale, version); decodeBlock(&bs, x2, y2 + 1, yPtr, yPitch, qscale, version); decodeBlock(&bs, x2 + 1, y2 + 1, yPtr, yPitch, qscale, version); - if (mborder && z == mblen) { + if (mbOrder && z == mbLength) { goto end; } } } end: - if (!mborder && bs.bitsAvailable() >= 11) { + if (!mbOrder && bs.bitsAvailable() >= 11) { const int eof = bs.getBits(11); assert(eof == 0x3FE || eof == 0x3FF); } diff --git a/mdec.h b/mdec.h index 6739055..6ccae9c 100644 --- a/mdec.h +++ b/mdec.h @@ -19,6 +19,6 @@ struct MdecOutput { } planes[3]; }; -int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, int w, int h, MdecOutput *out); +int decodeMDEC(const uint8_t *src, int len, const uint8_t *mbOrder, int mbLength, int w, int h, MdecOutput *out); #endif // MDEC_H__ diff --git a/video.cpp b/video.cpp index f12cd9c..7ba83ce 100644 --- a/video.cpp +++ b/video.cpp @@ -30,6 +30,7 @@ Video::Video() { _transformShadowBuffer = 0; _transformShadowLayerDelta = 0; memset(&_mdec, 0, sizeof(_mdec)); + _backgroundPsx = 0; } Video::~Video() { @@ -79,6 +80,17 @@ void Video::updateYuvDisplay() { } void Video::copyYuvBackBuffer() { + if (_backgroundPsx) { + _mdec.x = 0; + _mdec.y = 0; + _mdec.w = W; + _mdec.h = H; + decodeMDEC(_backgroundPsx, W * H * sizeof(uint16_t), 0, 0, W, H, &_mdec); + } +} + +void Video::clearYuvBackBuffer() { + _backgroundPsx = 0; } void Video::updateScreen() { @@ -476,15 +488,15 @@ uint8_t Video::findWhiteColor() const { } void Video::decodeBackgroundPsx(const uint8_t *src, int size, int w, int h, int x, int y) { - _mdec.x = x; - _mdec.y = y; - _mdec.w = w; - _mdec.h = h; - if (size < 0) { // size not available - size = w * h * sizeof(uint16_t); + if (size < 0) { + _backgroundPsx = src; + } else { + _mdec.x = x; + _mdec.y = y; + _mdec.w = w; + _mdec.h = h; + decodeMDEC(src, size, 0, 0, w, h, &_mdec); } - decodeMDEC(src, size, 0, 0, w, h, &_mdec); - copyYuvBackBuffer(); } void Video::decodeBackgroundOverlayPsx(const uint8_t *src, int x, int y) { @@ -499,14 +511,14 @@ void Video::decodeBackgroundOverlayPsx(const uint8_t *src, int x, int y) { const int len = READ_LE_UINT16(src + offset + 2); _mdec.w = src[offset + 4] * 16; _mdec.h = src[offset + 5] * 16; - const int mborderlen = src[offset + 6]; - const int mborderalign = src[offset + 7]; + const int mbOrderLength = src[offset + 6]; + const int mbOrderOffset = src[offset + 7]; const uint8_t *data = &src[offset + 8]; - if (mborderalign == 0) { + if (mbOrderOffset == 0) { decodeMDEC(data, len - 8, 0, 0, _mdec.w, _mdec.h, &_mdec); } else { // different macroblocks order - decodeMDEC(data + mborderalign, len - 8 - mborderalign, data, mborderlen, _mdec.w, _mdec.h, &_mdec); + decodeMDEC(data + mbOrderOffset, len - 8 - mbOrderOffset, data, mbOrderLength, _mdec.w, _mdec.h, &_mdec); } offset += len; } diff --git a/video.h b/video.h index 59b6023..28225ce 100644 --- a/video.h +++ b/video.h @@ -25,7 +25,7 @@ struct Video { H = 192 }; - static const uint8_t _fontCharactersTable[78]; + static const uint8_t _fontCharactersTable[39 * 2]; uint8_t _palette[256 * 3]; uint16_t _displayPaletteBuffer[256 * 3]; @@ -48,6 +48,7 @@ struct Video { } _drawLine; MdecOutput _mdec; + const uint8_t *_backgroundPsx; Video(); ~Video(); @@ -58,6 +59,7 @@ struct Video { void updateGameDisplay(uint8_t *buf); void updateYuvDisplay(); void copyYuvBackBuffer(); + void clearYuvBackBuffer(); void updateScreen(); void clearBackBuffer(); void clearPalette();