diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a109c72..4c9bb2b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,9 +71,9 @@ jobs: cd ${{ env.build_dir }} mkdir ${{ env.package_dir }} if [[ "${{ runner.os }}" == 'Windows' ]]; then - cp ${{ matrix.config.build_type }}/${{ env.app_name }}.exe ${{ matrix.config.build_type }}/SDL2.dll ${{ matrix.config.build_type }}/getopt.dll ../${{ env.app_name }}.ini ${{ env.package_dir }} + cp ${{ matrix.config.build_type }}/${{ env.app_name }}.exe ${{ matrix.config.build_type }}/SDL2.dll ${{ matrix.config.build_type }}/getopt.dll ../${{ env.app_name }}.ini ../icon.bmp ${{ env.package_dir }} else - cp ${{ env.app_name }} ../${{ env.app_name }}.ini ${{ env.package_dir }} + cp ${{ env.app_name }} ../${{ env.app_name }}.ini ../icon.bmp ${{ env.package_dir }} fi - name: Zip Package diff --git a/CHANGES.txt b/CHANGES.txt index b1e93b8..01f1df7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +* release 0.2.9f + - added 'linear' graphics scaler + - enabled PSX options menu + - fixed '1x' scaling + * release 0.2.9e - fixed graphics glitches with PSX backgrounds - removed 'inih' and 'libxbr-standalone' dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index c0b5262..db64a0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if(NSWITCH) add_definitions(-D__SWITCH__) add_custom_target(${CMAKE_PROJECT_NAME}.nro DEPENDS ${CMAKE_PROJECT_NAME} - COMMAND nacptool --create "Heart of Darkness" "cyx, usineur" "0.2.9d" ${CMAKE_PROJECT_NAME}.nacp + COMMAND nacptool --create "Heart of Darkness" "cyx, usineur" "0.2.9f" ${CMAKE_PROJECT_NAME}.nacp COMMAND elf2nro ${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/3p/res/icon.jpg --nacp=${CMAKE_PROJECT_NAME}.nacp ) add_custom_target(nxlink diff --git a/Makefile b/Makefile index cf08144..6e41552 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ SRCS = andy.cpp benchmark.cpp fileio.cpp fs_posix.cpp game.cpp \ resource.cpp screenshot.cpp sound.cpp staticres.cpp system_sdl2.cpp \ util.cpp video.cpp -SCALERS := scaler_nearest.cpp scaler_xbr.cpp +SCALERS := scaler_xbr.cpp OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d) diff --git a/game.h b/game.h index e3cd14e..09f08d8 100644 --- a/game.h +++ b/game.h @@ -161,12 +161,10 @@ struct Game { bool _specialAnimFlag; AndyShootData _andyShootsTable[kMaxAndyShoots]; int _andyShootsCount; - uint8_t _mstOp68_type, _mstOp68_arg9, _mstOp67_type; - uint8_t _mstOp67_flags1; - uint16_t _mstOp67_unk; + uint8_t _mstOp68_type, _mstOp68_flags1, _mstOp67_type, _mstOp67_flags1; int _mstOp67_x1, _mstOp67_x2, _mstOp67_y1, _mstOp67_y2; int8_t _mstOp67_screenNum; - uint16_t _mstOp68_flags1; + uint16_t _mstOp68_flags2; int _mstOp68_x1, _mstOp68_x2, _mstOp68_y1, _mstOp68_y2; int8_t _mstOp68_screenNum; uint32_t _mstLevelGatesMask; @@ -204,7 +202,6 @@ struct Game { int _xMstPos1, _yMstPos1; int _xMstPos2, _yMstPos2; // xMstDist1, yMstDist1 int _xMstPos3, _yMstPos3; - int _mstHelper1Count; int _mstActionNum; uint32_t _mstAndyVarMask; int _mstChasingMonstersCount; diff --git a/icon.bmp b/icon.bmp new file mode 100644 index 0000000..9cde77b Binary files /dev/null and b/icon.bmp differ diff --git a/main.cpp b/main.cpp index d0c3554..85257af 100644 --- a/main.cpp +++ b/main.cpp @@ -272,7 +272,6 @@ int main(int argc, char *argv[]) { setupAudio(g); if (isPsx) { g->_video->initPsx(); - _runMenu = false; } if (_displayLoadingScreen) { g->displayLoadingScreen(); diff --git a/mdec.cpp b/mdec.cpp index 936bc7b..4efd5e1 100644 --- a/mdec.cpp +++ b/mdec.cpp @@ -170,7 +170,7 @@ static void decodeBlock(BitStream *bs, int x8, int y8, uint8_t *dst, int dstPitc for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { const int val = (int)round(idctData[y * 8 + x]); // (-128,127) range - dst[x] = (val < -128) ? 0 : ((val > 127) ? 255 : (128 + val)); + dst[x] = (val <= -128) ? 0 : ((val >= 127) ? 255 : (128 + val)); } dst += dstPitch; } diff --git a/menu.cpp b/menu.cpp index 075f758..d9b84b3 100644 --- a/menu.cpp +++ b/menu.cpp @@ -250,10 +250,13 @@ void Menu::loadData() { if (_res->_isPsx) { for (int i = 0; i < 3; ++i) { - DatSpritesGroup *sprites = (DatSpritesGroup *)(ptr + ptrOffset); - ptrOffset += sizeof(DatSpritesGroup) + ((le32toh(sprites->size) + 3) & ~3); + _psxSprites[i] = (DatSpritesGroup *)(ptr + ptrOffset); + ptrOffset += sizeof(DatSpritesGroup) + ((le32toh(_psxSprites[i]->size) + 3) & ~3); + } + for (int i = 0; i < 3; ++i) { + _psxPalettes[i] = ptr + ptrOffset; + ptrOffset += 0x300; } - ptrOffset += 0x300 * 3; } _iconsSprites = (DatSpritesGroup *)(ptr + ptrOffset); @@ -338,6 +341,7 @@ SssObject *Menu::playSound(int num) { void Menu::drawBitmap(const uint8_t *data, uint32_t size, bool setPalette) { if (_res->_isPsx) { + memset(_video->_frontLayer, 0, Video::W * Video::H); _video->decodeBackgroundPsx(data, size, Video::W, Video::H); } else { decodeLZW(data, _video->_frontLayer); @@ -353,7 +357,10 @@ void Menu::drawSprite(const DatSpritesGroup *spriteGroup, const uint8_t *ptr, ui const uint16_t size = READ_LE_UINT16(ptr + 2); if (num == i) { if (_res->_isPsx) { - _video->decodeBackgroundOverlayPsx(ptr); + const int count = READ_LE_UINT32(ptr + 4); + if (count != 0 && (count & 0x100) == 0) { + _video->decodeBackgroundOverlayPsx(ptr); + } } else { if (x < 0) { x = ptr[0]; @@ -375,7 +382,10 @@ void Menu::drawSpriteAnim(DatSpritesGroup *spriteGroup, const uint8_t *ptr, uint } ptr += spriteGroup[num].currentFrameOffset; if (_res->_isPsx) { - _video->decodeBackgroundOverlayPsx(ptr); + const int count = READ_LE_UINT32(ptr + 4); + if (count != 0 && (count & 0x100) == 0) { + _video->decodeBackgroundOverlayPsx(ptr); + } } else { _video->decodeSPR(ptr + 8, _video->_frontLayer, ptr[0], ptr[1], 0, READ_LE_UINT16(ptr + 4), READ_LE_UINT16(ptr + 6)); } @@ -448,11 +458,15 @@ void Menu::drawTitleScreen(int option) { } int Menu::handleTitleScreen() { - const int firstOption = kTitleScreen_AssignPlayer; - const int lastOption = _res->_isPsx ? kTitleScreenPSX_Save : kTitleScreen_Quit; + const int firstOption = _res->_isPsx ? kTitleScreen_Play : kTitleScreen_AssignPlayer; + const int lastOption = _res->_isPsx ? kTitleScreen_Options : kTitleScreen_Quit; int currentOption = kTitleScreen_Play; - while (!g_system->inp.quit) { + while (1) { g_system->processEvents(); + if (g_system->inp.quit) { + currentOption = kTitleScreen_Quit; + break; + } if (g_system->inp.keyReleased(SYS_INP_UP)) { if (currentOption > firstOption) { playSound(kSound_0x70); @@ -540,8 +554,10 @@ void Menu::setCurrentPlayer(int num) { _checkpointNum = _res->_datHdr.levelCheckpointsCount[_levelNum] - 1; } } - const DatBitmapsGroup *bitmap = &_checkpointsBitmaps[_levelNum][_checkpointNum]; - memcpy(_paletteBuffer + 205 * 3, _checkpointsBitmapsData[_levelNum] + bitmap->palette, 50 * 3); + if (!_res->_isPsx) { + const DatBitmapsGroup *bitmap = &_checkpointsBitmaps[_levelNum][_checkpointNum]; + memcpy(_paletteBuffer + 205 * 3, _checkpointsBitmapsData[_levelNum] + bitmap->palette, 50 * 3); + } g_system->setPalette(_paletteBuffer, 256, 6); } @@ -576,16 +592,18 @@ void Menu::drawPlayerProgress(int state, int cursor) { ++player; } player = (cursor == 0 || cursor == 5) ? _config->currentPlayer : (cursor - 1); - uint8_t *p = _video->_frontLayer; - const int offset = (player * 17) + 92; - for (int i = 0; i < 16; ++i) { // player - memcpy(p + i * Video::W + 6935, p + i * Video::W + (offset + 1) * 256 + 8, 72); - } - for (int i = 0; i < 16; ++i) { // level - memcpy(p + i * Video::W + 11287, p + i * Video::W + (offset + 1) * 256 + 83, 76); - } - for (int i = 0; i < 16; ++i) { // checkpoint - memcpy(p + i * Video::W + 15639, p + i * Video::W + (offset + 1) * 256 + 172, 76); + if (!_res->_isPsx) { + uint8_t *p = _video->_frontLayer; + const int offset = (player * 17) + 92; + for (int i = 0; i < 16; ++i) { // player + memcpy(p + i * Video::W + 6935, p + i * Video::W + (offset + 1) * 256 + 8, 72); + } + for (int i = 0; i < 16; ++i) { // level + memcpy(p + i * Video::W + 11287, p + i * Video::W + (offset + 1) * 256 + 83, 76); + } + for (int i = 0; i < 16; ++i) { // checkpoint + memcpy(p + i * Video::W + 15639, p + i * Video::W + (offset + 1) * 256 + 172, 76); + } } if (!isEmptySetupCfg(_config, player)) { DatBitmapsGroup *bitmap = &_checkpointsBitmaps[_levelNum][_checkpointNum]; @@ -608,13 +626,31 @@ void Menu::drawPlayerProgress(int state, int cursor) { } void Menu::handleAssignPlayer() { - memcpy(_paletteBuffer, _playerBitmapData + _playerBitmapSize, 256 * 3); + if (_res->_isPsx) { + memset(_paletteBuffer, 0, 256 * 3); + static const int16_t indexes[] = { 0, 3, 6, 18, 36, 53, 67, 81, 99, 111, 125, 139, 156, 169, 181, 186, 191, -1 }; + static const uint8_t colors[] = { + 0x01,0x00,0x00, 0x02,0x02,0x03, 0x04,0x04,0x07, 0x07,0x08,0x0d, 0x0a,0x0c,0x10, 0x0d,0x0f,0x14, + 0x0f,0x11,0x18, 0x12,0x14,0x1c, 0x14,0x18,0x20, 0x17,0x1a,0x24, 0x19,0x1d,0x27, 0x1c,0x20,0x2b, + 0x1e,0x23,0x2f, 0x21,0x27,0x33, 0x24,0x2a,0x38, 0x26,0x2c,0x3b, 0x28,0x30,0x3f + }; + int offset = 0; + for (int i = 0; indexes[i] != -1; ++i) { + memcpy(&_paletteBuffer[indexes[i] * 3], &colors[offset], 3); + offset += 3; + } + } else { + memcpy(_paletteBuffer, _playerBitmapData + _playerBitmapSize, 256 * 3); + } int state = 1; int cursor = 0; setCurrentPlayer(_config->currentPlayer); drawPlayerProgress(state, cursor); - while (!g_system->inp.quit) { + while (1) { g_system->processEvents(); + if (g_system->inp.quit) { + break; + } if (g_system->inp.keyReleased(SYS_INP_SHOOT) || g_system->inp.keyReleased(SYS_INP_JUMP)) { if (state != 0 && cursor == 5) { playSound(kSound_0x80); @@ -704,7 +740,7 @@ void Menu::updateBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const } } for (int i = 0; i < 3; ++i) { - if (_bitmapCircularListIndex[i] != -1) { + if (_bitmapCircularListIndex[i] != -1 && !_res->_isPsx) { const DatBitmapsGroup *bitmap = &bitmapsGroup[_bitmapCircularListIndex[i]]; memcpy(_paletteBuffer + (105 + 50 * i) * 3, bitmapData + bitmap->palette, 50 * 3); } @@ -713,12 +749,14 @@ void Menu::updateBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const } void Menu::drawBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const uint8_t *bitmapData, int num, int count, bool updatePalette) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - if (updatePalette) { - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + if (updatePalette) { + g_system->setPalette(_paletteBuffer, 256, 6); + } } updateBitmapsCircularList(bitmapsGroup, bitmapData, num, count); - static const int xPos[] = { -60, 68, 196 }; + static const int16_t xPos[] = { -60, 68, 196 }; for (int i = 0; i < 3; ++i) { if (_bitmapCircularListIndex[i] != -1) { const DatBitmapsGroup *bitmap = &bitmapsGroup[_bitmapCircularListIndex[i]]; @@ -1432,21 +1470,27 @@ void Menu::changeToOption(int num) { // nothing to do } else if (_optionNum == kMenu_Load + 1) { _loadLevelButtonState = 0; - memcpy(_paletteBuffer, _optionsBitmapData[5] + _optionsBitmapSize[5], 192 * 3); - memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[5] + _optionsBitmapSize[5], 192 * 3); + memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } drawLevelScreen(); } else if (_optionNum == kMenu_Load + 2) { _loadCheckpointButtonState = 0; _checkpointNum = 0; setLevelCheckpoint(_config->currentPlayer); - memcpy(_paletteBuffer, _optionsBitmapData[6] + _optionsBitmapSize[6], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[6] + _optionsBitmapSize[6], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } drawCheckpointScreen(); } else if (_optionNum == kMenu_Settings + 1) { _settingNum = kSettingNum_Difficulty; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } handleSettingsScreen(5); } else if (_optionNum == kMenu_Cutscenes + 1) { _loadCutsceneButtonState = 0; @@ -1454,8 +1498,10 @@ void Menu::changeToOption(int num) { drawCutsceneScreen(); } else if (_optionsBitmapSize[_optionNum] != 0) { drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } refreshScreen(); } } @@ -1489,8 +1535,10 @@ void Menu::handleLoadLevel(int num) { if (_levelNum >= _lastLevelNum) { _levelNum = 0; } - memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _condMask = 0x20; } } else if (num == 20) { @@ -1501,8 +1549,10 @@ void Menu::handleLoadLevel(int num) { if (_levelNum < 0) { _levelNum = _lastLevelNum - 1; } - memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _condMask = 0x40; } } @@ -1674,8 +1724,11 @@ bool Menu::handleOptions() { _optionNum = kMenu_Settings; changeToOption(0); _condMask = 0; - while (!g_system->inp.quit) { + while (1) { g_system->processEvents(); + if (g_system->inp.quit) { + break; + } if (g_system->inp.keyPressed(SYS_INP_ESC)) { _optionNum = -1; break; @@ -1705,8 +1758,10 @@ bool Menu::handleOptions() { _iconsSprites[0x27].num = 0; _iconsSprites[0x26].num = 0; _iconsSprites[0x28].num = 0; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _settingNum = kSettingNum_Difficulty; } handleSettingsScreen(num); @@ -1715,8 +1770,10 @@ bool Menu::handleOptions() { if (prevOptionNum != _optionNum) { _iconsSprites[0x2C].num = 0; _iconsSprites[0x2E].num = 0; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _controlsNum = 2; } handleControlsScreen(num); @@ -1727,8 +1784,10 @@ bool Menu::handleOptions() { _iconsSprites[0x18].num = 0; _iconsSprites[0x17].num = 0; _iconsSprites[0x1A].num = 0; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _joystickControlsNum = 1; } handleJoystickControlsScreen(num); @@ -1739,24 +1798,30 @@ bool Menu::handleOptions() { _iconsSprites[0x20].num = 0; _iconsSprites[0x1F].num = 0; _iconsSprites[0x22].num = 0; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _keyboardControlsNum = 1; } handleKeyboardControlsScreen(num); break; case 4: if (prevOptionNum != _optionNum) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _difficultyNum = _config->players[_config->currentPlayer].difficulty; } handleDifficultyScreen(num); break; case 5: if (prevOptionNum != _optionNum) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - g_system->setPalette(_paletteBuffer, 256, 6); + if (!_res->_isPsx) { + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + } _soundVolume = _g->_snd_masterVolume; _soundNum = kSoundNum_Confirm; _soundCounter = 0; diff --git a/menu.h b/menu.h index 1d8c180..3f53989 100644 --- a/menu.h +++ b/menu.h @@ -70,10 +70,11 @@ struct Menu { const uint8_t *_optionsButtonSpritesData; DatSpritesGroup *_currentOptionButtonSprite; int _currentOptionButtonSound; - const uint8_t *_digitsData; const uint8_t *_optionData; const uint8_t *_soundData; + DatSpritesGroup *_psxSprites[3]; + const uint8_t *_psxPalettes[3]; uint8_t _paletteBuffer[256 * 3]; uint8_t _loadLevelButtonState; diff --git a/mixer.cpp b/mixer.cpp index 17002e8..524b316 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -15,7 +15,7 @@ Mixer::~Mixer() { } void Mixer::queue(const int16_t *ptr, const int16_t *end, int panType, int panL, int panR, bool stereo) { - if (_mixingQueueSize >= kPcmChannels) { + if (_mixingQueueSize >= kMixingQueueSize) { warning("MixingQueue overflow %d", _mixingQueueSize); return; } diff --git a/mixer.h b/mixer.h index b6dc124..cf83ce5 100644 --- a/mixer.h +++ b/mixer.h @@ -15,11 +15,11 @@ struct MixerChannel { struct Mixer { - static const int kPcmChannels = 32; + static const int kMixingQueueSize = 32; void (*_lock)(int); - MixerChannel _mixingQueue[kPcmChannels]; + MixerChannel _mixingQueue[kMixingQueueSize]; int _mixingQueueSize; Mixer(); diff --git a/monsters.cpp b/monsters.cpp index 2dcb5cd..d289816 100644 --- a/monsters.cpp +++ b/monsters.cpp @@ -988,7 +988,6 @@ void Game::executeMstCode() { } ++_executeMstLogicCounter; if (_mstLevelGatesMask != 0) { - _mstHelper1Count = 0; executeMstCodeHelper1(); _mstLevelGatesMask = 0; } @@ -1183,10 +1182,11 @@ int Game::mstWalkPathUpdateWalkNode(MstWalkPath *walkPath, MstWalkNode *walkNode } void Game::executeMstCodeHelper1() { + int count = 0; for (int i = 0; i < _res->_mstHdr.walkPathDataCount; ++i) { MstWalkPath *walkPath = &_res->_mstWalkPathData[i]; if (walkPath->mask & _mstLevelGatesMask) { - ++_mstHelper1Count; + ++count; for (uint32_t j = 0; j < walkPath->count; ++j) { for (int k = 0; k < 2; ++k) { walkPath->data[j].coords[0][k] = -1; @@ -1206,7 +1206,7 @@ void Game::executeMstCodeHelper1() { mstWalkPathUpdateIndex(walkPath, 1); } } - if (_mstHelper1Count != 0) { + if (count != 0) { for (int i = 0; i < kMaxMonsterObjects1; ++i) { MonsterObject1 *m = &_monsterObjects1Table[i]; if (!m->m46) { @@ -4434,9 +4434,9 @@ int Game::mstTask_main(Task *t) { } e = CLIP(e, -1, _res->_mstHdr.screensCount - 1); if (p[0] == 224) { - _mstOp67_type = m->unk8; - _mstOp67_flags1 = m->unk9; - _mstOp67_unk = m->unkC; + _mstOp67_type = m->type; + _mstOp67_flags1 = m->flags1; + // _mstOp67_flags2 = m->flags2; _mstOp67_x1 = a; _mstOp67_x2 = b; _mstOp67_y1 = c; @@ -4444,9 +4444,9 @@ int Game::mstTask_main(Task *t) { _mstOp67_screenNum = e; break; } else if (p[0] == 225) { - _mstOp68_type = m->unk8; - _mstOp68_arg9 = m->unk9; - _mstOp68_flags1 = m->unkC; + _mstOp68_type = m->type; + _mstOp68_flags1 = m->flags1; + _mstOp68_flags2 = m->flags2; _mstOp68_x1 = a; _mstOp68_x2 = b; _mstOp68_y1 = c; @@ -4465,7 +4465,7 @@ int Game::mstTask_main(Task *t) { } } } - mstOp67_addMonster(t, a, b, c, d, e, m->unk8, m->unk9, m->unkC, m->unkB, 0, m->unkE); + mstOp67_addMonster(t, a, b, c, d, e, m->type, m->flags1, m->flags2, m->unkB, 0, m->unkE); } break; case 226: { // 68 - add_monster_group @@ -6864,7 +6864,7 @@ void Game::mstOp68_addMonsterGroup(Task *t, const uint8_t *p, int a, int b, int } int j = 0; for (int i = 0; i < a; ++i) { - mstOp67_addMonster(t, _mstOp67_x1, _mstOp67_x2, _mstOp67_y1, _mstOp67_y2, _mstOp67_screenNum, _mstOp67_type, _mstOp67_flags1, _mstOp68_flags1, data[j].m42Index, data[j].m46Index, d); + mstOp67_addMonster(t, _mstOp67_x1, _mstOp67_x2, _mstOp67_y1, _mstOp67_y2, _mstOp67_screenNum, _mstOp67_type, _mstOp67_flags1, _mstOp68_flags2, data[j].m42Index, data[j].m46Index, d); if (--c == 0) { return; } @@ -6873,7 +6873,7 @@ void Game::mstOp68_addMonsterGroup(Task *t, const uint8_t *p, int a, int b, int } } for (int i = 0; i < b; ++i) { - mstOp67_addMonster(t, _mstOp68_x1, _mstOp68_x2, _mstOp68_y1, _mstOp68_y2, _mstOp68_screenNum, _mstOp68_type, _mstOp68_arg9, _mstOp68_flags1, data[j].m42Index, data[j].m46Index, d); + mstOp67_addMonster(t, _mstOp68_x1, _mstOp68_x2, _mstOp68_y1, _mstOp68_y2, _mstOp68_screenNum, _mstOp68_type, _mstOp68_flags1, _mstOp68_flags2, data[j].m42Index, data[j].m46Index, d); if (--c == 0) { return; } diff --git a/resource.cpp b/resource.cpp index 6ff9f1b..eeaf290 100644 --- a/resource.cpp +++ b/resource.cpp @@ -1753,11 +1753,11 @@ void Resource::loadMstData(File *fp) { _mstOp223Data[i].indexVar2 = fp->readUint16(); _mstOp223Data[i].indexVar3 = fp->readUint16(); _mstOp223Data[i].indexVar4 = fp->readUint16(); - _mstOp223Data[i].unk8 = fp->readByte(); - _mstOp223Data[i].unk9 = fp->readByte(); + _mstOp223Data[i].type = fp->readByte(); + _mstOp223Data[i].flags1 = fp->readByte(); _mstOp223Data[i].indexVar5 = fp->readByte(); _mstOp223Data[i].unkB = fp->readByte(); - _mstOp223Data[i].unkC = fp->readUint16(); + _mstOp223Data[i].flags2 = fp->readUint16(); _mstOp223Data[i].unkE = fp->readUint16(); _mstOp223Data[i].maskVars = fp->readUint32(); bytesRead += 20; diff --git a/resource.h b/resource.h index 2370e8d..07f46e3 100644 --- a/resource.h +++ b/resource.h @@ -316,11 +316,11 @@ struct MstOp223Data { int16_t indexVar2; // 2 int16_t indexVar3; // 4 int16_t indexVar4; // 6 - uint8_t unk8; // 8 - uint8_t unk9; + uint8_t type; // 8 + uint8_t flags1; int8_t indexVar5; // A int8_t unkB; // B - uint16_t unkC; // C + uint16_t flags2; // C uint16_t unkE; // E uint32_t maskVars; // 0x10 }; // sizeof == 20 diff --git a/scaler.h b/scaler.h index a917e66..4e90983 100644 --- a/scaler.h +++ b/scaler.h @@ -1,7 +1,7 @@ /* - * Heart of Darkness engine rewrite - * Copyright (C) 2009-2011 Gregory Montoir (cyx@users.sourceforge.net) - */ +* Heart of Darkness engine rewrite +* Copyright (C) 2009-2011 Gregory Montoir (cyx@users.sourceforge.net) +*/ #ifndef SCALER_H__ #define SCALER_H__ @@ -14,11 +14,10 @@ typedef void (*ScaleProc)(uint32_t *dst, int dstPitch, const uint8_t *src, int s struct Scaler { const char *name; int factorMin, factorMax; - PaletteProc palette; - ScaleProc scale[3]; + PaletteProc palette; // palette changes + ScaleProc scale[3]; // 2x-4x factors }; -extern const Scaler scaler_nearest; extern const Scaler scaler_xbr; #endif // SCALER_H__ diff --git a/scaler_nearest.cpp b/scaler_nearest.cpp deleted file mode 100644 index 923d71a..0000000 --- a/scaler_nearest.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "scaler.h" - -template -static void scale_nearest(uint32_t *dst, int dstPitch, const uint8_t *src, int srcPitch, int w, int h, const uint32_t *palette) { - while (h--) { - uint32_t *p = dst; - for (int i = 0; i < w; ++i, p += N) { - const uint32_t c = palette[src[i]]; - for (int j = 0; j < N; ++j) { - for (int k = 0; k < N; ++k) { - *(p + j * dstPitch + k) = c; - } - } - } - dst += dstPitch * N; - src += srcPitch; - } -} - -const Scaler scaler_nearest = { - "nearest", - 2, 4, - 0, - { scale_nearest<2>, scale_nearest<3>, scale_nearest<4> } -}; diff --git a/scaler_xbr.cpp b/scaler_xbr.cpp index f87a5c3..cadc197 100644 --- a/scaler_xbr.cpp +++ b/scaler_xbr.cpp @@ -4,23 +4,22 @@ #include "scaler.h" -static uint8_t _yuv[256 * 3]; - -static int diffYuv(int x, int y) { - const int dy = _yuv[x * 3] - _yuv[y * 3]; - const int du = _yuv[x * 3 + 1] - _yuv[y * 3 + 1]; - const int dv = _yuv[x * 3 + 2] - _yuv[y * 3 + 2]; - return ABS(dy) + ABS(du) + ABS(dv); -} +static uint8_t _yuv[256][3]; +static int16_t _diffYuv[256][256]; template static uint32_t interpolate(uint32_t a, uint32_t b) { static const uint32_t kMask = 0xFF00FF; - const uint32_t m1 = (((((b & kMask) - (a & kMask)) * M) >> S) + (a & kMask)) & kMask; - a >>= 8; - b >>= 8; - const uint32_t m2 = (((((b & kMask) - (a & kMask)) * M) >> S) + (a & kMask)) & kMask; + const uint32_t a_rb = a & kMask; + const uint32_t a_ag = (a >> 8) & kMask; + + const uint32_t b_rb = b & kMask; + const uint32_t b_ag = (b >> 8) & kMask; + + const uint32_t m1 = ((((b_rb - a_rb) * M) >> S) + a_rb) & kMask; + const uint32_t m2 = ((((b_ag - a_ag) * M) >> S) + a_ag) & kMask; + return m1 | (m2 << 8); } @@ -32,7 +31,7 @@ static uint32_t interpolate(uint32_t a, uint32_t b) { #define ALPHA_BLEND_192_W(a, b) interpolate<3,2>(a, b) #define ALPHA_BLEND_224_W(a, b) interpolate<7,3>(a, b) -#define df(A, B) diffYuv(A, B) +#define df(A, B) _diffYuv[A][B] #define eq(A, B) (df(A, B) < 155) #define filt2b(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3) do { \ @@ -255,9 +254,24 @@ static void palette_xbr(const uint32_t *palette) { const int r = (palette[i] >> 16) & 255; const int g = (palette[i] >> 8) & 255; const int b = palette[i] & 255; - _yuv[i * 3] = ( 299 * r + 587 * g + 114 * b) / 1000; - _yuv[i * 3 + 1] = (-169 * r - 331 * g + 500 * b) / 1000 + 128; - _yuv[i * 3 + 2] = ( 500 * r - 419 * g - 81 * b) / 1000 + 128; + _yuv[i][0] = ( 299 * r + 587 * g + 114 * b) / 1000; + _yuv[i][1] = (-169 * r - 331 * g + 500 * b) / 1000 + 128; + _yuv[i][2] = ( 500 * r - 419 * g - 81 * b) / 1000 + 128; + } + for (int j = 0; j < 256; ++j) { + for (int i = 0; i < j; ++i) { + if (i != j) { + const int dy = _yuv[i][0] - _yuv[j][0]; + const int du = _yuv[i][1] - _yuv[j][1]; + const int dv = _yuv[i][2] - _yuv[j][2]; + _diffYuv[j][i] = ABS(dy) + ABS(du) + ABS(dv); + } + } + } + for (int j = 0; j < 256; ++j) { + for (int i = j; i < 256; ++i) { + _diffYuv[j][i] = _diffYuv[i][j]; + } } } diff --git a/system_sdl2.cpp b/system_sdl2.cpp index 4838ab2..05fce03 100644 --- a/system_sdl2.cpp +++ b/system_sdl2.cpp @@ -18,14 +18,23 @@ static bool axis[4]= { false, false, false, false }; static int _scalerMultiplier = 3; static const Scaler *_scaler = &scaler_xbr; +static ScaleProc _scalerProc; -static const struct { - const char *name; - const Scaler *scaler; -} _scalers[] = { - { "nearest", &scaler_nearest }, - { "xbr", &scaler_xbr }, - { 0, 0 } +const Scaler scaler_linear = { + "linear", + 2, 4 +}; + +const Scaler scaler_nearest = { + "nearest", + 2, 4 +}; + +static const Scaler *_scalers[] = { + &scaler_linear, + &scaler_nearest, + &scaler_xbr, + 0 }; struct KeyMapping { @@ -301,20 +310,21 @@ void System_SDL2::copyRectWidescreen(int w, int h, const uint8_t *buf, const uin } void System_SDL2::setScaler(const char *name, int multiplier) { - if (multiplier != 0) { + if (multiplier > 0) { _scalerMultiplier = multiplier; } if (name) { - for (int i = 0; _scalers[i].name; ++i) { - if (strcmp(name, _scalers[i].name) == 0) { - _scaler = _scalers[i].scaler; + const Scaler *scaler = 0; + for (int i = 0; _scalers[i]; ++i) { + if (strcmp(name, _scalers[i]->name) == 0) { + scaler = _scalers[i]; break; } } - if (_scalerMultiplier < _scaler->factorMin) { - _scalerMultiplier = _scaler->factorMin; - } else if (_scalerMultiplier > _scaler->factorMax) { - _scalerMultiplier = _scaler->factorMax; + if (!scaler) { + warning("Unknown scaler '%s', using default '%s'", name, _scaler->name); + } else { + _scaler = scaler; } } } @@ -346,7 +356,7 @@ void System_SDL2::setPalette(const uint8_t *pal, int n, int depth) { if (_backgroundTexture) { _pal[0] = 0; } - if (_scalerMultiplier != 1 && _scaler->palette) { + if (_scaler->palette) { _scaler->palette(_pal); } } @@ -437,12 +447,12 @@ void System_SDL2::updateScreen(bool drawWidescreen) { src -= _shakeDx; } } - if (_scalerMultiplier == 1) { + if (!_scalerProc) { for (int i = 0; i < w * h; ++i) { dst[i] = _pal[src[i]]; } } else { - (_scaler->scale[_scalerMultiplier - 2])(dst, dstPitch, src, w, w, h, _pal); + _scalerProc(dst, dstPitch, src, w, w, h, _pal); } SDL_UnlockTexture(_texture); @@ -456,10 +466,12 @@ void System_SDL2::updateScreen(bool drawWidescreen) { r.x = _shakeDx * _scalerMultiplier; r.y = _shakeDy * _scalerMultiplier; SDL_RenderGetLogicalSize(_renderer, &r.w, &r.h); - r.x += (r.w - _texW) / 2; - r.w = _texW; - r.y += (r.h - _texH) / 2; - r.h = _texH; + const int w = _screenW * _scalerMultiplier; + const int h = _screenH * _scalerMultiplier; + r.x += (r.w - w) / 2; + r.w = w; + r.y += (r.h - h) / 2; + r.h = h; if (_backgroundTexture) { SDL_RenderCopy(_renderer, _backgroundTexture, 0, &r); } @@ -839,10 +851,25 @@ void System_SDL2::updateKeys(PlayerInput *inp) { } void System_SDL2::prepareScaledGfx(const char *caption, bool fullscreen, bool widescreen, bool yuv) { - _texW = _screenW * _scalerMultiplier; - _texH = _screenH * _scalerMultiplier; - const int windowW = widescreen ? _texH * 16 / 9 : _texW; - const int windowH = _texH; + const int w = _screenW * _scalerMultiplier; + const int h = _screenH * _scalerMultiplier; + if (_scalerMultiplier > 1) { + if (_scalerMultiplier < _scaler->factorMin) { + _scalerMultiplier = _scaler->factorMin; + } else if (_scalerMultiplier > _scaler->factorMax) { + _scalerMultiplier = _scaler->factorMax; + } + _scalerProc = _scaler->scale[_scalerMultiplier - 2]; + } + if (_scalerProc) { + _texW = w; + _texH = h; + } else { + _texW = _screenW; + _texH = _screenH; + } + const int windowW = widescreen ? h * 16 / 9 : w; + const int windowH = h; const int flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; _window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowW, windowH, flags); SDL_Surface *icon = SDL_LoadBMP(kIconBmp); diff --git a/vcpkg.json b/vcpkg.json index ee78ac4..cfe6cb8 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "hode", - "version-string": "0.2.9d", + "version-string": "0.2.9f", "dependencies": [ "sdl2", "getopt",