diff --git a/.vscode/launch.json b/.vscode/launch.json index 4cc435870a..7090699dd9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "cppvsdbg", "request": "launch", "program": "${command:cmake.launchTargetPath}", - "args": ["-l", "1", "--dvd", "${workspaceRoot}/orig/GZ2E01/GZ2E01.iso"], + "args": ["-l", "1", "--dvd", "${workspaceRoot}/orig/GZ2E01/GZ2E01.iso", "--console"], "MIMode": "gdb", "miDebuggerPath": "gdb", "symbolSearchPath": "${command:cmake.launchTargetPath}", diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a84fd04c9..8e7df6bd92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -318,6 +318,48 @@ endif () include(src/dusk/randomizer/randomizer.cmake) +option(DUSK_ENABLE_DISCORD_RPC "Enable Discord Rich Presence support" ON) +if (DUSK_ENABLE_DISCORD_RPC AND NOT ANDROID AND NOT IOS AND NOT TVOS) + + FetchContent_Populate(discord_rpc + URL https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.tar.gz + URL_HASH SHA256=e13427019027acd187352dacba6c65953af66fdf3c35fcf38fc40b454a9d7855 + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + # RapidJSON is a git submodule absent from the discord-rpc tarball; fetch separately. + FetchContent_Populate(rapidjson + URL https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.tar.gz + URL_HASH SHA256=bf7ced29704a1e696fbccf2a2b4ea068e7774fa37f6d7dd4039d0787f8bed98e + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + + if (NOT TARGET discord-rpc) + set(_drpc ${discord_rpc_SOURCE_DIR}/src) + set(_drpc_src + ${_drpc}/discord_rpc.cpp + ${_drpc}/rpc_connection.cpp + ${_drpc}/serialization.cpp + ) + if (WIN32) + list(APPEND _drpc_src ${_drpc}/connection_win.cpp ${_drpc}/discord_register_win.cpp) + elseif (APPLE) + list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_osx.m) + else () + list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_linux.cpp) + endif () + add_library(discord-rpc STATIC ${_drpc_src}) + target_include_directories(discord-rpc PUBLIC + ${discord_rpc_SOURCE_DIR}/include + ${rapidjson_SOURCE_DIR}/include + ) + if (UNIX) + target_link_libraries(discord-rpc PUBLIC pthread) + endif () + endif () + list(APPEND GAME_LIBS discord-rpc) + list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD_RPC=1) +endif () + # Edit & Continue if (MSVC) if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -359,12 +401,6 @@ target_include_directories(game_base PRIVATE ${GAME_INCLUDE_DIRS}) target_link_libraries(game_debug PRIVATE ${GAME_LIBS}) target_link_libraries(game_base PRIVATE ${GAME_LIBS}) -# Combined game library -add_library(game STATIC - $ - $) -target_link_libraries(game PUBLIC ${GAME_LIBS}) - if(ANDROID) add_library(dusk SHARED src/dusk/main.cpp) set_target_properties(dusk PROPERTIES OUTPUT_NAME main) @@ -374,7 +410,7 @@ endif () target_compile_definitions(dusk PRIVATE TARGET_PC AVOID_UB=1 VERSION=0) target_include_directories(dusk PRIVATE include) -target_link_libraries(dusk PRIVATE game aurora::main) +target_link_libraries(dusk PRIVATE game_base game_debug aurora::main) if (TARGET crashpad_handler) add_dependencies(dusk crashpad_handler) endif () diff --git a/CMakePresets.json b/CMakePresets.json index 90307aa061..92799249a9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -148,8 +148,7 @@ "cacheVariables": { "CMAKE_C_COMPILER": "cl", "CMAKE_CXX_COMPILER": "cl", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install", - "AURORA_DAWN_PROVIDER": "vendor" + "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install" }, "vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { @@ -359,7 +358,10 @@ "inherits": [ "relwithdebinfo", "ci" - ] + ], + "cacheVariables": { + "AURORA_SDL3_PROVIDER": "vendor" + } }, { "name": "x-linux-ci-gcc", @@ -382,7 +384,6 @@ "ci" ], "cacheVariables": { - "AURORA_DAWN_PROVIDER": "vendor", "AURORA_NOD_PROVIDER": "vendor", "CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": { "type": "BOOL", diff --git a/README.md b/README.md index c41985d394..7322441b74 100644 --- a/README.md +++ b/README.md @@ -1,103 +1,59 @@ -## Dusk +![DuskLogo](res/logo-mascot.webp) -### Building -#### Prerequisites -* [CMake 3.25+](https://cmake.org) - * Windows: Install `CMake Tools` in Visual Studio - * macOS: `brew install cmake` -* [Python 3+](https://python.org) - * Windows: [Microsoft Store](https://go.microsoft.com/fwlink?linkID=2082640) - * Verify it's added to `%PATH%` by typing `python` in `cmd`. - * macOS: `brew install python@3` -* **[Windows]** [Visual Studio 2026 Community](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) - * Select `C++ Development` and verify the following packages are included: - * `Windows 11 SDK` - * `CMake Tools` - * `C++ Clang Compiler` - * `C++ Clang-cl` -* **[macOS]** [Xcode 16.4+](https://developer.apple.com/xcode/download/) -* **[Linux]** Actively tested on Ubuntu 24.04, Arch Linux & derivatives. - * Ubuntu 24.04+ packages - ``` - build-essential curl git ninja-build clang lld zlib1g-dev libcurl4-openssl-dev \ - libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev libpulse-dev \ - libudev-dev libpng-dev libncurses5-dev cmake libx11-xcb-dev python3 python-is-python3 \ - libclang-dev libfreetype-dev libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev \ - libxss-dev libxtst-dev - ``` - * Arch Linux packages - ``` - base-devel cmake ninja llvm vulkan-headers python python-markupsafe clang lld alsa-lib libpulse libxrandr freetype2 - ``` - * Fedora packages - ``` - cmake vulkan-headers ninja-build clang-devel llvm-devel libpng-devel - ``` - * It's also important that you install the developer tools and libraries - ``` - sudo dnf groupinstall "Development Tools" "Development Libraries" - ``` -#### Setup -Clone and initialize the Dusk repository -```sh -git clone --recursive https://github.com/TwilitRealm/dusk.git -cd dusk -git pull -git submodule update --init --recursive -``` +- ### **[Official Website](https://twilitrealm.dev)** +- ### **[Discord](https://discord.gg/QACynxeyna)** -#### Building +# Setup +**⚠️Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.** -**CLion (Windows / macOS / Linux)** +### 1. Verify your ROM dump +First make sure your dump of the game is clean and supported by Dusk. You can do this by checking the sha1 hash of your dump against this list of supported versions. -Open the project directory in CLion. Enable the appropriate presets for your platform: +| Version | sha1 hash | +| ------------ | ---------------------------------------- | +| GameCube USA | 75edd3ddff41f125d1b4ce1a40378f1b565519e7 | -![CLion](assets/clion.png) +### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases) -**Visual Studio (Windows)** +### 3. Setup the game +#### Windows +- Extract the zip folder +- Place your dump of the game into the same folder where you extracted to +- Launch `dusk.exe` -Open the project directory in Visual Studio. The CMake configuration will be loaded automatically. +#### macOS +- TODO -**ninja (macOS)** +#### Linux +- TODO -```sh -cmake --preset macos-default-relwithdebinfo -cmake --build --preset macos-default-relwithdebinfo -``` +#### iOS +- TODO -Alternate presets available: -- `macos-default-debug`: Clang, Debug +#### android +- TODO -**ninja (Linux)** +# Building +If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). -```sh -cmake --preset linux-default-relwithdebinfo -cmake --build --preset linux-default-relwithdebinfo -``` +# Credits +- Taka +- encounter +- Antidote +- caseif +- CraftyBoss +- crowell +- dooplecks +- gymnast86 +- Irastris +- kipcode66 +- Lars +- LunarSoap +- Maddie +- MelonSpeedruns +- Pheenoh +- PJB +- Roeming +- YunataSavior -Alternate presets available: -- `linux-default-debug`: GCC, Debug -- `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo -- `linux-clang-debug`: Clang, Debug - -**ninja (Windows)** - -```sh -cmake --preset windows-msvc-relwithdebinfo -cmake --build --preset windows-msvc-relwithdebinfo -``` - -Alternate presets available: -- `windows-msvc-debug`: MSVC, Debug -- `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo -- `windows-clang-debug`: Clang-cl, Debug - -#### Running -Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ -```sh -build/{preset}/dusk /path/to/game.rvz -``` -If no path is specified, Dusk defaults to `game.iso` in the current working directory. - -#### 30 FPS on Debug -When compiled fully in a Debug the game runs too slowly to hit playable 30 FPS. To avoid this, you can set a CMake cache variable to optimize specific critical files without hampering debuggability in the rest of the program: `-DDUSK_SELECTED_OPT=ON`. When building for MSVC (Windows) you must also modify `CMAKE_CXX_FLAGS_DEBUG` and `CMAKE_C_FLAGS_DEBUG` to remove `/RTC1` from the flags, like so: `-DCMAKE_CXX_FLAGS_DEBUG="/MDd /Zi /Ob0 /Od" -DCMAKE_C_FLAGS_DEBUG="/MDd /Zi /Ob0 /Od"` +Special thanks to the TP Decomp team, the GC/Wii Decomp community, the Aurora developers, and the TP speedrunning community. diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 0000000000..0b1befa49f --- /dev/null +++ b/docs/building.md @@ -0,0 +1,98 @@ +### Building +#### Prerequisites +* [CMake 3.25+](https://cmake.org) + * Windows: Install `CMake Tools` in Visual Studio + * macOS: `brew install cmake` +* [Python 3+](https://python.org) + * Windows: [Microsoft Store](https://go.microsoft.com/fwlink?linkID=2082640) + * Verify it's added to `%PATH%` by typing `python` in `cmd`. + * macOS: `brew install python@3` +* **[Windows]** [Visual Studio 2026 Community](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) + * Select `C++ Development` and verify the following packages are included: + * `Windows 11 SDK` + * `CMake Tools` + * `C++ Clang Compiler` + * `C++ Clang-cl` +* **[macOS]** [Xcode 16.4+](https://developer.apple.com/xcode/download/) +* **[Linux]** Actively tested on Ubuntu 24.04, Arch Linux & derivatives. + * Ubuntu 24.04+ packages + ``` + build-essential curl git ninja-build clang lld zlib1g-dev libcurl4-openssl-dev \ + libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev libpulse-dev \ + libudev-dev libpng-dev libncurses5-dev cmake libx11-xcb-dev python3 python-is-python3 \ + libclang-dev libfreetype-dev libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev \ + libxss-dev libxtst-dev + ``` + * Arch Linux packages + ``` + base-devel cmake ninja llvm vulkan-headers python python-markupsafe clang lld alsa-lib libpulse libxrandr freetype2 + ``` + * Fedora packages + ``` + cmake vulkan-headers ninja-build clang-devel llvm-devel libpng-devel + ``` + * It's also important that you install the developer tools and libraries + ``` + sudo dnf groupinstall "Development Tools" "Development Libraries" + ``` +#### Setup +Clone and initialize the Dusk repository +```sh +git clone --recursive https://github.com/TwilitRealm/dusk.git +cd dusk +git pull +git submodule update --init --recursive +``` + +#### Building + +**CLion (Windows / macOS / Linux)** + +Open the project directory in CLion. Enable the appropriate presets for your platform: + +![CLion](../assets/clion.png) + +**Visual Studio (Windows)** + +Open the project directory in Visual Studio. The CMake configuration will be loaded automatically. + +**ninja (macOS)** + +```sh +cmake --preset macos-default-relwithdebinfo +cmake --build --preset macos-default-relwithdebinfo +``` + +Alternate presets available: +- `macos-default-debug`: Clang, Debug + +**ninja (Linux)** + +```sh +cmake --preset linux-default-relwithdebinfo +cmake --build --preset linux-default-relwithdebinfo +``` + +Alternate presets available: +- `linux-default-debug`: GCC, Debug +- `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo +- `linux-clang-debug`: Clang, Debug + +**ninja (Windows)** + +```sh +cmake --preset windows-msvc-relwithdebinfo +cmake --build --preset windows-msvc-relwithdebinfo +``` + +Alternate presets available: +- `windows-msvc-debug`: MSVC, Debug +- `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo +- `windows-clang-debug`: Clang-cl, Debug + +#### Running +Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ +```sh +build/{preset}/dusk /path/to/game.rvz +``` +If no path is specified, Dusk defaults to `game.iso` in the current working directory. diff --git a/extern/aurora b/extern/aurora index c21a7f75ab..26da4c6bb0 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit c21a7f75ab1a2fd8ea896fa45b1005b2f903de77 +Subproject commit 26da4c6bb08937ab07b5bd8bbf779b143c672a88 diff --git a/files.cmake b/files.cmake index 7a180c496e..e5e2258929 100644 --- a/files.cmake +++ b/files.cmake @@ -15,7 +15,6 @@ set(DOLZEL_FILES src/m_Do/m_Do_DVDError.cpp src/m_Do/m_Do_MemCard.cpp src/m_Do/m_Do_MemCardRWmng.cpp - src/m_Do/m_Do_machine_exception.cpp src/m_Do/m_Do_hostIO.cpp src/c/c_damagereaction.cpp src/c/c_dylink.cpp @@ -1346,6 +1345,7 @@ set(DUSK_FILES src/dusk/file_select.cpp src/dusk/file_select.hpp src/dusk/frame_interpolation.cpp + src/dusk/game_clock.cpp src/dusk/globals.cpp src/dusk/gyro.cpp src/dusk/io.cpp @@ -1388,6 +1388,7 @@ set(DUSK_FILES src/dusk/OSContext.cpp src/dusk/OSThread.cpp src/dusk/OSMutex.cpp + src/dusk/discord_presence.cpp # Randomizer files src/dusk/randomizer/game/flags.h src/dusk/randomizer/game/stages.cpp diff --git a/include/d/actor/d_a_e_wb.h b/include/d/actor/d_a_e_wb.h index dd36474025..ba680366fb 100644 --- a/include/d/actor/d_a_e_wb.h +++ b/include/d/actor/d_a_e_wb.h @@ -220,6 +220,15 @@ public: /* 0x17E2 */ s16 wait_roll_angle; ///< @brief Roll angle during wait state. /* 0x17E4 */ u8 field_0x17e4[0x17e8 - 0x17e4]; /* 0x17E8 */ f32 ride_speed_max; ///< @brief Speed rate for riding calculations. +#if TARGET_PC + cXyz himo_mat_interp_prev[2][16]; + cXyz himo_mat_interp_curr[2][16]; + cXyz himo_tex_interp_prev[2]; + cXyz himo_tex_interp_curr[2]; + bool himo_interp_prev_valid; + bool himo_interp_curr_valid; + s8 demo_cam_sync_ticks; +#endif }; STATIC_ASSERT(sizeof(e_wb_class) == 0x17EC); diff --git a/include/d/actor/d_a_mirror.h b/include/d/actor/d_a_mirror.h index fd69c8682e..06c5603899 100644 --- a/include/d/actor/d_a_mirror.h +++ b/include/d/actor/d_a_mirror.h @@ -25,6 +25,9 @@ public: /* 0x164 */ cXyz mMinVal; /* 0x170 */ cXyz mMaxVal; /* 0x17C */ cXyz mViewScale; +#if TARGET_PC + bool mbReset = false; +#endif }; /** diff --git a/include/d/actor/d_a_movie_player.h b/include/d/actor/d_a_movie_player.h index 0ddc675c24..0e666ae470 100644 --- a/include/d/actor/d_a_movie_player.h +++ b/include/d/actor/d_a_movie_player.h @@ -94,6 +94,12 @@ static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr); #define THP_TEXTURE_SET_COUNT 3 #endif +#if TARGET_PC +namespace dusk { + void MoviePlayerShutdown(); +} +#endif + struct daMP_THPPlayer { /* 0x000 */ DVDFileInfo fileInfo; /* 0x03C */ THPHeader header; diff --git a/include/d/actor/d_a_obj_sw.h b/include/d/actor/d_a_obj_sw.h index 64674b0b9c..9e2793755a 100644 --- a/include/d/actor/d_a_obj_sw.h +++ b/include/d/actor/d_a_obj_sw.h @@ -68,10 +68,8 @@ public: /* 0x904 */ cXyz field_0x904[2]; /* 0x91C */ int field_0x91c; /* 0x920 */ cXyz field_0x920[63]; - /* 0xC14 */ f32 field_0xc14[4]; - /* 0xC24 */ u8 field_0xc24[0xd10 - 0xc24]; - /* 0xD10 */ s8 field_0xd10[4]; - /* 0xD14 */ u8 field_0xd14[0xd50 - 0xd14]; + /* 0xC14 */ f32 field_0xc14[63]; + /* 0xD10 */ s8 field_0xd10[64]; /* 0xD50 */ mDoExt_3DlineMat1_c field_0xd50; /* 0xD8C */ int field_0xd8c; }; diff --git a/include/d/d_com_inf_game.h b/include/d/d_com_inf_game.h index 40bc63d7ed..91714031d2 100644 --- a/include/d/d_com_inf_game.h +++ b/include/d/d_com_inf_game.h @@ -4886,8 +4886,7 @@ inline void dComIfGd_drawXluListDark() { inline void dComIfGd_drawXluListInvisible() { ZoneScoped; #ifdef TARGET_PC - if (dusk::getSettings().game.enableWaterRefraction && - !dusk::getSettings().game.enableFrameInterpolation) { + if (!dusk::getSettings().game.disableWaterRefraction) { #endif g_dComIfG_gameInfo.drawlist.drawXluListInvisible(); #ifdef TARGET_PC @@ -4898,8 +4897,7 @@ inline void dComIfGd_drawXluListInvisible() { inline void dComIfGd_drawOpaListInvisible() { ZoneScoped; #ifdef TARGET_PC - if (dusk::getSettings().game.enableWaterRefraction && - !dusk::getSettings().game.enableFrameInterpolation) { + if (!dusk::getSettings().game.disableWaterRefraction) { #endif g_dComIfG_gameInfo.drawlist.drawOpaListInvisible(); #ifdef TARGET_PC diff --git a/include/d/d_drawlist.h b/include/d/d_drawlist.h index 4126c715f3..8368c9e92e 100644 --- a/include/d/d_drawlist.h +++ b/include/d/d_drawlist.h @@ -209,6 +209,10 @@ public: /* 0x04 */ TGXTexObj* mpTexObj; /* 0x08 */ Mtx mVolumeMtx; /* 0x38 */ Mtx mMtx; +#if TARGET_PC + const void* mVolumeMtxKey; + const void* mMtxKey; +#endif }; // Size: 0x68 struct cBgD_Vtx_t; diff --git a/include/d/d_file_select.h b/include/d/d_file_select.h index 72f7cb7f42..cf081a3b10 100644 --- a/include/d/d_file_select.h +++ b/include/d/d_file_select.h @@ -10,6 +10,7 @@ #include "JSystem/J3DGraphLoader/J3DAnmLoader.h" class dFile_info_c; +class J2DPicture; class dDlst_FileSel_c : public dDlst_base_c { public: @@ -113,6 +114,14 @@ public: /* 0x04 */ J2DScreen* Scr3m; }; +class dDlst_FileSelFade_c : public dDlst_base_c { +public: + void draw(); + virtual ~dDlst_FileSelFade_c() {} + + /* 0x04 */ J2DPicture* mpPict; +}; + class dFs_HIO_c : public JORReflexible { public: dFs_HIO_c(); @@ -676,6 +685,9 @@ public: #if PLATFORM_GCN /* 0x2378 */ J2DPicture* mpFadePict; #endif +#ifdef TARGET_PC + dDlst_FileSelFade_c mFadeDlst; +#endif #if PLATFORM_WII || PLATFORM_SHIELD /* 0x2376 */ u8 field_0x2376[SAVEFILE_SIZE]; @@ -684,6 +696,10 @@ public: #endif }; +#ifdef TARGET_PC +STATIC_ASSERT(sizeof(dFile_select_c) == 0x237C + sizeof(dDlst_FileSelFade_c)); +#else STATIC_ASSERT(sizeof(dFile_select_c) == 0x237C); +#endif #endif /* D_FILE_D_FILE_SELECT_H */ diff --git a/include/d/d_menu_fmap.h b/include/d/d_menu_fmap.h index 026e98e056..48db37fef3 100644 --- a/include/d/d_menu_fmap.h +++ b/include/d/d_menu_fmap.h @@ -75,7 +75,9 @@ public: /* 0x8 */ BE(u16) mAreaName; /* 0xA */ u8 mCount; #ifdef _MSVC_LANG - u8* __get_mRoomNos() const { return (u8*)(this + 1); } + // Room numbers start at offset 0xB (right after mCount), NOT at sizeof(data)=12. + // (u8*)(this+1) would give offset 12 because MSVC sizeof=12; use &mCount+1 instead. + u8* __get_mRoomNos() const { return (u8*)&mCount + 1; } __declspec(property(get = __get_mRoomNos)) u8* mRoomNos; #else /* 0xB */ u8 mRoomNos[0]; diff --git a/include/d/d_menu_ring.h b/include/d/d_menu_ring.h index f28c20aac2..39d29a35e8 100644 --- a/include/d/d_menu_ring.h +++ b/include/d/d_menu_ring.h @@ -204,6 +204,9 @@ private: /* 0x6D1 */ u8 field_0x6d1; /* 0x6D2 */ u8 field_0x6d2; /* 0x6D3 */ u8 field_0x6d3; +#if TARGET_PC + f32 mSelectItemSlideElapsed[4]; +#endif }; #endif /* D_MENU_D_MENU_RING_H */ diff --git a/include/d/d_select_cursor.h b/include/d/d_select_cursor.h index c77da550f8..1bd5991d16 100644 --- a/include/d/d_select_cursor.h +++ b/include/d/d_select_cursor.h @@ -47,6 +47,10 @@ public: mPositionY = y; } +#ifdef TARGET_PC + void refreshAspectScale(); +#endif + void onUpdateFlag() { mUpdateFlag = true; } void resetUpdateFlag() { mUpdateFlag = false; } @@ -79,6 +83,9 @@ private: /* 0x58 */ f32 mPositionX; /* 0x5C */ f32 mPositionY; /* 0x60 */ f32 mParam1; +#ifdef TARGET_PC + f32 mBaseParam1; +#endif /* 0x64 */ f32 mParam2; /* 0x68 */ f32 mParam3; /* 0x6C */ f32 mParam4; diff --git a/include/dusk/audio/DuskAudioSystem.h b/include/dusk/audio/DuskAudioSystem.h index 724776f5f1..8cdd757c82 100644 --- a/include/dusk/audio/DuskAudioSystem.h +++ b/include/dusk/audio/DuskAudioSystem.h @@ -12,6 +12,8 @@ namespace dusk::audio { void SetMasterVolume(f32 value); + void SetPaused(bool paused); + u32 GetResetCount(int channelIdx); f32 VolumeFromU16(u16 value); diff --git a/include/dusk/discord_presence.hpp b/include/dusk/discord_presence.hpp new file mode 100644 index 0000000000..899b2ad5f9 --- /dev/null +++ b/include/dusk/discord_presence.hpp @@ -0,0 +1,18 @@ +#pragma once + +#ifdef DUSK_DISCORD_RPC + +namespace dusk { +namespace discord { + +void Initialize(); + +void RunCallbacks(); + +void UpdatePresence(); + +void Shutdown(); +} +} + +#endif // DUSK_DISCORD_RPC diff --git a/include/dusk/dusk.h b/include/dusk/dusk.h index b751990d9c..911ddbb535 100644 --- a/include/dusk/dusk.h +++ b/include/dusk/dusk.h @@ -6,7 +6,6 @@ #include "aurora/gfx.h" extern AuroraInfo auroraInfo; -extern const char* configPath; namespace dusk { extern AuroraStats lastFrameAuroraStats; diff --git a/include/dusk/frame_interpolation.h b/include/dusk/frame_interpolation.h index 383d16d288..bec9b600cf 100644 --- a/include/dusk/frame_interpolation.h +++ b/include/dusk/frame_interpolation.h @@ -1,5 +1,4 @@ -#ifndef DUSK_FRAME_INTERP_H -#define DUSK_FRAME_INTERP_H +#pragma once #include #include @@ -7,6 +6,7 @@ #include class camera_process_class; +class view_class; #ifdef __cplusplus namespace dusk { @@ -16,42 +16,36 @@ void ensure_initialized(); void begin_record(); void end_record(); -void interpolate(float step); +void begin_frame(bool enabled, bool is_sim_frame, float step); +void interpolate(); float get_interpolation_step(); -void notify_presentation_frame(); void request_presentation_sync(); bool presentation_sync_active(); -void notify_sim_tick_complete(); -uint32_t begin_presentation_ui_pass(); -uint32_t get_presentation_ui_advance_ticks(); -void end_presentation_ui_pass(); +bool is_enabled(); + +// TODO: These should be phased out as UI is progressively updated to use game_clock +void set_ui_tick_pending(bool value); +bool get_ui_tick_pending(); + +bool is_sim_frame(); -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); +void interp_view(::view_class* view); +void record_final_mtx(Mtx m, const void *key); +void record_final_mtx(Mtx m); -bool lookup_replacement(const void* source, Mtx out); +bool lookup_replacement(const void* key, Mtx out); bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out); +typedef void (*InterpolationCallBack)(bool isSimFrame, void* pUserWork); +// call on a sim tick, will get called during presentation +void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork); + void begin_presentation_camera(); void end_presentation_camera(); -struct PresentationCameraScope { - PresentationCameraScope() { begin_presentation_camera(); } - ~PresentationCameraScope() { end_presentation_camera(); } - PresentationCameraScope(const PresentationCameraScope&) = delete; - PresentationCameraScope& operator=(const PresentationCameraScope&) = delete; - PresentationCameraScope(PresentationCameraScope&&) = delete; - PresentationCameraScope& operator=(PresentationCameraScope&&) = delete; -}; - -uint64_t alloc_simple_shadow_pair_base(); } // namespace frame_interp } // namespace dusk #endif - -#endif diff --git a/include/dusk/game_clock.h b/include/dusk/game_clock.h new file mode 100644 index 0000000000..4a394b5c2e --- /dev/null +++ b/include/dusk/game_clock.h @@ -0,0 +1,33 @@ +#ifndef DUSK_GAME_CLOCK_H +#define DUSK_GAME_CLOCK_H + +#include + +namespace dusk { +namespace game_clock { + +void ensure_initialized(); +void reset_accumulator(); +void reset_frame_timer(); + +constexpr float sim_pace() { return 1.0f / 30.0f; } +constexpr float period_for_original_frames(float frame_count) { return frame_count * sim_pace(); } +constexpr float ui_maximum_dt() { return 0.05f; } +constexpr float ui_initial_dt() { return 1.0f / 60.0f; } + +struct MainLoopPacer { + float presentation_dt_seconds; + bool is_interpolating; + bool do_sim_tick; + float interpolation_step; + float sim_pace; +}; + +MainLoopPacer advance_main_loop(); + +float consume_interval(const void* consumer); + +} // namespace game_clock +} // namespace dusk + +#endif // DUSK_GAME_CLOCK_H diff --git a/include/dusk/logging.h b/include/dusk/logging.h index 0a9cbf238d..9b31b96bf2 100644 --- a/include/dusk/logging.h +++ b/include/dusk/logging.h @@ -4,10 +4,12 @@ #include #include +#include + void aurora_log_callback(AuroraLogLevel level, const char* module, const char* message, unsigned int len); namespace dusk { - void InitializeFileLogging(const char* configDir, AuroraLogLevel logLevel); + void InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel); void ShutdownFileLogging(); const char* GetLogFilePath(); void SendToStubLog(AuroraLogLevel level, const char* module, const char* message); diff --git a/include/dusk/main.h b/include/dusk/main.h index a9194e2aba..065f507d36 100644 --- a/include/dusk/main.h +++ b/include/dusk/main.h @@ -1,10 +1,14 @@ #ifndef DUSK_MAIN_H #define DUSK_MAIN_H +#include + namespace dusk { extern bool IsRunning; extern bool IsShuttingDown; extern bool IsGameLaunched; + extern bool IsFocusPaused; + extern std::filesystem::path ConfigPath; } #endif // DUSK_MAIN_H diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 3b3c33bb2f..2cec252006 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -68,13 +68,16 @@ struct UserSettings { ConfigVar enableMirrorMode; ConfigVar invertCameraXAxis; ConfigVar disableMainHUD; + ConfigVar pauseOnFocusLost; // Graphics ConfigVar bloomMode; ConfigVar bloomMultiplier; - ConfigVar enableWaterRefraction; + ConfigVar disableWaterRefraction; ConfigVar enableFrameInterpolation; + ConfigVar internalResolutionScale; ConfigVar shadowResolutionMultiplier; + ConfigVar enableDepthOfField; // Audio ConfigVar noLowHpSound; @@ -92,6 +95,15 @@ struct UserSettings { ConfigVar gyroInvertYaw; // Cheats + ConfigVar infiniteHearts; + ConfigVar infiniteArrows; + ConfigVar infiniteBombs; + ConfigVar infiniteOil; + ConfigVar infiniteOxygen; + ConfigVar infiniteRupees; + ConfigVar moonJump; + ConfigVar superClawshot; + ConfigVar alwaysGreatspin; ConfigVar enableFastIronBoots; ConfigVar canTransformAnywhere; ConfigVar fastSpinner; diff --git a/include/f_pc/f_pc_leaf.h b/include/f_pc/f_pc_leaf.h index 33d7e85d29..414d706b6a 100644 --- a/include/f_pc/f_pc_leaf.h +++ b/include/f_pc/f_pc_leaf.h @@ -25,7 +25,7 @@ typedef struct leafdraw_class : base_process_class { #endif /* 0xB8 */ leafdraw_method_class* leaf_methods; /* 0xBC */ s8 unk_0xBC; - /* 0xBD */ u8 unk_0xBD; + /* 0xBD */ u8 draw_interp_frame; /* 0xBE */ draw_priority_class draw_priority; } leafdraw_class; diff --git a/include/f_pc/f_pc_node.h b/include/f_pc/f_pc_node.h index 3be7fe6c8f..0d96fd2de5 100644 --- a/include/f_pc/f_pc_node.h +++ b/include/f_pc/f_pc_node.h @@ -18,6 +18,7 @@ typedef struct process_node_class { /* 0x0BC */ layer_class layer; /* 0x0E8 */ node_list_class layer_nodelist[16]; /* 0x1A8 */ s8 unk_0x1A8; + /* 0x1A9 */ s8 draw_interp_frame; } process_node_class; typedef struct node_process_profile_definition { diff --git a/include/m_Do/m_Do_graphic.h b/include/m_Do/m_Do_graphic.h index f921912656..5d29049520 100644 --- a/include/m_Do/m_Do_graphic.h +++ b/include/m_Do/m_Do_graphic.h @@ -286,12 +286,7 @@ public: #if WIDESCREEN_SUPPORT static void setTvSize(); - #if TARGET_PC - static void onWide(f32 width, f32 height); - #else static void onWide(); - #endif - static void offWide(); static u8 isWide(); @@ -304,7 +299,7 @@ public: #endif #if TARGET_PC - static void setWindowSize(AuroraWindowSize const& size); + static void updateRenderSize(); #endif static TGXTexObj mFrameBufferTexObj; diff --git a/include/m_Do/m_Do_lib.h b/include/m_Do/m_Do_lib.h index 8130cab8da..14e57ddf5a 100644 --- a/include/m_Do/m_Do_lib.h +++ b/include/m_Do/m_Do_lib.h @@ -43,10 +43,6 @@ struct mDoLib_clipper { }; void mDoLib_project(Vec* src, Vec* dst); -#if TARGET_PC -void mDoLib_project(Vec* src, Vec* dst, JGeometry::TBox2 viewport); -#endif - u32 mDoLib_setResTimgObj(ResTIMG const* res, TGXTexObj* o_texObj, u32 tlut_name, GXTlutObj* o_tlutObj); void mDoLib_pos2camera(Vec* src, Vec* dst); diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h index a27db4fa00..2e5b3bd38d 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h @@ -79,6 +79,10 @@ public: virtual void viewCalc(); virtual ~J3DModel() {} +#if TARGET_PC + static void interp_callback(bool isSimFrame, void* pUserWork); +#endif + J3DModelData* getModelData() { return mModelData; } void onFlag(u32 flag) { mFlags |= flag; } @@ -105,9 +109,7 @@ public: void setAnmMtx(int jointNo, Mtx m) { mMtxBuffer->setAnmMtx(jointNo, m); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw( - reinterpret_cast(mMtxBuffer->getAnmMtx(jointNo)), - mMtxBuffer->getAnmMtx(jointNo)); + dusk::frame_interp::record_final_mtx(mMtxBuffer->getAnmMtx(jointNo)); #endif } MtxP getAnmMtx(int jointNo) { return mMtxBuffer->getAnmMtx(jointNo); } diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModelData.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModelData.h index 6e3d54ff45..52e5018c1b 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModelData.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModelData.h @@ -23,6 +23,10 @@ public: void syncJ3DSysPointers() const; void syncJ3DSysFlags() const; +#if TARGET_PC + bool needsInterpCallBack() const; +#endif + virtual ~J3DModelData() {} void simpleCalcMaterial(Mtx mtx) { simpleCalcMaterial(0, mtx); } diff --git a/libs/JSystem/include/JSystem/J3DGraphBase/J3DMaterial.h b/libs/JSystem/include/JSystem/J3DGraphBase/J3DMaterial.h index 829156ad1b..70e368eec4 100644 --- a/libs/JSystem/include/JSystem/J3DGraphBase/J3DMaterial.h +++ b/libs/JSystem/include/JSystem/J3DGraphBase/J3DMaterial.h @@ -33,6 +33,9 @@ public: void copy(J3DMaterial*); s32 newSharedDisplayList(u32); s32 newSingleSharedDisplayList(u32); +#if TARGET_PC + bool needsInterpCallBack() const; +#endif virtual void calc(f32 const (*)[4]); virtual void calcDiffTexMtx(f32 const (*)[4]); @@ -46,7 +49,6 @@ public: virtual void change(); J3DMaterial() { initialize(); } - ~J3DMaterial() {} J3DMaterial* getNext() { return mNext; } J3DShape* getShape() { return mShape; } J3DTevBlock* getTevBlock() { return mTevBlock; } diff --git a/libs/JSystem/include/JSystem/JFramework/JFWDisplay.h b/libs/JSystem/include/JSystem/JFramework/JFWDisplay.h index fab39a296b..28967cc0a2 100644 --- a/libs/JSystem/include/JSystem/JFramework/JFWDisplay.h +++ b/libs/JSystem/include/JSystem/JFramework/JFWDisplay.h @@ -101,10 +101,6 @@ public: void setDrawDoneMethod(EDrawDone drawDone) { mDrawDoneMethod = drawDone; } void setFader(JUTFader* fader) { mFader = fader; } -#ifdef TARGET_PC - // For frame interpolation - void setFaderSimSteps(u32 steps); -#endif void resetFader() { setFader(NULL); } JUTFader* getFader() const { return mFader; } void setClearColor(JUtility::TColor color) { mClearColor = color; } diff --git a/libs/JSystem/include/JSystem/JUtility/JUTFader.h b/libs/JSystem/include/JSystem/JUtility/JUTFader.h index 6c98a6840f..b85e4a6cd4 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTFader.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTFader.h @@ -11,8 +11,10 @@ class JUTFader { public: enum EStatus { - UNKSTATUS_M1 = -1, - UNKSTATUS_0 = 0, + None, + Wait, + FadeIn, + FadeOut, }; JUTFader(int, int, int, int, JUtility::TColor); @@ -29,12 +31,12 @@ public: void setColor(JUtility::TColor color) { mColor.set(color); } /* 0x04 */ s32 mStatus; - /* 0x08 */ u16 field_0x8; - /* 0x0A */ u16 field_0xa; + /* 0x08 */ u16 mDuration; + /* 0x0A */ u16 mTimer; /* 0x0C */ JUtility::TColor mColor; /* 0x10 */ JGeometry::TBox2 mBox; - /* 0x20 */ int mEStatus; - /* 0x24 */ u32 field_0x24; + /* 0x20 */ int mStatusTimer; + /* 0x24 */ u32 mNextStatus; }; #endif /* JUTFADER_H */ diff --git a/libs/JSystem/include/JSystem/JUtility/JUTVideo.h b/libs/JSystem/include/JSystem/JUtility/JUTVideo.h index 9a23a4dc7e..dfc6fd0b6c 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTVideo.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTVideo.h @@ -33,24 +33,16 @@ public: static void postRetraceProc(u32); static void drawDoneCallback(); - u16 getFbWidth() const { - #if TARGET_PC - return m_WindowSize.fb_width; - #else - return mRenderObj->fbWidth; - #endif - } - u16 getEfbHeight() const { - #if TARGET_PC - return m_WindowSize.fb_height; - #else - return mRenderObj->efbHeight; - #endif - } + u16 getFbWidth() const { return mRenderObj->fbWidth; } + u16 getEfbHeight() const { return mRenderObj->efbHeight; } void getBounds(u16& width, u16& height) const { width = (u16)getFbWidth(); height = (u16)getEfbHeight(); } +#ifdef TARGET_PC + u32 getRenderWidth() const { return mRenderWidth; } + u32 getRenderHeight() const { return mRenderHeight; } +#endif u16 getXfbHeight() const { return u16(mRenderObj->xfbHeight); } u8 isAntiAliasing() const { return u8(mRenderObj->aa); } Pattern getSamplePattern() const { return mRenderObj->sample_pattern; } @@ -63,7 +55,7 @@ public: GXRenderModeObj* getRenderMode() const { return mRenderObj; } #if TARGET_PC - void setWindowSize(AuroraWindowSize const& size); + void setRenderSize(u32 width, u32 height); #endif private: @@ -89,7 +81,8 @@ private: #if TARGET_PC public: - AuroraWindowSize m_WindowSize; + u32 mRenderWidth; + u32 mRenderHeight; #endif }; diff --git a/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp b/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp index 36f54a23c6..3ac3e5d197 100644 --- a/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp +++ b/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp @@ -64,10 +64,6 @@ void J2DGrafContext::setup2D() { } void J2DGrafContext::setScissor() { -#if TARGET_PC - GXSetScissor(mScissorBounds.i.x, mScissorBounds.i.y, mScissorBounds.getWidth(), - mScissorBounds.getHeight()); -#else JGeometry::TBox2 bounds(0, 0, 1024, 1024); JGeometry::TBox2 curBounds(mScissorBounds); mScissorBounds.intersect(bounds); @@ -81,7 +77,6 @@ void J2DGrafContext::setScissor() { } else { GXSetScissor(0, 0, 0, 0); } -#endif } void J2DGrafContext::scissor(JGeometry::TBox2 const& bounds) { diff --git a/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp b/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp index f2bd737b4f..8c895d5077 100644 --- a/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp +++ b/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp @@ -97,6 +97,16 @@ s32 J3DModel::entryModelData(J3DModelData* pModelData, u32 mdlFlags, u32 mtxNum) return kJ3DError_Success; } +#if TARGET_PC +void J3DModel::interp_callback(bool isSimFrame, void* pUserWork) { + J3DModel* i_this = static_cast(pUserWork); + if (!isSimFrame) { + i_this->calcMaterial(); + i_this->diff(); + } +} +#endif + s32 J3DModel::createShapePacket(J3DModelData* pModelData) { J3D_ASSERTMSG(173, pModelData != NULL, "Error : null pointer."); @@ -452,11 +462,11 @@ void J3DModel::calc() { #ifdef TARGET_PC for (u16 i = 0; i < mModelData->getJointNum(); ++i) { - dusk::frame_interp::record_final_mtx_raw(reinterpret_cast(getAnmMtx(i)), getAnmMtx(i)); + dusk::frame_interp::record_final_mtx(getAnmMtx(i)); } for (u16 i = 0; i < mModelData->getWEvlpMtxNum(); ++i) { - dusk::frame_interp::record_final_mtx_raw(reinterpret_cast(getWeightAnmMtx(i)), getWeightAnmMtx(i)); + dusk::frame_interp::record_final_mtx(getWeightAnmMtx(i)); } #endif } @@ -485,6 +495,11 @@ void J3DModel::entry() { joint->entryIn(); } } + +#if TARGET_PC + if (mModelData->needsInterpCallBack()) + dusk::frame_interp::add_interpolation_callback(&J3DModel::interp_callback, this); +#endif } void J3DModel::viewCalc() { @@ -496,7 +511,7 @@ void J3DModel::viewCalc() { J3DCalcViewBaseMtx(j3dSys.getViewMtx(), mBaseScale, mBaseTransformMtx, (MtxP)&mInternalView); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(&mInternalView, mInternalView); + dusk::frame_interp::record_final_mtx(mInternalView); #endif } } else if (isCpuSkinningOn()) { @@ -504,7 +519,7 @@ void J3DModel::viewCalc() { J3DCalcViewBaseMtx(j3dSys.getViewMtx(), mBaseScale, mBaseTransformMtx, (MtxP)&mInternalView); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(&mInternalView, mInternalView); + dusk::frame_interp::record_final_mtx(mInternalView); #endif } } else if (checkFlag(J3DMdlFlag_SkinPosCpu)) { @@ -528,7 +543,7 @@ void J3DModel::viewCalc() { #ifdef TARGET_PC for (u16 i = 0; i < mModelData->getDrawMtxNum(); ++i) { - dusk::frame_interp::record_final_mtx_raw(&getDrawMtxPtr()[i], getDrawMtxPtr()[i]); + dusk::frame_interp::record_final_mtx(getDrawMtxPtr()[i]); } #endif diff --git a/libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp b/libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp index e296676187..3eed051b6c 100644 --- a/libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp +++ b/libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp @@ -84,6 +84,15 @@ void J3DModelData::simpleCalcMaterial(u16 idx, Mtx param_1) { } } +#if TARGET_PC +bool J3DModelData::needsInterpCallBack() const { + for (u16 i = 0, n = getMaterialNum(); i < n; i++) + if (getMaterialNodePointer(i)->needsInterpCallBack()) + return true; + return false; +} +#endif + void J3DModelData::syncJ3DSysPointers() const { j3dSys.setTexture(getTexture()); j3dSys.setVtxPos(getVtxPosArray(), getVtxNum()); diff --git a/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp b/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp index 0c772305b2..48d4731ed9 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp @@ -265,7 +265,7 @@ void J3DMaterial::diff(u32 diffFlags) { } void J3DMaterial::calc(f32 const (*param_0)[4]) { - if (j3dSys.checkFlag(0x40000000)) { + if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) { mTexGenBlock->calcPostTexMtx(param_0); } else { mTexGenBlock->calc(param_0); @@ -276,7 +276,7 @@ void J3DMaterial::calc(f32 const (*param_0)[4]) { } void J3DMaterial::calcDiffTexMtx(f32 const (*param_0)[4]) { - if (j3dSys.checkFlag(0x40000000)) { + if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) { mTexGenBlock->calcPostTexMtxWithoutViewMtx(param_0); } else { mTexGenBlock->calcWithoutViewMtx(param_0); @@ -288,7 +288,7 @@ void J3DMaterial::setCurrentMtx() { } void J3DMaterial::calcCurrentMtx() { - if (!j3dSys.checkFlag(0x40000000)) { + if (!j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) { mCurrentMtx.setCurrentTexMtx( getTexCoord(0)->getTexGenMtx(), getTexCoord(1)->getTexGenMtx(), @@ -371,6 +371,30 @@ s32 J3DMaterial::newSingleSharedDisplayList(u32 dlSize) { return kJ3DError_Success; } +#if TARGET_PC +bool J3DMaterial::needsInterpCallBack() const { + for (int i = 0, n = getTexGenNum(); i < n; i++) { + J3DTexMtx* pTexMtx = mTexGenBlock->getTexMtx(i); + if (pTexMtx != NULL) { + u32 texMtxMode = pTexMtx->getTexMtxInfo().mInfo & 0x3f; + + // uses j3dSys.getViewMtx() + switch (texMtxMode) { + case J3DTexMtxMode_EnvmapBasic: + case J3DTexMtxMode_EnvmapOld: + case J3DTexMtxMode_Envmap: + case J3DTexMtxMode_ProjmapBasic: + case J3DTexMtxMode_Projmap: + case J3DTexMtxMode_ViewProjmap: + case J3DTexMtxMode_ViewProjmapBasic: + return true; + } + } + } + return false; +} +#endif + void J3DPatchedMaterial::initialize() { J3DMaterial::initialize(); } diff --git a/libs/JSystem/src/J3DGraphBase/J3DTevs.cpp b/libs/JSystem/src/J3DGraphBase/J3DTevs.cpp index 09ddc0b405..719976770b 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DTevs.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DTevs.cpp @@ -37,9 +37,9 @@ void loadTexCoordGens(u32 texGenNum, J3DTexCoord* texCoords) { var_r28 = 61; J3DGDWriteXFCmdHdr(GX_XF_REG_DUALTEX0, texGenNum); - if (j3dSys.checkFlag(0x40000000)) { + if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) { for (int i = 0; i < texGenNum; i++) { - if (texCoords[i].getTexGenMtx() != 60) { + if (texCoords[i].getTexGenMtx() != GX_IDENTITY) { var_r28 = i * 3; } else { var_r28 = 61; diff --git a/libs/JSystem/src/JAudio2/JAISeqMgr.cpp b/libs/JSystem/src/JAudio2/JAISeqMgr.cpp index a1f3554815..1d0e42d47e 100644 --- a/libs/JSystem/src/JAudio2/JAISeqMgr.cpp +++ b/libs/JSystem/src/JAudio2/JAISeqMgr.cpp @@ -120,11 +120,19 @@ void JAISeqMgr::mixOut() { } JAISeq* JAISeqMgr::beginStartSeq_() { - JAISeq* seq = JKR_NEW JAISeq(this, field_0x10); +#ifdef TARGET_PC + if (JAISeq::getFreeMemCount() == 0) { + JUT_WARN(273, "%s", "JASPoolAllocObject::::operator new failed .\n"); + return NULL; + } + return JKR_NEW JAISeq(this, field_0x10); +#else + JAISeq* seq = new JAISeq(this, field_0x10); if (seq == NULL) { JUT_WARN(273, "%s", "JASPoolAllocObject::::operator new failed .\n"); } return seq; +#endif } bool JAISeqMgr::endStartSeq_(JAISeq* seq, JAISoundHandle* handle) { diff --git a/libs/JSystem/src/JFramework/JFWDisplay.cpp b/libs/JSystem/src/JFramework/JFWDisplay.cpp index 38dbc7eab1..9ea826feee 100644 --- a/libs/JSystem/src/JFramework/JFWDisplay.cpp +++ b/libs/JSystem/src/JFramework/JFWDisplay.cpp @@ -205,14 +205,6 @@ void JFWDisplay::preGX() { } } -#ifdef TARGET_PC -static s32 s_faderSimSteps = -1; - -void JFWDisplay::setFaderSimSteps(u32 steps) { - s_faderSimSteps = static_cast(steps); -} -#endif - void JFWDisplay::endGX() { s32 bufferNum = JUTXfb::getManager()->getBufferNum(); u16 width = JUTVideo::getManager()->getFbWidth(); @@ -224,17 +216,10 @@ void JFWDisplay::endGX() { if (mFader != NULL) { ortho.setPort(); #ifdef TARGET_PC - u32 advance_count = 1; - if (dusk::getSettings().game.enableFrameInterpolation && s_faderSimSteps >= 0) { - advance_count = static_cast(s_faderSimSteps); - s_faderSimSteps = -1; - } else { - s_faderSimSteps = -1; - } - for (u32 i = 0; i < advance_count; i++) { + if (dusk::frame_interp::get_ui_tick_pending()) { mFader->advance(); } - if (mFader->getStatus() != 1) { + if (mFader->getStatus() != JUTFader::Wait) { mFader->draw(); } #else @@ -394,6 +379,7 @@ static void waitPrecise(Limiter& limiter, Uint64 targetNs) { static void waitForTick(u32 p1, u16 p2) { #if TARGET_PC if (dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit) { + dusk::frameUsagePct = 0.f; return; } if (dusk::getTransientSettings().skipFrameRateLimit) { diff --git a/libs/JSystem/src/JUtility/JUTFader.cpp b/libs/JSystem/src/JUtility/JUTFader.cpp index f7fa963e63..599ae22720 100644 --- a/libs/JSystem/src/JUtility/JUTFader.cpp +++ b/libs/JSystem/src/JUtility/JUTFader.cpp @@ -10,51 +10,51 @@ JUTFader::JUTFader(int x, int y, int width, int height, JUtility::TColor pColor) : mColor(pColor), mBox(x, y, x + width, y + height) { - mStatus = 0; - field_0x8 = 0; - field_0xa = 0; - field_0x24 = 0; - mEStatus = UNKSTATUS_M1; + mStatus = None; + mDuration = 0; + mTimer = 0; + mNextStatus = 0; + mStatusTimer = -1; } void JUTFader::advance() { - if (0 <= mEStatus && mEStatus-- == 0) { - mStatus = field_0x24; + if (0 <= mStatusTimer && mStatusTimer-- == 0) { + mStatus = mNextStatus; } - if (mStatus == 1) { + if (mStatus == Wait) { return; } switch (mStatus) { - case 0: + case None: mColor.a = 0xFF; break; - case 2: + case FadeIn: #if AVOID_UB - if (field_0x8 == 0) { - mStatus = 1; + if (mDuration == 0) { + mStatus = Wait; break; } #endif - mColor.a = 0xFF - ((++field_0xa * 0xFF) / field_0x8); + mColor.a = 0xFF - ((++mTimer * 0xFF) / mDuration); - if (field_0xa >= field_0x8) { - mStatus = 1; + if (mTimer >= mDuration) { + mStatus = Wait; } break; - case 3: + case FadeOut: #if AVOID_UB - if (field_0x8 == 0) { - mStatus = 0; + if (mDuration == 0) { + mStatus = None; break; } #endif - mColor.a = ((++field_0xa * 0xFF) / field_0x8); + mColor.a = ((++mTimer * 0xFF) / mDuration); - if (field_0xa >= field_0x8) { - mStatus = 0; + if (mTimer >= mDuration) { + mStatus = None; } break; @@ -77,53 +77,53 @@ void JUTFader::draw() { } } -bool JUTFader::startFadeIn(int param_0) { +bool JUTFader::startFadeIn(int duration) { bool statusCheck = mStatus == 0; if (statusCheck) { - mStatus = 2; - field_0xa = 0; - field_0x8 = param_0; + mStatus = FadeIn; + mTimer = 0; + mDuration = duration; } return statusCheck; } -bool JUTFader::startFadeOut(int param_0) { +bool JUTFader::startFadeOut(int duration) { bool statusCheck = mStatus == 1; if (statusCheck) { - mStatus = 3; - field_0xa = 0; - field_0x8 = param_0; + mStatus = FadeOut; + mTimer = 0; + mDuration = duration; } return statusCheck; } -void JUTFader::setStatus(JUTFader::EStatus i_status, int param_1) { +void JUTFader::setStatus(JUTFader::EStatus i_status, int timer) { switch (i_status) { - case 0: - if (param_1 != 0) { - field_0x24 = 0; - mEStatus = param_1; + case None: + if (timer != 0) { + mNextStatus = None; + mStatusTimer = timer; break; } - mStatus = 0; - field_0x24 = 0; - mEStatus = 0; + mStatus = None; + mNextStatus = None; + mStatusTimer = 0; break; - case 1: - if (param_1 != 0) { - field_0x24 = 1; - mEStatus = param_1; + case Wait: + if (timer != 0) { + mNextStatus = Wait; + mStatusTimer = timer; break; } - mStatus = 1; - field_0x24 = 1; - mEStatus = 0; + mStatus = Wait; + mNextStatus = Wait; + mStatusTimer = 0; break; } } diff --git a/libs/JSystem/src/JUtility/JUTVideo.cpp b/libs/JSystem/src/JUtility/JUTVideo.cpp index f718fcac23..5586342f0e 100644 --- a/libs/JSystem/src/JUtility/JUTVideo.cpp +++ b/libs/JSystem/src/JUtility/JUTVideo.cpp @@ -205,7 +205,8 @@ void JUTVideo::setRenderMode(GXRenderModeObj const* pObj) { void JUTVideo::waitRetraceIfNeed() {} #if TARGET_PC -void JUTVideo::setWindowSize(AuroraWindowSize const& size) { - m_WindowSize = size; +void JUTVideo::setRenderSize(u32 width, u32 height) { + mRenderWidth = width; + mRenderHeight = height; } #endif diff --git a/res/logo-mascot.webp b/res/logo-mascot.webp new file mode 100644 index 0000000000..c22f3bc90f Binary files /dev/null and b/res/logo-mascot.webp differ diff --git a/src/d/actor/d_a_alink_crawl.inc b/src/d/actor/d_a_alink_crawl.inc index 4a657c1de8..2dbf88d3e1 100644 --- a/src/d/actor/d_a_alink_crawl.inc +++ b/src/d/actor/d_a_alink_crawl.inc @@ -37,18 +37,40 @@ void daAlink_c::setCrawlMoveDirectionArrow() { } if (field_0x3198 & 4) { - if (!bvar) { - direction |= data_80452F38; - } else { - direction |= data_80452F39; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + if (!bvar) { + direction |= data_80452F39; + } else { + direction |= data_80452F38; + } + } else + #endif + { + if (!bvar) { + direction |= data_80452F38; + } else { + direction |= data_80452F39; + } } } if (field_0x3198 & 8) { - if (!bvar) { - direction |= data_80452F39; - } else { - direction |= data_80452F38; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + if (!bvar) { + direction |= data_80452F38; + } else { + direction |= data_80452F39; + } + } else + #endif + { + if (!bvar) { + direction |= data_80452F39; + } else { + direction |= data_80452F38; + } } } diff --git a/src/d/actor/d_a_alink_cut.inc b/src/d/actor/d_a_alink_cut.inc index 8e61a262cb..f33d2935c5 100644 --- a/src/d/actor/d_a_alink_cut.inc +++ b/src/d/actor/d_a_alink_cut.inc @@ -817,6 +817,12 @@ BOOL daAlink_c::checkDownAttackState() { } BOOL daAlink_c::checkCutLargeTurnState() const { + #if TARGET_PC + if (dusk::getSettings().game.alwaysGreatspin) { + return TRUE; + } + #endif + return ((dComIfGs_isEventBit(dSv_event_flag_c::F_0344) || checkNoResetFlg3(FLG3_TRANING_CUT_LARGE_TURN)) && dComIfGs_getLife() == dComIfGs_getMaxLifeGauge() ) diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index 3641015993..d152190161 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -290,6 +290,12 @@ BOOL daAlink_c::checkHookshotStickBG(cBgS_PolyInfo& i_polyinfo) { } #endif + #if TARGET_PC + if (dusk::getSettings().game.superClawshot) { + return TRUE; + } + #endif + if (dComIfG_Bgsp().ChkPolyHSStick(i_polyinfo)) { dBgW_Base* bgw_p = dComIfG_Bgsp().GetBgWBasePointer(i_polyinfo); if (bgw_p != NULL && bgw_p->ChkPushPullOk()) { @@ -448,6 +454,12 @@ void daAlink_c::setHookshotSight() { max_length = mpHIO->mItem.mHookshot.m.mMaxLength; } + #if TARGET_PC + if (dusk::getSettings().game.superClawshot) { + max_length = 69420.0f; + } + #endif + BOOL line_cross = checkSightLine(max_length, &sight_pos); if (mHookTargetAcKeep.getActor() != NULL) { @@ -890,6 +902,14 @@ void daAlink_c::setHookshotPos() { max_length = mpHIO->mItem.mHookshot.m.mMaxLength; } + #if TARGET_PC + if (dusk::getSettings().game.superClawshot) { + return_speed = 2870.0f; + shoot_speed = 2870.0f; + max_length = 69420.0f; + } + #endif + if (mItemMode == HS_MODE_RETURN_e) { if (targetAc_p != NULL) { if (checkLv7BossRoom()) { @@ -899,6 +919,12 @@ void daAlink_c::setHookshotPos() { } } + #if TARGET_PC + if (dusk::getSettings().game.superClawshot) { + return_speed = 500.0f; + } + #endif + if (checkModeFlg(0x400)) { return_speed += current.pos.abs(field_0x3798); } @@ -1548,6 +1574,12 @@ int daAlink_c::procHookshotFly() { f32 temp_f31 = field_0x37d4.abs(); f32 temp_f30 = mpHIO->mItem.mHookshot.m.mStickReturnSpeed + spAC.abs(mHookshotTopPos); + #if TARGET_PC + if (dusk::getSettings().game.superClawshot) { + temp_f30 = 500.0f + spAC.abs(mHookshotTopPos); + } + #endif + if (temp_f31 < temp_f30 || mProcVar1.field_0x300a == 0) { setHookshotReturnEnd(); } else { diff --git a/src/d/actor/d_a_alink_kandelaar.inc b/src/d/actor/d_a_alink_kandelaar.inc index 88c2152e03..339ff90ce6 100644 --- a/src/d/actor/d_a_alink_kandelaar.inc +++ b/src/d/actor/d_a_alink_kandelaar.inc @@ -180,12 +180,7 @@ void daAlink_c::preKandelaarDraw() { mat_p->setTevColor(2, &color); cXyz proj; - - #if TARGET_PC - mDoLib_project(&mKandelaarFlamePos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&mKandelaarFlamePos, &proj); - #endif camera_process_class* camera_p = dComIfGp_getCamera(0); f32 trimHeight; diff --git a/src/d/actor/d_a_balloon_2D.cpp b/src/d/actor/d_a_balloon_2D.cpp index 6d9c66b464..6b5b5a2bd2 100644 --- a/src/d/actor/d_a_balloon_2D.cpp +++ b/src/d/actor/d_a_balloon_2D.cpp @@ -318,11 +318,7 @@ void daBalloon2D_c::addScoreCount(cXyz* param_1, u32 param_2, u8 param_3) { field_0x5f8[current].field_0xf = field_0x5f8[prev].field_0xf; } cXyz acStack_2c; - #if TARGET_PC - mDoLib_project(param_1, &acStack_2c, { 0, 0, FB_WIDTH, FB_HEIGHT }); - #else mDoLib_project(param_1, &acStack_2c); - #endif field_0x5f8[0].field_0x0.set(acStack_2c); field_0x5f8[0].field_0xc = param_2; field_0x5f8[0].field_0xe = 60; diff --git a/src/d/actor/d_a_bg.cpp b/src/d/actor/d_a_bg.cpp index e73723d1f9..9c453b6553 100644 --- a/src/d/actor/d_a_bg.cpp +++ b/src/d/actor/d_a_bg.cpp @@ -623,6 +623,11 @@ int daBg_c::create() { dComIfGp_roomControl_onStatusFlag(roomNo, 0x10); OS_REPORT(" room%d\n", roomNo); + +#if TARGET_PC + draw_interp_frame = true; +#endif + return cPhs_COMPLEATE_e; } diff --git a/src/d/actor/d_a_boomerang.cpp b/src/d/actor/d_a_boomerang.cpp index 64dd71f985..590897640e 100644 --- a/src/d/actor/d_a_boomerang.cpp +++ b/src/d/actor/d_a_boomerang.cpp @@ -337,13 +337,7 @@ void daBoomerang_sight_c::setSight(const cXyz* i_pos, int i_no) { } Vec proj; - - #if TARGET_PC - mDoLib_project(&m_pos[i_no], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&m_pos[i_no], &proj); - #endif - m_proj_posX[i_no] = proj.x; m_proj_posY[i_no] = proj.y; } diff --git a/src/d/actor/d_a_demo00.cpp b/src/d/actor/d_a_demo00.cpp index 871e9ebca6..99ad6c1587 100644 --- a/src/d/actor/d_a_demo00.cpp +++ b/src/d/actor/d_a_demo00.cpp @@ -1658,12 +1658,7 @@ int daDemo00_c::draw() { MTXCopy(mModel.field_0x5d4->getAnmMtx(0), mDoMtx_stack_c::get()); spb0.set(0.0f, 0.0f, 0.0f); mDoMtx_stack_c::multVec(&spb0, &sp98); - - #if TARGET_PC - mDoLib_project(&sp98, &spa4, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&sp98, &spa4); - #endif if (spa4.x >= -700.0f && spa4.x < 1600.0f && spa4.y >= -200.0f && spa4.y < 600.0f) { if (mModel.mID.field_0x18 == 0 || mModel.mID.field_0x18 == 1) { diff --git a/src/d/actor/d_a_dshutter.cpp b/src/d/actor/d_a_dshutter.cpp index fc122cd4e3..264f559e07 100644 --- a/src/d/actor/d_a_dshutter.cpp +++ b/src/d/actor/d_a_dshutter.cpp @@ -215,15 +215,14 @@ int daDsh_c::create() { mType = getType(); -#ifdef TARGET_PC - const char* l_resName[] = {l_arcName[mType], ""}; -#else - // !@bug By making this static, it is only initialized the first time it runs - // If gate types that use other arcs are loaded later (without reloading the code) - // this array never gets updated and will load the incorrect arc - // On GC/Wii, REL loading causes this to reset/reinitialize so the bug is avoided - // but TPHD is all statically linked so daDsh_c::CreateHeap fails to get model data and the gate unloads + // !@bug Static-init only runs once, so slot 0 keeps the first mType's arc name forever. + // GC/Wii dodges this via REL reload; TPHD is statically linked so later gates of a + // different type load the wrong arc and CreateHeap fails. The storage must stay static + // because mResLoader.load holds the pointer past create(), so we just overwrite slot 0 + // each call instead. static const char* l_resName[] = {l_arcName[mType], ""}; +#ifdef TARGET_PC + l_resName[0] = l_arcName[mType]; #endif int phase = mResLoader.load(l_resName, NULL); diff --git a/src/d/actor/d_a_e_fk.cpp b/src/d/actor/d_a_e_fk.cpp index 87734da262..5840df0495 100644 --- a/src/d/actor/d_a_e_fk.cpp +++ b/src/d/actor/d_a_e_fk.cpp @@ -429,13 +429,7 @@ void daE_FK_c::DamageAction() { bool daE_FK_c::checkViewArea() { Vec proj; - - #if TARGET_PC - mDoLib_project(¤t.pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(¤t.pos, &proj); - #endif - return (proj.x >= 0.0f && proj.x <= FB_WIDTH) && (proj.y >= 0.0f && proj.y <= FB_HEIGHT); } diff --git a/src/d/actor/d_a_e_fs.cpp b/src/d/actor/d_a_e_fs.cpp index 54dd10ad81..3ed859c686 100644 --- a/src/d/actor/d_a_e_fs.cpp +++ b/src/d/actor/d_a_e_fs.cpp @@ -463,13 +463,7 @@ static void damage_check(e_fs_class* i_this) { static bool checkViewArea(cXyz* i_pos) { Vec proj; - - #if TARGET_PC - mDoLib_project(i_pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(i_pos, &proj); - #endif - bool ret = false; if (proj.x >= 0.0f && proj.x <= FB_WIDTH && proj.y >= 0.0f && proj.y <= FB_HEIGHT) { ret = true; diff --git a/src/d/actor/d_a_e_rd.cpp b/src/d/actor/d_a_e_rd.cpp index 3067cc456a..e540e7dccd 100644 --- a/src/d/actor/d_a_e_rd.cpp +++ b/src/d/actor/d_a_e_rd.cpp @@ -6601,13 +6601,14 @@ static int daE_RD_Execute(e_rd_class* i_this) { 1.2f, }; + #if AVOID_UB + s16 x = 0; + s16 y = 0; + #endif for (int i = 0; i < 2; i++) { MtxPush(); + #if !AVOID_UB s16 x, y; - - #if AVOID_UB - x = 0; - y = 0; #endif if (i == 0) { diff --git a/src/d/actor/d_a_e_sm.cpp b/src/d/actor/d_a_e_sm.cpp index 8894399cec..b85e22e640 100644 --- a/src/d/actor/d_a_e_sm.cpp +++ b/src/d/actor/d_a_e_sm.cpp @@ -1362,13 +1362,7 @@ void daE_SM_c::E_SM_C_Hook() { bool daE_SM_c::CheckViewArea() { Vec vec; - - #if TARGET_PC - mDoLib_project(¤t.pos, &vec, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(¤t.pos, &vec); - #endif - bool rv = false; if (vec.x >= 0.0f && vec.x <= FB_WIDTH && vec.y >= 0.0f && vec.y <= FB_HEIGHT) { diff --git a/src/d/actor/d_a_e_wb.cpp b/src/d/actor/d_a_e_wb.cpp index 819439879e..75031c42bb 100644 --- a/src/d/actor/d_a_e_wb.cpp +++ b/src/d/actor/d_a_e_wb.cpp @@ -18,6 +18,8 @@ #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_graphic.h" #include "res/Object/Always.h" +#include "dusk/dusk.h" +#include "dusk/frame_interpolation.h" #include @@ -184,6 +186,30 @@ static bool hio_set; static daE_WB_HIO_c l_HIO; +#if TARGET_PC +static void e_wb_rein_interp_callback(bool isSimFrame, void* pUserWork) { + e_wb_class* i_this = (e_wb_class*)pUserWork; + if (!i_this->himo_interp_prev_valid || !i_this->himo_interp_curr_valid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + for (int r = 0; r < 2; r++) { + cXyz* dst = i_this->himo_mat[r].getPos(0); + for (int i = 0; i < 16; i++) { + const cXyz& p0 = i_this->himo_mat_interp_prev[r][i]; + const cXyz& p1 = i_this->himo_mat_interp_curr[r][i]; + dst[i] = p0 + (p1 - p0) * alpha; + } + } + cXyz* dst = i_this->himo_tex.getPos(0); + for (int i = 0; i < 2; i++) { + const cXyz& p0 = i_this->himo_tex_interp_prev[i]; + const cXyz& p1 = i_this->himo_tex_interp_curr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static void himo_control1(e_wb_class* i_this, cXyz* i_pos, int i_no, s8 param_3) { fopEn_enemy_c* enemy = &i_this->enemy; cXyz mae, ato; @@ -508,6 +534,21 @@ static int daE_WB_Draw(e_wb_class* i_this) { dComIfGd_set3DlineMat(&i_this->himo_mat[1]); i_this->himo_tex.update(2, l_color, &actor->tevStr); dComIfGd_set3DlineMat(&i_this->himo_tex); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->himo_interp_curr_valid) { + memcpy(i_this->himo_mat_interp_prev, i_this->himo_mat_interp_curr, sizeof(i_this->himo_mat_interp_curr)); + memcpy(i_this->himo_tex_interp_prev, i_this->himo_tex_interp_curr, sizeof(i_this->himo_tex_interp_curr)); + i_this->himo_interp_prev_valid = true; + } + for (int r = 0; r < 2; r++) { + memcpy(i_this->himo_mat_interp_curr[r], i_this->himo_mat[r].getPos(0), 16 * sizeof(cXyz)); + } + memcpy(i_this->himo_tex_interp_curr, i_this->himo_tex.getPos(0), 2 * sizeof(cXyz)); + i_this->himo_interp_curr_valid = true; + dusk::frame_interp::add_interpolation_callback(&e_wb_rein_interp_callback, i_this); + } +#endif } return 1; @@ -3726,6 +3767,9 @@ static void demo_camera(e_wb_class* i_this) { boss = (e_rdb_class*)fopAcM_SearchByName(fpcNm_E_RDB_e); } cXyz mae, ato, eye, center; +#if TARGET_PC + const s16 entry_demo_mode = i_this->demo_mode; +#endif switch (i_this->demo_mode) { case 1: { @@ -4255,6 +4299,9 @@ static void demo_camera(e_wb_class* i_this) { if (i_this->demo_timer == 325) { fpcM_Search(s_wbZrevise_sub, i_this); +#if TARGET_PC + i_this->demo_cam_sync_ticks = 2; +#endif } if (i_this->demo_timer == 335) { @@ -4495,6 +4542,9 @@ static void demo_camera(e_wb_class* i_this) { i_this->demo_cam_way_spd.z = fabsf(i_this->demo_cam_way.z - i_this->demo_cam_ctr.z); i_this->demo_cam_morf = 0; pla->setPlayerPosAndAngle(&pla->current.pos, pla->shape_angle.y - 4000, 0); +#if TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } if (i_this->demo_timer == 345) { daPy_getPlayerActorClass()->setThrowDamage(boss->enemy.shape_angle.y - 8000 + TREG_S(8), @@ -4741,6 +4791,9 @@ static void demo_camera(e_wb_class* i_this) { i_this->demo_cam_eye.x += 300.0f + VREG_F(8); i_this->demo_cam_eye.y += 150.0f + VREG_F(9); i_this->demo_cam_eye.z -= 1400.0f + VREG_F(10); +#if TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } } else { i_this->demo_cam_eye = enemy->current.pos; @@ -4996,6 +5049,15 @@ static void demo_camera(e_wb_class* i_this) { } } } +#if TARGET_PC + if (entry_demo_mode != i_this->demo_mode) { + i_this->demo_cam_sync_ticks = 2; + } + if (i_this->demo_cam_sync_ticks > 0) { + dusk::frame_interp::request_presentation_sync(); + i_this->demo_cam_sync_ticks--; + } +#endif } static void anm_se_eff_set(e_wb_class* i_this) { diff --git a/src/d/actor/d_a_midna.cpp b/src/d/actor/d_a_midna.cpp index 01d472e075..7bb844932e 100644 --- a/src/d/actor/d_a_midna.cpp +++ b/src/d/actor/d_a_midna.cpp @@ -1054,9 +1054,9 @@ void daMidna_c::setBodyPartMatrix() { } mpModel->calcWeightEnvelopeMtx(); #ifdef TARGET_PC - // Frame interpolation: Record weight envelopes for Midna here, as they are otherwise missed causing distortion + // FRAME INTERP NOTE: Record weight envelopes for Midna here, as they are otherwise missed causing distortion for (u16 i = 0; i < mpModel->getModelData()->getWEvlpMtxNum(); i++) { - dusk::frame_interp::record_final_mtx_raw(reinterpret_cast(mpModel->getWeightAnmMtx(i)), mpModel->getWeightAnmMtx(i)); + dusk::frame_interp::record_final_mtx(mpModel->getWeightAnmMtx(i)); } #endif } diff --git a/src/d/actor/d_a_mirror.cpp b/src/d/actor/d_a_mirror.cpp index 5468d70f87..fb4142c0bb 100644 --- a/src/d/actor/d_a_mirror.cpp +++ b/src/d/actor/d_a_mirror.cpp @@ -13,6 +13,9 @@ #include #include #include "m_Do/m_Do_lib.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif #ifndef __MWERKS__ #include "dusk/math.h" @@ -27,11 +30,19 @@ static char* l_arcName = "Mirror"; static char* l_arcName2 = "MR-Table"; dMirror_packet_c::dMirror_packet_c() { +#ifdef TARGET_PC + GXInitTexObj(&mTexObj, nullptr, 0, 0, static_cast(-1), GX_MAX_TEXWRAPMODE, + GX_MAX_TEXWRAPMODE, GX_FALSE); +#endif reset(); } void dMirror_packet_c::reset() { +#if TARGET_PC + mbReset = true; +#else mModelCount = 0; +#endif } void dMirror_packet_c::calcMinMax() { @@ -73,6 +84,13 @@ void dMirror_packet_c::calcMinMax() { } int dMirror_packet_c::entryModel(J3DModel* i_model) { +#if TARGET_PC + if (mbReset) { + mModelCount = 0; + mbReset = false; + } +#endif + if (mModelCount >= 0x40) { return 0; } diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp index c3074ac877..079584f714 100644 --- a/src/d/actor/d_a_movie_player.cpp +++ b/src/d/actor/d_a_movie_player.cpp @@ -3342,13 +3342,8 @@ static void daMP_THPGXYuv2RgbSetup(const GXRenderModeObj* rmode) { Mtx44 m; Mtx e_m; -#if TARGET_PC - w = JUTVideo::getManager()->getFbWidth(); - h = JUTVideo::getManager()->getEfbHeight(); -#else w = rmode->fbWidth; h = rmode->efbHeight; -#endif var_f31 = 0.0f; #if WIDESCREEN_SUPPORT @@ -4383,6 +4378,8 @@ static void daMP_ActivePlayer_Draw() { daMP_DrawPosX = static_cast(rect.PosX); daMP_DrawPosY = static_cast(rect.PosY); + + daMP_THPPlayerSetVolume((dusk::getSettings().audio.masterVolume / 100.0f) * 127.0f, 0); #endif int frame = daMP_THPPlayerDrawCurrentFrame( @@ -4583,3 +4580,12 @@ actor_process_profile_definition g_profile_MOVIE_PLAYER = { }; AUDIO_INSTANCES; + +#if TARGET_PC +void dusk::MoviePlayerShutdown() { + // We need to cleanly shut down the threads to avoid crashes on shutdown. + if (daMP_c::m_myObj) { + daMP_c::m_myObj->daMP_c_Finish(); + } +} +#endif \ No newline at end of file diff --git a/src/d/actor/d_a_npc.cpp b/src/d/actor/d_a_npc.cpp index 6ec2fbe7a9..123bf66800 100644 --- a/src/d/actor/d_a_npc.cpp +++ b/src/d/actor/d_a_npc.cpp @@ -2694,12 +2694,7 @@ BOOL daNpcT_chkActorInScreen(fopAc_ac_c* i_ActorP, f32 param_1, f32 param_2, f32 } for (int i = 0; i < 8; i++) { - #if TARGET_PC - mDoLib_project(&pos_array[i], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&pos_array[i], &proj); - #endif - if (0.0f < proj.x && proj.x < FB_WIDTH && 0.0f < proj.y && proj.y < FB_HEIGHT) { continue; } diff --git a/src/d/actor/d_a_npc_ne.cpp b/src/d/actor/d_a_npc_ne.cpp index ae43981593..1324c56cf5 100644 --- a/src/d/actor/d_a_npc_ne.cpp +++ b/src/d/actor/d_a_npc_ne.cpp @@ -18,6 +18,7 @@ #include "f_op/f_op_kankyo_mng.h" #include "c/c_damagereaction.h" #include "Z2AudioLib/Z2Instances.h" +#include "dusk/frame_interpolation.h" #include static home_path_pnt home_path[38] = { @@ -2655,6 +2656,9 @@ static void demo_camera(npc_ne_class* i_this) { i_this->mCameraFovY = 55.0f; camera->mCamera.SetTrimSize(3); daPy_getPlayerActorClass()->changeOriginalDemo(); +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif // fallthrough case 2: @@ -2683,6 +2687,9 @@ static void demo_camera(npc_ne_class* i_this) { if (i_this->mDemoCounter == 0) { i_this->mCameraCenter1.set(387.0f, 133.0f, -866.0f); i_this->mCameraEye1.set(284.0f, 208.0f, -585.0f); +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } if (i_this->mDemoCounter == 12) { @@ -2719,6 +2726,9 @@ static void demo_camera(npc_ne_class* i_this) { i_this->mCameraFovY = 45.0f; camera->mCamera.SetTrimSize(3); daPy_getPlayerActorClass()->changeOriginalDemo(); +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif // fallthrough case 11: @@ -2799,8 +2809,14 @@ static void demo_camera(npc_ne_class* i_this) { MtxPosition(&vec, &i_this->mCameraEye2); i_this->mCameraEye2 += player->current.pos; player->changeDemoParam2(2); +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } else if (i_this->mDemoCounter == 120) { player->changeDemoParam2(0); +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } } } @@ -2853,6 +2869,9 @@ static void demo_camera(npc_ne_class* i_this) { i_this->mCameraCenter1 = _this->current.pos; i_this->mCameraCenter1.y += 20.0f; i_this->mCameraFovY = 55.0f; +#ifdef TARGET_PC + dusk::frame_interp::request_presentation_sync(); +#endif } camera->mCamera.Set(i_this->mCameraCenter1, i_this->mCameraEye1, diff --git a/src/d/actor/d_a_obj_Lv5Key.cpp b/src/d/actor/d_a_obj_Lv5Key.cpp index 2a5369d834..5b15898c59 100644 --- a/src/d/actor/d_a_obj_Lv5Key.cpp +++ b/src/d/actor/d_a_obj_Lv5Key.cpp @@ -207,7 +207,7 @@ void daObjLv5Key_c::Fall(int param_0) { OS_REPORT("FALL SPD = %f\n", speed.y); - if (mAcch.ChkGroundHit()) { + if (mAcch.ChkGroundHit() IF_DUSK(|| current.pos.abs(home.pos) > 200.0f)) { fopAcM_GetSpeed(this); fopAcM_SetSpeedF(this, 4.0f); fopAcM_SetSpeed(this, 0.0f, 22.0f, 0.0f); @@ -229,7 +229,7 @@ void daObjLv5Key_c::Fall(int param_0) { mAcch.CrrPos(dComIfG_Bgsp()); current.pos.y = prev_y; - if (mAcch.ChkGroundHit()) { + if (mAcch.ChkGroundHit() IF_DUSK(|| current.pos.abs(home.pos) > 200.0f)) { setAction(&daObjLv5Key_c::Land, 1); } } diff --git a/src/d/actor/d_a_obj_ari.cpp b/src/d/actor/d_a_obj_ari.cpp index 3e2727e2f2..267b0003af 100644 --- a/src/d/actor/d_a_obj_ari.cpp +++ b/src/d/actor/d_a_obj_ari.cpp @@ -499,13 +499,7 @@ void daObjARI_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&vec1, &vec2); - #endif - f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_bhashi.cpp b/src/d/actor/d_a_obj_bhashi.cpp index 33595c7a77..00a35bc158 100644 --- a/src/d/actor/d_a_obj_bhashi.cpp +++ b/src/d/actor/d_a_obj_bhashi.cpp @@ -285,13 +285,7 @@ bool Hahen_c::CheckCull() { bool Hahen_c::checkViewArea() { Vec proj; - - #if TARGET_PC - mDoLib_project(&pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&pos, &proj); - #endif - return (proj.x >= -50.0f && proj.x <= 658.0f) && (proj.y >= -50.0f && proj.y <= 498.0f); } diff --git a/src/d/actor/d_a_obj_cho.cpp b/src/d/actor/d_a_obj_cho.cpp index 27b0b8ce0e..8fbc2dbde8 100644 --- a/src/d/actor/d_a_obj_cho.cpp +++ b/src/d/actor/d_a_obj_cho.cpp @@ -289,13 +289,7 @@ void daObjCHO_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&vec1, &vec2); - #endif - f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_crvfence.cpp b/src/d/actor/d_a_obj_crvfence.cpp index 03ff2b1d6a..9712205ea3 100644 --- a/src/d/actor/d_a_obj_crvfence.cpp +++ b/src/d/actor/d_a_obj_crvfence.cpp @@ -224,13 +224,7 @@ void daObjCRVFENCE_c::NormalAction() { bool daObjCRVFENCE_c::checkViewArea(cXyz* param_1) { Vec sp24; - - #if TARGET_PC - mDoLib_project(param_1, &sp24, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(param_1, &sp24); - #endif - bool rv = false; bool bVar1 = false; diff --git a/src/d/actor/d_a_obj_crvhahen.cpp b/src/d/actor/d_a_obj_crvhahen.cpp index 0b44a57ec8..2dc91c6e6b 100644 --- a/src/d/actor/d_a_obj_crvhahen.cpp +++ b/src/d/actor/d_a_obj_crvhahen.cpp @@ -137,13 +137,7 @@ void daObjCRVHAHEN_c::CheckCull() { bool daObjCRVHAHEN_c::checkViewArea(cXyz* i_this) { Vec proj; - - #if TARGET_PC - mDoLib_project(i_this, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(i_this, &proj); - #endif - bool ret = false; if (proj.x >= 0.0f && proj.x <= FB_WIDTH && proj.y >= 0.0f && proj.y <= FB_HEIGHT) { diff --git a/src/d/actor/d_a_obj_dan.cpp b/src/d/actor/d_a_obj_dan.cpp index 53dbf4e1e4..cc176b9a20 100644 --- a/src/d/actor/d_a_obj_dan.cpp +++ b/src/d/actor/d_a_obj_dan.cpp @@ -267,13 +267,7 @@ void daObjDAN_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&vec1, &vec2); - #endif - f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_gomikabe.cpp b/src/d/actor/d_a_obj_gomikabe.cpp index a5b58a44a5..66963f0efd 100644 --- a/src/d/actor/d_a_obj_gomikabe.cpp +++ b/src/d/actor/d_a_obj_gomikabe.cpp @@ -201,13 +201,7 @@ void daObjGOMIKABE_c::CheckCull() { bool daObjGOMIKABE_c::checkViewArea(cXyz param_1) { Vec local_24; - - #if TARGET_PC - mDoLib_project(¶m_1, &local_24, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(¶m_1, &local_24); - #endif - bool rv = false; if (local_24.x >= 0.0f && local_24.x <= FB_WIDTH && local_24.y >= 0.0f && local_24.y <= FB_HEIGHT) { rv = true; diff --git a/src/d/actor/d_a_obj_hhashi.cpp b/src/d/actor/d_a_obj_hhashi.cpp index ea45fa5ea1..d5ab5558b0 100644 --- a/src/d/actor/d_a_obj_hhashi.cpp +++ b/src/d/actor/d_a_obj_hhashi.cpp @@ -214,13 +214,7 @@ void daObjHHASHI_c::CheckCull() { bool daObjHHASHI_c::checkViewArea(int param_1) { Vec local_20; - - #if TARGET_PC - mDoLib_project(&field_0x5b0[param_1], &local_20, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&field_0x5b0[param_1], &local_20); - #endif - bool rv = false; if (local_20.x >= 0.0f && local_20.x <= FB_WIDTH && local_20.y >= 0.0f && local_20.y <= FB_HEIGHT) { rv = true; diff --git a/src/d/actor/d_a_obj_kamakiri.cpp b/src/d/actor/d_a_obj_kamakiri.cpp index daa6560e6f..2b641d7769 100644 --- a/src/d/actor/d_a_obj_kamakiri.cpp +++ b/src/d/actor/d_a_obj_kamakiri.cpp @@ -517,13 +517,7 @@ void daObjKAM_c::Z_BufferChk() { cXyz currentOffset; currentOffset = current.pos; currentOffset.y += 20.0f; - - #if TARGET_PC - mDoLib_project(¤tOffset, ¤tProj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(¤tOffset, ¤tProj); - #endif - camera_process_class* camera = dComIfGp_getCamera(0); f32 cameraHeight; if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_katatsumuri.cpp b/src/d/actor/d_a_obj_katatsumuri.cpp index 03d40a1066..805aa37b44 100644 --- a/src/d/actor/d_a_obj_katatsumuri.cpp +++ b/src/d/actor/d_a_obj_katatsumuri.cpp @@ -611,13 +611,7 @@ void daObjKAT_c::Z_BufferChk() { cXyz curWithOff; curWithOff = current.pos; curWithOff.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&curWithOff, &projected, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&curWithOff, &projected); - #endif - camera_process_class* camera = dComIfGp_getCamera(0); f32 unkFloat1; if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_kuwagata.cpp b/src/d/actor/d_a_obj_kuwagata.cpp index 914e25dfb1..80020208d3 100644 --- a/src/d/actor/d_a_obj_kuwagata.cpp +++ b/src/d/actor/d_a_obj_kuwagata.cpp @@ -528,13 +528,7 @@ void daObjKUW_c::Z_BufferChk() { cStack_68 = current.pos; cStack_68.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&cStack_68, &local_5c); - #endif - camera_process_class* cc = dComIfGp_getCamera(0); f32 trimHeight; if (cc != NULL) { diff --git a/src/d/actor/d_a_obj_stone.cpp b/src/d/actor/d_a_obj_stone.cpp index f74adf12a7..080069e4f0 100644 --- a/src/d/actor/d_a_obj_stone.cpp +++ b/src/d/actor/d_a_obj_stone.cpp @@ -981,9 +981,7 @@ int daObjStone_c::draw() { if (!model) { f32 shadow_size = l_shadow_size[mStoneType]; TGXTexObj* pTex = dDlst_shadowControl_c::getSimpleTex(); - cXyz pos = current.pos; - - dComIfGd_setSimpleShadow(&pos, mChkObj.GetGroundH(), shadow_size, mChkObj.m_gnd, 0, + dComIfGd_setSimpleShadow(¤t.pos, mChkObj.GetGroundH(), shadow_size, mChkObj.m_gnd, 0, 1.0f, pTex); } return 1; diff --git a/src/d/actor/d_a_obj_ten.cpp b/src/d/actor/d_a_obj_ten.cpp index 1efe358607..fbedd6a8c9 100644 --- a/src/d/actor/d_a_obj_ten.cpp +++ b/src/d/actor/d_a_obj_ten.cpp @@ -593,13 +593,7 @@ void daObjTEN_c::Z_BufferChk() { cXyz cStack_68; cStack_68 = current.pos; cStack_68.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&cStack_68, &local_5c); - #endif - camera_process_class* camera = dComIfGp_getCamera(0); f32 trimHeight; if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_tombo.cpp b/src/d/actor/d_a_obj_tombo.cpp index 6fcbc938d9..a518e3cf25 100644 --- a/src/d/actor/d_a_obj_tombo.cpp +++ b/src/d/actor/d_a_obj_tombo.cpp @@ -504,13 +504,7 @@ void daObjTOMBO_c::Z_BufferChk() { cXyz cStack_68; cStack_68 = current.pos; cStack_68.y += 20.0f; - - #if TARGET_PC - mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&cStack_68, &local_5c); - #endif - camera_process_class* pCamera = dComIfGp_getCamera(0); f32 trimHeight; if (pCamera != NULL) { diff --git a/src/d/actor/d_a_obj_zra_freeze.cpp b/src/d/actor/d_a_obj_zra_freeze.cpp index 08932c439d..1525bdb572 100644 --- a/src/d/actor/d_a_obj_zra_freeze.cpp +++ b/src/d/actor/d_a_obj_zra_freeze.cpp @@ -38,12 +38,7 @@ BOOL daZraFreeze_c::chkActorInScreen() { mDoMtx_stack_c::transM(0.0f, 0.0f, 0.0f); PSMTXMultVecArray(mDoMtx_stack_c::get(), vec, vec, 8); for (int i = 0; i < 8; i++) { - #if TARGET_PC - mDoLib_project(&vec[i], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&vec[i], &proj); - #endif - if (0.0f < proj.x && proj.x < FB_WIDTH && 0.0f < proj.y && proj.y < FB_HEIGHT) { continue; } diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 4c8b31c4c6..8ceb0ef237 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -421,13 +421,7 @@ void daPy_sightPacket_c::draw() { void daPy_sightPacket_c::setSight() { Vec proj; - - #if TARGET_PC - mDoLib_project(&mPos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&mPos, &proj); - #endif - mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); mDoMtx_stack_c::scaleM(32.0f, 32.0f, 32.0f); mDoMtx_copy(mDoMtx_stack_c::get(), mProjMtx); diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 034d35961e..702337d9e5 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -700,13 +700,13 @@ void dFlower_packet_c::draw() { #ifdef TARGET_PC Mtx flower_mtx; if (dusk::frame_interp::lookup_replacement(reinterpret_cast(&sp44->m_modelMtx), flower_mtx)) { + GXLoadPosMtxImm(flower_mtx, 0); - } else { + } else #endif + { GXLoadPosMtxImm(sp44->m_modelMtx, 0); -#ifdef TARGET_PC } -#endif GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0); #if TARGET_PC @@ -855,6 +855,7 @@ void dFlower_packet_c::draw() { #ifdef TARGET_PC Mtx flower_mtx; if (dusk::frame_interp::lookup_replacement(reinterpret_cast(&sp34->m_modelMtx), flower_mtx)) { + cMtx_concat(j3dSys.getViewMtx(), flower_mtx, flower_mtx); GXLoadPosMtxImm(flower_mtx, 0); } else { #endif @@ -994,7 +995,7 @@ void dFlower_packet_c::update() { mDoMtx_stack_c::scaleM(temp_f31, temp_f31, temp_f31); cMtx_concat(j3dSys.getViewMtx(), temp_r28, data_p->m_modelMtx); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(reinterpret_cast(&data_p->m_modelMtx), data_p->m_modelMtx); + dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), data_p->m_modelMtx); #endif } } diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index 0f651a3203..ab2724060f 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -756,13 +756,13 @@ void dGrass_packet_c::draw() { #ifdef TARGET_PC Mtx grass_mtx; if (dusk::frame_interp::lookup_replacement(reinterpret_cast(&var_r29->m_modelMtx), grass_mtx)) { + cMtx_concat(j3dSys.getViewMtx(), grass_mtx, grass_mtx); GXLoadPosMtxImm(grass_mtx, 0); - } else { + } else #endif + { GXLoadPosMtxImm(var_r29->m_modelMtx, 0); -#ifdef TARGET_PC } -#endif GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0); if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { if (var_r29->field_0x02 < -1) { @@ -1018,7 +1018,7 @@ void dGrass_packet_c::update() { cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), data_p->m_modelMtx); } #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(reinterpret_cast(&data_p->m_modelMtx), data_p->m_modelMtx); + dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), data_p->m_modelMtx); #endif } } diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index b93d569003..f805a6a08b 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -7063,6 +7063,15 @@ bool dCamera_c::subjectCamera(s32 param_0) { } cXyz sp1E0(val0, val2, val1); + +#if TARGET_PC + f32 aspect = mDoGph_gInf_c::getAspect(); + f32 baseAspect = FB_WIDTH / FB_HEIGHT; + if (aspect > baseAspect) { + sp1E0.z += (aspect - baseAspect) * 4; + } +#endif + sp1D4 = dCamMath::xyzRotateX(sp1E0, angle_x); sp1E0 = dCamMath::xyzRotateY(sp1D4, angle_y); f32 sp6C = sp12 ? 40.0f : 0.0f; @@ -11009,6 +11018,15 @@ static int camera_execute(camera_process_class* i_this) { i_this->mCamera.CalcTrimSize(); store(i_this); + +#ifdef TARGET_PC + // record new camera for our sim frame + dusk::frame_interp::record_camera(i_this, get_camera_id(i_this)); + // interpolate the view now so that this sim frame's view matrix matches what + // we'll be rendering with later + dusk::frame_interp::interp_view(&i_this->view); +#endif + view_setup(i_this); return 1; } @@ -11077,9 +11095,6 @@ static int camera_draw(camera_process_class* i_this) { C_MTXPerspective(process->view.projMtx, process->view.fovy, process->view.aspect, process->view.near_, process->view.far_); mDoMtx_lookAt(process->view.viewMtx, &process->view.lookat.eye, &process->view.lookat.center, &process->view.lookat.up, process->view.bank); -#ifdef TARGET_PC - dusk::frame_interp::record_camera(process, camera_id); -#endif #if WIDESCREEN_SUPPORT mDoGph_gInf_c::setWideZoomProjection(process->view.projMtx); diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index e903e39ce4..373791f994 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -1096,16 +1096,7 @@ void dDlst_shadowReal_c::draw() { GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXSetCurrentMtx(GX_PNMTX0); -#ifdef TARGET_PC - Mtx receiver_proj_mtx; - if (dusk::frame_interp::lookup_replacement(&mReceiverProjMtx, receiver_proj_mtx)) { - GXLoadTexMtxImm(receiver_proj_mtx, GX_TEXMTX0, GX_MTX3x4); - } else { -#endif - GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); -#ifdef TARGET_PC - } -#endif + GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); mShadowRealPoly.draw(); } @@ -1263,14 +1254,9 @@ u8 dDlst_shadowReal_c::setShadowRealMtx(cXyz* param_0, cXyz* param_1, f32 param_ C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f); C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f); cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx); -#ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(&mViewMtx, mViewMtx); - dusk::frame_interp::record_final_mtx_raw(&mReceiverProjMtx, mReceiverProjMtx); -#endif return r29; } - u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 param_3, f32 param_4, dKy_tevstr_c* param_5, f32 i_cameraZ, f32 param_7) { dScnKy_env_light_c* env_light = dKy_getEnvlight(); @@ -1292,6 +1278,7 @@ u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 par } field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5); + if (!field_0x1) { return 0; } @@ -1331,14 +1318,14 @@ void dDlst_shadowSimple_c::draw() { GXSetVtxDesc(GX_VA_POS, GX_INDEX8); #ifdef TARGET_PC Mtx volume_mtx; - if (dusk::frame_interp::lookup_replacement(&mVolumeMtx, volume_mtx)) { + if (dusk::frame_interp::lookup_replacement(mVolumeMtxKey, volume_mtx)) { + cMtx_concat(j3dSys.getViewMtx(), volume_mtx, volume_mtx); GXLoadPosMtxImm(volume_mtx, GX_PNMTX0); - } else { + } else #endif + { GXLoadPosMtxImm(mVolumeMtx, GX_PNMTX0); -#ifdef TARGET_PC } -#endif GXSetCurrentMtx(GX_PNMTX0); GXCallDisplayList(l_frontMat, 0x40); GXCallDisplayList(l_shadowVolumeDL, 0x40); @@ -1346,14 +1333,14 @@ void dDlst_shadowSimple_c::draw() { GXCallDisplayList(l_shadowVolumeDL, 0x40); #ifdef TARGET_PC Mtx shadow_mtx; - if (dusk::frame_interp::lookup_replacement(&mMtx, shadow_mtx)) { + if (dusk::frame_interp::lookup_replacement(mMtxKey, shadow_mtx)) { + cMtx_concat(j3dSys.getViewMtx(), shadow_mtx, shadow_mtx); GXLoadPosMtxImm(shadow_mtx, GX_PNMTX1); - } else { + } else #endif + { GXLoadPosMtxImm(mMtx, GX_PNMTX1); -#ifdef TARGET_PC } -#endif GXSetCurrentMtx(GX_PNMTX1); if (mpTexObj != NULL) { @@ -1383,6 +1370,12 @@ void dDlst_shadowSimple_c::draw() { GXCallDisplayList(l_shadowVolumeDL, 0x40); } +#if TARGET_PC +static const void* getInterpKey(const void* base, int idx) { + return reinterpret_cast(reinterpret_cast(base) ^ idx); +} +#endif + void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3, s16 param_4, f32 param_5, TGXTexObj* param_6) { if (param_5 < 0.0f) { @@ -1406,6 +1399,10 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa mDoMtx_stack_c::transS(param_0->x, param_1 + f30, param_0->z); mDoMtx_stack_c::YrotM(param_4); mDoMtx_stack_c::scaleM(param_2, f30 + f30 + 16.0f, param_2 * param_5); +#if TARGET_PC + mVolumeMtxKey = getInterpKey(param_0, 0x1); + dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), mVolumeMtxKey); +#endif cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mVolumeMtx); f32 f31 = JMAFastSqrt(1.0f - param_3->x * param_3->x); f32 f29; @@ -1431,17 +1428,11 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa mDoMtx_stack_c::get()[2][3] = param_0->z; mDoMtx_stack_c::YrotM(param_4); mDoMtx_stack_c::scaleM(param_2, 1.0f, param_2 * param_5); - cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx); #ifdef TARGET_PC - 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); - } + mMtxKey = getInterpKey(param_0, 0x2); + dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), mMtxKey); #endif + cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx); mpTexObj = param_6; } @@ -1544,9 +1535,10 @@ void dDlst_shadowControl_c::imageDraw(Mtx param_0) { #ifdef TARGET_PC GXCreateFrameBuffer(r26, r26); needsRestore = true; -#endif +#else GXSetViewport(0.0f, 0.0f, r26, r26, 0.0f, 1.0f); GXSetScissor(0, 0, r26, r26); +#endif } GXSetTevColor(GX_TEVREG0, l_imageDrawColor[chan]); if (chan == 3) { diff --git a/src/d/d_file_select.cpp b/src/d/d_file_select.cpp index e9cad6243e..6742996008 100644 --- a/src/d/d_file_select.cpp +++ b/src/d/d_file_select.cpp @@ -70,11 +70,7 @@ dFs_HIO_c::dFs_HIO_c() { select_icon_appear_frames = 5; appear_display_wait_frames = 15; field_0x000d = 15; - #if TARGET_PC - card_wait_frames = 0; - #else card_wait_frames = 90; - #endif test_frame_counts[0] = 1.11f; test_frame_counts[1] = 1.11f; test_frame_counts[2] = 1.11f; @@ -2108,11 +2104,7 @@ void dFile_select_c::yesnoCursorShow() { mSelIcon->setPos(pos.x, pos.y, mYnSelPane[field_0x0268]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); - #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); - #endif } } @@ -2265,11 +2257,7 @@ void dFile_select_c::YesNoCancelMove() { m3mSelPane[mSelectMenuNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); - #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); - #endif #if PLATFORM_WII || PLATFORM_SHIELD field_0x4333 = mSelectMenuNum; @@ -2381,7 +2369,7 @@ void dFile_select_c::CommandExec() { break; } - mWaitTimer = g_fsHIO.card_wait_frames; + mWaitTimer = IF_DUSK(dusk::getSettings().game.instantSaves ? 0 :) g_fsHIO.card_wait_frames; } void dFile_select_c::DataEraseWait() { @@ -3153,11 +3141,7 @@ void dFile_select_c::screenSet() { mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(5209, mSelIcon != NULL); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); - #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); - #endif Vec vtxCenter; vtxCenter = mSelFilePanes[mSelectNum]->getGlobalVtxCenter(false, 0); @@ -3210,6 +3194,9 @@ void dFile_select_c::screenSet() { timg, NULL); mpFadePict->setBlackWhite(black, white); mpFadePict->setAlpha(0); +#ifdef TARGET_PC + mFadeDlst.mpPict = mpFadePict; +#endif #endif } @@ -3290,11 +3277,7 @@ void dFile_select_c::screenSetCopySel() { mSelIcon2 = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(5406, mSelIcon2 != NULL); - #if TARGET_PC - mSelIcon2->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); - #else mSelIcon2->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); - #endif Vec center = mCpSelPane[0]->getGlobalVtxCenter(false, 0); mSelIcon2->setPos(center.x, center.y, mCpSelPane[0]->getPanePtr(), true); @@ -3686,11 +3669,7 @@ void dFile_select_c::selFileCursorShow() { mSelIcon->setPos(local_1c.x, local_1c.y, mSelFilePanes[mSelectNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); - #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); - #endif } void dFile_select_c::menuWakuAlpahAnmInit(u8 i_idx, u8 param_1, u8 param_2, u8 param_3) { @@ -3733,11 +3712,7 @@ void dFile_select_c::menuCursorShow() { mSelIcon->setPos(local_24.x, local_24.y, m3mSelPane[mSelectMenuNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); - #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); - #endif } } @@ -3839,6 +3814,16 @@ void dFile_select_c::fileSelectWide() { fileSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); fileSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); fileSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + #if TARGET_PC + if (mSelIcon) { + mSelIcon->refreshAspectScale(); + } + + if (mSelIcon2) { + mSelIcon2->refreshAspectScale(); + } + #endif } #endif @@ -3877,9 +3862,7 @@ void dFile_select_c::_draw() { #if PLATFORM_GCN #if TARGET_PC - mpFadePict->draw(0, 0, - mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), false, false, - false); + dComIfGd_set2DOpaTop(&mFadeDlst); #else mpFadePict->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), false, false, @@ -3929,6 +3912,13 @@ void dDlst_FileSel3m_c::draw() { Scr3m->draw(0.0f, 0.0f, graf); } +#ifdef TARGET_PC +void dDlst_FileSelFade_c::draw() { + mpPict->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), false, false, false); +} +#endif + void dFile_select_c::errorMoveAnmInitSet(int param_1, int param_2) { mErrorMsgPane->setAnimation(field_0x0090); field_0x0130 = param_1; @@ -4771,7 +4761,7 @@ void dFile_select_c::MemCardFormatYesSel2Disp() { bool isErrorTxtChange = errorTxtChangeAnm(); bool isYnMenuMove = yesnoMenuMoveAnm(); if (isErrorTxtChange == true && isYnMenuMove == true) { - mWaitTimer = g_fsHIO.card_wait_frames; + mWaitTimer = IF_DUSK(dusk::getSettings().game.instantSaves ? 0 :) g_fsHIO.card_wait_frames; mDoMemCd_Format(); mCardCheckProc = MEMCARDCHECKPROC_FORMAT; } @@ -4842,7 +4832,7 @@ void dFile_select_c::MemCardMakeGameFileSelDisp() { if (isErrorTxtChange == true && isYnMenuMove == true && isKetteiTxtDisp == true) { if (field_0x0268 != 0) { - mWaitTimer = g_fsHIO.card_wait_frames; + mWaitTimer = IF_DUSK(dusk::getSettings().game.instantSaves ? 0 :) g_fsHIO.card_wait_frames; setInitSaveData(); dataSave(); mCardCheckProc = MEMCARDCHECKPROC_MAKE_GAMEFILE; diff --git a/src/d/d_gameover.cpp b/src/d/d_gameover.cpp index baec970a32..870fb00f14 100644 --- a/src/d/d_gameover.cpp +++ b/src/d/d_gameover.cpp @@ -37,11 +37,10 @@ void dDlst_Gameover_CAPTURE_c::draw() { TGXTexObj tex_obj; Mtx44 m; -#if TARGET_PC - GXSetTexCopySrc(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); - GXSetTexCopyDst(mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), GX_TF_RGB565, GX_TRUE); -#else GXSetTexCopySrc(0, 0, FB_WIDTH, FB_HEIGHT); +#if TARGET_PC + GXSetTexCopyDst(FB_WIDTH, FB_HEIGHT, GX_TF_RGB565, GX_FALSE); +#else GXSetTexCopyDst(FB_WIDTH / 2, FB_HEIGHT / 2, GX_TF_RGB565, GX_TRUE); #endif GXCopyTex(mDoGph_gInf_c::mZbufferTex, 0); diff --git a/src/d/d_insect.cpp b/src/d/d_insect.cpp index 380f545bd3..3f1d2fae11 100644 --- a/src/d/d_insect.cpp +++ b/src/d/d_insect.cpp @@ -82,11 +82,7 @@ void dInsect_c::CalcZBuffer(f32 param_0) { pos = current.pos; pos.y += 20.0f; - #if TARGET_PC - mDoLib_project(&pos, &pos_projected, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&pos, &pos_projected); - #endif if (dComIfGp_getCamera(0)) { camera_trim_height = dComIfGp_getCamera(0)->mCamera.mTrimHeight; diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 9bb96efc82..6b84fbae43 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -35,6 +35,7 @@ #if TARGET_PC #include "dusk/imgui/ImGuiBloomWindow.hpp" #include "dusk/settings.h" +#include "dusk/frame_interpolation.h" #endif static void GxXFog_set(); @@ -8251,6 +8252,10 @@ static int dKy_Create(void* i_this) { kankyo_class* kankyo = (kankyo_class*)i_this; BOOL next_time_set = false; +#if TARGET_PC + kankyo->base.draw_interp_frame = true; +#endif + stage_envr_info_class* stage_envr_p = dComIfGp_getStageEnvrInfo(); if (stage_envr_p != NULL && dComIfGp_getStartStageRoomNo() != -1) { stage_envr_p += dComIfGp_getStartStageRoomNo(); @@ -11004,11 +11009,7 @@ void dKy_depth_dist_set(void* process_p) { f32 var_f31 = sp24.abs(camera_p->view.lookat.eye); if (var_f31 < 2000.0f && var_f31 < kankyo->field_0x1268) { - #if TARGET_PC - mDoLib_project(&actor_p->eyePos, &sp30, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&actor_p->eyePos, &sp30); - #endif if ((sp30.x >= 0.0f && sp30.x < FB_WIDTH) && (sp30.y >= 0.0f && #if DEBUG diff --git a/src/d/d_kankyo_debug.cpp b/src/d/d_kankyo_debug.cpp index 03bfeac196..7fdad26ed2 100644 --- a/src/d/d_kankyo_debug.cpp +++ b/src/d/d_kankyo_debug.cpp @@ -915,12 +915,7 @@ void dKydb_dungeonlight_draw() { rot.y = 0; dDbVw_drawCubeXlu(player->current.pos, size, rot, color); - #if TARGET_PC - mDoLib_project(&g_env_light.dungeonlight[i].mPosition, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&g_env_light.dungeonlight[i].mPosition, &proj); - #endif - if (proj.x > 30.0f) { proj.x -= 30.0f; } diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 31ba59e33e..64cf2247e0 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -116,12 +116,7 @@ void dKyr_lenzflare_move() { cXyz vect; cXyz proj; cXyz center; - - #if TARGET_PC - mDoLib_project(lenz_packet->mPositions, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(lenz_packet->mPositions, &proj); - #endif center.x = FB_WIDTH / 2; center.y = FB_HEIGHT / 2; @@ -221,12 +216,7 @@ void dKyr_sun_move() { } cXyz proj; - - #if TARGET_PC - mDoLib_project(sun_packet->mPos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(sun_packet->mPos, &proj); - #endif for (int i = 0; i < 5; i++) { cXyz chkpnt = proj; @@ -4127,11 +4117,7 @@ void dKyr_drawStar(Mtx drawMtx, u8** tex) { } } -#if TARGET_PC - mDoLib_project(&moon_pos, &moon_proj, {0, 0, FB_WIDTH, FB_HEIGHT}); -#else mDoLib_project(&moon_pos, &moon_proj); -#endif // Dusk optimization: we use vertex color rather than GX_TEVREG0 to set star color. // This allows us to merge all the stars into a single draw. @@ -4280,11 +4266,7 @@ void dKyr_drawStar(Mtx drawMtx, u8** tex) { sp68.y = spBC.y + star_pos.y; sp68.z = spBC.z + star_pos.z; - #if TARGET_PC - mDoLib_project(&sp68, &star_proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&sp68, &star_proj); - #endif moon_proj.z = 0.0f; star_proj.z = 0.0f; @@ -4699,11 +4681,7 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { } if (g_env_light.daytime > 105.0f && g_env_light.daytime < 240.0f && !dComIfGp_event_runCheck() && sun_packet != NULL && sun_packet->mSunAlpha > 0.0f) { - #if TARGET_PC - mDoLib_project(&sun_packet->mPos[0], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&sun_packet->mPos[0], &proj); - #endif if (proj.x > 0.0f && proj.x < FB_WIDTH && proj.y > spC4 && proj.y < (458.0f - spC4)) { pass = 0; } @@ -4968,12 +4946,7 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { x = 100.0f; y = 100.0f; z = 100.0f; - - #if TARGET_PC - mDoLib_project(&spF0, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&spF0, &proj); - #endif if (proj.x > -x && proj.x < (FB_WIDTH + x) && proj.y > -y && proj.y < (458.0f + z)) { break; @@ -5023,12 +4996,7 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { x = 100.0f; y = 100.0f; z = 100.0f; - - #if TARGET_PC - mDoLib_project(&spE4, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&spE4, &proj); - #endif if (proj.x > -x && proj.x < (FB_WIDTH + x) && proj.y > -y && proj.y < (458.0f + z)) { break; @@ -6068,13 +6036,7 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { sp34.x = 80.0f; sp34.y = 80.0f; sp34.z = 80.0f; - - #if TARGET_PC - mDoLib_project(&sp7C, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&sp7C, &proj); - #endif - if (!(proj.x > -sp34.x) || !(proj.x < (FB_WIDTH + sp34.x)) || !(proj.y > -sp34.y) || !(proj.y < (458.0f + sp34.z))) { @@ -6299,12 +6261,7 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { sp44.y = 80.0f; sp44.z = 80.0f; - #if TARGET_PC - mDoLib_project(&spA4, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&spA4, &proj); - #endif - if (!(proj.x > -sp44.x) || !(proj.x < (FB_WIDTH + sp44.x)) || !(proj.y > -sp44.y) || !(proj.y < (458.0f + sp44.z))) { diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index a31ccdedfd..916bd2c223 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -16,10 +16,6 @@ #ifdef TARGET_PC constexpr u16 kMapResolutionMultiplier = 4; -// Line widths are relative to the framebuffer size. Since we're rendering to a separate -// framebuffer, we have to scale them accordingly. The original game used about half of the -// EFB for the map rendering, so this is a reasonable approximation. -constexpr u8 kMapLineWidthMultiplier = 2; #endif void dMpath_n::dTexObjAggregate_c::create() { @@ -242,11 +238,7 @@ void dDrawPath_c::rendering(dDrawPath_c::line_class const* p_line) { int width = getLineWidth(p_line->field_0x1); if (width > 0 && p_line->mDataNum >= 2) { -#ifdef TARGET_PC - GXSetLineWidth(width * kMapLineWidthMultiplier, GX_TO_ZERO); -#else - GXSetLineWidth(width * 2, GX_TO_ZERO); -#endif + GXSetLineWidth(width, GX_TO_ZERO); GXSetTevColor(GX_TEVREG0, *getLineColor(p_line->field_0x0 & 0x3F, p_line->field_0x1)); GXBegin(GX_LINESTRIP, GX_VTXFMT0, p_line->mDataNum); @@ -435,8 +427,12 @@ void dRenderingFDAmap_c::preRenderingMap() { const u16 w = mTexWidth * kMapResolutionMultiplier; const u16 h = mTexHeight * kMapResolutionMultiplier; GXCreateFrameBuffer(w, h); - GXSetViewport(0.0f, 0.0f, w, h, 0.0f, 1.0f); - GXSetScissor(0, 0, w, h); + // Set logical viewport dimensions + GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); + GXSetScissor(0, 0, mTexWidth, mTexHeight); + // Set render viewport dimensions + GXSetViewportRender(0.0f, 0.0f, w, h, 0.0f, 1.0f); + GXSetScissorRender(0, 0, w, h); #else GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); GXSetScissor(0, 0, mTexWidth, mTexHeight); @@ -517,13 +513,8 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li BE(u16)* data_p = p_line->mpData; s32 data_num = p_line->mDataNum; -#ifdef TARGET_PC - GXSetLineWidth(width * kMapLineWidthMultiplier, GX_TO_ZERO); - GXSetPointSize(width * kMapLineWidthMultiplier, GX_TO_ONE); -#else GXSetLineWidth(width, GX_TO_ONE); GXSetPointSize(width, GX_TO_ONE); -#endif GXColor lineColor = *getDecoLineColor(p_line->field_0x0 & 0x3f, p_line->field_0x1); GXSetTevColor(GX_TEVREG0, lineColor); lineColor.r = lineColor.r - 4; diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index 7ae416c4be..46c9c1a9d9 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -164,11 +164,22 @@ void dMenu_Collect2D_c::menuCollectWide() { // Item Description Text mpScreen->search(MULTI_CHAR('infotxtn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + #if TARGET_PC + if (mpDrawCursor) { + mpDrawCursor->refreshAspectScale(); + } + #endif } #endif void dMenu_Collect2D_c::_create() { mpHeap->getTotalFreeSize(); + + #if TARGET_PC + mpDrawCursor = NULL; + #endif + mpScreen = JKR_NEW J2DScreen(); mpScreen->setPriority("zelda_collect_soubi_screen.blo", 0x1020000, dComIfGp_getCollectResArchive()); @@ -1100,23 +1111,11 @@ void dMenu_Collect2D_c::cursorPosSet() { Vec pos = mpSelPm[mCursorX][mCursorY]->getGlobalVtxCenter(false, 0); mpDrawCursor->setPos(pos.x, pos.y, mpSelPm[mCursorX][mCursorY]->getPanePtr(), false); if (mCursorY == 5) { - #if TARGET_PC - mpDrawCursor->setParam(1.1f * mDoGph_gInf_c::hudAspectScaleUp, 0.85f, 0.05f, 0.5f, 0.5f); - #else mpDrawCursor->setParam(1.1f, 0.85f, 0.05f, 0.5f, 0.5f); - #endif } else if (mCursorX == 6 && mCursorY == 0) { - #if TARGET_PC - mpDrawCursor->setParam(0.6f * mDoGph_gInf_c::hudAspectScaleUp, 0.85f, 0.03f, 0.6f, 0.6f); - #else mpDrawCursor->setParam(0.6f, 0.85f, 0.03f, 0.6f, 0.6f); - #endif } else { - #if TARGET_PC - mpDrawCursor->setParam(1.0f * mDoGph_gInf_c::hudAspectScaleUp, 1.0f, 0.1f, 0.7f, 0.7f); - #else mpDrawCursor->setParam(1.0f, 1.0f, 0.1f, 0.7f, 0.7f); - #endif } } @@ -2688,12 +2687,7 @@ u8 dMenu_Collect3D_c::getMaskMdlVisible() { f32 dMenu_Collect3D_c::mViewOffsetY = -100.0f; void dMenu_Collect3D_c::setupItem3D(Mtx param_0) { -#if TARGET_PC - f32 scaleFactor = mDoGph_gInf_c::getHeight() / FB_HEIGHT; - GXSetViewport(0.0f, mViewOffsetY * scaleFactor, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, 1.0f); -#else GXSetViewport(0.0f, mViewOffsetY, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f); -#endif mViewOffsetY = -100.0f; Mtx44 projection; C_MTXPerspective(projection, 45.0f, mDoGph_gInf_c::getAspect(), 1.0f, 100000.0f); diff --git a/src/d/d_menu_dmap.cpp b/src/d/d_menu_dmap.cpp index 739dfc7843..17d9193241 100644 --- a/src/d/d_menu_dmap.cpp +++ b/src/d/d_menu_dmap.cpp @@ -864,33 +864,15 @@ void dMenu_DmapBg_c::draw() { J2DOrthoGraph* grafContext = (J2DOrthoGraph*)dComIfGp_getCurrentGrafPort(); grafContext->setup2D(); -#if TARGET_PC - // GXGetScissor uses 11-bit GC register fields (max 2047) which overflow - // at window widths > ~1705px, producing garbage values on restore. - scissor_left = 0; - scissor_top = 0; - scissor_width = (u32)mDoGph_gInf_c::getWidth(); - scissor_height = (u32)mDoGph_gInf_c::getHeight(); -#else GXGetScissor(&scissor_left, &scissor_top, &scissor_width, &scissor_height); -#endif -#if TARGET_PC - grafContext->scissor(field_0xd94, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else - grafContext->scissor(field_0xd94, 0.0f, FB_WIDTH, FB_HEIGHT); -#endif + grafContext->scissor(field_0xd94, 0.0f, FB_WIDTH, FB_HEIGHT); grafContext->setScissor(); mBaseScreen->draw(field_0xd94, field_0xd98, grafContext); dMenu_Dmap_c::myclass->drawFloorScreenBack(mFloorScreen, field_0xd94, field_0xd98, grafContext); -#if TARGET_PC - f32 dVar21 = mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth(); - f32 dVar16 = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); -#else f32 dVar21 = mDoGph_gInf_c::getWidthF() / FB_WIDTH; f32 dVar16 = mDoGph_gInf_c::getHeightF() / FB_HEIGHT; -#endif mMapScreen[0]->draw(field_0xd94, field_0xd98, grafContext); if (mpBackTexture != NULL) { @@ -922,15 +904,9 @@ void dMenu_DmapBg_c::draw() { mpBackTexture->draw(local_28c, field_0xd94 + mpBackTexture->getBounds().i.y, mpBackTexture->getWidth(), mpBackTexture->getHeight(), false, false, false); -#if TARGET_PC - grafContext->scissor(field_0xd94, - 0, mDoGph_gInf_c::getWidth(), - scissor_height); -#else grafContext->scissor(field_0xd94 + mDoGph_gInf_c::getMinXF(), scissor_top, mDoGph_gInf_c::getWidthF(), scissor_height); -#endif grafContext->setScissor(); } @@ -957,11 +933,7 @@ void dMenu_DmapBg_c::draw() { Vec local_26c = pane.getGlobalVtx(mMapPane, &local_110, 0, false, 0); drawIcon(local_26c.x + field_0xd94, local_26c.y, field_0xda8, 1.0f); -#if TARGET_PC - grafContext->scissor(field_0xd94, scissor_top, mDoGph_gInf_c::getWidth(), scissor_height); -#else grafContext->scissor(field_0xd94 + mDoGph_gInf_c::getMinXF(), scissor_top, mDoGph_gInf_c::getWidthF(), scissor_height); -#endif grafContext->setScissor(); grafContext->scissor(scissor_left, scissor_top, scissor_width, scissor_height); grafContext->setScissor(); @@ -1012,7 +984,36 @@ void dMenu_DmapBg_c::update() { JUT_ASSERT(2323, mpBackTexture != NULL); void* spec = mpArchive->getResource("spec/spec.dat"); + #if TARGET_PC + struct dmap_spec { + /* 0x00 */ BE(f32) field_0x0; + /* 0x04 */ BE(f32) field_0x4; + /* 0x08 */ BE(f32) field_0x8; + /* 0x0C */ u8 field_0xc; + /* 0x0D */ u8 field_0xd; + /* 0x0E */ u8 field_0xe; + /* 0x0F */ u8 field_0xf; + /* 0x10 */ u8 field_0x10; + /* 0x11 */ u8 field_0x11; + /* 0x12 */ u8 field_0x12; + /* 0x13 */ u8 field_0x13; + }; + dmap_spec* dspec = (dmap_spec*)spec; + + field_0xd80 = dspec->field_0x0; + field_0xd84 = dspec->field_0x4; + field_0xd88 = dspec->field_0x8; + field_0xd8c = dspec->field_0xc; + field_0xd8d = dspec->field_0xd; + field_0xd8e = dspec->field_0xe; + field_0xd8f = dspec->field_0xf; + field_0xd90 = dspec->field_0x10; + field_0xd91 = dspec->field_0x11; + field_0xd92 = dspec->field_0x12; + field_0xd93 = dspec->field_0x13; + #else memcpy(&field_0xd80, spec, 20); + #endif } } diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index 558ad05d6d..8692156daf 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -276,18 +276,14 @@ void dMenu_Fmap2DBack_c::draw() { u32 scissorLeft, scissorTop, scissorWidth, scissorHeight; GXGetScissor(&scissorLeft, &scissorTop, &scissorWidth, &scissorHeight); -#if TARGET_PC - grafPort->scissor(mTransX, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else grafPort->scissor(mTransX, 0.0f, FB_WIDTH, FB_HEIGHT); -#endif grafPort->setScissor(); mpBackTex->setBlackWhite(field_0x1208, field_0x120c); mpBackTex->setAlpha(mAlphaRate * 255.0f * g_fmapHIO.mBackgroundAlpha); mpBackTex->draw(mTransX + mDoGph_gInf_c::getMinXF(), - mTransZ + mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidth(), - mDoGph_gInf_c::getHeight(), false, false, false); + mTransZ + mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), + mDoGph_gInf_c::getHeightF(), false, false, false); mpBackScreen->draw(mTransX, mTransZ, grafPort); mpBaseScreen->draw(mTransX, mTransZ, grafPort); @@ -297,13 +293,8 @@ void dMenu_Fmap2DBack_c::draw() { Vec vec2 = mpMapArea->getGlobalVtx(&mtx, 3, false, 0); -#if TARGET_PC - f32 width = mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth(); - f32 height = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); -#else f32 width = mDoGph_gInf_c::getWidthF() / FB_WIDTH; f32 height = mDoGph_gInf_c::getHeightF() / FB_HEIGHT; -#endif grafPort->scissor(mTransX + ((vec1.x - mDoGph_gInf_c::getMinXF()) / width), mTransZ + (vec1.y / height), (vec2.x - vec1.x) / width, @@ -351,8 +342,13 @@ void dMenu_Fmap2DBack_c::draw() { scrollAreaDraw(); } - blinkMove(30); - moveLightDropAnime(); +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + blinkMove(30); + moveLightDropAnime(); + } setCenterPosX(field_0x11dc, 1); drawIcon(mTransX, mTransZ, mAlphaRate, field_0xfa8 * mSpotTextureFadeAlpha); @@ -360,11 +356,7 @@ void dMenu_Fmap2DBack_c::draw() { drawDebugRegionArea(); } -#if TARGET_PC - grafPort->scissor(scissorLeft, scissorTop, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else grafPort->scissor(scissorLeft, scissorTop, scissorWidth, scissorHeight); -#endif grafPort->setScissor(); if (isArrowDrawFlag()) { @@ -392,16 +384,15 @@ void dMenu_Fmap2DBack_c::draw() { &mArrowPos2DY); #ifdef TARGET_PC - for (u32 i = 0; i < dusk::frame_interp::get_presentation_ui_advance_ticks(); ++i) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { field_0x11e0 -= g_fmapHIO.mCursorSpeed; if (field_0x11e0 < 0.0f) { field_0x11e0 += 360.0f; } -#ifdef TARGET_PC } -#endif mpPointParent->getPanePtr()->rotate(mpPointParent->getSizeX() / 2.0f, mpPointParent->getSizeY() / 2.0f, ROTATE_Z, @@ -1778,14 +1769,19 @@ void dMenu_Fmap2DBack_c::calcBlink() { t * (g_fmapHIO.mMapBlink[i + 1].mUnselectedRegion.mBlinkSpeed - g_fmapHIO.mMapBlink[i].mUnselectedRegion.mBlinkSpeed); - field_0x1218++; - if (field_0x1218 >= selected_blink_speed) { - field_0x1218 = 0; - } +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x1218++; + if (field_0x1218 >= selected_blink_speed) { + field_0x1218 = 0; + } - field_0x121a++; - if (field_0x121a >= unselected_blink_speed) { - field_0x121a = 0; + field_0x121a++; + if (field_0x121a >= unselected_blink_speed) { + field_0x121a = 0; + } } f32 t_selected = 0.0f; @@ -2580,11 +2576,7 @@ void dMenu_Fmap2DTop_c::draw() { J2DOrthoGraph* ctx = static_cast(dComIfGp_getCurrentGrafPort()); ctx->setup2D(); GXGetScissor(&scissor_left, &scissor_top, &scissor_width, &scissor_height); -#if TARGET_PC - ctx->scissor(mTransX, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else ctx->scissor(mTransX, 0.0f, FB_WIDTH, FB_HEIGHT); -#endif ctx->setScissor(); mpTitleScreen->draw(mTransX, mTransY, ctx); ctx->scissor(scissor_left, scissor_top, scissor_width, scissor_height); diff --git a/src/d/d_menu_letter.cpp b/src/d/d_menu_letter.cpp index cef018372f..a0155ef6b4 100644 --- a/src/d/d_menu_letter.cpp +++ b/src/d/d_menu_letter.cpp @@ -223,13 +223,8 @@ void dMenu_Letter_c::_draw() { f32 y1 = local_178.y; Vec local_184; local_184 = afStack_138.getGlobalVtx(field_0x1ec, &mtx, 3, false, 0); -#if TARGET_PC - f32 dVar17 = mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth(); - f32 dVar16 = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); -#else f32 dVar17 = mDoGph_gInf_c::getWidthF() / FB_WIDTH; f32 dVar16 = mDoGph_gInf_c::getHeightF() / FB_HEIGHT; -#endif f32 fVar1 = (x1 - mDoGph_gInf_c::getMinXF()) / dVar17; f32 fVar2 = y1 / dVar16; grafContext->scissor(fVar1, fVar2, diff --git a/src/d/d_menu_option.cpp b/src/d/d_menu_option.cpp index 9384bc06b9..af322a1c01 100644 --- a/src/d/d_menu_option.cpp +++ b/src/d/d_menu_option.cpp @@ -555,19 +555,23 @@ void dMenu_Option_c::_draw() { #endif mpBlackTex->setAlpha(0xff); + #if TARGET_PC mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); #endif + mpBackScreen->draw(0.0f, 0.0f, ctx); f32 alpha = (f32)g_drawHIO.mOptionScreen.mBackgroundAlpha * (f32)field_0x374; mpBlackTex->setAlpha(alpha); + #if TARGET_PC mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); #endif + mpScreen->draw(0.0f, 0.0f, ctx); mpClipScreen->draw(0.0f, 0.0f, ctx); #if TARGET_PC diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp index 4615d4b2a6..36b3d63c9e 100644 --- a/src/d/d_menu_ring.cpp +++ b/src/d/d_menu_ring.cpp @@ -29,6 +29,10 @@ #include +#if TARGET_PC +#include "dusk/game_clock.h" +#endif + typedef void (dMenu_Ring_c::*initFunc)(); static initFunc stick_init[] = { /* STATUS_WAIT */ &dMenu_Ring_c::stick_wait_init, @@ -183,6 +187,9 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i } for (int i = 0; i < 4; i++) { field_0x674[i] = 0; +#if TARGET_PC + mSelectItemSlideElapsed[i] = 0.0f; +#endif field_0x518[i] = 0.0f; field_0x528[i] = 0.0f; field_0x538[i] = 0.0f; @@ -1022,6 +1029,9 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) { field_0x6b8[0] != dComIfGs_getMixItemIndex(0)) { field_0x674[0] = 1; +#if TARGET_PC + mSelectItemSlideElapsed[0] = 0.0f; +#endif } } else if (field_0x6b3 == 1) { field_0x538[0] = g_ringHIO.mUnselectItemScale; @@ -1030,6 +1040,9 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) { field_0x6b8[1] != dComIfGs_getMixItemIndex(1)) { field_0x674[1] = 1; +#if TARGET_PC + mSelectItemSlideElapsed[1] = 0.0f; +#endif } } if (field_0x674[0] == 1) { @@ -1520,7 +1533,15 @@ void dMenu_Ring_c::setSelectItem(int i_idx, u8 i_itemNo) { void dMenu_Ring_c::drawSelectItem() { for (int i = 0; i < 4; i++) { if (field_0x674[i] != 0) { +#if TARGET_PC + mSelectItemSlideElapsed[i] += dusk::game_clock::consume_interval(this); + const f32 u = std::min(mSelectItemSlideElapsed[i] / dusk::game_clock::period_for_original_frames(10.0f), 1.0f); + if (u >= 1.0f) { + setSelectItemForce(i); + } else { +#else if (field_0x674[i] < 10) { +#endif f32 initSizeX = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeX() * 1.7f; f32 initSizeY = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeY() * 1.7f; f32 initScaleX = dMeter2Info_getMeterItemPanePtr(i)->getInitScaleX(); @@ -1528,7 +1549,11 @@ void dMenu_Ring_c::drawSelectItem() { Vec pos = dMeter2Info_getMeterItemPanePtr(i)->getGlobalVtxCenter( dMeter2Info_getMeterItemPanePtr(i)->mPane, true, 0); +#if TARGET_PC + f32 fVar14 = 0.1f + 0.8f * u; +#else f32 fVar14 = field_0x674[i] / 10.0f; +#endif if (field_0x6cd != 0xff) { fVar14 = 1.0f - fVar14; } @@ -1549,9 +1574,11 @@ void dMenu_Ring_c::drawSelectItem() { 0); } } +#if !TARGET_PC field_0x674[i]++; } else { setSelectItemForce(i); +#endif } } } @@ -1562,6 +1589,9 @@ void dMenu_Ring_c::setSelectItemForce(int i_idx) { if (field_0x674[i_idx] != 0) { dComIfGs_setSelectItemIndex(i_idx, field_0x6b4[i_idx]); field_0x674[i_idx] = 0; +#if TARGET_PC + mSelectItemSlideElapsed[i_idx] = 0.0f; +#endif } } else if (field_0x674[i_idx] != 0) { for (int i = 0; i < 2; i++) { @@ -1569,6 +1599,9 @@ void dMenu_Ring_c::setSelectItemForce(int i_idx) { dComIfGs_setSelectItemIndex(i, field_0x6b4[i]); } field_0x674[i_idx] = 0; +#if TARGET_PC + mSelectItemSlideElapsed[i_idx] = 0.0f; +#endif } } diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp index 0935eb4e52..53dbe37ca4 100644 --- a/src/d/d_menu_save.cpp +++ b/src/d/d_menu_save.cpp @@ -18,6 +18,7 @@ #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_graphic.h" #include "d/d_msg_scrn_explain.h" +#include "dusk/frame_interpolation.h" #include "dusk/settings.h" #include "JSystem/J2DGraph/J2DAnmLoader.h" #include "f_op/f_op_msg_mng.h" @@ -386,11 +387,7 @@ void dMenu_save_c::screenSet() { mSelectedFile = dComIfGs_getDataNum(); mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); - #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); - #endif Vec pos; pos = mpSelData[mSelectedFile]->getGlobalVtxCenter(false, 0); @@ -719,7 +716,9 @@ void dMenu_save_c::_move() { } (this->*MenuSaveProc[mMenuProc])(); +#if !TARGET_PC saveSelAnm(); +#endif if (mWarning != NULL) { mWarning->_move(); @@ -736,36 +735,46 @@ void dMenu_save_c::saveSelAnm() { } void dMenu_save_c::selFileWakuAnm() { - mFileWakuAnmFrame += 2; - if (mFileWakuAnmFrame >= mpFileWakuAnm->getFrameMax()) { - mFileWakuAnmFrame -= mpFileWakuAnm->getFrameMax(); +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + mFileWakuAnmFrame += 2; + if (mFileWakuAnmFrame >= mpFileWakuAnm->getFrameMax()) { + mFileWakuAnmFrame -= mpFileWakuAnm->getFrameMax(); + } + + mFileWakuRotAnmFrame += 2; + if (mFileWakuRotAnmFrame >= mpFileWakuRotAnm->getFrameMax()) { + mFileWakuRotAnmFrame -= mpFileWakuRotAnm->getFrameMax(); + } } mpFileWakuAnm->setFrame(mFileWakuAnmFrame); - - mFileWakuRotAnmFrame += 2; - if (mFileWakuRotAnmFrame >= mpFileWakuRotAnm->getFrameMax()) { - mFileWakuRotAnmFrame -= mpFileWakuRotAnm->getFrameMax(); - } mpFileWakuRotAnm->setFrame(mFileWakuRotAnmFrame); } void dMenu_save_c::bookIconAnm() { - field_0x154 += 2; - if (field_0x154 >= field_0x150->getFrameMax()) { - field_0x154 -= field_0x150->getFrameMax(); +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x154 += 2; + if (field_0x154 >= field_0x150->getFrameMax()) { + field_0x154 -= field_0x150->getFrameMax(); + } + + field_0x15c += 2; + if (field_0x15c >= field_0x158->getFrameMax()) { + field_0x15c -= field_0x158->getFrameMax(); + } + + field_0x164 += 2; + if (field_0x164 >= field_0x160->getFrameMax()) { + field_0x164 -= field_0x160->getFrameMax(); + } } field_0x150->setFrame(field_0x154); - - field_0x15c += 2; - if (field_0x15c >= field_0x158->getFrameMax()) { - field_0x15c -= field_0x158->getFrameMax(); - } field_0x158->setFrame(field_0x15c); - - field_0x164 += 2; - if (field_0x164 >= field_0x160->getFrameMax()) { - field_0x164 -= field_0x160->getFrameMax(); - } field_0x160->setFrame(field_0x164); } @@ -2523,11 +2532,7 @@ void dMenu_save_c::yesnoCursorShow() { mSelIcon->setPos(pos.x, pos.y, mpNoYes[mYesNoCursor]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); - #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); - #endif } } @@ -2676,11 +2681,7 @@ void dMenu_save_c::selFileCursorShow() { mSelIcon->setPos(pos.x, pos.y, mpSelData[mSelectedFile]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); - #if TARGET_PC - mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); - #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); - #endif } void dMenu_save_c::yesnoWakuAlpahAnmInit(u8 yesnoIdx, u8 startAlpha, u8 endAlpha, u8 anmTimer) { @@ -2813,11 +2814,20 @@ void dMenu_save_c::menuSaveWide() { mSaveSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); mSaveSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); mSaveSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + #if TARGET_PC + if (mSelIcon) { + mSelIcon->refreshAspectScale(); + } + #endif } #endif void dMenu_save_c::_draw2() { if (field_0x21a1 == 0) { +#if TARGET_PC + saveSelAnm(); +#endif if (mpScrnExplain != NULL) { dComIfGd_set2DOpa(&mMenuSaveExplain); } diff --git a/src/d/d_menu_window.cpp b/src/d/d_menu_window.cpp index af8a734fe7..7f76f807df 100644 --- a/src/d/d_menu_window.cpp +++ b/src/d/d_menu_window.cpp @@ -32,15 +32,9 @@ public: if (getDrawFlag() == 1) { setDrawFlag(); dComIfGp_onPauseFlag(); - - #if TARGET_PC - GXSetTexCopySrc(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); - #else GXSetTexCopySrc(0, 0, FB_WIDTH, FB_HEIGHT); - #endif - #if TARGET_PC - GXSetTexCopyDst(mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_ENABLE); + GXSetTexCopyDst(FB_WIDTH, FB_HEIGHT, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_DISABLE); #else GXSetTexCopyDst(FB_WIDTH / 2, FB_HEIGHT / 2, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_ENABLE); #endif @@ -48,17 +42,17 @@ public: GXPixModeSync(); #if TARGET_PC // init mTexObj at capture time so the gpu ref survives window resizes - mCaptureWidth = mDoGph_gInf_c::getWidth(); - mCaptureHeight = mDoGph_gInf_c::getHeight(); - GXInitTexObj(&mTexObj, mDoGph_gInf_c::getFrameBufferTex(), mCaptureWidth, mCaptureHeight, + mCaptureWidth = JUTVideo::getManager()->getRenderWidth(); + mCaptureHeight = JUTVideo::getManager()->getRenderHeight(); + GXInitTexObj(&mTexObj, mDoGph_gInf_c::getFrameBufferTex(), FB_WIDTH / 2, FB_HEIGHT / 2, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_CLAMP, GX_CLAMP, GX_FALSE); GXInitTexObjLOD(&mTexObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); #endif } else { #if TARGET_PC // If the window was resized since capture, force a re-capture at the new size - if (mCaptureWidth != (u16)mDoGph_gInf_c::getWidth() || - mCaptureHeight != (u16)mDoGph_gInf_c::getHeight()) { + if (mCaptureWidth != JUTVideo::getManager()->getRenderWidth() || + mCaptureHeight != JUTVideo::getManager()->getRenderHeight()) { mFlag = 1; return; } @@ -137,8 +131,8 @@ private: /* 0x5 */ u8 mAlpha; /* 0x6 */ u8 mTopFlag; #if TARGET_PC - u16 mCaptureWidth; - u16 mCaptureHeight; + u32 mCaptureWidth; + u32 mCaptureHeight; TGXTexObj mTexObj; #endif }; @@ -705,7 +699,7 @@ void dMw_c::collect_open_proc() { dMeter2Info_set2DVibrationM(); } - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = COLLECT_MOVE; } } @@ -920,7 +914,7 @@ void dMw_c::collect_letter_move_proc() { } void dMw_c::collect_letter_close_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = COLLECT_MOVE; } } @@ -952,7 +946,7 @@ void dMw_c::collect_fishing_move_proc() { } void dMw_c::collect_fishing_close_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = COLLECT_MOVE; } } @@ -983,7 +977,7 @@ void dMw_c::collect_skill_move_proc() { } void dMw_c::collect_skill_close_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = COLLECT_MOVE; } } @@ -1014,13 +1008,13 @@ void dMw_c::collect_insect_move_proc() { } void dMw_c::collect_insect_close_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = COLLECT_MOVE; } } void dMw_c::insect_open_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { field_0x152 = 0; dComIfGp_setHeapLockFlag(1); dMw_insect_create(1); @@ -1056,7 +1050,7 @@ void dMw_c::insect_move_proc() { } void dMw_c::insect_close_proc() { - if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) { + if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) { mMenuProc = NO_MENU; } } diff --git a/src/d/d_meter2_draw.cpp b/src/d/d_meter2_draw.cpp index 417dcad319..8e824f583b 100644 --- a/src/d/d_meter2_draw.cpp +++ b/src/d/d_meter2_draw.cpp @@ -638,12 +638,11 @@ void dMeter2Draw_c::draw() { var_f29 = g_drawHIO.mLightDrop.mDropPikariAnimSpeed_Completed; int temp_r5_2 = g_drawHIO.mLightDrop.mPikariInterval * 15; #ifdef TARGET_PC - // Set even if not advancing + // FRAME INTERP NOTE: Set even if not advancing var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete; - - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 tick = 0; tick < ui_advance_ticks; ++tick) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { if (field_0x756 <= temp_r5_2) { int temp_r4 = (field_0x756 % g_drawHIO.mLightDrop.mPikariInterval); int temp_r3_5 = field_0x756 / g_drawHIO.mLightDrop.mPikariInterval; @@ -669,17 +668,12 @@ void dMeter2Draw_c::draw() { } field_0x756 = -1; -#ifdef TARGET_PC - break; -#endif } else { field_0x756++; } } } -#ifdef TARGET_PC } -#endif for (int i = 0; i < 16; i++) { if (field_0x66c[i] > 0.0f) { @@ -1349,9 +1343,9 @@ void dMeter2Draw_c::drawPikari(f32 i_posX, f32 i_posY, f32* i_framep, f32 i_scal *i_framep = 0.0f; } else { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 i = 0; i < ui_advance_ticks; ++i) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { *i_framep += param_8; if (*i_framep > var_f31) { if (param_9 == 1 || param_9 == 2 || param_9 == 3) { @@ -1366,9 +1360,7 @@ void dMeter2Draw_c::drawPikari(f32 i_posX, f32 i_posY, f32* i_framep, f32 i_scal } else if (*i_framep == 18.0f && param_9 == 2) { mDoAud_seStart(Z2SE_SY_ITEM_COMBINE_ICON, NULL, 0, 0); } -#ifdef TARGET_PC } -#endif playPikariBckAnimation(*i_framep); playPikariBpkAnimation(*i_framep); diff --git a/src/d/d_meter_button.cpp b/src/d/d_meter_button.cpp index 88f750d6ca..d36a124d17 100644 --- a/src/d/d_meter_button.cpp +++ b/src/d/d_meter_button.cpp @@ -16,6 +16,7 @@ #include "d/d_msg_out_font.h" #include "d/d_msg_string.h" #include "d/d_pane_class.h" +#include "dusk/frame_interpolation.h" #include #if VERSION == VERSION_GCN_JPN @@ -280,15 +281,20 @@ void dMeterButton_c::draw() { s16 temp_r6 = g_drawHIO.mEmpButton.mRepeatHitFrameNum; s16 temp_r6_2 = g_drawHIO.mEmpButton.mRepeatHitFrameNum / 2; - field_0x4b8[i]++; +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x4b8[i]++; - if (field_0x4b8[i] >= temp_r6) { - field_0x4b8[i] = 0; + if (field_0x4b8[i] >= temp_r6) { + field_0x4b8[i] = 0; - if (field_0x4bc[i] == 0) { - field_0x4bc[i] = 1; - } else { - field_0x4bc[i] = 0; + if (field_0x4bc[i] == 0) { + field_0x4bc[i] = 1; + } else { + field_0x4bc[i] = 0; + } } } diff --git a/src/d/d_meter_haihai.cpp b/src/d/d_meter_haihai.cpp index daf30b9aae..5ea5dad5b7 100644 --- a/src/d/d_meter_haihai.cpp +++ b/src/d/d_meter_haihai.cpp @@ -11,6 +11,7 @@ #include "d/d_com_inf_game.h" #include "d/d_meter_HIO.h" #include "d/d_pane_class.h" +#include "dusk/frame_interpolation.h" dMeterHaihai_c::dMeterHaihai_c(u8 i_type) { mType = i_type; @@ -286,14 +287,19 @@ void dMeterHaihai_c::updateHaihai() { void dMeterHaihai_c::playBckAnime(J2DAnmTransformKey* i_bck) { if (checkPlayAnime(1)) { if (i_bck != NULL) { - if (mType == 4) { - mBckFrame += g_drawHIO.mWiiLockArrowBCKAnimSpeed; - } else { - mBckFrame += g_drawHIO.mScrollArrowBCKAnimSpeed; - } +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (mType == 4) { + mBckFrame += g_drawHIO.mWiiLockArrowBCKAnimSpeed; + } else { + mBckFrame += g_drawHIO.mScrollArrowBCKAnimSpeed; + } - if (mBckFrame >= i_bck->getFrameMax()) { - mBckFrame -= i_bck->getFrameMax(); + if (mBckFrame >= i_bck->getFrameMax()) { + mBckFrame -= i_bck->getFrameMax(); + } } } else { mBtkFrame = 1.0f; @@ -309,14 +315,19 @@ void dMeterHaihai_c::playBckAnime(J2DAnmTransformKey* i_bck) { void dMeterHaihai_c::playBtkAnime(J2DAnmTextureSRTKey* i_btk) { if (checkPlayAnime(2)) { if (i_btk != NULL) { - if (mType == 4) { - mBtkFrame += g_drawHIO.mWiiLockArrowBTKAnimSpeed; - } else { - mBtkFrame += g_drawHIO.mScrollArrowBTKAnimSpeed; - } +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (mType == 4) { + mBtkFrame += g_drawHIO.mWiiLockArrowBTKAnimSpeed; + } else { + mBtkFrame += g_drawHIO.mScrollArrowBTKAnimSpeed; + } - if (mBtkFrame >= i_btk->getFrameMax()) { - mBtkFrame -= i_btk->getFrameMax(); + if (mBtkFrame >= i_btk->getFrameMax()) { + mBtkFrame -= i_btk->getFrameMax(); + } } } else { mBtkFrame = 1.0f; @@ -331,14 +342,19 @@ void dMeterHaihai_c::playBtkAnime(J2DAnmTextureSRTKey* i_btk) { void dMeterHaihai_c::playBpkAnime(J2DAnmColor* i_bpk) { if (checkPlayAnime(0)) { if (i_bpk != NULL) { - if (mType == 4) { - mBpkFrame += g_drawHIO.mWiiLockArrowBPKAnimSpeed; - } else { - mBpkFrame += g_drawHIO.mScrollArrowBPKAnimSpeed; - } +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (mType == 4) { + mBpkFrame += g_drawHIO.mWiiLockArrowBPKAnimSpeed; + } else { + mBpkFrame += g_drawHIO.mScrollArrowBPKAnimSpeed; + } - if (mBpkFrame >= i_bpk->getFrameMax()) { - mBpkFrame -= i_bpk->getFrameMax(); + if (mBpkFrame >= i_bpk->getFrameMax()) { + mBpkFrame -= i_bpk->getFrameMax(); + } } } else { mBpkFrame = 1.0f; diff --git a/src/d/d_meter_string.cpp b/src/d/d_meter_string.cpp index ad95c53edd..c28d6d5481 100644 --- a/src/d/d_meter_string.cpp +++ b/src/d/d_meter_string.cpp @@ -16,6 +16,7 @@ #include "d/d_meter2_info.h" #include "d/d_meter_HIO.h" #include "d/d_pane_class.h" +#include "dusk/frame_interpolation.h" #include dMeterString_c::dMeterString_c(int i_stringID) { @@ -105,16 +106,27 @@ void dMeterString_c::draw() { f32 var_f30 = 1.0f; if (mAnimFrame < 60.0f) { - mAnimFrame += g_drawHIO.mMiniGame.mReadyFightTextAnimSpeed; - if (mAnimFrame > 60.0f) { - mAnimFrame = 60.0f; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + mAnimFrame += g_drawHIO.mMiniGame.mReadyFightTextAnimSpeed; + if (mAnimFrame > 60.0f) { + mAnimFrame = 60.0f; + } } playBckAnimation(mAnimFrame); } else if (mAnimFrame < (f32)g_drawHIO.mMiniGame.mReadyFightTextWaitFrames + 60.0f) { - mAnimFrame += var_f30; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + mAnimFrame += var_f30; } else if (mAnimFrame < var_f31) { - mAnimFrame += var_f30; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + mAnimFrame += var_f30; var_f30 = acc(g_drawHIO.mMiniGame.field_0x172, var_f31 - mAnimFrame, 0); } @@ -128,13 +140,21 @@ void dMeterString_c::draw() { if (mPikariAnimFrame > 0.0f) { drawPikari(); } else if (mPikariAnimFrame == -1.0f && +#if TARGET_PC + dusk::frame_interp::get_ui_tick_pending() && +#endif mAnimFrame > g_drawHIO.mMiniGame.mReadyFightPikariAppearFrames) { mPikariAnimFrame = 18.0f - g_drawHIO.mMiniGame.mReadyFightPikariAnimSpeed; } - if (mAnimFrame >= var_f31) { - dMeter2Info_resetMeterString(); +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (mAnimFrame >= var_f31) { + dMeter2Info_resetMeterString(); + } } } } diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 488af685db..9b7b64ebda 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -1468,24 +1468,12 @@ void dMsgObject_c::fukiPosCalc(bool param_1) { fopAc_ac_c* player = dComIfGp_getPlayer(0); cXyz local_3c; cXyz cStack_48; - - #if TARGET_PC - mDoLib_project(&player->eyePos, &cStack_48, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&player->eyePos, &cStack_48); - #endif - f32 temp; if ((field_0x100->pos == cXyz(0.0f, 0.0f, 0.0f))) { temp = cStack_48.y; } else { - - #if TARGET_PC - mDoLib_project(&field_0x100->pos, &local_3c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&field_0x100->pos, &local_3c); - #endif - if (local_3c.x >= 0.0f && local_3c.x <= FB_WIDTH && local_3c.y >= 0.0f && local_3c.y <= FB_HEIGHT) { diff --git a/src/d/d_msg_out_font.cpp b/src/d/d_msg_out_font.cpp index 4d15b069d3..efc655d529 100644 --- a/src/d/d_msg_out_font.cpp +++ b/src/d/d_msg_out_font.cpp @@ -5,6 +5,7 @@ #include "JSystem/JUtility/JUTTexture.h" #include "d/d_meter2_info.h" #include "d/d_msg_object.h" +#include "dusk/frame_interpolation.h" #include "f_op/f_op_msg_mng.h" COutFontSet_c::COutFontSet_c() { @@ -311,6 +312,15 @@ void COutFont_c::draw(J2DTextBox* i_textbox, f32 param_1, f32 param_2, f32 param sp256[i] = field_0x1b4[i]; } +#ifdef TARGET_PC + bool uiTickPending = dusk::frame_interp::get_ui_tick_pending(); + if (!uiTickPending) { + for (int i = 0; i < 70; i++) { + sp256[i] = -1; + } + } +#endif + for (int i = 0; i < 35; i++) { u8 type = mpOfs[i]->getType(); J2DTextBox* tbox = mpOfs[i]->getTextBoxPtr(); @@ -505,9 +515,14 @@ void COutFont_c::draw(J2DTextBox* i_textbox, f32 param_1, f32 param_2, f32 param case 20: case 21: case 22: - field_0x1b4[type]++; - if (field_0x1b4[type] >= 28) { - field_0x1b4[type] = 0; +#ifdef TARGET_PC + if (uiTickPending) +#endif + { + field_0x1b4[type]++; + if (field_0x1b4[type] >= 28) { + field_0x1b4[type] = 0; + } } mpPane[type]->rotate(0.5f * sizeX, 0.5f * sizeY, ROTATE_Z, diff --git a/src/d/d_msg_scrn_howl.cpp b/src/d/d_msg_scrn_howl.cpp index 03729377a5..1d39cba1a1 100644 --- a/src/d/d_msg_scrn_howl.cpp +++ b/src/d/d_msg_scrn_howl.cpp @@ -607,17 +607,10 @@ void dMsgScrnHowl_c::drawGuide() { J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort(); Vec local_b0 = field_0x128; Vec local_bc = field_0x140; -#if TARGET_PC - grafContext->scissor( - (local_b0.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth()), - field_0x2118, (local_bc.x - local_b0.x) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth()), - field_0x2120); -#else grafContext->scissor( (local_b0.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH), field_0x2118, (local_bc.x - local_b0.x) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH), field_0x2120); -#endif grafContext->setScissor(); f32 local_cc = mpLineH[0]->getGlobalPosX(); s16 sVar12 = 0; @@ -745,19 +738,11 @@ void dMsgScrnHowl_c::drawGuide2() { } Vec local_58 = field_0x128; Vec local_64 = field_0x140; -#if TARGET_PC - f32 local_70 = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); - grafContext->scissor( - (local_58.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth()), - field_0x2118, (local_64.x - local_58.x) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth()), - field_0x2120); -#else f32 local_70 = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); grafContext->scissor( (local_58.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH), field_0x2118, (local_64.x - local_58.x) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH), field_0x2120); -#endif grafContext->setScissor(); f32 local_74 = mpLineH[0]->getGlobalPosX(); s16 local_134 = 0; @@ -859,15 +844,9 @@ void dMsgScrnHowl_c::drawEffect() { Vec vec1 = field_0x128; Vec vec2 = field_0x140; mDoGph_gInf_c::getHeightF(); -#if TARGET_PC - grafContext->scissor( - (vec1.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth()), field_0x2118, - 12.0f + ((vec2.x - vec1.x) / (mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth())), field_0x2120); -#else grafContext->scissor( (vec1.x - mDoGph_gInf_c::getMinXF()) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH), field_0x2118, 12.0f + ((vec2.x - vec1.x) / (mDoGph_gInf_c::getWidthF() / FB_WIDTH)), field_0x2120); -#endif grafContext->setScissor(); u8 timer = daAlink_getAlinkActorClass()->getWolfHowlMgrP()->getReleaseTimer(); u8 screenAlpha = mpScreen->search(MULTI_CHAR('line00'))->getAlpha(); diff --git a/src/d/d_msg_scrn_item.cpp b/src/d/d_msg_scrn_item.cpp index 53ef97607c..672700682d 100644 --- a/src/d/d_msg_scrn_item.cpp +++ b/src/d/d_msg_scrn_item.cpp @@ -557,22 +557,11 @@ void dMsgScrnItem_c::fukiPosCalc(u8 param_1) { cXyz local_70; cXyz cStack_7c; f32 f3; - - #if TARGET_PC - mDoLib_project(&player->eyePos, &cStack_7c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&player->eyePos, &cStack_7c); - #endif - if (iVar6->pos == cXyz(0.0f, 0.0f, 0.0f)) { f3 = cStack_7c.y; } else { - #if TARGET_PC - mDoLib_project(&iVar6->pos, &local_70, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&iVar6->pos, &local_70); - #endif - if (local_70.x >= 0.0f && local_70.x <= FB_WIDTH && local_70.y >= 0.0f && local_70.y <= FB_HEIGHT) { diff --git a/src/d/d_msg_scrn_light.cpp b/src/d/d_msg_scrn_light.cpp index c34397aad2..19671b5d57 100644 --- a/src/d/d_msg_scrn_light.cpp +++ b/src/d/d_msg_scrn_light.cpp @@ -204,16 +204,14 @@ void dMsgScrnLight_c::draw(f32* i_anmFrame, f32 i_posX, f32 i_posY, f32 i_scaleX if (mPlayAnim) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 i = 0; i < ui_advance_ticks; ++i) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { *i_anmFrame += 1.0f; if (*i_anmFrame >= mpBck->getFrameMax()) { *i_anmFrame = 0.0f; } -#ifdef TARGET_PC } -#endif mBckFrame = *i_anmFrame; mBpkFrame = *i_anmFrame; @@ -229,17 +227,15 @@ void dMsgScrnLight_c::draw(f32* i_anmFrame, f32 i_posX, f32 i_posY, f32 i_scaleX if (mPlayAnim) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 i = 0; i < ui_advance_ticks; ++i) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { *i_anmFrame += i_anmRate; if (*i_anmFrame >= mpBck->getFrameMax()) { *i_anmFrame = 0.0f; } -#ifdef TARGET_PC } -#endif mBckFrame = *i_anmFrame; mBpkFrame = *i_anmFrame; diff --git a/src/d/d_msg_scrn_talk.cpp b/src/d/d_msg_scrn_talk.cpp index 68b471a14d..c9f925e784 100644 --- a/src/d/d_msg_scrn_talk.cpp +++ b/src/d/d_msg_scrn_talk.cpp @@ -441,22 +441,11 @@ void dMsgScrnTalk_c::fukiPosCalc(u8 param_1) { cXyz local_70; cXyz cStack_7c; f32 f3y; - - #if TARGET_PC - mDoLib_project(&player->eyePos, &cStack_7c, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&player->eyePos, &cStack_7c); - #endif - if (msgActor->pos == cXyz(0.0f, 0.0f, 0.0f)) { f3y = cStack_7c.y; } else { - #if TARGET_PC - mDoLib_project(&msgActor->pos, &local_70, {0, 0, FB_WIDTH, FB_HEIGHT}); - #else mDoLib_project(&msgActor->pos, &local_70); - #endif - if (local_70.x >= 0.0f && local_70.x <= FB_WIDTH_BASE && local_70.y >= 0.0f && local_70.y <= FB_HEIGHT_BASE) { diff --git a/src/d/d_msg_unit.cpp b/src/d/d_msg_unit.cpp index 98dd33b4a8..f773abd373 100644 --- a/src/d/d_msg_unit.cpp +++ b/src/d/d_msg_unit.cpp @@ -271,6 +271,30 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) { u32 filesize = pHeader->size; u8* pSection = ((u8*)pHeader) + filepos; + #if TARGET_PC + // patch bug in the original game where filepos would be incremented by the next section's size rather than the current section size. + // in certain scenarios this would read past the end of the file, incrementing filepos by 0 in an infinite loop + while (filepos < filesize) { + switch (((bmg_section_t*)pSection)->magic) { + case 'FLW1': + break; + case 'FLI1': + break; + case 'INF1': + pInfoBlock = (bmg_section_t*)pSection; + break; + case 'DAT1': + pMsgDataBlock = pSection; + break; + case 'STR1': + pStrAttributeBlock = (str1_section_t*)pSection; + break; + } + + filepos += ((bmg_section_t*)pSection)->size; + pSection += ((bmg_section_t*)pSection)->size; + } + #else for (; filepos < filesize; filepos += ((bmg_section_t*)pSection)->size) { switch (((bmg_section_t*)pSection)->magic) { case 'FLW1': @@ -289,6 +313,7 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) { } pSection += ((bmg_section_t*)pSection)->size; } + #endif // This section is weird. The debug seems like entriesStr is outside the condition // but the normal build doesn't really work with that. Same for pInfoBlock->entries. diff --git a/src/d/d_name.cpp b/src/d/d_name.cpp index 120bcff752..e4232eff34 100644 --- a/src/d/d_name.cpp +++ b/src/d/d_name.cpp @@ -1288,7 +1288,11 @@ void dName_c::selectCursorPosSet(int row) { #if TARGET_PC void dName_c::nameWide() { //Resize Select Icon - mSelIcon->setParam(0.82f * mDoGph_gInf_c::hudAspectScaleUp, 0.77f, 0.05f, 0.4f, 0.4f); + #if TARGET_PC + if (mSelIcon) { + mSelIcon->refreshAspectScale(); + } + #endif // List of Characters Box static u64 l_tagName[65] = { @@ -1540,11 +1544,7 @@ void dName_c::screenSet() { mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(0, mSelIcon != NULL); - #if TARGET_PC - mSelIcon->setParam(0.82f * mDoGph_gInf_c::hudAspectScaleUp, 0.77f, 0.05f, 0.4f, 0.4f); - #else mSelIcon->setParam(0.82f, 0.77f, 0.05f, 0.4f, 0.4f); - #endif Vec pos = mMojiIcon[mCharRow + mCharColumn * 5]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(pos.x, pos.y, mMojiIcon[mCharRow + mCharColumn * 5]->getPanePtr(), true); diff --git a/src/d/d_ovlp_fade.cpp b/src/d/d_ovlp_fade.cpp index 1ae49ab74a..43732cf4be 100644 --- a/src/d/d_ovlp_fade.cpp +++ b/src/d/d_ovlp_fade.cpp @@ -26,8 +26,8 @@ static void dOvlpFd_startFadeIn(int param_0) { JUTFader* fader = JFWDisplay::getManager()->getFader(); JUT_ASSERT(0, fader != NULL); - fader->setStatus(JUTFader::UNKSTATUS_0, 0); - fader->setStatus(JUTFader::UNKSTATUS_0, -1); + fader->setStatus(JUTFader::None, 0); + fader->setStatus(JUTFader::None, -1); fader->startFadeIn(param_0); } diff --git a/src/d/d_ovlp_fade2.cpp b/src/d/d_ovlp_fade2.cpp index 37dbeedba2..c6c6cc735e 100644 --- a/src/d/d_ovlp_fade2.cpp +++ b/src/d/d_ovlp_fade2.cpp @@ -12,13 +12,8 @@ #include "m_Do/m_Do_graphic.h" void dOvlpFd2_dlst_c::draw() { -#if TARGET_PC - GXSetViewport(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, 1.0f); - GXSetScissor(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else GXSetViewport(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f); GXSetScissor(0, 0, FB_WIDTH, FB_HEIGHT); -#endif GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); diff --git a/src/d/d_ovlp_fade3.cpp b/src/d/d_ovlp_fade3.cpp index d6f432f3ee..0b3c03db2b 100644 --- a/src/d/d_ovlp_fade3.cpp +++ b/src/d/d_ovlp_fade3.cpp @@ -13,11 +13,10 @@ #include "m_Do/m_Do_graphic.h" void dDlst_snapShot_c::draw() { -#if TARGET_PC - GXSetTexCopySrc(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); - GXSetTexCopyDst(mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), GX_TF_RGBA8, GX_TRUE); -#else GXSetTexCopySrc(0, 0, FB_WIDTH, FB_HEIGHT); +#if TARGET_PC + GXSetTexCopyDst(FB_WIDTH, FB_HEIGHT, GX_TF_RGBA8, GX_FALSE); +#else GXSetTexCopyDst(FB_WIDTH / 2, FB_HEIGHT / 2, GX_TF_RGBA8, GX_TRUE); #endif GXCopyTex(mDoGph_gInf_c::getFrameBufferTex(), GX_FALSE); @@ -25,13 +24,8 @@ void dDlst_snapShot_c::draw() { } void dOvlpFd3_dlst_c::draw() { -#if TARGET_PC - GXSetViewport(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, 1.0f); - GXSetScissor(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); -#else GXSetViewport(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f); GXSetScissor(0, 0, FB_WIDTH, FB_HEIGHT); -#endif GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); @@ -112,19 +106,6 @@ void dOvlpFd3_dlst_c::draw() { GXBegin(GX_QUADS, GX_VTXFMT0, 4); - #if TARGET_PC - GXPosition2s16(-FB_WIDTH / 2, FB_HEIGHT / 2); - GXTexCoord2s8(0, 0); - - GXPosition2s16(FB_WIDTH / 2, FB_HEIGHT / 2); - GXTexCoord2s8(1, 0); - - GXPosition2s16(FB_WIDTH / 2, -FB_HEIGHT / 2); - GXTexCoord2s8(1, 1); - - GXPosition2s16(-FB_WIDTH / 2, -FB_HEIGHT / 2); - GXTexCoord2s8(0, 1); - #else GXPosition2s16(-mDoGph_gInf_c::getWidth() / 2, mDoGph_gInf_c::getHeight() / 2); GXTexCoord2s8(0, 0); @@ -136,7 +117,6 @@ void dOvlpFd3_dlst_c::draw() { GXPosition2s16(-mDoGph_gInf_c::getWidth() / 2, -mDoGph_gInf_c::getHeight() / 2); GXTexCoord2s8(0, 1); - #endif GXEnd(); diff --git a/src/d/d_pane_class.cpp b/src/d/d_pane_class.cpp index 78855b2d1c..4d5104ffcf 100644 --- a/src/d/d_pane_class.cpp +++ b/src/d/d_pane_class.cpp @@ -356,12 +356,8 @@ Vec CPaneMgr::getGlobalVtx(J2DPane* p_pane, Mtx* param_1, u8 param_2, bool param Mtx m; MtxP mp = (MtxP)param_1; J2DPane* parent = p_pane->getParentPane(); - -#if TARGET_PC - J2DOrthoGraph ortho(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), -1.0f, 1.0f); -#else + J2DOrthoGraph ortho(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, -1.0f, 1.0f); -#endif ortho.setOrtho(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), -1.0f, 1.0f); if (parent != NULL) { diff --git a/src/d/d_resorce.cpp b/src/d/d_resorce.cpp index 0bf537bfd7..73f031beae 100644 --- a/src/d/d_resorce.cpp +++ b/src/d/d_resorce.cpp @@ -296,7 +296,11 @@ J3DModelData* dRes_info_c::loaderBasicBmd(u32 i_tag, void* i_data) { addWarpMaterial(modelData); } - if (i_tag == 'BMDR' || i_tag == 'BMWR') { + // FRAME INTERP NOTE: Always create shared DL buffers so we can use J3DMaterial::diff() +#ifndef TARGET_PC + if (i_tag == 'BMDR' || i_tag == 'BMWR') +#endif + { s32 result = modelData->newSharedDisplayList(J3DMdlFlag_UseSingleDL); if (result != kJ3DError_Success) { return NULL; diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index 8516601e9b..c162d5c9f0 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -1419,12 +1419,7 @@ static int phase_4(dScnPly_c* i_this) { dComIfGp_setPlayerPtr(i, NULL); } -#if TARGET_PC - dComIfGp_setWindow(0, 0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, - 1.0f, 0, 2); -#else dComIfGp_setWindow(0, 0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f, 0, 2); -#endif dComIfGp_setCameraInfo(0, NULL, 0, 0, -1); dComIfGd_setWindow(NULL); dComIfGd_setViewport(NULL); diff --git a/src/d/d_select_cursor.cpp b/src/d/d_select_cursor.cpp index 2cdd454737..0773433b4d 100644 --- a/src/d/d_select_cursor.cpp +++ b/src/d/d_select_cursor.cpp @@ -69,6 +69,9 @@ dSelect_cursor_c::dSelect_cursor_c(u8 param_0, f32 param_1, JKRArchive* param_2) field_0x84[i] = 0.0f; } mParam1 = mpCursorHIO->mXAxisExpansion; +#ifdef TARGET_PC + mBaseParam1 = mParam1; +#endif mParam2 = mpCursorHIO->mYAxisExpansion; mParam3 = mpCursorHIO->mOscillation; mParam4 = mpCursorHIO->mRatioX; @@ -259,6 +262,13 @@ void dSelect_cursor_c::update() { if (field_0xb6 == 3) { fVar1 = 0.5f; } +#ifdef TARGET_PC + if (mpPane) { + Vec pos = mpPaneMgr->getGlobalVtxCenter(mpPane, false, 0); + mPositionX = pos.x; + mPositionY = pos.y; + } +#endif mpPaneMgr->translate(mPositionX, mPositionY); if (mpCursorHIO->mDebugON) { mParam1 = mpCursorHIO->mXAxisExpansion; @@ -272,9 +282,9 @@ void dSelect_cursor_c::update() { if (field_0x30) { if (chkPlayAnime(0)) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 tick = 0; tick < ui_advance_ticks; ++tick) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { if (mNameIdx == 1) { field_0x44 += mpCursorHIO->field_0x8 * fVar1; } else { @@ -284,9 +294,7 @@ void dSelect_cursor_c::update() { if (field_0x44 >= field_0x30->getFrameMax()) { field_0x44 -= field_0x30->getFrameMax(); } -#ifdef TARGET_PC } -#endif field_0x30->setFrame(field_0x44); setBpkAnimation(field_0x30); @@ -303,9 +311,9 @@ void dSelect_cursor_c::update() { if (field_0x34[i]) { if ((i == 0 && chkPlayAnime(2)) || (i == 1 && chkPlayAnime(3))) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 tick = 0; tick < ui_advance_ticks; ++tick) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { if (mNameIdx == 1) { field_0x48[i] += mpCursorHIO->field_0x8 * fVar1; } else { @@ -314,9 +322,7 @@ void dSelect_cursor_c::update() { if (field_0x48[i] >= field_0x34[i]->getFrameMax()) { field_0x48[i] -= field_0x34[i]->getFrameMax(); } -#ifdef TARGET_PC } -#endif field_0x34[i]->setFrame(field_0x48[i]); } @@ -326,9 +332,9 @@ void dSelect_cursor_c::update() { if (field_0x2C && chkPlayAnime(1)) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 tick = 0; tick < ui_advance_ticks; ++tick) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { if (mNameIdx == 1) { field_0x40 += mpCursorHIO->field_0x8 * fVar1; } else { @@ -337,9 +343,7 @@ void dSelect_cursor_c::update() { if (field_0x40 >= field_0x2C->getFrameMax()) { field_0x40 -= field_0x2C->getFrameMax(); } -#ifdef TARGET_PC } -#endif field_0x2C->setFrame(field_0x40); setBckAnimation(field_0x2C); @@ -348,13 +352,11 @@ void dSelect_cursor_c::update() { if (chkPlayAnime(1) && mNameIdx == 0) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 tick = 0; tick < ui_advance_ticks; ++tick) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { setCursorAnimation(); -#ifdef TARGET_PC } -#endif } mpScreen->animation(); @@ -412,6 +414,9 @@ void dSelect_cursor_c::setPos(f32 i_posX, f32 i_posY, J2DPane* i_pane, bool i_sc void dSelect_cursor_c::setParam(f32 i_param1, f32 i_param2, f32 i_param3, f32 i_param4, f32 i_param5) { mParam1 = i_param1; +#ifdef TARGET_PC + mBaseParam1 = i_param1; +#endif mParam2 = i_param2; mParam3 = i_param3; mParam4 = i_param4; @@ -570,3 +575,9 @@ void dSelect_cursor_c::setBckAnimation(J2DAnmTransformKey* param_0) { void dSelect_cursor_c::moveCenter(J2DPane* i_pane, f32 i_x, f32 i_y) { i_pane->translate(i_x,i_y); } + +#ifdef TARGET_PC +void dSelect_cursor_c::refreshAspectScale() { + mParam1 = mBaseParam1 * mDoGph_gInf_c::hudAspectScaleUp; +} +#endif diff --git a/src/d/d_select_icon.cpp b/src/d/d_select_icon.cpp index 3a4671fefa..32be9c15e2 100644 --- a/src/d/d_select_icon.cpp +++ b/src/d/d_select_icon.cpp @@ -9,9 +9,9 @@ dSi_HIO_c::dSi_HIO_c() {} void dSelect_icon_c::animation() { if (field_0x10->getAlpha() != 0) { #ifdef TARGET_PC - const u32 ui_advance_ticks = dusk::frame_interp::get_presentation_ui_advance_ticks(); - for (u32 i = 0; i < ui_advance_ticks; ++i) { + if (dusk::frame_interp::get_ui_tick_pending()) #endif + { field_0x20 += field_0x2c; if (field_0x20 >= field_0x1c->getFrameMax()) { field_0x20 = 0.0f; @@ -22,9 +22,9 @@ void dSelect_icon_c::animation() { if (field_0x28 >= field_0x24->getFrameMax()) { field_0x28 = 0.0f; } -#ifdef TARGET_PC } - // Set even if not advancing +#ifdef TARGET_PC + // FRAME INTERP NOTE: Set even if not advancing field_0x1c->setFrame(field_0x20); #endif diff --git a/src/d/d_shop_system.cpp b/src/d/d_shop_system.cpp index f1636bb093..5871d65d2a 100644 --- a/src/d/d_shop_system.cpp +++ b/src/d/d_shop_system.cpp @@ -855,11 +855,7 @@ int dShopSystem_c::seq_wait(fopAc_ac_c* param_0, dMsgFlow_c* param_1) { } inline void pos3Dto2D(Vec* a, Vec* b) { -#if TARGET_PC - mDoLib_project(a, b, {0, 0, FB_WIDTH, FB_HEIGHT}); -#else mDoLib_project(a, b); -#endif } int dShopSystem_c::seq_start(fopAc_ac_c* actor, dMsgFlow_c* i_flow) { @@ -1572,10 +1568,22 @@ BOOL dShopSystem_c::checkShopOpen() { } bool dShopSystem_c::checkLeftTrigger(STControl* i_stick) { +#if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + return i_stick->checkRightTrigger(); + } +#endif + return i_stick->checkLeftTrigger(); } bool dShopSystem_c::checkRightTrigger(STControl* i_stick) { +#if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + return i_stick->checkLeftTrigger(); + } +#endif + return i_stick->checkRightTrigger(); } diff --git a/src/d/d_timer.cpp b/src/d/d_timer.cpp index 552874b552..cb40e3444a 100644 --- a/src/d/d_timer.cpp +++ b/src/d/d_timer.cpp @@ -23,9 +23,7 @@ #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); @@ -1340,27 +1338,22 @@ 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++) { - 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; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (m_getin_info[i].bck_frame > 0.0f && m_getin_info[i].bck_frame < temp) { + 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; + } + } else if (m_getin_info[i].bck_frame < g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f) { + m_getin_info[i].bck_frame++; + } else if (m_getin_info[i].bck_frame < temp) { + m_getin_info[i].bck_frame++; } - } else if (m_getin_info[i].bck_frame < g_drawHIO.mMiniGame.mGetInTextWaitFrames + 60.0f) { - m_getin_info[i].bck_frame++; - } else if (m_getin_info[i].bck_frame < temp) { - m_getin_info[i].bck_frame++; } } @@ -1369,7 +1362,7 @@ void dDlst_TimerScrnDraw_c::draw() { 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); + temp - m_getin_info[i].bck_frame, 0); } if (m_getin_info[i].bck_frame < 60.0f) { @@ -1382,7 +1375,7 @@ void dDlst_TimerScrnDraw_c::draw() { if (g_drawHIO.mMiniGame.mGetInTextLocation == 1) { mpGetInRoot->translate(m_getin_info[i].pos_x + g_drawHIO.mMiniGame.mGetInTextPosX, - m_getin_info[i].pos_y + g_drawHIO.mMiniGame.mGetInTextPosY); + m_getin_info[i].pos_y + g_drawHIO.mMiniGame.mGetInTextPosY); } else { f32 temp_f2 = m_getin_info[i].bck_frame - 40.0f; f32 var_f3 = ((temp_f2 * 0.5f) * temp_f2) * 0.15f; @@ -1396,20 +1389,25 @@ void dDlst_TimerScrnDraw_c::draw() { } mpGetInRoot->scale(g_drawHIO.mMiniGame.mGetInTextSizeX, - g_drawHIO.mMiniGame.mGetInTextSizeY); + g_drawHIO.mMiniGame.mGetInTextSizeY); mpGetInScreen->draw(0.0f, 0.0f, graf_ctx); if (m_getin_info[i].pikari_frame > 0.0f) { drawPikari(i); } else if (m_getin_info[i].pikari_frame == -1.0f) { - if (m_getin_info[i].field_0xc == 0) { - if (m_getin_info[i].bck_frame > g_drawHIO.mMiniGame.mGetInPikariAppearFrames) { +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (m_getin_info[i].field_0xc == 0) { + if (m_getin_info[i].bck_frame > g_drawHIO.mMiniGame.mGetInPikariAppearFrames) { + m_getin_info[i].pikari_frame = + 18.0f - g_drawHIO.mMiniGame.mGetInPikariAnimSpeed; + } + } else if (m_getin_info[i].bck_frame > g_drawHIO.mMiniGame.mStartPikariAppearFrames) { m_getin_info[i].pikari_frame = - 18.0f - g_drawHIO.mMiniGame.mGetInPikariAnimSpeed; + 18.0f - g_drawHIO.mMiniGame.mStartPikariAnimSpeed; } - } 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/audio/DuskAudioSystem.cpp b/src/dusk/audio/DuskAudioSystem.cpp index c818e46738..3577d3c9c7 100644 --- a/src/dusk/audio/DuskAudioSystem.cpp +++ b/src/dusk/audio/DuskAudioSystem.cpp @@ -77,6 +77,14 @@ void dusk::audio::SetMasterVolume(const f32 value) { MasterVolume = value; } +void dusk::audio::SetPaused(const bool paused) { + if (paused) { + SDL_PauseAudioStreamDevice(PlaybackStream); + } else { + SDL_ResumeAudioStreamDevice(PlaybackStream); + } +} + void dusk::audio::SetEnableReverb(const bool value) { JASCriticalSection section; diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index c377d1ba54..176967359d 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -10,7 +10,7 @@ #include #include -#include "dusk/dusk.h" +#include "dusk/main.h" using namespace dusk::config; @@ -24,7 +24,7 @@ static absl::flat_hash_map RegisteredConfigVar static bool RegistrationDone = false; static std::string GetConfigJsonPath() { - return fmt::format("{}{}", configPath, ConfigFileName); + return (dusk::ConfigPath / ConfigFileName).string(); } ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl) : name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) { diff --git a/src/dusk/crash_reporting.cpp b/src/dusk/crash_reporting.cpp index 73f432e418..0499f0d6a1 100644 --- a/src/dusk/crash_reporting.cpp +++ b/src/dusk/crash_reporting.cpp @@ -3,6 +3,7 @@ #include "dusk/app_info.hpp" #include "dusk/dusk.h" #include "dusk/logging.h" +#include "dusk/main.h" #include "dusk/settings.h" #include "version.h" @@ -66,7 +67,7 @@ std::string GetReleaseName() { } std::filesystem::path GetSentryDatabasePath() { - return std::filesystem::path(configPath) / "sentry"; + return dusk::ConfigPath / "sentry"; } std::filesystem::path GetLogAttachmentPath() { diff --git a/src/dusk/discord_presence.cpp b/src/dusk/discord_presence.cpp new file mode 100644 index 0000000000..3b12075c8b --- /dev/null +++ b/src/dusk/discord_presence.cpp @@ -0,0 +1,122 @@ +#ifdef DUSK_DISCORD_RPC + +#include "dusk/discord_presence.hpp" +#include "dusk/logging.h" +#include "dusk/main.h" +#include "dusk/map_loader_definitions.h" +#include "d/d_com_inf_game.h" +#include "discord_rpc.h" +#include "fmt/format.h" + +#include +#include +#include + +namespace dusk { +namespace discord { + +static int64_t g_startTime = 0; +static bool g_initialized = false; +static const char* APPLICATION_ID = "1495632471994405035"; + +static void OnReady(const DiscordUser* user) { + DuskLog.info("Discord: Connected as {}", user->username); +} + +static void OnDisconnected(int errorCode, const char* message) { + DuskLog.warn("Discord: Disconnected ({}: {})", errorCode, message); +} + +static void OnError(int errorCode, const char* message) { + DuskLog.warn("Discord: Error ({}: {})", errorCode, message); +} + +static const char* LookupMapName(const char* mapFile) { + if (!mapFile || mapFile[0] == '\0') return nullptr; + for (const auto& region : gameRegions) { + for (const auto& map : region.maps) { + if (map.mapFile && strcmp(mapFile, map.mapFile) == 0) { + return map.mapName; + } + } + } + return nullptr; +} + +void Initialize() { + g_startTime = static_cast( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count() + ); + + DiscordEventHandlers handlers{}; + handlers.ready = OnReady; + handlers.disconnected = OnDisconnected; + handlers.errored = OnError; + Discord_Initialize(APPLICATION_ID, &handlers, 0, nullptr); + g_initialized = true; + + DuskLog.info("Discord Rich Presence initialized"); +} + +void RunCallbacks() { + if (!g_initialized) return; + Discord_RunCallbacks(); +} + +void UpdatePresence() { + if (!g_initialized) return; + + static auto lastUpdate = std::chrono::steady_clock::time_point{}; + const auto now = std::chrono::steady_clock::now(); + if (now - lastUpdate < std::chrono::seconds(15)) return; + lastUpdate = now; + + static std::string detailsBuf; + static std::string stateBuf; + + DiscordRichPresence presence{}; + presence.startTimestamp = g_startTime; + presence.largeImageKey = "icon"; + presence.largeImageText = "Dusk"; + + if (dusk::IsGameLaunched) { + const char* stageName = dComIfGp_getLastPlayStageName(); + + // stageName is empty until a room is actually entered + if (stageName[0] != '\0') { + const char* locationName = LookupMapName(stageName); + + if (locationName) { + detailsBuf = locationName; + } + else { + detailsBuf = "Twilight Princess"; + } + + presence.details = detailsBuf.c_str(); + + stateBuf = fmt::format(FMT_STRING("{}/{} \u2665 | {} Rupees"), + dComIfGs_getLife() / 4, dComIfGs_getMaxLife() / 5, dComIfGs_getRupee()); + + presence.state = stateBuf.c_str(); + } + } + + Discord_UpdatePresence(&presence); + DuskLog.debug("Discord Rich Presence sent"); +} + +void Shutdown() { + if (!g_initialized) return; + Discord_ClearPresence(); + Discord_Shutdown(); + g_initialized = false; + DuskLog.info("Discord Rich Presence shut down"); +} + +} // namespace discord +} // namespace dusk + +#endif // DUSK_DISCORD_RPC diff --git a/src/dusk/frame_interpolation.cpp b/src/dusk/frame_interpolation.cpp index aa62d6a98a..e0057790df 100644 --- a/src/dusk/frame_interpolation.cpp +++ b/src/dusk/frame_interpolation.cpp @@ -1,80 +1,31 @@ #include "dusk/frame_interpolation.h" #include +#include "mtx.h" #include "f_op/f_op_camera_mng.h" #include "m_Do/m_Do_graphic.h" namespace { -enum class Op : uint8_t { - OpenChild, - FinalMtx, -}; - -struct Label { - const void* key = nullptr; - int32_t id = 0; - - bool operator==(const Label& other) const { - return key == other.key && id == other.id; - } -}; - -struct Data { - Label child_label{}; - size_t child_index = 0; - Mtx matrix{}; - const Mtx* dest = nullptr; - uint64_t stable_tag = 0; -}; - -struct Path; - -struct ChildBucket { - Label label{}; - std::vector> nodes; -}; - -struct OpBucket { - Op op = Op::OpenChild; - std::vector values; -}; - -struct Path { - std::vector children; - std::vector ops; - std::vector> items; - Label draw_scope{}; - uint32_t simple_shadow_pair_seq = 0; -}; struct Recording { - Path root; + std::unordered_map matrix_values; }; -struct MatrixValue { - Mtx value; -}; - -using FinalMtxLookup = std::unordered_map; -using FinalMtxLookupTagged = std::unordered_map; - bool s_initialized = false; bool g_enabled = false; bool g_recording = false; bool g_interpolating = false; bool g_sync_presentation = false; -uint32_t g_presentation_counter = 0; float g_step = 0.0f; -uint32_t g_pending_presentation_ui_ticks = 0; -uint32_t g_current_presentation_ui_ticks = 0; +bool g_is_sim_frame = false; +bool g_ui_tick_pending = false; Recording g_current_recording; Recording g_previous_recording; -std::vector g_current_path; -std::unordered_map g_replacements; +std::unordered_map g_replacements; struct CameraSnapshot { cXyz eye{}; @@ -95,6 +46,13 @@ CameraSnapshot s_cam_curr{}; view_class s_presentation_view_backup{}; int s_presentation_depth = 0; +struct InterpolationCallBackWork { + dusk::frame_interp::InterpolationCallBack pCallBack; + void* pUserWork; +}; + +std::vector s_interpolationCallBackWork; + void copy_view_to_snap(CameraSnapshot* dst, const view_class& v) { dst->eye = v.lookat.eye; dst->center = v.lookat.center; @@ -107,14 +65,6 @@ void copy_view_to_snap(CameraSnapshot* dst, const view_class& v) { dst->valid = true; } -inline void copy_matrix(const Mtx src, Mtx dst) { - MTXCopy(src, dst); -} - -inline void concat_matrix(const Mtx lhs, const Mtx rhs, Mtx out) { - MTXConcat(lhs, rhs, out); -} - inline void lerp_matrix(Mtx out, const Mtx lhs, const Mtx rhs, float step) { const float old_weight = 1.0f - step; for (size_t row = 0; row < 3; ++row) { @@ -148,162 +98,22 @@ inline bool matrix_differs(const Mtx lhs, const Mtx rhs, float epsilon = 0.0001f return false; } -Data& append_op(Op op) { - auto& items = g_current_path.back()->items; - auto& buckets = g_current_path.back()->ops; - auto it = std::find_if(buckets.begin(), buckets.end(), - [op](const OpBucket& bucket) { return bucket.op == op; }); - if (it == buckets.end()) { - buckets.push_back({op, {}}); - it = buckets.end() - 1; - } - items.emplace_back(op, it->values.size()); - return it->values.emplace_back(); -} - -const Data* find_matching_data(const Path& path, Op op, size_t index) { - auto it = std::find_if(path.ops.begin(), path.ops.end(), - [op](const OpBucket& bucket) { return bucket.op == op; }); - if (it == path.ops.end() || index >= it->values.size()) { - return nullptr; - } - return &it->values[index]; -} - -const OpBucket* find_op_bucket(const Path& path, Op op) { - auto it = std::find_if(path.ops.begin(), path.ops.end(), - [op](const OpBucket& bucket) { return bucket.op == op; }); - if (it == path.ops.end()) { - return nullptr; - } - return &*it; -} - -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) { - return; - } - - for (const Data& data : bucket->values) { - if (data.dest != nullptr) { - dest_lookup[data.dest] = &data; - } - if (data.stable_tag != 0) { - tag_lookup[data.stable_tag] = &data; - } - } -} - -const Data* find_matching_final_mtx(const FinalMtxLookup& lookup, const Data& new_data) { - if (new_data.dest == nullptr) { - return nullptr; - } - - auto it = lookup.find(new_data.dest); - if (it == lookup.end()) { - return nullptr; - } - return it->second; -} - -ChildBucket& get_child_bucket(Path& path, const Label& label) { - auto it = std::find_if(path.children.begin(), path.children.end(), - [&label](const ChildBucket& bucket) { return bucket.label == label; }); - if (it == path.children.end()) { - path.children.push_back({}); - it = path.children.end() - 1; - it->label = label; - } - return *it; -} - -const ChildBucket* find_child_bucket(const Path& path, const Label& label) { - auto it = std::find_if(path.children.begin(), path.children.end(), - [&label](const ChildBucket& bucket) { return bucket.label == label; }); - if (it == path.children.end()) { - return nullptr; - } - return &*it; -} - -void store_replacement(const Data& old_data, const Data& new_data, float step) { - if (new_data.dest == nullptr) { - return; - } - - auto& replacement = g_replacements[new_data.dest]; - lerp_matrix(replacement.value, old_data.matrix, new_data.matrix, step); -} - -void interpolate_branch(const Path& old_path, const Path& new_path, float step) { - FinalMtxLookup 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; - const size_t index = item.second; - const Data* new_data = find_matching_data(new_path, op, index); - if (new_data == nullptr) { - continue; - } - - if (op == Op::OpenChild) { - const ChildBucket* new_children = find_child_bucket(new_path, new_data->child_label); - if (new_children == nullptr || new_data->child_index >= new_children->nodes.size()) - { - continue; - } - - const Path& new_child = *new_children->nodes[new_data->child_index]; - const ChildBucket* old_children = find_child_bucket(old_path, new_data->child_label); - if (old_children != nullptr && new_data->child_index < old_children->nodes.size()) - { - interpolate_branch(*old_children->nodes[new_data->child_index], new_child, step); - } else { - interpolate_branch(new_child, new_child, step); - } - continue; - } - - const Data* indexed_old_data = find_matching_data(old_path, op, index); - 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); - } - } -} - const Mtx* resolve_replacement(const Mtx* source, Mtx* scratch) { if (!g_interpolating || source == nullptr || dusk::frame_interp::presentation_sync_active()) { return source; } - auto it = g_replacements.find(source); + auto it = g_replacements.find(reinterpret_cast(source)); if (it == g_replacements.end()) { return source; } - copy_matrix(it->second.value, *scratch); + MTXCopy(it->second, *scratch); return scratch; } bool has_recording_data(const Recording& recording) { - return !recording.root.items.empty() || !recording.root.children.empty(); + return !recording.matrix_values.empty(); } void clear_replacements() { @@ -314,10 +124,27 @@ void clear_replacements() { namespace dusk::frame_interp { void ensure_initialized() { - g_enabled = getSettings().game.enableFrameInterpolation; s_initialized = true; } +void begin_frame(bool enabled, bool is_sim_frame, float step) { + g_enabled = enabled; + g_is_sim_frame = is_sim_frame; + g_step = std::clamp(step, 0.0f, 1.0f); + if (is_sim_frame) { + s_interpolationCallBackWork.clear(); + s_cam_prev = std::move(s_cam_curr); + } +} + +bool is_enabled() { + return g_enabled; +} + +bool is_sim_frame() { + return g_is_sim_frame; +} + void begin_record() { ensure_initialized(); @@ -326,7 +153,6 @@ void begin_record() { g_sync_presentation = false; g_previous_recording = {}; g_current_recording = {}; - g_current_path.clear(); clear_replacements(); s_cam_prev.valid = false; s_cam_curr.valid = false; @@ -336,8 +162,6 @@ void begin_record() { g_sync_presentation = false; g_previous_recording = std::move(g_current_recording); g_current_recording = {}; - g_current_path.clear(); - g_current_path.push_back(&g_current_recording.root); g_recording = true; g_interpolating = false; clear_replacements(); @@ -347,11 +171,6 @@ void begin_record() { s_cam_prev.valid = false; s_cam_curr.valid = false; return; - } else { - copy_view_to_snap(&s_cam_prev, cam->view); -#if WIDESCREEN_SUPPORT - s_cam_prev.wideZoom = s_cam_curr.valid ? s_cam_curr.wideZoom : false; -#endif } } @@ -359,21 +178,20 @@ void end_record() { g_recording = false; } -void interpolate(float step) { +void interpolate() { ensure_initialized(); clear_replacements(); - g_step = std::clamp(step, 0.0f, 1.0f); g_interpolating = g_enabled && !g_recording && !g_sync_presentation && has_recording_data(g_current_recording); if (!g_interpolating) { return; } - const Path& old_root = has_recording_data(g_previous_recording) ? g_previous_recording.root : g_current_recording.root; - interpolate_branch(old_root, g_current_recording.root, g_step); -} - -void notify_presentation_frame() { - ensure_initialized(); - ++g_presentation_counter; + for (auto const& old : g_previous_recording.matrix_values) { + if (auto it = g_current_recording.matrix_values.find(old.first); + it != g_current_recording.matrix_values.end()) + { + lerp_matrix(g_replacements[old.first], old.second, it->second, g_step); + } + } } void request_presentation_sync() { @@ -396,92 +214,40 @@ float get_interpolation_step() { return presentation_sync_active() ? 1.0f : g_step; } -void notify_sim_tick_complete() { +void set_ui_tick_pending(bool value) { + if (g_ui_tick_pending == value) { return; } + g_ui_tick_pending = value; +} + +bool get_ui_tick_pending() { ensure_initialized(); - g_pending_presentation_ui_ticks++; + return g_enabled ? g_ui_tick_pending : true; } -uint32_t begin_presentation_ui_pass() { - ensure_initialized(); - g_current_presentation_ui_ticks = g_pending_presentation_ui_ticks; - g_pending_presentation_ui_ticks = 0; - return g_current_presentation_ui_ticks; -} - -uint32_t get_presentation_ui_advance_ticks() { - if (!s_initialized) { - return 0; - } - if (!g_enabled) { - return 1; - } - return g_current_presentation_ui_ticks; -} - -void end_presentation_ui_pass() { - if (!s_initialized) { - return; - } - g_current_presentation_ui_ticks = 0; -} - -void open_child(const void* key, int32_t id) { - if (!s_initialized || !g_recording) { +void record_final_mtx(Mtx m, const void* key) { + if (!s_initialized || !g_recording || m == nullptr) { return; } - Label label{key, id}; - auto& siblings = get_child_bucket(*g_current_path.back(), label).nodes; - Data& data = append_op(Op::OpenChild); - data.child_label = label; - data.child_index = siblings.size(); - siblings.emplace_back(std::make_unique()); - Path* const child = siblings.back().get(); - child->draw_scope = label; - g_current_path.push_back(child); + auto& it = g_current_recording.matrix_values[reinterpret_cast(key)]; + MTXCopy(m, it); } -void close_child() { - if (!s_initialized || !g_recording || g_current_path.size() <= 1) { - return; - } - - g_current_path.pop_back(); +void record_final_mtx(Mtx m) { + record_final_mtx(m, m); } -void record_final_mtx_raw(const Mtx* dest, const Mtx src) { - if (!s_initialized || !g_recording || dest == nullptr) { - return; - } - - 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); -} - -bool lookup_replacement(const void* source, Mtx out) { - if (presentation_sync_active() || !g_interpolating || source == nullptr) { +bool lookup_replacement(const void* key, Mtx out) { + if (presentation_sync_active() || !g_interpolating || key == nullptr) { return false; } - auto it = g_replacements.find(reinterpret_cast(source)); + auto it = g_replacements.find(reinterpret_cast(key)); if (it == g_replacements.end()) { return false; } - copy_matrix(it->second.value, out); + MTXCopy(it->second, out); return true; } @@ -498,7 +264,7 @@ bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out) { return false; } - concat_matrix(*resolved_lhs, *resolved_rhs, out); + MTXConcat(*resolved_lhs, *resolved_rhs, out); return true; } @@ -512,25 +278,12 @@ void record_camera(::camera_process_class* cam, int camera_id) { #endif } -void begin_presentation_camera() { - ensure_initialized(); - if (!g_enabled) { +void interp_view(::view_class* view) { + if (!g_enabled) return; - } - if (s_presentation_depth > 0) { - s_presentation_depth++; - return; - } - if (!s_cam_prev.valid || !s_cam_curr.valid) { - return; - } - view_class* const view = dComIfGd_getView(); - if (view == nullptr) { + if (!s_cam_prev.valid || !s_cam_curr.valid) return; - } - - std::memcpy(&s_presentation_view_backup, view, sizeof(view_class)); const f32 step = get_interpolation_step(); cXyz eye; @@ -553,12 +306,52 @@ void begin_presentation_camera() { view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step; view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step; - // FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the next sim frame, but I don't care enough to right now + // FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the + // next sim frame, but I don't care enough to right now #if WIDESCREEN_SUPPORT - if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ? s_cam_curr.wideZoom : s_cam_prev.wideZoom) { + if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ? + s_cam_curr.wideZoom : + s_cam_prev.wideZoom) + { mDoGph_gInf_c::onWideZoom(); } #endif +} + +static void run_interpolation_callbacks() { + for (size_t i = 0; i < s_interpolationCallBackWork.size(); i++) { + auto const& work = s_interpolationCallBackWork[i]; + work.pCallBack(g_is_sim_frame, work.pUserWork); + } +} + +void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork) { + if (!is_enabled() || s_presentation_depth > 0 || !g_is_sim_frame) + return; + + s_interpolationCallBackWork.emplace_back(pCallBack, pUserWork); +} + +void begin_presentation_camera() { + ensure_initialized(); + if (!g_enabled) { + return; + } + if (s_presentation_depth > 0) { + s_presentation_depth++; + return; + } + if (!s_cam_prev.valid || !s_cam_curr.valid) { + return; + } + + view_class* const view = dComIfGd_getView(); + if (view == nullptr) { + return; + } + + std::memcpy(&s_presentation_view_backup, view, sizeof(view_class)); + interp_view(view); // FRAME INTERP TODO: Largely copied from d_camera's camera_draw function from this point, got any better ideas? C_MTXPerspective(view->projMtx, view->fovy, view->aspect, view->near_, view->far_); @@ -616,11 +409,11 @@ void begin_presentation_camera() { mDoLib_clipper::setup(view->fovy, view->aspect, view->near_, far_); -#if WIDESCREEN_SUPPORT - mDoGph_gInf_c::offWideZoom(); -#endif + // FRAME INTERP NOTE: Removed the call to offWideZoom that was here, it causes problems with presentation during cutscenes. s_presentation_depth = 1; + + run_interpolation_callbacks(); } void end_presentation_camera() { @@ -637,20 +430,4 @@ void end_presentation_camera() { std::memcpy(view, &s_presentation_view_backup, sizeof(view_class)); } } - -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/game_clock.cpp b/src/dusk/game_clock.cpp new file mode 100644 index 0000000000..a262d0283c --- /dev/null +++ b/src/dusk/game_clock.cpp @@ -0,0 +1,82 @@ +#include "dusk/game_clock.h" + +#include +#include +#include +#include + +namespace dusk { +namespace game_clock { + +using clock = std::chrono::steady_clock; + +bool s_initialized = false; +clock::time_point s_previous_sample{}; +float s_sim_accumulator = 0.0f; + +std::unordered_map s_interval_last_sample; + +void ensure_initialized() { + if (s_initialized) { + return; + } + s_previous_sample = clock::now(); + s_sim_accumulator = sim_pace(); + s_initialized = true; +} + +void reset_accumulator() { + ensure_initialized(); + s_sim_accumulator = fmodf(s_sim_accumulator, sim_pace()); +} + +void reset_frame_timer() { + s_previous_sample = clock::now(); + s_sim_accumulator = 0.0f; +} + +MainLoopPacer advance_main_loop() { + ensure_initialized(); + + const clock::time_point now = clock::now(); + const float presentation_dt = std::chrono::duration(now - s_previous_sample).count(); + s_previous_sample = now; + + s_sim_accumulator += presentation_dt; + + MainLoopPacer out{}; + out.presentation_dt_seconds = presentation_dt; + + const bool should_interpolate = dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit; + out.is_interpolating = should_interpolate; + out.sim_pace = sim_pace(); + + if (!should_interpolate) { + s_sim_accumulator = 0.0f; + out.do_sim_tick = true; + out.interpolation_step = 0.0f; + return out; + } else { + out.do_sim_tick = s_sim_accumulator >= sim_pace(); + out.interpolation_step = out.do_sim_tick ? 0.0f : s_sim_accumulator / sim_pace(); + return out; + } +} + +float consume_interval(const void* consumer) { + ensure_initialized(); + const uintptr_t key = reinterpret_cast(consumer); + const clock::time_point now = clock::now(); + + float dt = ui_initial_dt(); + const auto it = s_interval_last_sample.find(key); + if (it != s_interval_last_sample.end()) { + dt = std::chrono::duration(now - it->second).count(); + dt = std::min(dt, ui_maximum_dt()); + } + s_interval_last_sample[key] = now; + return dt; +} + +} // namespace game_clock +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index daaa2d6180..aa3d1ac093 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -49,9 +49,10 @@ namespace dusk { ImGui::SeparatorText("Free-look Data"); static float eyeYawDeg = 0.0f; - static float moveSpeed = 10000.0f; + static float moveSpeed = 5000.0f; static float rotSpeed = 5.0f; static cXyz freeLookPos = cXyz::Zero; + static bool freeLookActive = false; bool changed = false; @@ -91,7 +92,17 @@ namespace dusk { changed = true; } - if (changed) { + if (!freeLookActive && changed) { + freeLookPos += dCam->Center(); + freeLookActive = true; + } + + if (ImGui::IsKeyDown(ImGuiKey_R)) { + freeLookPos = cXyz::Zero; + freeLookActive = false; + } + + if (freeLookActive) { dCam->Reset(freeLookPos, freeLookPos + (frontDir * 100.0f)); } diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 8b4881d797..f849f4cf71 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -17,6 +17,7 @@ #include "dusk/audio/DuskAudioSystem.h" #include "dusk/config.hpp" #include "dusk/dusk.h" +#include "dusk/frame_interpolation.h" #include "dusk/main.h" #include "dusk/settings.h" #include "m_Do/m_Do_controller_pad.h" @@ -281,7 +282,7 @@ namespace dusk { void ImGuiConsole::UpdateSettings() { getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); - if (mDoMain::developmentMode == 1 && mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigY(PAD_1)) { + if (dusk::frame_interp::get_ui_tick_pending() && mDoMain::developmentMode == 1 && (mDoCPd_c::getHold(PAD_1) & (PAD_TRIGGER_R | PAD_TRIGGER_L)) == (PAD_TRIGGER_R | PAD_TRIGGER_L) && mDoCPd_c::getTrigY(PAD_1)) { getTransientSettings().moveLinkActive = !getTransientSettings().moveLinkActive; } if (mDoMain::developmentMode != 1) { @@ -318,6 +319,9 @@ namespace dusk { } } + // The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg, + // so make the window bg fully transparent temporarily + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); if (showMenu && ImGui::BeginMainMenuBar()) { m_menuGame.draw(); m_menuEnhancements.draw(); @@ -336,6 +340,7 @@ namespace dusk { ImGui::EndMainMenuBar(); } + ImGui::PopStyleColor(); if (!getSettings().backend.wasPresetChosen) { m_firstRunPreset.draw(); diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index ecbbf1b4c8..aaa2e5e10c 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -9,7 +9,6 @@ #include #include "ImGuiFirstRunPreset.hpp" -#include "ImGuiMenuEnhancements.hpp" #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" #include "ImGuiMenuRandomizer.hpp" diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp index 46bfa8f3ab..4b6a7fb531 100644 --- a/src/dusk/imgui/ImGuiEngine.cpp +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -126,7 +126,7 @@ void ImGuiEngine_Initialize(float scale) { auto* colors = style.Colors; colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 0.98f); colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); @@ -137,7 +137,7 @@ void ImGuiEngine_Initialize(float scale) { colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f); colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 0.80f); colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f); colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f); diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index c218185c92..fb2d181562 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -13,7 +13,7 @@ static void ApplyPresetClassic() { auto& s = getSettings(); s.video.lockAspectRatio.setValue(true); s.game.bloomMode.setValue(BloomMode::Classic); - VILockAspectRatio(defaultAspectRatioW, defaultAspectRatioH); + AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT); } static void ApplyPresetHD() { diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp deleted file mode 100644 index a494f81771..0000000000 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "imgui.h" - -#include "ImGuiMenuEnhancements.hpp" -#include "ImGuiConfig.hpp" -#include "dusk/settings.h" - -namespace dusk { - ImGuiMenuEnhancements::ImGuiMenuEnhancements() {} - - void ImGuiMenuEnhancements::draw() { - if (ImGui::BeginMenu("Enhancements")) { - if (ImGui::BeginMenu("Gameplay")) { - ImGui::SeparatorText("Preferences"); - - config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Mirrors the world horizontally, matching the Wii version of the game."); - } - - config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Disables the main HUD of the game.\n" - "Useful for recording or a more immersive experience!"); - } - - ImGui::SeparatorText("Difficulty"); - - config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); - - config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Any hit will instantly kill you."); - } - - config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Hearts will never drop from enemies,\n" - "pots and various other places."); - } - - ImGui::SeparatorText("Quality of Life"); - - config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Wallet sizes are like in the HD version. (500, 1000, 2000)"); - } - - config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time."); - } - - config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version."); - } - - config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version."); - } - - config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Skip the delay when writing to the Memory Card."); - } - - config::ImGuiCheckbox("Hold B for Instant Text", getSettings().game.instantText); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Make text scroll immediately by holding B."); - } - - config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Prevents Link from playing a struggle animation\n" - "when grabbing ledges or climbing on vines."); - } - - config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full."); - } - - config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Link won't recoil when his sword hits walls."); - } - - config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save."); - } - - config::ImGuiCheckbox("Skip Warning Screen", getSettings().game.skipWarningScreen); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Skip the warning screen shown when starting the game."); - } - - config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day."); - } - - config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously."); - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Graphics")) { - config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Improves the shadow resolution, making them higher quality."); - } - - config::ImGuiCheckbox("Unlock Framerate", getSettings().game.enableFrameInterpolation); - const bool frameInterpolationHovered = ImGui::IsItemHovered(); - ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f)); - ImGui::TextUnformatted("[EXPERIMENTAL]"); - ImGui::PopStyleColor(); - if (frameInterpolationHovered || ImGui::IsItemHovered()) { - ImGui::SetTooltip("Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, animation glitches, or instability may occur."); - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Audio")) { - config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Disable the beeping sound when having low health."); - } - - config::ImGuiCheckbox("Non-Stop Midna's Lament", getSettings().game.midnasLamentNonStop); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing."); - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Input")) { - config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); - - ImGui::SeparatorText("Gyro"); - - config::ImGuiCheckbox("Gyro Aim", getSettings().game.enableGyroAim); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Enables the gyroscope on supported controllers\n" - "while in look mode (C-Up) and while aiming the\n" - "Slingshot, Gale Boomerang, Hero's Bow, Clawshot(s),\n" - "Ball and Chain, and Dominion Rod."); - } - - config::ImGuiCheckbox("Gyro Rollgoal", getSettings().game.enableGyroRollgoal); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Enables the gyroscope on supported controllers to\n" - "tilt the Rollgoal table in Hena's Cabin."); - } - - if (getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal) { - config::ImGuiSliderFloat("Gyro Pitch Sensitivity", getSettings().game.gyroSensitivityY, 0.25f, 4.0f, "%.2f"); - config::ImGuiSliderFloat("Gyro Yaw Sensitivity", getSettings().game.gyroSensitivityX, 0.25f, 4.0f, "%.2f"); - - if (getSettings().game.enableGyroRollgoal) { - config::ImGuiSliderFloat("Rollgoal Sensitivity", getSettings().game.gyroSensitivityRollgoal, 0.25f, 4.0f, "%.2f"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Additional multiplier for scaling how strongly\n" - "the gyroscope affects the Rollgoal table."); - } - } - - config::ImGuiSliderFloat("Gyro Deadband", getSettings().game.gyroDeadband, 0.0f, 0.5f, "%.3f"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Angular rates below this magnitude are treated as zero,\n" - "reducing drift and jitter when the controller is still."); - } - - config::ImGuiSliderFloat("Gyro Smoothing", getSettings().game.gyroSmoothing, 0.0f, 1.0f, "%.2f"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Low values track raw gyro input more closely,\n" - "while higher values smooth out input over time."); - } - - config::ImGuiCheckbox("Invert Gyro Pitch", getSettings().game.gyroInvertPitch); - config::ImGuiCheckbox("Invert Gyro Yaw", getSettings().game.gyroInvertYaw); - } - - ImGui::SeparatorText("Tools"); - - config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x."); - } - - ImGui::EndMenu(); - } - - ImGui::Separator(); - - if (ImGui::BeginMenu("Cheats")) { - config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots); - - config::ImGuiCheckbox("Can Transform Anywhere", getSettings().game.canTransformAnywhere); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Allows you to transform even if NPCs are looking."); - } - - config::ImGuiCheckbox("Fast Spinner", getSettings().game.fastSpinner); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Speeds up Spinner movement when holding R."); - } - - config::ImGuiCheckbox("Free Magic Armor", getSettings().game.freeMagicArmor); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Makes the magic armor work without rupees."); - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Technical")) { - config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" - "the first released version."); - } - - ImGui::EndMenu(); - } - - ImGui::EndMenu(); - } - } -} diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.hpp b/src/dusk/imgui/ImGuiMenuEnhancements.hpp deleted file mode 100644 index f40baaad65..0000000000 --- a/src/dusk/imgui/ImGuiMenuEnhancements.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DUSK_IMGUI_MENUENHANCEMENTS_HPP -#define DUSK_IMGUI_MENUENHANCEMENTS_HPP - -#include -#include -#include - -#include "imgui.h" - -namespace dusk { - class ImGuiMenuEnhancements { - public: - ImGuiMenuEnhancements(); - void draw(); - }; -} - -#endif // DUSK_IMGUI_MENUENHANCEMENTS_HPP diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index b0c20b4d46..448bd531ff 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -5,12 +5,11 @@ #include "ImGuiConsole.hpp" #include "ImGuiMenuGame.hpp" #include "ImGuiConfig.hpp" -#include #include "JSystem/JUtility/JUTGamePad.h" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/audio/DuskDsp.hpp" -#include "dusk/dusk.h" +#include "dusk/main.h" #include "dusk/hotkeys.h" #include "dusk/settings.h" #include "m_Do/m_Do_controller_pad.h" @@ -19,7 +18,13 @@ #include #include -#include "dusk/main.h" +namespace { +constexpr int kInternalResolutionScaleMax = 12; +} // namespace + +namespace aurora::gx { +extern bool enableLodBias; +} namespace dusk { void ImGuiMenuGame::ToggleFullscreen() { @@ -31,118 +36,13 @@ namespace dusk { ImGuiMenuGame::ImGuiMenuGame() {} void ImGuiMenuGame::draw() { - if (ImGui::BeginMenu("Game")) { - if (ImGui::BeginMenu("Graphics")) { - if (!IsMobile) { - if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) { - ToggleFullscreen(); - } - - if (ImGui::MenuItem("Default Window Size")) { - getSettings().video.enableFullscreen.setValue(false); - VISetWindowFullscreen(false); - VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2); - VICenterWindow(); - } - } - - bool vsync = getSettings().video.enableVsync; - if (ImGui::Checkbox("Enable Vsync", &vsync)) { - getSettings().video.enableVsync.setValue(vsync); - aurora_enable_vsync(vsync); - config::Save(); - } - - bool lockAspect = getSettings().video.lockAspectRatio; - if (ImGui::Checkbox("Force 4:3 Aspect Ratio", &lockAspect)) { - getSettings().video.lockAspectRatio.setValue(lockAspect); - - if (lockAspect) { - VILockAspectRatio(defaultAspectRatioW, defaultAspectRatioH); - } else { - VIUnlockAspectRatio(); - } - - config::Save(); - } - - constexpr const char* bloomModeNames[] = {"Off", "Classic", "Dusk"}; - int bloomMode = static_cast(getSettings().game.bloomMode.getValue()); - if (ImGui::BeginCombo("Bloom", bloomModeNames[bloomMode])) { - for (int i = 0; i < IM_ARRAYSIZE(bloomModeNames); i++) { - const bool selected = bloomMode == i; - if (ImGui::Selectable(bloomModeNames[i], selected)) { - getSettings().game.bloomMode.setValue(static_cast(i)); - config::Save(); - } - if (selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - - bool bloomOff = bloomMode == static_cast(BloomMode::Off); - if (bloomOff) ImGui::BeginDisabled(); - float mult = getSettings().game.bloomMultiplier.getValue(); - if (ImGui::SliderFloat("Bloom Brightness", &mult, 0.0f, 1.0f, "%.2f")) { - getSettings().game.bloomMultiplier.setValue(mult); - config::Save(); - } - if (bloomOff) ImGui::EndDisabled(); - - config::ImGuiCheckbox("Enable Water Refraction", getSettings().game.enableWaterRefraction); - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Audio")) { - ImGui::Text("Master Volume"); - if (config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100)) { - dusk::audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f); - } - - if (config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb)) { - dusk::audio::SetEnableReverb(getSettings().audio.enableReverb); - } - /* - // TODO: Implement additional settings - ImGui::Text("Main Music Volume"); - ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0, 100); - - ImGui::Text("Sub Music Volume"); - ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0, 100); - - ImGui::Text("Sound Effects Volume"); - ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0, 100); - - ImGui::Text("Fanfare Volume"); - ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0, 100); - - Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface(); - if (audioMgr != nullptr) { - } - */ - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Controller")) { - ImGui::MenuItem("Configure Controller", nullptr, &m_showControllerConfig); - ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Interface")) { - config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI); - config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation); -#if DUSK_ENABLE_SENTRY_NATIVE - config::ImGuiCheckbox("Enable Crash Reporting", getSettings().backend.enableCrashReporting); -#endif - - ImGui::EndMenu(); - } + if (ImGui::BeginMenu("Settings")) { + drawAudioMenu(); + drawCheatsMenu(); + drawGameplayMenu(); + drawGraphicsMenu(); + drawInputMenu(); + drawInterfaceMenu(); ImGui::Separator(); @@ -158,6 +58,398 @@ namespace dusk { } } + void ImGuiMenuGame::drawGraphicsMenu() { + if (ImGui::BeginMenu("Graphics")) { + ImGui::SeparatorText("Display"); + + if (!IsMobile) { + if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) { + ToggleFullscreen(); + } + + if (ImGui::Button("Restore Default Window Size")) { + getSettings().video.enableFullscreen.setValue(false); + VISetWindowFullscreen(false); + VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2); + VICenterWindow(); + } + } + + ImGui::Separator(); + + bool vsync = getSettings().video.enableVsync; + if (ImGui::Checkbox("Enable VSync", &vsync)) { + getSettings().video.enableVsync.setValue(vsync); + aurora_enable_vsync(vsync); + config::Save(); + } + + bool lockAspect = getSettings().video.lockAspectRatio; + if (ImGui::Checkbox("Force 4:3 Aspect Ratio", &lockAspect)) { + getSettings().video.lockAspectRatio.setValue(lockAspect); + + if (lockAspect) { + AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT); + } else { + AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH); + } + + config::Save(); + } + + ImGui::SeparatorText("Resolution"); + + u32 internalResolutionWidth = 0; + u32 internalResolutionHeight = 0; + AuroraGetRenderSize(&internalResolutionWidth, &internalResolutionHeight); + ImGui::TextDisabled("Current internal resolution: %ux%u", internalResolutionWidth, + internalResolutionHeight); + + int scale = std::clamp(getSettings().game.internalResolutionScale.getValue(), 0, + kInternalResolutionScaleMax); + if (ImGui::SliderInt("Internal Resolution", &scale, 0, kInternalResolutionScaleMax, + scale == 0 ? "Auto" : "%dx")) + { + getSettings().game.internalResolutionScale.setValue(scale); + VISetFrameBufferScale(static_cast(scale)); + config::Save(); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Auto renders at the native window resolution.\n" + "Higher values scale the game's internal framebuffer."); + } + + config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Improves the shadow resolution, making them higher quality."); + } + + ImGui::SeparatorText("Post-Processing"); + + constexpr const char* bloomModeNames[] = {"Off", "Classic", "Dusk"}; + int bloomMode = static_cast(getSettings().game.bloomMode.getValue()); + if (ImGui::BeginCombo("Bloom", bloomModeNames[bloomMode])) { + for (int i = 0; i < IM_ARRAYSIZE(bloomModeNames); i++) { + const bool selected = bloomMode == i; + if (ImGui::Selectable(bloomModeNames[i], selected)) { + getSettings().game.bloomMode.setValue(static_cast(i)); + config::Save(); + } + if (selected) { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + + bool bloomOff = bloomMode == static_cast(BloomMode::Off); + if (bloomOff) ImGui::BeginDisabled(); + float mult = getSettings().game.bloomMultiplier.getValue(); + if (ImGui::SliderFloat("Bloom Brightness", &mult, 0.0f, 1.0f, "%.2f")) { + getSettings().game.bloomMultiplier.setValue(mult); + config::Save(); + } + if (bloomOff) ImGui::EndDisabled(); + + ImGui::SeparatorText("Rendering"); + + config::ImGuiCheckbox("Unlock Framerate", getSettings().game.enableFrameInterpolation); + const bool frameInterpolationHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f)); + ImGui::TextUnformatted("[EXPERIMENTAL]"); + ImGui::PopStyleColor(); + if (frameInterpolationHovered || ImGui::IsItemHovered()) { + ImGui::SetTooltip("Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, animation glitches, or instability may occur."); + } + + ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias); + + config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField); + + ImGui::EndMenu(); + } + } + + void ImGuiMenuGame::drawGameplayMenu() { + if (ImGui::BeginMenu("Gameplay")) { + ImGui::SeparatorText("General"); + + config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Mirrors the world horizontally, matching the Wii version of the game."); + } + + config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Disables the main HUD of the game.\n" + "Useful for recording or a more immersive experience!"); + } + + config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" + "the first released version."); + } + + ImGui::SeparatorText("Difficulty"); + + config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); + + config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Any hit will instantly kill you."); + } + + config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Hearts will never drop from enemies,\n" + "pots and various other places."); + } + + ImGui::SeparatorText("Quality of Life"); + + config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Wallet sizes are like in the HD version. (500, 1000, 2000)"); + } + + config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time."); + } + + config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version."); + } + + config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version."); + } + + config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Skip the delay when writing to the Memory Card."); + } + + config::ImGuiCheckbox("Hold B for Instant Text", getSettings().game.instantText); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Make text scroll immediately by holding B."); + } + + config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Prevents Link from playing a struggle animation\n" + "when grabbing ledges or climbing on vines."); + } + + config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full."); + } + + config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Link won't recoil when his sword hits walls."); + } + + config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save."); + } + + config::ImGuiCheckbox("Skip Warning Screen", getSettings().game.skipWarningScreen); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Skip the warning screen shown when starting the game."); + } + + config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day."); + } + + config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously."); + } + + ImGui::EndMenu(); + } + } + + void ImGuiMenuGame::drawCheatsMenu() { + if (ImGui::BeginMenu("Cheats")) { + ImGui::SeparatorText("Resources"); + config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts); + config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows); + config::ImGuiCheckbox("Infinite Bombs", getSettings().game.infiniteBombs); + config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil); + config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen); + config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees); + + ImGui::SeparatorText("Abilities"); + config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump); + config::ImGuiCheckbox("Super Clawshot", getSettings().game.superClawshot); + config::ImGuiCheckbox("Always Greatspin", getSettings().game.alwaysGreatspin); + config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots); + + config::ImGuiCheckbox("Can Transform Anywhere", getSettings().game.canTransformAnywhere); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows you to transform even if NPCs are looking."); + } + + config::ImGuiCheckbox("Fast Spinner", getSettings().game.fastSpinner); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Speeds up Spinner movement when holding R."); + } + + config::ImGuiCheckbox("Free Magic Armor", getSettings().game.freeMagicArmor); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Makes the magic armor work without rupees."); + } + + ImGui::EndMenu(); + } + } + + void ImGuiMenuGame::drawAudioMenu() { + if (ImGui::BeginMenu("Audio")) { + + ImGui::SeparatorText("Volume"); + + ImGui::Text("Master Volume"); + if (config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100)) { + dusk::audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f); + } + + /* + // TODO: Implement additional settings + ImGui::Text("Main Music Volume"); + ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0, 100); + + ImGui::Text("Sub Music Volume"); + ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0, 100); + + ImGui::Text("Sound Effects Volume"); + ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0, 100); + + ImGui::Text("Fanfare Volume"); + ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0, 100); + + Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface(); + if (audioMgr != nullptr) { + } + */ + + ImGui::SeparatorText("Effects"); + + if (config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb)) { + dusk::audio::SetEnableReverb(getSettings().audio.enableReverb); + } + + + ImGui::SeparatorText("Tweaks"); + + config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Disable the beeping sound when having low health."); + } + + config::ImGuiCheckbox("Non-Stop Midna's Lament", getSettings().game.midnasLamentNonStop); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing."); + } + + ImGui::EndMenu(); + } + } + + void ImGuiMenuGame::drawInputMenu() { + if (ImGui::BeginMenu("Input")) { + ImGui::SeparatorText("Controller"); + + if (ImGui::Button("Configure Controller")){ + m_showControllerConfig = !m_showControllerConfig; + } + + ImGui::SeparatorText("Camera"); + + config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); + + ImGui::SeparatorText("Gyro"); + + config::ImGuiCheckbox("Gyro Aim", getSettings().game.enableGyroAim); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enables the gyroscope on supported controllers\n" + "while in look mode (C-Up) and while aiming the\n" + "Slingshot, Gale Boomerang, Hero's Bow, Clawshot(s),\n" + "Ball and Chain, and Dominion Rod."); + } + + config::ImGuiCheckbox("Gyro Rollgoal", getSettings().game.enableGyroRollgoal); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enables the gyroscope on supported controllers to\n" + "tilt the Rollgoal table in Hena's Cabin."); + } + + if (getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal) { + config::ImGuiSliderFloat("Gyro Pitch Sensitivity", getSettings().game.gyroSensitivityY, 0.25f, 4.0f, "%.2f"); + config::ImGuiSliderFloat("Gyro Yaw Sensitivity", getSettings().game.gyroSensitivityX, 0.25f, 4.0f, "%.2f"); + + if (getSettings().game.enableGyroRollgoal) { + config::ImGuiSliderFloat("Rollgoal Sensitivity", getSettings().game.gyroSensitivityRollgoal, 0.25f, 4.0f, "%.2f"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Additional multiplier for scaling how strongly\n" + "the gyroscope affects the Rollgoal table."); + } + } + + config::ImGuiSliderFloat("Gyro Deadband", getSettings().game.gyroDeadband, 0.0f, 0.5f, "%.3f"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Angular rates below this magnitude are treated as zero,\n" + "reducing drift and jitter when the controller is still."); + } + + config::ImGuiSliderFloat("Gyro Smoothing", getSettings().game.gyroSmoothing, 0.0f, 1.0f, "%.2f"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Low values track raw gyro input more closely,\n" + "while higher values smooth out input over time."); + } + + config::ImGuiCheckbox("Invert Gyro Pitch", getSettings().game.gyroInvertPitch); + config::ImGuiCheckbox("Invert Gyro Yaw", getSettings().game.gyroInvertYaw); + } + + ImGui::SeparatorText("Tools"); + + config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x."); + } + + ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); + + ImGui::EndMenu(); + } + } + + void ImGuiMenuGame::drawInterfaceMenu() { + if (ImGui::BeginMenu("Interface")) { + config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI); + config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation); +#if DUSK_ENABLE_SENTRY_NATIVE + config::ImGuiCheckbox("Enable Crash Reporting", getSettings().backend.enableCrashReporting); +#endif + if (!IsMobile) { + config::ImGuiCheckbox("Pause on Focus Lost", getSettings().game.pauseOnFocusLost); + } + + ImGui::EndMenu(); + } + } + static void drawVirtualStick(const char* id, const ImVec2& stick) { float scale = ImGuiScale(); ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10)); diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index 4d51cbc865..e21374c8f4 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -19,6 +19,13 @@ namespace dusk { static void ToggleFullscreen(); private: + void drawAudioMenu(); + void drawInputMenu(); + void drawGraphicsMenu(); + void drawGameplayMenu(); + void drawCheatsMenu(); + void drawInterfaceMenu(); + struct { int m_selectedPort = 0; bool m_isReading = false; diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 9bb7670e88..97f5b5a8d3 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -2,6 +2,7 @@ #include "imgui.h" #include "aurora/gfx.h" +#include "ImGuiConfig.hpp" #include "dusk/hotkeys.h" #include "dusk/settings.h" #include "ImGuiConsole.hpp" @@ -15,10 +16,58 @@ #include "dusk/main.h" #include "m_Do/m_Do_main.h" +#include +#include + +#if defined(__APPLE__) +#include +#endif + +#if defined(_WIN32) || (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || (defined(__linux__) && !defined(__ANDROID__)) +#define DUSK_CAN_OPEN_DATA_FOLDER 1 + +namespace fs = std::filesystem; + +static void OpenDataFolder() { + const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); +#if defined(_WIN32) + const std::string url = std::string("file:///") + path; +#else + const std::string url = std::string("file://") + path; +#endif + (void)SDL_OpenURL(url.c_str()); +} +#else +#define DUSK_CAN_OPEN_DATA_FOLDER 0 +#endif + namespace dusk { ImGuiMenuTools::ImGuiMenuTools() {} void ImGuiMenuTools::draw() { + if (ImGui::BeginMenu("Tools")) { + if (!dusk::IsGameLaunched) { + ImGui::BeginDisabled(); + } + + 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); + + if (!dusk::IsGameLaunched) { + ImGui::EndDisabled(); + } + +#if DUSK_CAN_OPEN_DATA_FOLDER + ImGui::Separator(); + if (ImGui::MenuItem("Open Data Folder")) { + OpenDataFolder(); + } +#endif + + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Debug")) { bool developmentMode = mDoMain::developmentMode == 1; if (ImGui::Checkbox("Development Mode", &developmentMode)) { @@ -28,6 +77,15 @@ namespace dusk { ImGui::Separator(); auto& collisionView = getTransientSettings().collisionView; + if (ImGui::BeginMenu("Graphics Settings")) { + bool disableWaterRefraction = getSettings().game.disableWaterRefraction; + if (ImGui::Checkbox("Disable Water Refraction", &disableWaterRefraction)) { + getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction); + config::Save(); + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Collision View")) { ImGui::Checkbox("Enable Terrain view", &collisionView.enableTerrainView); ImGui::Checkbox("Enable wireframe view", &collisionView.enableWireframe); @@ -49,9 +107,6 @@ namespace dusk { ImGui::MenuItem("Debug Overlay", hotkeys::SHOW_DEBUG_OVERLAY, &m_showDebugOverlay); ImGui::MenuItem("Heap Viewer", hotkeys::SHOW_HEAP_VIEWER, &m_showHeapOverlay); 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("Bloom", nullptr, &m_showBloomWindow); @@ -86,7 +141,9 @@ namespace dusk { ImGui::SetNextWindowBgAlpha(0.65f); if (ImGui::Begin("Debug Overlay", nullptr, windowFlags)) { ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.2f}\n"), io.Framerate)); - ImGuiStringViewText(fmt::format(FMT_STRING("Frame usage: {:.1f}%\n"), frameUsagePct)); + if (frameUsagePct > 0.f) { + ImGuiStringViewText(fmt::format(FMT_STRING("Frame usage: {:.1f}%\n"), frameUsagePct)); + } ImGui::Separator(); diff --git a/src/dusk/imgui/ImGuiProcessOverlay.cpp b/src/dusk/imgui/ImGuiProcessOverlay.cpp index 04a87f00b6..ed71e6c485 100644 --- a/src/dusk/imgui/ImGuiProcessOverlay.cpp +++ b/src/dusk/imgui/ImGuiProcessOverlay.cpp @@ -9,53 +9,109 @@ #include "f_pc/f_pc_layer_iter.h" #include "f_pc/f_pc_leaf.h" #include "f_pc/f_pc_node.h" +#include "d/d_debug_viewer.h" #include "imgui.h" #include "ImGuiConsole.hpp" #include "ImGuiMenuTools.hpp" #include "imgui_internal.h" namespace dusk { - bool showTreeRecursive; + static bool BeginProcTable() { + static ImGuiTableFlags table_flags = + ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | + ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + + if (ImGui::BeginTable("proc_table", 7)) { + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 128); + ImGui::TableSetupColumn("En", ImGuiTableColumnFlags_WidthFixed, 32); + ImGui::TableSetupColumn("Vs", ImGuiTableColumnFlags_WidthFixed, 32); + ImGui::TableSetupColumn("ProcName"); + ImGui::TableSetupColumn("Param", ImGuiTableColumnFlags_WidthFixed, 128); + ImGui::TableSetupColumn("Pi", ImGuiTableColumnFlags_WidthFixed, 64); + ImGui::TableSetupColumn("DwPi", ImGuiTableColumnFlags_WidthFixed, 64); + ImGui::TableHeadersRow(); + return true; + } + return false; + } static int ShowProcess(void* p, void*) { auto proc = static_cast(p); - char buf[64]; - snprintf(buf, sizeof(buf), "%d", proc->id); + ImGui::TableNextRow(); + ImGui::PushID(proc); + bool pending = proc->create_req != nullptr; + if (pending) + ImGui::PushStyleColor(ImGuiCol_Text, {255, 200, 0, 255}); + ImGui::TableNextColumn(); - ImVec2 avail = ImGui::GetContentRegionAvail(); + char id_buf[32]; + sprintf(id_buf, "%d", proc->id); - ImVec2 vec = { avail.x, 0 }; - if (ImGui::BeginChild(buf, vec, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { - ImGui::Text("[%d] %s", proc->id, GetProcName(proc->profname)); - ImGui::Text("init_state: %d, create_phase: %d", proc->state.init_state, proc->state.create_phase); + int flags = ImGuiTreeNodeFlags_SpanAllColumns; + bool isLayer = fpcBs_Is_JustOfType(g_fpcNd_type, proc->subtype); + if (isLayer) { + flags |= ImGuiTreeNodeFlags_DefaultOpen; + } else { + flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; + } - const char* ofTypeName = "unknown"; - if (proc->subtype == g_fpcNd_type) { - ofTypeName = "Node"; - } - else if (proc->subtype == g_fpcLf_type) { - ofTypeName = "Leaf"; - } + bool open = ImGui::TreeNodeEx(id_buf, flags); + fopAc_ac_c* ac = fopAcM_IsActor(proc) ? (fopAc_ac_c*)proc : nullptr; + if (ac != nullptr && ImGui::IsItemHovered()) { + fopAcM_DrawCullingBox(ac, {0, 255, 255, 255}); + } - ImGui::Text("OfType: %d (%s), layer: %d", proc->subtype, ofTypeName, proc->layer_tag.layer->layer_id); + ImGui::TableNextColumn(); + bool enable = !fpcM_IsPause(proc, 1); + if (ImGui::Checkbox("##enable", &enable)) { + if (enable) + fpcM_PauseDisable(proc, 1); + else + fpcM_PauseEnable(proc, 1); + } - if (proc->create_req != nullptr) { - ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Pending create request"); - } - - if (showTreeRecursive) { - if (fpcBs_Is_JustOfType(g_fpcNd_type, proc->subtype)) { - auto procNode = static_cast(p); - - ImGui::Text("Owns layer %d", procNode->layer.layer_id); - - fpcLyIt_OnlyHere(&procNode->layer, ShowProcess, nullptr); - } + ImGui::TableNextColumn(); + if (fpcBs_Is_JustOfType(g_fpcLf_type, proc->subtype)) { + leafdraw_class* lf = (leafdraw_class*)proc; + bool vis = lf->unk_0xBC == 0; + if (ImGui::Checkbox("##visible", &vis)) { + if (vis) + lf->unk_0xBC = 0; + else + lf->unk_0xBC = 1; } } - ImGui::EndChild(); + ImGui::TableNextColumn(); + ImGui::Text("%s", ac != nullptr ? fopAcM_getProcNameString(ac) : GetProcName(proc->profname)); + + ImGui::TableNextColumn(); + if (proc->profname == fpcNm_ROOM_SCENE_e) { + ImGui::Text("Room %d", proc->parameters); + } else { + ImGui::Text("%08x", proc->parameters); + } + + ImGui::TableNextColumn(); + ImGui::Text("%d", proc->priority.current_info.list_id); + + ImGui::TableNextColumn(); + if (fpcBs_Is_JustOfType(g_fpcLf_type, proc->subtype)) { + ImGui::Text("%d", fpcM_DrawPriority(proc)); + } else { + ImGui::Text("--"); + } + + if (isLayer && open) { + auto procNode = static_cast(p); + fpcLyIt_OnlyHere(&procNode->layer, ShowProcess, nullptr); + ImGui::TreePop(); + } + + if (pending) + ImGui::PopStyleColor(1); + ImGui::PopID(); return 1; } @@ -76,15 +132,11 @@ namespace dusk { if (ImGui::Begin("Processes", &m_showProcessManagement)) { if (ImGui::BeginTabBar("Tabs")) { - showTreeRecursive = true; if (ImGui::BeginTabItem("Tree")) { - fpcLyIt_OnlyHere(fpcLy_RootLayer(), ShowProcess, nullptr); - ImGui::EndTabItem(); - } - - showTreeRecursive = false; - if (ImGui::BeginTabItem("All layers")) { - fpcLyIt_All(ShowProcess, nullptr); + if (BeginProcTable()) { + fpcLyIt_OnlyHere(fpcLy_RootLayer(), ShowProcess, nullptr); + ImGui::EndTable(); + } ImGui::EndTabItem(); } diff --git a/src/dusk/logging.cpp b/src/dusk/logging.cpp index 3fdd6cdf45..172059aea4 100644 --- a/src/dusk/logging.cpp +++ b/src/dusk/logging.cpp @@ -168,14 +168,14 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m aurora::Module DuskLog("dusk"); -void dusk::InitializeFileLogging(const char* configDir, AuroraLogLevel logLevel) { +void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) { std::lock_guard lock(g_logMutex); - if (g_logFile != nullptr || configDir == nullptr) { + if (g_logFile != nullptr || configDir.empty()) { return; } std::error_code ec; - const std::filesystem::path logsDir = std::filesystem::path(configDir) / "logs"; + const std::filesystem::path logsDir = configDir / "logs"; std::filesystem::create_directories(logsDir, ec); if (ec) { std::fprintf(stderr, "[WARNING | dusk] Failed to create log directory '%s': %s\n", diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index cc33fc12a3..aacca0dbc9 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -42,13 +42,16 @@ UserSettings g_userSettings = { .enableMirrorMode {"game.enableMirrorMode", false}, .invertCameraXAxis {"game.invertCameraXAxis", false}, .disableMainHUD {"game.disableMainHUD", false}, + .pauseOnFocusLost {"game.pauseOnFocusLost", false}, // Graphics .bloomMode {"game.bloomMode", BloomMode::Classic}, .bloomMultiplier {"game.bloomMultiplier", 1.0f}, - .enableWaterRefraction {"game.enableWaterRefraction", true}, + .disableWaterRefraction {"game.disableWaterRefraction", false}, .enableFrameInterpolation = {"game.enableFrameInterpolation", false}, + .internalResolutionScale {"game.internalResolutionScale", 0}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, + .enableDepthOfField {"game.enableDepthOfField", true}, // Audio .noLowHpSound {"game.noLowHpSound", false}, @@ -66,6 +69,15 @@ UserSettings g_userSettings = { .gyroInvertYaw {"game.gyroInvertYaw", false}, // Cheats + .infiniteHearts {"game.infiniteHearts", false}, + .infiniteArrows{"game.infiniteArrows", false}, + .infiniteBombs{"game.infiniteBombs", false}, + .infiniteOil{"game.infiniteOil", false}, + .infiniteOxygen{"game.infiniteOxygen", false}, + .infiniteRupees{"game.infiniteRupees", false}, + .moonJump{"game.moonJump", false}, + .superClawshot{"game.superClawshot", false}, + .alwaysGreatspin{"game.alwaysGreatspin", false}, .enableFastIronBoots {"game.enableFastIronBoots", false}, .canTransformAnywhere {"game.canTransformAnywhere", false}, .fastSpinner {"game.fastSpinner", false}, @@ -126,10 +138,13 @@ void registerSettings() { Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.disableMainHUD); + Register(g_userSettings.game.pauseOnFocusLost); Register(g_userSettings.game.bloomMode); Register(g_userSettings.game.bloomMultiplier); - Register(g_userSettings.game.enableWaterRefraction); + Register(g_userSettings.game.disableWaterRefraction); + Register(g_userSettings.game.internalResolutionScale); Register(g_userSettings.game.shadowResolutionMultiplier); + Register(g_userSettings.game.enableDepthOfField); Register(g_userSettings.game.enableFastIronBoots); Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.freeMagicArmor); @@ -139,6 +154,15 @@ void registerSettings() { Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.enableTurboKeybind); Register(g_userSettings.game.fastSpinner); + Register(g_userSettings.game.infiniteHearts); + Register(g_userSettings.game.infiniteArrows); + Register(g_userSettings.game.infiniteBombs); + Register(g_userSettings.game.infiniteOil); + Register(g_userSettings.game.infiniteOxygen); + Register(g_userSettings.game.infiniteRupees); + Register(g_userSettings.game.moonJump); + Register(g_userSettings.game.superClawshot); + Register(g_userSettings.game.alwaysGreatspin); Register(g_userSettings.game.enableFrameInterpolation); Register(g_userSettings.game.enableGyroAim); Register(g_userSettings.game.enableGyroRollgoal); diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 668541f49c..07e420445c 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -332,14 +332,6 @@ static VIRetraceCallback sVIPostRetraceCallback = NULL; extern "C" { -void VIConfigure(const GXRenderModeObj* rm) { - STUB_LOG(); -} - -void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) { - STUB_LOG(); -} - u32 VIGetRetraceCount() { return sRetraceCount; } diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 93a9148957..46b277f421 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -732,6 +732,62 @@ static void fapGm_AfterRecord() { dusk::frame_interp::end_record(); fapGm_After(); } + +static void duskExecute() { + if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + dynamic_cast(link)->handleWolfHowl(); + } + } + + if ((mDoCPd_c::getHold(PAD_1) & (PAD_TRIGGER_R | PAD_TRIGGER_L)) == PAD_TRIGGER_R && mDoCPd_c::getTrigY(PAD_1)) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + dynamic_cast(link)->handleQuickTransform(); + } + } + + if (dusk::getSettings().game.moonJump && (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1))) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + link->speed.y = 56.0f; + } + } + + if (dusk::getSettings().game.fastSpinner && mDoCPd_c::getHoldR(PAD_1)) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + auto spinnerActor = (fopAc_ac_c*)dynamic_cast(link)->getSpinnerActor(); + if (spinnerActor) { + if (spinnerActor->speedF < 60.f) + spinnerActor->speedF += 2.f; + } + } + } + + if (dusk::getSettings().game.infiniteHearts) { + dComIfGs_setLife((dComIfGs_getMaxLife() / 5) * 4); + } + + if (dusk::getSettings().game.infiniteArrows) { + dComIfGs_setArrowNum(dComIfGs_getArrowMax()); + } + + if (dusk::getSettings().game.infiniteBombs) { + dComIfGs_setBombNum(0, 99); + dComIfGs_setBombNum(1, 99); + dComIfGs_setBombNum(2, 99); + } + + if (dusk::getSettings().game.infiniteOil) { + dComIfGs_setOil(dComIfGs_getMaxOil()); + } + + if (dusk::getSettings().game.infiniteRupees) { + dComIfGs_setRupee(9999); + } + + if (dusk::getSettings().game.infiniteOxygen) { + dComIfGp_setOxygen(dComIfGp_getMaxOxygen()); + } +} #endif void fapGm_Execute() { @@ -747,27 +803,7 @@ void fapGm_Execute() { #endif #if TARGET_PC - if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { - if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { - dynamic_cast(link)->handleWolfHowl(); - } - } - - if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigY(PAD_1)) { - if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { - dynamic_cast(link)->handleQuickTransform(); - } - } - - if (dusk::getSettings().game.fastSpinner && mDoCPd_c::getHoldR(PAD_1)) { - if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { - auto spinnerActor = (fopAc_ac_c*)dynamic_cast(link)->getSpinnerActor(); - if (spinnerActor) { - if (spinnerActor->speedF < 60.f) - spinnerActor->speedF += 2.f; - } - } - } + duskExecute(); #endif #ifdef TARGET_PC diff --git a/src/f_pc/f_pc_draw.cpp b/src/f_pc/f_pc_draw.cpp index 697d19cf29..8b775257fc 100644 --- a/src/f_pc/f_pc_draw.cpp +++ b/src/f_pc/f_pc_draw.cpp @@ -26,13 +26,7 @@ int fpcDw_Execute(base_process_class* i_proc) { } fpcLy_SetCurrentLayer(i_proc->layer_tag.layer); -#ifdef TARGET_PC - dusk::frame_interp::open_child(i_proc, 0); -#endif ret = draw_func(i_proc); -#ifdef TARGET_PC - dusk::frame_interp::close_child(); -#endif fpcLy_SetCurrentLayer(save_layer); return ret; } diff --git a/src/f_pc/f_pc_leaf.cpp b/src/f_pc/f_pc_leaf.cpp index eab6532a92..7f6d6df802 100644 --- a/src/f_pc/f_pc_leaf.cpp +++ b/src/f_pc/f_pc_leaf.cpp @@ -6,6 +6,10 @@ #include "f_pc/f_pc_leaf.h" #include "f_pc/f_pc_debug_sv.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + s16 fpcLf_GetPriority(const leafdraw_class* i_leaf) { return fpcDwPi_Get(&i_leaf->draw_priority); } @@ -16,6 +20,11 @@ int fpcLf_DrawMethod(leafdraw_method_class* i_methods, void* i_process) { int fpcLf_Draw(leafdraw_class* i_leaf) { int ret = 0; +#if TARGET_PC + if (!i_leaf->draw_interp_frame && !dusk::frame_interp::is_sim_frame()) { + return ret; + } +#endif if (i_leaf->unk_0xBC == 0) { ret = fpcLf_DrawMethod(i_leaf->leaf_methods, i_leaf); } @@ -56,6 +65,9 @@ int fpcLf_Create(leafdraw_class* i_leaf) { LEAFDRAW_BASE(i_leaf).subtype = fpcBs_MakeOfType(&g_fpcLf_type); fpcDwPi_Init(&i_leaf->draw_priority, pprofile->priority); i_leaf->unk_0xBC = 0; +#if TARGET_PC + i_leaf->draw_interp_frame = false; +#endif } int ret = fpcMtd_Create(&i_leaf->leaf_methods->base, i_leaf); diff --git a/src/f_pc/f_pc_manager.cpp b/src/f_pc/f_pc_manager.cpp index 4d424ad75e..ad226b4d1d 100644 --- a/src/f_pc/f_pc_manager.cpp +++ b/src/f_pc/f_pc_manager.cpp @@ -65,7 +65,7 @@ void fpcM_Management(fpcM_ManagementFunc i_preExecuteFn, fpcM_ManagementFunc i_p #ifdef TARGET_PC // FRAME INTERP NOTE: Called in m_Do_main when interp is enabled - if (!dusk::getSettings().game.enableFrameInterpolation || dusk::getTransientSettings().skipFrameRateLimit) + if (!dusk::frame_interp::is_enabled()) #endif { cAPIGph_Painter(); diff --git a/src/f_pc/f_pc_node.cpp b/src/f_pc/f_pc_node.cpp index 205d392ff1..ca7bcc044b 100644 --- a/src/f_pc/f_pc_node.cpp +++ b/src/f_pc/f_pc_node.cpp @@ -7,6 +7,13 @@ #include "f_pc/f_pc_layer_iter.h" #include "f_pc/f_pc_debug_sv.h" +#if TARGET_PC +#include "f_op/f_op_draw_iter.h" +#include "f_pc/f_pc_manager.h" + +#include "dusk/frame_interpolation.h" +#endif + int fpcNd_DrawMethod(nodedraw_method_class* i_method_class, void* i_data) { return fpcMtd_Method(i_method_class->draw_method, i_data); } @@ -18,7 +25,17 @@ int fpcNd_Draw(process_node_class* i_procNode) { if (i_procNode->unk_0x1A8 == 0) { layer_class* save_layer = fpcLy_CurrentLayer(); fpcLy_SetCurrentLayer(&var_r28->layer); - ret = fpcNd_DrawMethod(i_procNode->nodedraw_method, i_procNode); +#if TARGET_PC + if (!i_procNode->draw_interp_frame && !dusk::frame_interp::is_sim_frame()) { + for (create_tag_class* i = fopDwIt_Begin(); i != NULL; i = fopDwIt_Next(i)) { + void* process = i->mpTagData; + fpcM_Draw(process); + } + } else +#endif + { + ret = fpcNd_DrawMethod(i_procNode->nodedraw_method, i_procNode); + } fpcLy_SetCurrentLayer(save_layer); } diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 36de5480e5..a0c0302b09 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -84,11 +84,12 @@ void mDoMemCd_Ctrl_c::ThdInit() { mProbeStat = 2; mCardState = CARD_STATE_NO_CARD_e; - #if TARGET_PC - mCardState = CARD_STATE_READY_e; - #endif - +#if TARGET_PC + mCardCommand = COMM_ATTACH_e; +#else mCardCommand = COMM_NONE_e; +#endif + mChannel = SLOT_A; OSInitMutex(&mMutex); diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index 024dd596a8..84bf51ecf5 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -25,6 +25,7 @@ #include #include #include "dusk/logging.h" +#include "dusk/frame_interpolation.h" u8 mDoExt::CurrentHeapAdjustVerbose; u8 mDoExt::HeapAdjustVerbose; @@ -349,6 +350,11 @@ void mDoExt_modelUpdateDL(J3DModel* i_model) { } void mDoExt_modelEntryDL(J3DModel* i_model) { +#if TARGET_PC + if (!dusk::frame_interp::is_sim_frame()) + return; +#endif + modelMtxErrorCheck(i_model); J3DModelData* model_data = i_model->getModelData(); diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index a56e448645..4dc505ac03 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -141,7 +141,7 @@ void dDlst_heapMap_c::draw() { f32 var_f29 = field_0x10 - field_0x8; f32 sp4C = field_0x14 - field_0xc; f32 sp48 = var_f29 * sp4C; - + uintptr_t start_addr = (uintptr_t)m_heap->getStartAddr(); uintptr_t end_addr = (uintptr_t)m_heap->getEndAddr(); u32 sp40 = end_addr - start_addr; @@ -156,7 +156,7 @@ void dDlst_heapMap_c::draw() { f32 var_f30 = (f32)sp38 * sp3C; uintptr_t sp34 = (uintptr_t)block - start_addr; f32 sp30 = (f32)sp34 * sp3C; - + f32 var_f28 = std::floor(sp30 / var_f29); f32 sp2C = sp30 - (var_f29 * var_f28); @@ -471,72 +471,32 @@ void darwFilter(GXColor matColor) { GXEnd(); } -#ifdef TARGET_PC -static void mDoGph_AdvanceFadeState() { - if (mDoGph_gInf_c::isFade() != 0) { - f32 fade_rate = mDoGph_gInf_c::getFadeRate() + mDoGph_gInf_c::getFadeSpeed(); - - if (fade_rate < 0.0f) { - fade_rate = 0.0f; - mDoGph_gInf_c::offFade(); - } else if (fade_rate > 1.0f) { - fade_rate = 1.0f; - } - - mDoGph_gInf_c::setFadeRate(fade_rate); - mDoGph_gInf_c::getFadeColor().a = 255.0f * fade_rate; - } else { - GXColor& fade_color = mDoGph_gInf_c::getFadeColor(); - if (dComIfG_getBrightness() != 255) { - fade_color.r = 0; - fade_color.g = 0; - fade_color.b = 0; - fade_color.a = 255 - dComIfG_getBrightness(); - } else { - fade_color.a = 0; - } - } -} - -static void mDoGph_AdvanceFadeState(u32 tick_count) { - for (u32 i = 0; i < tick_count; ++i) { - mDoGph_AdvanceFadeState(); - } -} - -static void mDoGph_DrawStoredFade() { - GXColor& fade_color = mDoGph_gInf_c::getFadeColor(); - if (fade_color.a != 0) { - darwFilter(fade_color); - } -} - void mDoGph_gInf_c::calcFade() { - mDoGph_AdvanceFadeState(); - mDoGph_DrawStoredFade(); -} -#else -void mDoGph_gInf_c::calcFade() { - if (mDoGph_gInf_c::mFade != 0) { - mFadeRate += mFadeSpeed; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + if (mFade != 0) { + mFadeRate += mFadeSpeed; - if (mFadeRate < 0.0f) { - mFadeRate = 0.0f; - mDoGph_gInf_c::mFade = 0; - } else { - if (mFadeRate > 1.0f) { - mFadeRate = 1.0f; + if (mFadeRate < 0.0f) { + mFadeRate = 0.0f; + mFade = 0; + } else { + if (mFadeRate > 1.0f) { + mFadeRate = 1.0f; + } } - } - mFadeColor.a = 255.0f * mFadeRate; - } else { - if (dComIfG_getBrightness() != 255) { - mFadeColor.r = 0; - mFadeColor.g = 0; - mFadeColor.b = 0; - mFadeColor.a = 255 - dComIfG_getBrightness(); + mFadeColor.a = 255.0f * mFadeRate; } else { - mFadeColor.a = 0; + if (dComIfG_getBrightness() != 255) { + mFadeColor.r = 0; + mFadeColor.g = 0; + mFadeColor.b = 0; + mFadeColor.a = 255 - dComIfG_getBrightness(); + } else { + mFadeColor.a = 0; + } } } @@ -544,7 +504,6 @@ void mDoGph_gInf_c::calcFade() { darwFilter(mFadeColor); } } -#endif #if PLATFORM_WII || PLATFORM_SHIELD u32 mDoGph_gInf_c::csr_c::m_blurID; @@ -603,21 +562,16 @@ struct tvSize { u16 width; u16 height; }; -const tvSize l_tvSize[2] = { +#ifndef TARGET_PC +const +#endif +tvSize l_tvSize[2] = { {FB_WIDTH_BASE, FB_HEIGHT_BASE}, {808, FB_HEIGHT_BASE}, }; -#if TARGET_PC -tvSize pc_tvSize = {608, 448}; -#endif - void mDoGph_gInf_c::setTvSize() { -#if TARGET_PC - const tvSize* tvsize = &pc_tvSize; -#else const tvSize* tvsize = &l_tvSize[mWide]; -#endif m_width = tvsize->width; m_height = tvsize->height; @@ -644,21 +598,11 @@ void mDoGph_gInf_c::setTvSize() { #endif } -#if TARGET_PC -void mDoGph_gInf_c::onWide(f32 width, f32 height) { - mWide = TRUE; - pc_tvSize.width = width; - pc_tvSize.height = height; - setTvSize(); - dMeter2Info_onWide2D(); -} -#else void mDoGph_gInf_c::onWide() { mWide = TRUE; setTvSize(); dMeter2Info_onWide2D(); } -#endif void mDoGph_gInf_c::offWide() { mWide = FALSE; @@ -800,8 +744,11 @@ void mDoGph_gInf_c::updateSafeAreaBounds() { return; } + u32 renderWidth = 0; + u32 renderHeight = 0; + AuroraGetRenderSize(&renderWidth, &renderHeight); if (windowSize.native_fb_width == 0 || windowSize.native_fb_height == 0 || - windowSize.fb_width == 0 || windowSize.fb_height == 0) + renderWidth == 0 || renderHeight == 0) { return; } @@ -814,23 +761,25 @@ void mDoGph_gInf_c::updateSafeAreaBounds() { const f32 safeRight = static_cast(safeRect.x + safeRect.w) * nativeScaleX; const f32 safeBottom = static_cast(safeRect.y + safeRect.h) * nativeScaleY; - const f32 viewportLeft = - (static_cast(windowSize.native_fb_width) - static_cast(windowSize.fb_width)) * - 0.5f; - const f32 viewportTop = - (static_cast(windowSize.native_fb_height) - static_cast(windowSize.fb_height)) * - 0.5f; - const f32 viewportRight = viewportLeft + static_cast(windowSize.fb_width); - const f32 viewportBottom = viewportTop + static_cast(windowSize.fb_height); + f32 viewportWidth = static_cast(windowSize.native_fb_width); + f32 viewportHeight = static_cast(windowSize.native_fb_height); + const f32 targetAspect = viewportWidth / viewportHeight; + const f32 contentAspect = static_cast(renderWidth) / static_cast(renderHeight); + if (targetAspect > contentAspect) { + viewportWidth = std::max(1.0f, std::round(viewportHeight * contentAspect)); + } else if (targetAspect < contentAspect) { + viewportHeight = std::max(1.0f, std::round(viewportWidth / contentAspect)); + } - const f32 leftInset = std::max(0.0f, safeLeft - viewportLeft) * - (m_widthF / static_cast(windowSize.fb_width)); - const f32 topInset = std::max(0.0f, safeTop - viewportTop) * - (m_heightF / static_cast(windowSize.fb_height)); - const f32 rightInset = std::max(0.0f, viewportRight - safeRight) * - (m_widthF / static_cast(windowSize.fb_width)); - const f32 bottomInset = std::max(0.0f, viewportBottom - safeBottom) * - (m_heightF / static_cast(windowSize.fb_height)); + const f32 viewportLeft = (static_cast(windowSize.native_fb_width) - viewportWidth) * 0.5f; + const f32 viewportTop = (static_cast(windowSize.native_fb_height) - viewportHeight) * 0.5f; + const f32 viewportRight = viewportLeft + viewportWidth; + const f32 viewportBottom = viewportTop + viewportHeight; + + const f32 leftInset = std::max(0.0f, safeLeft - viewportLeft) * (m_widthF / viewportWidth); + const f32 topInset = std::max(0.0f, safeTop - viewportTop) * (m_heightF / viewportHeight); + const f32 rightInset = std::max(0.0f, viewportRight - safeRight) * (m_widthF / viewportWidth); + const f32 bottomInset = std::max(0.0f, viewportBottom - safeBottom) * (m_heightF / viewportHeight); const f32 safeMinXF = m_minXF + leftInset; const f32 safeMinYF = m_minYF + topInset; @@ -851,13 +800,13 @@ void mDoGph_gInf_c::updateSafeAreaBounds() { m_safeHeightF = safeHeightF; } -void mDoGph_gInf_c::setWindowSize(AuroraWindowSize const& size) { - JUTVideo::getManager()->setWindowSize(size); - dComIfGp_setWindow(0, 0.0f, 0.0f, getWidth(), getHeight(), 0.0f, 1.0f, 0, 2); - mFader->mBox.set(0, 0, getWidth(), getHeight()); - - f32 newWidth = (getWidth() / getHeight()) * 448.0f; - onWide(newWidth, 448.0f); +void mDoGph_gInf_c::updateRenderSize() { + u32 width, height; + AuroraGetRenderSize(&width, &height); + JUTVideo::getManager()->setRenderSize(width, height); + l_tvSize[1].width = static_cast(static_cast(width) / static_cast(height) * + static_cast(l_tvSize[1].height)); + onWide(); } #endif @@ -954,9 +903,6 @@ int mDoGph_AfterOfDraw() { JUTVideo::getManager()->setRenderMode(mDoMch_render_c::getRenderModeObj()); mDoGph_gInf_c::endFrame(); -#ifdef TARGET_PC - dusk::frame_interp::notify_sim_tick_complete(); -#endif return 1; } @@ -996,7 +942,7 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_ GXProject(param_0->lookat.center.x, param_0->lookat.center.y, param_0->lookat.center.z, param_0->viewMtx, sp4C, sp34, &sp1C, &sp18, &sp14); - + param_2 = (0xFF0000 - (int)(16777215.0f * sp14)) >> 8; param_2 = cLib_minMaxLimit(param_2, -0x400, 0); } @@ -1209,6 +1155,9 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_ GXSetProjection(ortho, GX_ORTHOGRAPHIC); GXSetCurrentMtx(0); +#ifdef TARGET_PC + if (dusk::getSettings().game.enableDepthOfField) +#endif if (l_tevColor0.a > -255 && sp8 == 1) { GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXPosition3s16(x_orig, y_orig_pos, -5); @@ -1361,8 +1310,8 @@ void mDoGph_gInf_c::bloom_c::draw2() { if (mMonoColor.a == 0 && !enabled) return; - f32 width = mDoGph_gInf_c::getWidth(); - f32 height = mDoGph_gInf_c::getHeight(); + f32 width = JUTVideo::getManager()->getRenderWidth(); + f32 height = JUTVideo::getManager()->getRenderHeight(); GXLoadTexObj(getFrameBufferTexObj(), GX_TEXMAP0); GXSetNumChans(0); @@ -1446,7 +1395,7 @@ void mDoGph_gInf_c::bloom_c::draw2() { CopyToTexObj(&tmpTex[texNo], texNo, rect.w, rect.h); return &tmpTex[texNo]; }; - + auto divQuad = [&](int divNo) { auto const& rect = divRects[divNo]; f32 x0 = rect.x / width; @@ -1479,8 +1428,8 @@ void mDoGph_gInf_c::bloom_c::draw2() { } if (enabled) { - GXCreateFrameBuffer(width * 0.75f, height * 0.5f); - GXSetViewport(0.0f, 0.0f, width, height, 0.0f, 1.0f); // use oversized viewport to make the math easier + GXCreateFrameBuffer(divRects[2].x + divRects[2].w, divRects[1].y + divRects[1].h); + GXSetViewportRender(0.0f, 0.0f, width, height, 0.0f, 1.0f); // use oversized viewport to make the math easier GXSetNumTevStages(3); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); @@ -1517,7 +1466,7 @@ void mDoGph_gInf_c::bloom_c::draw2() { GXTexObj* texPass0 = divCopyTex(Pass0, 2); GXLoadTexObj(texPass0, GX_TEXMAP0); - f32 blurScale = mBlureSize * ((448.0f / getHeight()) / 6400.0f); + f32 blurScale = mBlureSize * ((448.0f / height) / 6400.0f); // Setup blur filter TEV. GXSetNumTexGens(8); @@ -1551,7 +1500,7 @@ void mDoGph_gInf_c::bloom_c::draw2() { // This is applied over two passes, the second one with an alpha of 25%; however, the clipping that this introduces is a bit integral to the look, // so we do the same thing, letting it clip. float brightnessF32 = (mBlureRatio * 16 / 255.0f); - + // Distribute the brightness through the total number of passes. f32 totalNumPasses = (divNum - divStart + 1); float brightnessPerPass = 255.0f * powf(brightnessF32, 1.0f / totalNumPasses); @@ -1623,13 +1572,8 @@ void mDoGph_gInf_c::bloom_c::draw() { bool enabled = mEnable && m_buffer != NULL; if (mMonoColor.a != 0 || enabled) { -#if TARGET_PC - f32 width = mDoGph_gInf_c::getWidth(); - f32 height = mDoGph_gInf_c::getHeight(); -#else f32 width = FB_WIDTH; f32 height = FB_HEIGHT; -#endif GXSetViewport(0.0f, 0.0f, width, height, 0.0f, 1.0f); GXSetScissor(0, 0, width, height); @@ -1744,7 +1688,7 @@ void mDoGph_gInf_c::bloom_c::draw() { GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); for (int texCoord = (int)GX_TEXCOORD1; texCoord < (int)GX_MAX_TEXCOORD; texCoord++) { GXSetTexCoordGen((GXTexCoordID)texCoord, GX_TG_MTX2x4, GX_TG_TEX0, texMtxID); - + #if TARGET_PC f32 dVar15 = mBlureSize * ((448.0f / height) / 6400.0f); #else @@ -1885,7 +1829,7 @@ static void retry_captue_frame(view_class* param_0, view_port_class* param_1, in var_r23 = height >> 1; GXSetTexCopySrc(x_orig, y_orig_pos, width, height); #ifdef TARGET_PC - GXSetTexCopyDst(width, height, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE); + GXSetTexCopyDst(width, height, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_FALSE); #else GXSetTexCopyDst(var_r24, var_r23, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE); #endif @@ -2114,8 +2058,6 @@ int mDoGph_Painter() { #if TARGET_PC dusk::g_imguiConsole.PreDraw(); - - const u32 pending_ui_ticks = dusk::frame_interp::begin_presentation_ui_pass(); #endif #if DEBUG @@ -2123,7 +2065,7 @@ int mDoGph_Painter() { #endif #ifdef TARGET_PC - for (u32 i = 0; i < pending_ui_ticks; ++i) + if (dusk::frame_interp::get_ui_tick_pending()) #endif { dComIfGp_particle_calcMenu(); @@ -2143,8 +2085,7 @@ int mDoGph_Painter() { j3dSys.drawInit(); GXSetDither(GX_ENABLE); - J2DOrthoGraph ortho(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), -1.0f, - 1.0f); + J2DOrthoGraph ortho(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, -1.0f, 1.0f); ortho.setOrtho(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), -1.0f, 1.0f); @@ -2190,13 +2131,8 @@ int mDoGph_Painter() { view_port_class new_port; new_port.x_orig = 0.0f; new_port.y_orig = 0.0f; - #if TARGET_PC - new_port.width = mDoGph_gInf_c::getWidth(); - new_port.height = mDoGph_gInf_c::getHeight(); - #else new_port.width = FB_WIDTH; new_port.height = FB_HEIGHT; - #endif new_port.near_z = view_port->near_z; new_port.far_z = view_port->far_z; new_port.scissor = view_port->scissor; @@ -2214,7 +2150,7 @@ int mDoGph_Painter() { view_port->height); #ifdef TARGET_PC - // Frame interpolation: Call setViewMtx earlier so that it's interpolated in time for draw_info to use it + // FRAME INTERP NOTE: Call setViewMtx earlier so that it's interpolated in time for draw_info to use it j3dSys.setViewMtx(camera_p->view.viewMtx); JPADrawInfo draw_info(j3dSys.getViewMtx(), camera_p->view.fovy, camera_p->view.aspect); #else @@ -2250,7 +2186,7 @@ int mDoGph_Painter() { dComIfGp_setCurrentView(&camera_p->view); dComIfGp_setCurrentViewport(view_port); GXSetProjection(camera_p->view.projMtx, GX_PERSPECTIVE); - + #if DEBUG captureScreenSetProjection(camera_p->view.projMtx); #endif @@ -2327,7 +2263,7 @@ int mDoGph_Painter() { #endif GX_DEBUG_GROUP(dComIfGd_drawOpaListPacket); - + #if DEBUG // "drawing up to special-use drawing (Opaque) except J3D (Rendering)" fapGm_HIO_c::stopCpuTimer("J3D以外などの特殊用(不透明)描画まで(レンダリング)"); @@ -2409,7 +2345,7 @@ int mDoGph_Painter() { GX_DEBUG_GROUP(dComIfGd_drawXluListInvisible); } } - + #if DEBUG // "drawing up to projection (Translucent)" @@ -2513,12 +2449,8 @@ int mDoGph_Painter() { retry_captue_frame(&camera_p->view, view_port, dComIfGp_getCameraZoomForcus(camera_id)); } - - #if TARGET_PC - GXSetViewport(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, 1.0f); - #else + GXSetViewport(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f); - #endif Mtx m2; Mtx44 m; @@ -2615,12 +2547,7 @@ int mDoGph_Painter() { if (strcmp(dComIfGp_getStartStageName(), "F_SP127") != 0 && (mDoGph_gInf_c::isFade() & 0x80) == 0) { -#ifdef TARGET_PC - mDoGph_AdvanceFadeState(pending_ui_ticks); - mDoGph_DrawStoredFade(); -#else mDoGph_gInf_c::calcFade(); -#endif } #if DEBUG @@ -2686,7 +2613,7 @@ int mDoGph_Painter() { GXSetClipMode(GX_CLIP_ENABLE); #if TARGET_PC - for (u32 i = 0; i < pending_ui_ticks; ++i) + if (dusk::frame_interp::get_ui_tick_pending()) #endif { dDlst_list_c::calcWipe(); @@ -2740,12 +2667,7 @@ int mDoGph_Painter() { if (strcmp(dComIfGp_getStartStageName(), "F_SP127") == 0 || (mDoGph_gInf_c::isFade() & 0x80) != 0) { -#ifdef TARGET_PC - mDoGph_AdvanceFadeState(pending_ui_ticks); - mDoGph_DrawStoredFade(); -#else mDoGph_gInf_c::calcFade(); -#endif } GX_DEBUG_GROUP(dComIfGp_particle_draw2DmenuFore, &draw_info3); @@ -2778,18 +2700,10 @@ int mDoGph_Painter() { #if TARGET_PC dusk::g_imguiConsole.PostDraw(); - - if (dusk::getSettings().game.enableFrameInterpolation) { - JFWDisplay::getManager()->setFaderSimSteps(pending_ui_ticks); - } #endif mDoGph_gInf_c::endRender(); -#ifdef TARGET_PC - dusk::frame_interp::end_presentation_ui_pass(); -#endif - #if WIDESCREEN_SUPPORT mDoGph_gInf_c::offWideZoom(); #endif diff --git a/src/m_Do/m_Do_lib.cpp b/src/m_Do/m_Do_lib.cpp index b541490353..921681d464 100644 --- a/src/m_Do/m_Do_lib.cpp +++ b/src/m_Do/m_Do_lib.cpp @@ -95,8 +95,13 @@ void mDoLib_project(Vec* src, Vec* dst) { xOffset = (0.5f * ((2.0f * viewPort->x_orig) + viewPort->width)) - (int)(FB_WIDTH / 2); xSize = FB_WIDTH; } else { +#if TARGET_PC + xOffset = mDoGph_gInf_c::getSafeMinXF(); + xSize = viewPort->width * mDoGph_gInf_c::hudAspectScaleUp; +#else xOffset = viewPort->x_orig; xSize = viewPort->width; +#endif } if (viewPort->y_orig != 0.0f) { @@ -108,73 +113,15 @@ void mDoLib_project(Vec* src, Vec* dst) { } dst->x = ((0.5f + (multVec.x * calcFloat)) * xSize) + xOffset; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + dst->x = ((0.5f + (-multVec.x * calcFloat)) * xSize) + xOffset; + } + #endif + dst->y = ((0.5f + (multVec.y * (-calcFloat))) * ySize) + yOffset; } - -#if TARGET_PC -void mDoLib_project(Vec* src, Vec* dst, JGeometry::TBox2 viewport) { - if (dComIfGd_getView() == NULL) { - dst->x = 0.0f; - dst->y = 0.0f; - dst->z = 0.0f; - return; - } - - { int unused; } - - Vec multVec; - cMtx_multVec(*dComIfGd_getProjViewMtx(), src, &multVec); - - f32 calcFloat = (src->x * (*dComIfGd_getProjViewMtx())[3][0]) + - (src->y * (*dComIfGd_getProjViewMtx())[3][1]) + - (src->z * (*dComIfGd_getProjViewMtx())[3][2]) + - (*dComIfGd_getProjViewMtx())[3][3]; - if (multVec.z >= 0.0f) { - multVec.z = 0.0f; - } - if (calcFloat <= 0.0f) { - if (calcFloat == 0.0f) { - dst->z = multVec.z * 500000.0f; - } else { - dst->z = multVec.z * (0.5f / calcFloat); - } - calcFloat = 500000.0f; - } else { - calcFloat = 0.5f / calcFloat; - dst->z = multVec.z * calcFloat; - } - - f32 xOffset; - f32 yOffset; - f32 xSize; - f32 ySize; - if (viewport.i.x != 0.0f) { - xOffset = (0.5f * ((2.0f * viewport.i.x) + viewport.f.x)) - (int)(FB_WIDTH / 2); - xSize = FB_WIDTH; - } else { - #if TARGET_PC - xOffset = mDoGph_gInf_c::getSafeMinXF(); - xSize = viewport.f.x * mDoGph_gInf_c::hudAspectScaleUp; - #else - xOffset = viewport.i.x; - xSize = viewport.f.x; - #endif - } - - if (viewport.i.y != 0.0f) { - yOffset = (0.5f * ((2.0f * viewport.i.y) + viewport.f.y)) - (int)(FB_HEIGHT / 2); - ySize = FB_HEIGHT; - } else { - yOffset = viewport.i.y; - ySize = viewport.f.y; - } - - dst->x = ((0.5f + (multVec.x * calcFloat)) * xSize) + xOffset; - dst->y = ((0.5f + (multVec.y * (-calcFloat))) * ySize) + yOffset; -} -#endif - void mDoLib_pos2camera(Vec* src, Vec* dst) { if (dComIfGd_getView() == NULL) { dst->x = 0.0f; diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 6fd58772b9..cc593bfb24 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -42,7 +42,6 @@ #include "SSystem/SComponent/c_counter.h" #include -#include #include #include #include @@ -51,6 +50,7 @@ #include "dusk/crash_reporting.h" #include "dusk/dusk.h" #include "dusk/frame_interpolation.h" +#include "dusk/game_clock.h" #include "dusk/gyro.h" #include "dusk/imgui/ImGuiEngine.hpp" #include "dusk/logging.h" @@ -66,9 +66,14 @@ #include "SDL3/SDL_filesystem.h" #include "cxxopts.hpp" +#include "d/actor/d_a_movie_player.h" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/config.hpp" #include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/settings.h" +#include "dusk/discord_presence.hpp" +#include "tracy/Tracy.hpp" +#include "f_pc/f_pc_draw.h" #include "tracy/Tracy.hpp" #if RANDOMIZER_ONLY @@ -97,6 +102,8 @@ const int audioHeapSize = 0x14D800; bool dusk::IsRunning = true; bool dusk::IsShuttingDown = false; bool dusk::IsGameLaunched = false; +bool dusk::IsFocusPaused = false; +std::filesystem::path dusk::ConfigPath; #endif s32 LOAD_COPYDATE(void*) { @@ -129,9 +136,6 @@ s32 LOAD_COPYDATE(void*) { AuroraInfo auroraInfo; AuroraStats dusk::lastFrameAuroraStats; float dusk::frameUsagePct = 0.0f; -const char* configPath; - -AuroraWindowSize preLaunchUIWindowSize; bool launchUILoop() { while (dusk::IsRunning && !dusk::IsGameLaunched) { @@ -141,9 +145,6 @@ bool launchUILoop() { case AURORA_SDL_EVENT: dusk::g_imguiConsole.HandleSDLEvent(event->sdl); break; - case AURORA_WINDOW_RESIZED: - preLaunchUIWindowSize = event->windowSize; - break; case AURORA_DISPLAY_SCALE_CHANGED: dusk::ImGuiEngine_Initialize(event->windowSize.scale); break; @@ -207,12 +208,7 @@ void main01(void) { OSReport("Entering Main Loop (main01)...\n"); - if (preLaunchUIWindowSize.width != 0) - mDoGph_gInf_c::setWindowSize(preLaunchUIWindowSize); - - constexpr float kSimStepSeconds = 1.0 / 30.0; - auto previous_time = std::chrono::steady_clock::now(); - float accumulator = kSimStepSeconds; + dusk::game_clock::ensure_initialized(); do { // 1. Update Window Events @@ -223,9 +219,16 @@ void main01(void) { goto eventsDone; case AURORA_SDL_EVENT: dusk::g_imguiConsole.HandleSDLEvent(event->sdl); - break; - case AURORA_WINDOW_RESIZED: - mDoGph_gInf_c::setWindowSize(event->windowSize); + if (event->sdl.type == SDL_EVENT_WINDOW_FOCUS_LOST && + dusk::getSettings().game.pauseOnFocusLost) { + dusk::IsFocusPaused = true; + dusk::audio::SetPaused(true); + } else if (event->sdl.type == SDL_EVENT_WINDOW_FOCUS_GAINED && + dusk::IsFocusPaused) { + dusk::IsFocusPaused = false; + dusk::audio::SetPaused(false); + dusk::game_clock::reset_frame_timer(); + } break; case AURORA_DISPLAY_SCALE_CHANGED: dusk::ImGuiEngine_Initialize(event->windowSize.scale); @@ -239,10 +242,12 @@ void main01(void) { eventsDone:; - auto current_time = std::chrono::steady_clock::now(); - float frame_seconds = std::chrono::duration(current_time - previous_time).count(); - previous_time = current_time; - accumulator += frame_seconds; + if (dusk::IsFocusPaused) { + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + continue; + } + + const dusk::game_clock::MainLoopPacer pacing = dusk::game_clock::advance_main_loop(); VIWaitForRetrace(); @@ -252,26 +257,35 @@ void main01(void) { continue; } - if (dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit) { - dusk::frame_interp::notify_presentation_frame(); - if (accumulator >= kSimStepSeconds) { + mDoGph_gInf_c::updateRenderSize(); + + dusk::frame_interp::begin_frame(pacing.is_interpolating, pacing.do_sim_tick, pacing.interpolation_step); + if (pacing.is_interpolating) { + if (pacing.do_sim_tick) { + dusk::frame_interp::set_ui_tick_pending(true); mDoCPd_c::read(); - dusk::gyro::read(kSimStepSeconds); + DuskDebugPad(); + dusk::gyro::read(pacing.sim_pace); fapGm_Execute(); mDoAud_Execute(); - accumulator = 0.0f; + dusk::game_clock::reset_accumulator(); } - dusk::frame_interp::interpolate(static_cast(accumulator / kSimStepSeconds)); - { - dusk::frame_interp::PresentationCameraScope presentation_camera; - cAPIGph_Painter(); + dusk::frame_interp::interpolate(); + dusk::frame_interp::begin_presentation_camera(); + if (!pacing.do_sim_tick) { + // run draw functions for anything specially marked to handle interp on non-sim + // ticks + fpcM_DrawIterater((fpcM_DrawIteraterFunc)fpcM_Draw); } + cAPIGph_Painter(); + dusk::frame_interp::end_presentation_camera(); + dusk::frame_interp::set_ui_tick_pending(false); } else { - accumulator = 0.0f; - + dusk::frame_interp::set_ui_tick_pending(true); + // Game Inputs mDoCPd_c::read(); - dusk::gyro::read(frame_seconds); + dusk::gyro::read(pacing.presentation_dt_seconds); // EXECUTE GAME LOGIC & RENDER // This calls mDoGph_Painter -> JFWDisplay -> GX Functions @@ -283,6 +297,11 @@ void main01(void) { aurora_end_frame(); FrameMark; + +#ifdef DUSK_DISCORD_RPC + dusk::discord::RunCallbacks(); + dusk::discord::UpdatePresence(); +#endif } while (dusk::IsRunning); exit:; @@ -365,7 +384,7 @@ static void ApplyCVarOverrides(const cxxopts::OptionValue& option) { } } -static const char* CalculateConfigPath() { +static std::filesystem::path CalculateConfigPath() { const auto result = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); if (!result) { DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); @@ -374,13 +393,12 @@ static const char* CalculateConfigPath() { return result; } -static void EnsureInitialPipelineCache(const char* configDir) { - if (configDir == nullptr) { +static void EnsureInitialPipelineCache(const std::filesystem::path& configDir) { + if (configDir.empty()) { return; } - const std::filesystem::path configPathFs(configDir); - const std::filesystem::path pipelineCachePath = configPathFs / "pipeline_cache.db"; + const std::filesystem::path pipelineCachePath = configDir / "pipeline_cache.db"; if (std::filesystem::exists(pipelineCachePath)) { return; } @@ -399,10 +417,10 @@ static void EnsureInitialPipelineCache(const char* configDir) { } std::error_code ec; - std::filesystem::create_directories(configPathFs, ec); + std::filesystem::create_directories(configDir, ec); if (ec) { DuskLog.warn("Failed to create config directory '{}' for pipeline cache: {}", - configPathFs.string(), ec.message()); + configDir.string(), ec.message()); return; } @@ -504,47 +522,53 @@ int game_main(int argc, char* argv[]) { exit(1); } - configPath = CalculateConfigPath(); + dusk::ConfigPath = CalculateConfigPath(); const auto startupLogLevel = static_cast(parsed_arg_options["log-level"].as()); - dusk::InitializeFileLogging(configPath, startupLogLevel); + dusk::InitializeFileLogging(dusk::ConfigPath, startupLogLevel); dusk::config::LoadFromUserPreferences(); ApplyCVarOverrides(parsed_arg_options["cvar"]); dusk::InitializeCrashReporting(); - EnsureInitialPipelineCache(configPath); - - AuroraConfig config{}; - config.appName = dusk::AppName; - config.configPath = configPath; - config.vsync = dusk::getSettings().video.enableVsync; - config.startFullscreen = dusk::getSettings().video.enableFullscreen; - config.windowPosX = -1; - config.windowPosY = -1; - config.windowWidth = defaultWindowWidth * 2; - config.windowHeight = defaultWindowHeight * 2; - config.desiredBackend = ResolveDesiredBackend(parsed_arg_options); - config.logCallback = &aurora_log_callback; - config.logLevel = startupLogLevel; - config.mem1Size = 256 * 1024 * 1024; - config.mem2Size = 24 * 1024 * 1024; - config.allowJoystickBackgroundEvents = true; - config.imGuiInitCallback = &aurora_imgui_init_callback; - config.allowTextureReplacements = true; - config.allowTextureDumps = false; - + EnsureInitialPipelineCache(dusk::ConfigPath); PADSetDefaultMapping(&defaultPadMapping); - auroraInfo = aurora_initialize(argc, argv, &config); + { + const auto configPathString = dusk::ConfigPath.string(); + AuroraConfig config{}; + config.appName = dusk::AppName; + config.configPath = configPathString.c_str(); + config.vsync = dusk::getSettings().video.enableVsync; + config.startFullscreen = dusk::getSettings().video.enableFullscreen; + config.windowPosX = -1; + config.windowPosY = -1; + config.windowWidth = defaultWindowWidth * 2; + config.windowHeight = defaultWindowHeight * 2; + config.desiredBackend = ResolveDesiredBackend(parsed_arg_options); + config.logCallback = &aurora_log_callback; + config.logLevel = startupLogLevel; + config.mem1Size = 256 * 1024 * 1024; + config.mem2Size = 24 * 1024 * 1024; + config.allowJoystickBackgroundEvents = true; + config.imGuiInitCallback = &aurora_imgui_init_callback; + config.allowTextureReplacements = true; + config.allowTextureDumps = false; + auroraInfo = aurora_initialize(argc, argv, &config); + } + +#ifdef DUSK_DISCORD_RPC + dusk::discord::Initialize(); +#endif VISetWindowTitle( fmt::format("Dusk {} [{}]", DUSK_WC_DESCRIBE, dusk::backend_name(auroraInfo.backend)) .c_str()); if (dusk::getSettings().video.lockAspectRatio) { - VILockAspectRatio(defaultAspectRatioW, defaultAspectRatioH); + AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT); } else { - VIUnlockAspectRatio(); + AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH); } + VISetFrameBufferScale(dusk::getSettings().game.internalResolutionScale.getValue()); dusk::audio::SetMasterVolume(dusk::getSettings().audio.masterVolume / 100.0f); dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb); @@ -568,6 +592,9 @@ int game_main(int argc, char* argv[]) { // pre game launch ui main loop if (!launchUILoop()) { dusk::ShutdownCrashReporting(); +#ifdef DUSK_DISCORD_RPC + dusk::discord::Shutdown(); +#endif aurora_shutdown(); return 0; } @@ -605,6 +632,8 @@ int game_main(int argc, char* argv[]) { main01(); + dusk::MoviePlayerShutdown(); + dusk::ShutdownCrashReporting(); dusk::ShutdownFileLogging(); fflush(stdout); @@ -615,6 +644,9 @@ int game_main(int argc, char* argv[]) { // Notifies all CVs and causes threads to exit OSResetSystem(OS_RESET_SHUTDOWN, 0, 0); +#ifdef DUSK_DISCORD_RPC + dusk::discord::Shutdown(); +#endif aurora_shutdown(); return 0;