diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1412aec639..0607841922 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,8 +8,9 @@ on: pull_request: env: - SCCACHE_GHA_ENABLED: "true" + # SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: "sccache" + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} jobs: build-linux: @@ -21,13 +22,13 @@ jobs: matrix: include: - name: GCC x86_64 - runner: ubuntu-latest + runner: [self-hosted, Linux] preset: gcc artifact_arch: x86_64 - - name: GCC aarch64 - runner: ubuntu-24.04-arm - preset: gcc - artifact_arch: aarch64 + # - name: GCC aarch64 + # runner: ubuntu-24.04-arm + # preset: gcc + # artifact_arch: aarch64 # - name: Clang x86_64 # runner: ubuntu-latest # preset: clang @@ -40,17 +41,22 @@ jobs: submodules: recursive - name: Install dependencies + if: 'false' # disabled for self-hosted run: | sudo apt-get update sudo apt-get -y install ninja-build clang lld openssl libcurl4-openssl-dev \ zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \ libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev libfreetype-dev \ libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev libssl-dev \ - libxss-dev libfuse2 + libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev - name: Setup sccache + if: 'false' # disabled for self-hosted uses: mozilla-actions/sccache-action@v0.0.9 + - name: Print sccache stats + run: sccache --show-stats + - name: Configure CMake run: cmake --preset x-linux-ci-${{matrix.preset}} @@ -68,9 +74,9 @@ jobs: build/install/Dusk-*.AppImage build/install/debug.tar.* - build-apple: name: Build Apple (${{matrix.name}}) + if: 'false' # TODO enable when CI is free runs-on: macos-latest strategy: fail-fast: false @@ -80,14 +86,14 @@ jobs: platform: macos preset: x-macos-ci artifact_name: macos-appleclang-universal - # - name: AppleClang iOS arm64 # TODO enable when CI is free - # platform: ios - # preset: x-ios-ci - # artifact_name: ios-appleclang-arm64 - # - name: AppleClang tvOS arm64 # TODO enable when CI is free - # platform: tvos - # preset: x-tvos-ci - # artifact_name: tvos-appleclang-arm64 + - name: AppleClang iOS arm64 + platform: ios + preset: x-ios-ci + artifact_name: ios-appleclang-arm64 + - name: AppleClang tvOS arm64 + platform: tvos + preset: x-tvos-ci + artifact_name: tvos-appleclang-arm64 steps: - uses: actions/checkout@v6 @@ -139,26 +145,22 @@ jobs: name: Build Windows (${{matrix.name}}) runs-on: ${{matrix.runner}} - env: - BUILD_DIR: C:\build - SCCACHE_DIR: C:\sccache - strategy: fail-fast: false matrix: include: - name: MSVC x86_64 - runner: windows-latest + runner: [self-hosted, Windows] preset: msvc msvc_arch: amd64 vcpkg_arch: x64 artifact_arch: x86_64 - - name: MSVC arm64 - runner: windows-11-arm - preset: arm64-msvc - msvc_arch: arm64 - vcpkg_arch: arm64 - artifact_arch: arm64 + # - name: MSVC arm64 + # runner: windows-11-arm + # preset: arm64-msvc + # msvc_arch: arm64 + # vcpkg_arch: arm64 + # artifact_arch: arm64 # - name: Clang x86_64 # runner: windows-latest # preset: clang @@ -185,11 +187,10 @@ jobs: uses: mozilla-actions/sccache-action@v0.0.9 - name: Install dependencies + if: 'false' # disabled for self-hosted run: | choco install ninja - vcpkg install zlib:${{matrix.vcpkg_arch}}-windows-static bzip2:${{matrix.vcpkg_arch}}-windows-static ` - zstd:${{matrix.vcpkg_arch}}-windows-static liblzma:${{matrix.vcpkg_arch}}-windows-static ` - freetype:${{matrix.vcpkg_arch}}-windows-static + vcpkg install freetype:${{matrix.vcpkg_arch}}-windows-static zstd:${{matrix.vcpkg_arch}}-windows-static - name: Configure CMake run: cmake --preset x-windows-ci-${{matrix.preset}} @@ -202,5 +203,7 @@ jobs: with: name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}} path: | - ${{env.BUILD_DIR}}/install/*.exe - ${{env.BUILD_DIR}}/install/debug.7z + build/install/*.exe + build/install/*.dll + build/install/res/ + build/install/debug.7z diff --git a/CMakeLists.txt b/CMakeLists.txt index 3750418a76..8b5b690224 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN") set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment") if (DUSK_MOVIE_SUPPORT) - find_package(libjpeg-turbo QUIET) + find_package(libjpeg-turbo 3.0 CONFIG QUIET) if (libjpeg-turbo_FOUND) message(STATUS "dusk: Using system libjpeg-turbo") else () @@ -299,8 +299,12 @@ include(src/dusk/randomizer/randomizer.cmake) # Edit & Continue if (MSVC) - add_compile_options("/ZI") - add_link_options("/INCREMENTAL") + if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL Debug) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue") + endif () + if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "EditAndContinue") + add_link_options("/INCREMENTAL") + endif () endif () if(ANDROID) diff --git a/CMakePresets.json b/CMakePresets.json index c3c7463be3..44e75973b9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -22,6 +22,20 @@ "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded" } }, + { + "name": "ci", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER_LAUNCHER": "sccache", + "CMAKE_CXX_COMPILER_LAUNCHER": "sccache", + "DUSK_ENABLE_SENTRY_NATIVE": { + "type": "BOOL", + "value": true + }, + "DUSK_SENTRY_DSN": "$env{SENTRY_DSN}", + "DUSK_SENTRY_ENVIRONMENT": "production" + } + }, { "name": "linux-default", "displayName": "Linux (default)", @@ -343,12 +357,9 @@ "name": "x-linux-ci", "hidden": true, "inherits": [ - "relwithdebinfo" - ], - "cacheVariables": { - "CMAKE_C_COMPILER_LAUNCHER": "sccache", - "CMAKE_CXX_COMPILER_LAUNCHER": "sccache" - } + "relwithdebinfo", + "ci" + ] }, { "name": "x-linux-ci-gcc", @@ -367,12 +378,9 @@ { "name": "x-macos-ci", "inherits": [ - "macos-default-relwithdebinfo" - ], - "cacheVariables": { - "CMAKE_C_COMPILER_LAUNCHER": "sccache", - "CMAKE_CXX_COMPILER_LAUNCHER": "sccache" - } + "macos-default-relwithdebinfo", + "ci" + ] }, { "name": "x-ios-ci", @@ -398,14 +406,16 @@ "name": "x-windows-ci", "hidden": true, "inherits": [ - "relwithdebinfo" + "relwithdebinfo", + "ci" ], - "binaryDir": "$env{BUILD_DIR}", "cacheVariables": { - "CMAKE_INSTALL_PREFIX": "$env{BUILD_DIR}/install", - "CMAKE_C_COMPILER_LAUNCHER": "sccache", - "CMAKE_CXX_COMPILER_LAUNCHER": "sccache", - "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "Embedded" + "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "Embedded", + "CMAKE_TOOLCHAIN_FILE": { + "type": "FILEPATH", + "value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + }, + "VCPKG_TARGET_TRIPLET": "x64-windows" } }, { diff --git a/ci/build-appimage.sh b/ci/build-appimage.sh index 82c4cffaeb..3ce3021b97 100755 --- a/ci/build-appimage.sh +++ b/ci/build-appimage.sh @@ -9,7 +9,7 @@ chmod +x linuxdeploy-$(uname -m).AppImage # Build AppImage cd "$GITHUB_WORKSPACE" mkdir -p build/appdir/usr/{bin,share/{applications,icons/hicolor}} -cp build/install/!(*.*) build/appdir/usr/bin +cp -r build/install/!(*.*) build/appdir/usr/bin cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor cp platforms/freedesktop/dusk.desktop build/appdir/usr/share/applications diff --git a/include/d/d_msg_scrn_howl.h b/include/d/d_msg_scrn_howl.h index bf28682d42..5db5db0232 100644 --- a/include/d/d_msg_scrn_howl.h +++ b/include/d/d_msg_scrn_howl.h @@ -110,6 +110,10 @@ struct dMsgScrnHowl_c : public dMsgScrnBase_c { /* 0x27A0 */ f32 field_0x27a0; /* 0x27A4 */ f32 field_0x27a4; /* 0x27A8 */ f32 field_0x27a8; + +#if TARGET_PC + u8 showCursor; +#endif }; #endif /* MSG_SCRN_D_MSG_SCRN_HOWL_H */ diff --git a/include/d/d_save.h b/include/d/d_save.h index 3356bd2e32..cdc0160d7d 100644 --- a/include/d/d_save.h +++ b/include/d/d_save.h @@ -500,19 +500,31 @@ public: } } char* getPlayerName() const { return const_cast(mPlayerName); } - void setPlayerName(const char* i_name) { strcpy(mPlayerName, i_name); } + void setPlayerName(const char* i_name) { +#if AVOID_UB + strncpy(mPlayerName, i_name, sizeof(mPlayerName) - 1); + mPlayerName[sizeof(mPlayerName) - 1] = '\0'; +#else + strcpy(mPlayerName, i_name); +#endif + } char* getHorseName() const { return const_cast(mHorseName); } - void setHorseName(const char* i_name) { strcpy(mHorseName, i_name); } + void setHorseName(const char* i_name) { +#if AVOID_UB + strncpy(mHorseName, i_name, sizeof(mHorseName) - 1); + mHorseName[sizeof(mHorseName) - 1] = '\0'; +#else + strcpy(mHorseName, i_name); +#endif + } u8 getClearCount() const { return mClearCount; } /* 0x00 */ BE(u64) unk0; /* 0x08 */ BE(s64) mTotalTime; /* 0x10 */ BE(u16) unk16; /* 0x12 */ BE(u16) mDeathCount; - /* 0x14 */ char mPlayerName[16]; - /* 0x24 */ u8 unk36; - /* 0x25 */ char mHorseName[16]; - /* 0x35 */ u8 unk53; + /* 0x14 */ char mPlayerName[17]; + /* 0x25 */ char mHorseName[17]; /* 0x36 */ u8 mClearCount; /* 0x37 */ u8 unk55[5]; }; // Size: 0x40 diff --git a/include/dusk/frame_interpolation.h b/include/dusk/frame_interpolation.h index 423ac9af37..3aadfe8520 100644 --- a/include/dusk/frame_interpolation.h +++ b/include/dusk/frame_interpolation.h @@ -34,6 +34,7 @@ void open_child(const void* key, int32_t id); void close_child(); void record_camera(::camera_process_class* cam, int camera_id); void record_final_mtx_raw(const Mtx* dest, const Mtx src); +void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag); bool lookup_replacement(const void* source, Mtx out); bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out); @@ -41,6 +42,7 @@ bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out); void camera_eye_from_view_mtx(MtxP view_mtx, cXyz* o_eye); bool build_star_view(Mtx o_view, Mtx o_cam_billboard_base, cXyz* o_anchor_eye, float* o_fovy); +uint64_t alloc_simple_shadow_pair_base(); } // namespace frame_interp } // namespace dusk #endif diff --git a/include/dusk/hotkeys.h b/include/dusk/hotkeys.h index 4879b2ddce..c3dd354538 100644 --- a/include/dusk/hotkeys.h +++ b/include/dusk/hotkeys.h @@ -9,15 +9,17 @@ constexpr const char* DO_RESET = "Cmd+R"; constexpr const char* DO_RESET = "Ctrl+R"; #endif -constexpr const char* TOGGLE_FULLSCREEN = "F11"; - constexpr const char* SHOW_PROCESS_MANAGEMENT = "F2"; constexpr const char* SHOW_DEBUG_OVERLAY = "F3"; constexpr const char* SHOW_HEAP_VIEWER = "F4"; -constexpr const char* SHOW_STUB_LOG = "F5"; -constexpr const char* SHOW_CAMERA_DEBUG = "F6"; -constexpr const char* SHOW_AUDIO_DEBUG = "F7"; +constexpr const char* SHOW_PLAYER_INFO = "F5"; +constexpr const char* SHOW_SAVE_EDITOR = "F6"; +constexpr const char* SHOW_MAP_LOADER = "F7"; constexpr const char* SHOW_STATE_SHARE = "F8"; +constexpr const char* SHOW_DEBUG_CAMERA = "F9"; +constexpr const char* SHOW_AUDIO_DEBUG = "F10"; + +constexpr const char* TOGGLE_FULLSCREEN = "F11"; constexpr const char* TURBO = "Tab"; diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp index fc727a1248..6df52abc5b 100644 --- a/src/d/actor/d_a_title.cpp +++ b/src/d/actor/d_a_title.cpp @@ -18,6 +18,11 @@ #include "JSystem/J2DGraph/J2DTextBox.h" #include "m_Do/m_Do_graphic.h" +#ifdef TARGET_PC +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" +#endif + class daTit_HIO_c : public JORReflexible { public: daTit_HIO_c(); @@ -343,6 +348,12 @@ void daTitle_c::fastLogoDispInit() { field_0x604 = 0; mWaitTimer = 30; mProcID = 5; + +#ifdef TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + dusk::frame_interp::request_presentation_sync(); + } +#endif } void daTitle_c::fastLogoDisp() { diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 24798f4482..e903e39ce4 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -1,28 +1,29 @@ #include "d/dolzel.h" // IWYU pragma: keep -#include #include "JSystem/J2DGraph/J2DAnimation.h" #include "JSystem/J2DGraph/J2DGrafContext.h" #include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J3DGraphBase/J3DDrawBuffer.h" -#include "JSystem/JKernel/JKRHeap.h" #include "SSystem/SComponent/c_bg_s_shdw_draw.h" #include "SSystem/SComponent/c_math.h" #include "d/d_com_inf_game.h" #include "d/d_drawlist.h" - -#include - -#include "absl/container/flat_hash_map.h" -#include "client/TracyScoped.hpp" #include "d/d_s_play.h" -#include "dusk/frame_interpolation.h" -#include "dusk/gx_helper.h" -#include "dusk/logging.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_lib.h" #include "m_Do/m_Do_mtx.h" +#if TARGET_PC +#include +#include +#include "JSystem/JKernel/JKRHeap.h" +#include "absl/container/flat_hash_map.h" +#include "client/TracyScoped.hpp" +#include "dusk/frame_interpolation.h" +#include "dusk/gx_helper.h" +#include "dusk/logging.h" +#endif + class dDlst_2Dm_c { public: virtual void draw(); @@ -1432,8 +1433,14 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa mDoMtx_stack_c::scaleM(param_2, 1.0f, param_2 * param_5); cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(&mVolumeMtx, mVolumeMtx); - dusk::frame_interp::record_final_mtx_raw(&mMtx, mMtx); + const uint64_t shadow_tag_base = dusk::frame_interp::alloc_simple_shadow_pair_base(); + if (shadow_tag_base != 0) { + dusk::frame_interp::record_final_mtx_raw_tagged(&mVolumeMtx, mVolumeMtx, shadow_tag_base); + dusk::frame_interp::record_final_mtx_raw_tagged(&mMtx, mMtx, shadow_tag_base + 1u); + } else { + dusk::frame_interp::record_final_mtx_raw(&mVolumeMtx, mVolumeMtx); + dusk::frame_interp::record_final_mtx_raw(&mMtx, mMtx); + } #endif mpTexObj = param_6; } diff --git a/src/d/d_msg_scrn_howl.cpp b/src/d/d_msg_scrn_howl.cpp index 965bd25075..03729377a5 100644 --- a/src/d/d_msg_scrn_howl.cpp +++ b/src/d/d_msg_scrn_howl.cpp @@ -19,6 +19,10 @@ #include "JSystem/J2DGraph/J2DScreen.h" #include "Z2AudioLib/Z2WolfHowlMgr.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + // POSIX already defines a macro with this name, but we know that this specific name is // used in TP based on assertion messages. This redefinition is scoped to this TU which // is unlikely to ever actually need the POSIX define, so we can just redefine it. @@ -307,6 +311,17 @@ void dMsgScrnHowl_c::exec() { mpButtonIcon[1]->setAlphaRate(field_0x1994 * alphaRate); mpButtonText[0]->setAlphaRate(field_0x1998 * alphaRate); mpButtonText[1]->setAlphaRate(field_0x1998 * alphaRate); + +#if TARGET_PC + showCursor = true; + if (field_0x2798 == 0) { + if (mPlotTime != field_0x212c) { + field_0x212c = mPlotTime; + } else { + showCursor = false; + } + } +#endif } void dMsgScrnHowl_c::drawSelf() { @@ -490,6 +505,7 @@ void dMsgScrnHowl_c::drawWave() { grafContext->setScissor(); #endif +#if !TARGET_PC bool bVar5 = true; if (field_0x2798 == 0) { if (mPlotTime != field_0x212c) { @@ -498,7 +514,14 @@ void dMsgScrnHowl_c::drawWave() { bVar5 = false; } } - if (bVar5) { +#endif + +#if TARGET_PC + if (showCursor) +#else + if (bVar5) +#endif + { for (int iVar10 = 0; iVar10 < field_0x2128 - 1; iVar10++) { f32 local_54 = local_e0; f32 local_c8 = field_0x180[sVar14]; diff --git a/src/d/d_timer.cpp b/src/d/d_timer.cpp index 41826c3029..552874b552 100644 --- a/src/d/d_timer.cpp +++ b/src/d/d_timer.cpp @@ -23,6 +23,10 @@ #include "m_Do/m_Do_lib.h" #include +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + static int dTimer_createStart2D(s32 param_0, u16 param_1); int dTimer_c::_create() { @@ -1336,29 +1340,44 @@ void dDlst_TimerScrnDraw_c::draw() { f32 temp = (f32)g_drawHIO.mMiniGame.mGetInTextAlphaFrames + ((f32)g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f); +#if TARGET_PC + const u32 pending_ui_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); +#else + const u32 pending_ui_ticks = 1u; +#endif + for (int i = 0; i < 51; i++) { - if (m_getin_info[i].bck_frame > 0.0f && m_getin_info[i].bck_frame < temp) { - f32 var_f29 = 1.0f; + for (u32 tick = 0; tick < pending_ui_ticks; tick++) { + if (!(m_getin_info[i].bck_frame > 0.0f && m_getin_info[i].bck_frame < temp)) { + break; + } if (m_getin_info[i].bck_frame < 60.0f) { m_getin_info[i].bck_frame += g_drawHIO.mMiniGame.mGetInTextAnimSpeed; if (m_getin_info[i].bck_frame > 60.0f) { m_getin_info[i].bck_frame = 60.0f; } - - playBckAnimation(m_getin_info[i].bck_frame); - } else if (m_getin_info[i].bck_frame < g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f) - { + } else if (m_getin_info[i].bck_frame < g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f) { m_getin_info[i].bck_frame++; - playBckAnimation(60.0f); } else if (m_getin_info[i].bck_frame < temp) { m_getin_info[i].bck_frame++; - playBckAnimation(60.0f); + } + } + if (m_getin_info[i].bck_frame > 0.0f && m_getin_info[i].bck_frame < temp) { + f32 var_f29 = 1.0f; + if (m_getin_info[i].bck_frame >= g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f && + m_getin_info[i].bck_frame < temp) { var_f29 = acc(g_drawHIO.mMiniGame.mGetInTextAlphaFrames, temp - m_getin_info[i].bck_frame, 0); } + if (m_getin_info[i].bck_frame < 60.0f) { + playBckAnimation(m_getin_info[i].bck_frame); + } else { + playBckAnimation(60.0f); + } + mpGetInParent->setAlphaRate(var_f29); if (g_drawHIO.mMiniGame.mGetInTextLocation == 1) { @@ -1388,8 +1407,7 @@ void dDlst_TimerScrnDraw_c::draw() { m_getin_info[i].pikari_frame = 18.0f - g_drawHIO.mMiniGame.mGetInPikariAnimSpeed; } - } else if (m_getin_info[i].bck_frame > g_drawHIO.mMiniGame.mStartPikariAppearFrames) - { + } else if (m_getin_info[i].bck_frame > g_drawHIO.mMiniGame.mStartPikariAppearFrames) { m_getin_info[i].pikari_frame = 18.0f - g_drawHIO.mMiniGame.mStartPikariAnimSpeed; } diff --git a/src/dusk/frame_interpolation.cpp b/src/dusk/frame_interpolation.cpp index 8c45c034c6..0fa7d036e0 100644 --- a/src/dusk/frame_interpolation.cpp +++ b/src/dusk/frame_interpolation.cpp @@ -28,6 +28,7 @@ struct Data { size_t child_index = 0; Mtx matrix{}; const Mtx* dest = nullptr; + uint64_t stable_tag = 0; }; struct Path; @@ -46,6 +47,8 @@ struct Path { std::vector children; std::vector ops; std::vector> items; + Label draw_scope{}; + uint32_t simple_shadow_pair_seq = 0; }; struct Recording { @@ -57,6 +60,7 @@ struct MatrixValue { }; using FinalMtxLookup = std::unordered_map; +using FinalMtxLookupTagged = std::unordered_map; bool s_initialized = false; @@ -65,7 +69,6 @@ bool g_recording = false; bool g_interpolating = false; bool g_sync_presentation = false; uint32_t g_presentation_counter = 0; -uint32_t g_presentation_sync_end = 0; float g_step = 0.0f; uint32_t g_pending_presentation_ui_ticks = 0; @@ -143,8 +146,9 @@ const OpBucket* find_op_bucket(const Path& path, Op op) { return &*it; } -void build_final_mtx_lookup(const Path& path, FinalMtxLookup& lookup) { - lookup.clear(); +void build_final_mtx_lookups(const Path& path, FinalMtxLookup& dest_lookup, FinalMtxLookupTagged& tag_lookup) { + dest_lookup.clear(); + tag_lookup.clear(); const OpBucket* bucket = find_op_bucket(path, Op::FinalMtx); if (bucket == nullptr) { @@ -152,10 +156,12 @@ void build_final_mtx_lookup(const Path& path, FinalMtxLookup& lookup) { } for (const Data& data : bucket->values) { - if (data.dest == nullptr) { - continue; + if (data.dest != nullptr) { + dest_lookup[data.dest] = &data; + } + if (data.stable_tag != 0) { + tag_lookup[data.stable_tag] = &data; } - lookup[data.dest] = &data; } } @@ -202,7 +208,8 @@ void store_replacement(const Data& old_data, const Data& new_data, float step) { void interpolate_branch(const Path& old_path, const Path& new_path, float step) { FinalMtxLookup old_final_mtx_lookup; - build_final_mtx_lookup(old_path, old_final_mtx_lookup); + FinalMtxLookupTagged old_final_mtx_lookup_tagged; + build_final_mtx_lookups(old_path, old_final_mtx_lookup, old_final_mtx_lookup_tagged); for (const auto& item : new_path.items) { const Op op = item.first; @@ -231,7 +238,17 @@ void interpolate_branch(const Path& old_path, const Path& new_path, float step) } const Data* indexed_old_data = find_matching_data(old_path, op, index); - const Data* old_data = op == Op::FinalMtx ? find_matching_final_mtx(old_final_mtx_lookup, *new_data) : indexed_old_data; + const Data* old_data = nullptr; + if (op == Op::FinalMtx) { + if (new_data->stable_tag != 0) { + const auto it = old_final_mtx_lookup_tagged.find(new_data->stable_tag); + old_data = it != old_final_mtx_lookup_tagged.end() ? it->second : nullptr; + } else { + old_data = find_matching_final_mtx(old_final_mtx_lookup, *new_data); + } + } else { + old_data = indexed_old_data; + } if (op == Op::FinalMtx) { store_replacement(old_data != nullptr ? *old_data : *new_data, *new_data, step); } @@ -280,10 +297,7 @@ void begin_record() { return; } - if (g_sync_presentation && g_presentation_counter > g_presentation_sync_end) { - g_sync_presentation = false; - } - + g_sync_presentation = false; g_previous_recording = std::move(g_current_recording); g_current_recording = {}; g_current_path.clear(); @@ -320,7 +334,6 @@ void request_presentation_sync() { return; } g_sync_presentation = true; - g_presentation_sync_end = g_presentation_counter + 1; } bool presentation_sync_active() { @@ -375,7 +388,9 @@ void open_child(const void* key, int32_t id) { data.child_label = label; data.child_index = siblings.size(); siblings.emplace_back(std::make_unique()); - g_current_path.push_back(siblings.back().get()); + Path* const child = siblings.back().get(); + child->draw_scope = label; + g_current_path.push_back(child); } void close_child() { @@ -393,6 +408,18 @@ void record_final_mtx_raw(const Mtx* dest, const Mtx src) { Data& data = append_op(Op::FinalMtx); data.dest = dest; + data.stable_tag = 0; + copy_matrix(src, data.matrix); +} + +void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag) { + if (!s_initialized || !g_recording || dest == nullptr) { + return; + } + + Data& data = append_op(Op::FinalMtx); + data.dest = dest; + data.stable_tag = stable_tag; copy_matrix(src, data.matrix); } @@ -506,4 +533,20 @@ bool build_star_view(Mtx o_view, Mtx o_cam_billboard_base, cXyz* o_anchor_eye, f *o_fovy = s_star_prev.fovy + (s_star_curr.fovy - s_star_prev.fovy) * step; return true; } + +uint64_t alloc_simple_shadow_pair_base() { + if (!s_initialized || !g_recording || g_current_path.size() <= 1) { + return 0; + } + + Path* const scope = g_current_path.back(); + const uint64_t h = static_cast(reinterpret_cast(scope->draw_scope.key)); + const uint32_t lo = scope->simple_shadow_pair_seq; + scope->simple_shadow_pair_seq += 2; + uint64_t tag0 = (h << 17) ^ (static_cast(lo) << 1u); + if (tag0 == 0) { + tag0 = 2; + } + return tag0; +} } // namespace dusk::frame_interp diff --git a/src/dusk/imgui/ImGuiAudio.cpp b/src/dusk/imgui/ImGuiAudio.cpp index 7e76ba4e9a..9abe4c5261 100644 --- a/src/dusk/imgui/ImGuiAudio.cpp +++ b/src/dusk/imgui/ImGuiAudio.cpp @@ -209,7 +209,7 @@ static void ShowAllJAISeqs() { } void dusk::ImGuiMenuTools::ShowAudioDebug() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showAudioDebug)) { + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug)) { return; } @@ -255,7 +255,8 @@ void dusk::ImGuiMenuTools::ShowAudioDebug() { } void dusk::ImGuiMenuTools::ShowSaveEditor() { - if (m_showSaveEditor) { - m_saveEditor.draw(m_showSaveEditor); + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor)) { + return; } + m_saveEditor.draw(m_showSaveEditor); } diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index 49e6040649..daaa2d6180 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -7,7 +7,7 @@ namespace dusk { void ImGuiMenuTools::ShowCameraOverlay() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showCameraOverlay)) { + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay)) { return; } diff --git a/src/dusk/imgui/ImGuiMapLoader.cpp b/src/dusk/imgui/ImGuiMapLoader.cpp index e443f879af..63f4befb44 100644 --- a/src/dusk/imgui/ImGuiMapLoader.cpp +++ b/src/dusk/imgui/ImGuiMapLoader.cpp @@ -9,7 +9,7 @@ namespace dusk { void ImGuiMenuTools::ShowMapLoader() { - if (!m_showMapLoader) { + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader)) { return; } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 3a9935353f..7b317c978b 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -48,13 +48,14 @@ namespace dusk { ImGui::MenuItem("Process Management", hotkeys::SHOW_PROCESS_MANAGEMENT, &m_showProcessManagement); ImGui::MenuItem("Debug Overlay", hotkeys::SHOW_DEBUG_OVERLAY, &m_showDebugOverlay); ImGui::MenuItem("Heap Viewer", hotkeys::SHOW_HEAP_VIEWER, &m_showHeapOverlay); - ImGui::MenuItem("Stub Log", hotkeys::SHOW_STUB_LOG, &m_showStubLog); - ImGui::MenuItem("Debug Camera", hotkeys::SHOW_CAMERA_DEBUG, &m_showCameraOverlay); - ImGui::MenuItem("Map Loader", nullptr, &m_showMapLoader); - ImGui::MenuItem("Player Info", nullptr, &m_showPlayerInfo); - ImGui::MenuItem("Save Editor", nullptr, &m_showSaveEditor); + ImGui::MenuItem("Player Info", hotkeys::SHOW_PLAYER_INFO, &m_showPlayerInfo); + ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor); + ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader); ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare); + ImGui::MenuItem("Debug Camera", hotkeys::SHOW_DEBUG_CAMERA, &m_showCameraOverlay); ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); + + ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog); if (!dusk::IsGameLaunched) { ImGui::EndDisabled(); @@ -128,7 +129,7 @@ namespace dusk { } void ImGuiMenuTools::ShowPlayerInfo() { - if (!m_showPlayerInfo) { + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo)) { return; } diff --git a/src/dusk/imgui/ImGuiStubLog.cpp b/src/dusk/imgui/ImGuiStubLog.cpp index d8638da297..1ac510faf8 100644 --- a/src/dusk/imgui/ImGuiStubLog.cpp +++ b/src/dusk/imgui/ImGuiStubLog.cpp @@ -3,7 +3,6 @@ #include "dusk/logging.h" #include "imgui.h" -#include "ImGuiConsole.hpp" #include "ImGuiMenuTools.hpp" namespace dusk { @@ -49,7 +48,7 @@ namespace dusk { void ImGuiMenuTools::ShowStubLog() { std::lock_guard lock(StubLogMutex); - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showStubLog)) { + if (!m_showStubLog) { return; } diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 51733dad8c..92c8707782 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -28,10 +28,6 @@ #include "d/d_menu_collect.h" #include "d/d_meter2_info.h" #include "d/d_s_play.h" -#include "dusk/endian.h" -#include "dusk/frame_interpolation.h" -#include "dusk/gx_helper.h" -#include "dusk/logging.h" #include "f_ap/f_ap_game.h" #include "f_op/f_op_actor_mng.h" #include "f_op/f_op_camera_mng.h" @@ -52,8 +48,12 @@ #if TARGET_PC #include "d/actor/d_a_horse.h" -#include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/dusk.h" +#include "dusk/endian.h" +#include "dusk/frame_interpolation.h" +#include "dusk/gx_helper.h" +#include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/logging.h" #endif class mDoGph_HIO_c : public JORReflexible { @@ -1989,12 +1989,13 @@ static void captureScreenPerspDrawInfo(JPADrawInfo& info) { static void drawItem3D() { ZoneScoped; #ifdef TARGET_PC - // Frame interpolation: Title screen needs 0.0f while everything else that runs through this is -100.0f. - // Running presentation faster than logic revealed the problem. Thanks, Nintendo. - if (fopAcM_SearchByName(fpcNm_TITLE_e) != nullptr) { - dMenu_Collect3D_c::setViewPortOffsetY(0.0f); - } else { - dMenu_Collect3D_c::setViewPortOffsetY(-100.0f); + if (dusk::getSettings().game.enableFrameInterpolation) { + // FRAME INTERP NOTE: Title screen needs 0.0f while everything else that runs through this is -100.0f. + if (fopAcM_SearchByName(fpcNm_TITLE_e) != nullptr) { + dMenu_Collect3D_c::setViewPortOffsetY(0.0f); + } else { + dMenu_Collect3D_c::setViewPortOffsetY(-100.0f); + } } #endif Mtx item_mtx; @@ -2033,12 +2034,11 @@ int mDoGph_Painter() { #endif #ifdef TARGET_PC - for (u32 i = 0; i < pending_ui_ticks; ++i) { + for (u32 i = 0; i < pending_ui_ticks; ++i) #endif + { dComIfGp_particle_calcMenu(); -#ifdef TARGET_PC } -#endif JFWDisplay::getManager()->setFader(mDoGph_gInf_c::getFader()); mDoGph_gInf_c::setClearColor(mDoGph_gInf_c::getBackColor()); @@ -2598,13 +2598,12 @@ int mDoGph_Painter() { #endif GXSetClipMode(GX_CLIP_ENABLE); -#ifdef TARGET_PC - for (u32 i = 0; i < pending_ui_ticks; ++i) { +#if TARGET_PC + for (u32 i = 0; i < pending_ui_ticks; ++i) #endif + { dDlst_list_c::calcWipe(); -#ifdef TARGET_PC } -#endif j3dSys.reinitGX(); ortho.setOrtho(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(),