From b26f3f7f5131a20fe591cf8a6d8e9d829c220462 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 31 May 2026 17:18:11 -0600 Subject: [PATCH 01/32] Update aurora & fix rebuilding on iOS reconfigure --- extern/aurora | 2 +- ios.toolchain.cmake | 57 ++++++++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/extern/aurora b/extern/aurora index 7dd107e1a4..839af55c15 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 7dd107e1a4b7ce07abbe11568f9f8c3031b4df0a +Subproject commit 839af55c1588a5c4be5c178c0bb30cfd0a0e4385 diff --git a/ios.toolchain.cmake b/ios.toolchain.cmake index fb6052fc9b..73d617ae45 100644 --- a/ios.toolchain.cmake +++ b/ios.toolchain.cmake @@ -952,45 +952,70 @@ if(DEFINED APPLE_TARGET_TRIPLE) set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") endif() +function(ios_toolchain_set_cached_flags variable description) + set(clean_flags "${${variable}}") + foreach(toolchain_flag IN LISTS ARGN) + if(NOT "${toolchain_flag}" STREQUAL "") + string(REPLACE "${toolchain_flag}" "" clean_flags "${clean_flags}") + endif() + endforeach() + string(REGEX REPLACE "[ \t]+" " " clean_flags "${clean_flags}") + string(STRIP "${clean_flags}" clean_flags) + + set(final_flags "") + foreach(toolchain_flag IN LISTS ARGN) + if(NOT "${toolchain_flag}" STREQUAL "") + string(APPEND final_flags " ${toolchain_flag}") + endif() + endforeach() + if(NOT "${clean_flags}" STREQUAL "") + string(APPEND final_flags " ${clean_flags}") + endif() + string(REGEX REPLACE "[ \t]+" " " final_flags "${final_flags}") + string(STRIP "${final_flags}" final_flags) + + set(${variable} "${final_flags}" CACHE INTERNAL "${description}") +endfunction() + #Check if Xcode generator is used since that will handle these flags automagically if(CMAKE_GENERATOR MATCHES "Xcode") message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") else() - set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all C build types.") + ios_toolchain_set_cached_flags(CMAKE_C_FLAGS "Flags used by the compiler during all C build types." + "${C_TARGET_FLAGS}" "${APPLE_TARGET_TRIPLE_FLAG}" "${SDK_NAME_VERSION_FLAGS}" "${OBJC_LEGACY_VARS}" "${BITCODE}" "${VISIBILITY}") set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") - set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all CXX build types.") + ios_toolchain_set_cached_flags(CMAKE_CXX_FLAGS "Flags used by the compiler during all CXX build types." + "${C_TARGET_FLAGS}" "${APPLE_TARGET_TRIPLE_FLAG}" "${SDK_NAME_VERSION_FLAGS}" "${OBJC_LEGACY_VARS}" "${BITCODE}" "${VISIBILITY}") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") if(NAMED_LANGUAGE_SUPPORT_INT) - set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all OBJC build types.") + ios_toolchain_set_cached_flags(CMAKE_OBJC_FLAGS "Flags used by the compiler during all OBJC build types." + "${C_TARGET_FLAGS}" "${APPLE_TARGET_TRIPLE_FLAG}" "${SDK_NAME_VERSION_FLAGS}" "${BITCODE}" "${VISIBILITY}" "${FOBJC_ARC}" "${OBJC_VARS}") set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") - set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all OBJCXX build types.") + ios_toolchain_set_cached_flags(CMAKE_OBJCXX_FLAGS "Flags used by the compiler during all OBJCXX build types." + "${C_TARGET_FLAGS}" "${APPLE_TARGET_TRIPLE_FLAG}" "${SDK_NAME_VERSION_FLAGS}" "${BITCODE}" "${VISIBILITY}" "${FOBJC_ARC}" "${OBJC_VARS}") set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") endif() - set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all C link types.") - set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all CXX link types.") + ios_toolchain_set_cached_flags(CMAKE_C_LINK_FLAGS "Flags used by the compiler for all C link types." + "${C_TARGET_FLAGS}" "${SDK_NAME_VERSION_FLAGS}" "-Wl,-search_paths_first") + ios_toolchain_set_cached_flags(CMAKE_CXX_LINK_FLAGS "Flags used by the compiler for all CXX link types." + "${C_TARGET_FLAGS}" "${SDK_NAME_VERSION_FLAGS}" "-Wl,-search_paths_first") if(NAMED_LANGUAGE_SUPPORT_INT) - set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all OBJC link types.") - set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all OBJCXX link types.") + ios_toolchain_set_cached_flags(CMAKE_OBJC_LINK_FLAGS "Flags used by the compiler for all OBJC link types." + "${C_TARGET_FLAGS}" "${SDK_NAME_VERSION_FLAGS}" "-Wl,-search_paths_first") + ios_toolchain_set_cached_flags(CMAKE_OBJCXX_LINK_FLAGS "Flags used by the compiler for all OBJCXX link types." + "${C_TARGET_FLAGS}" "${SDK_NAME_VERSION_FLAGS}" "-Wl,-search_paths_first") endif() set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp" CACHE INTERNAL "Flags used by the compiler for all ASM build types.") From 37abcaf616c353ddd9ec1ee48bb2922e2c95e327 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 31 May 2026 17:18:11 -0600 Subject: [PATCH 02/32] Use BUILD_SHARED_LIBS=OFF on base linux/macos presets --- CMakePresets.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 748c4df396..6c02a06a26 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -46,6 +46,10 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/${presetName}", "cacheVariables": { + "BUILD_SHARED_LIBS": { + "type": "BOOL", + "value": false + }, "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install" }, "vendor": { @@ -201,6 +205,10 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/${presetName}", "cacheVariables": { + "BUILD_SHARED_LIBS": { + "type": "BOOL", + "value": false + }, "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install" }, "vendor": { @@ -414,11 +422,7 @@ "value": true }, "CMAKE_OSX_DEPLOYMENT_TARGET": "11.0", - "CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew", - "BUILD_SHARED_LIBS": { - "type": "BOOL", - "value": false - } + "CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew" } }, { From bd90c3fc69047b6ae8d8c57522e462a01a8d0baf Mon Sep 17 00:00:00 2001 From: qubitnano <146656568+qubitnano@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:22:45 -0400 Subject: [PATCH 03/32] flake.nix: devendor aurora, add BUILD_SHARED_LIBS=OFF (#1956) * flake.nix: devendor aurora * flake.nix: nixfmt * flake.nix: add BUILD_SHARED_LIBS=OFF --- flake.nix | 241 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 126 insertions(+), 115 deletions(-) diff --git a/flake.nix b/flake.nix index 0a2156a4d5..713acef074 100644 --- a/flake.nix +++ b/flake.nix @@ -57,12 +57,22 @@ inherit (pkgs.stdenv.hostPlatform) isDarwin; hasNodPrebuilt = nodPrebuiltInfo ? ${system}; - aurora = pkgs.fetchFromGitHub { - owner = "encounter"; - repo = "aurora"; - rev = "10006618ee493f248b8597e4dfa1d2871d76a1d9"; - hash = "sha256-lY2xuVyB7aPJ9+2wwLRB3F5U/BuPSxdSpegdG+qNd9o="; - }; + aurora = builtins.pathExists "${self}/extern/aurora/CMakeLists.txt"; + needSubmodules = '' + dusklight: The aurora submodule is not vendored. Add submodules=1 to build. + + As a flake input: + + dusklight.url = "git+https://github.com/TwilitRealm/dusklight?ref=main&submodules=1"; + + nix command: + + nix run 'git+https://github.com/TwilitRealm/dusklight?submodules=1' + + Local checkout: + + nix run '.?submodules=1#dusklight' + ''; dawn = pkgs.fetchzip { url = "https://github.com/encounter/dawn-build/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz"; @@ -153,119 +163,120 @@ }; }; - dusklight = pkgs.stdenv.mkDerivation { - pname = "dusklight"; - version = versionSuffix; - src = ./.; + dusklight = + if !aurora then + throw needSubmodules + else + pkgs.stdenv.mkDerivation { + pname = "dusklight"; + version = versionSuffix; + src = ./.; - postUnpack = '' - chmod -R u+w "$sourceRoot" - rm -rf "$sourceRoot/extern/aurora" - mkdir -p "$sourceRoot/extern" - cp -r ${aurora} "$sourceRoot/extern/aurora" - chmod -R u+w "$sourceRoot/extern/aurora" - substituteInPlace "$sourceRoot/extern/aurora/CMakeLists.txt" \ - --replace-warn "add_subdirectory(tests)" "" - ''; - - nativeBuildInputs = [ - pkgs.cmake - pkgs.ninja - pkgs.pkg-config - pkgs.python3 - pkgs.python3Packages.markupsafe - ] - ++ lib.optionals (!isDarwin) [ pkgs.autoPatchelfHook ]; - - buildInputs = [ - pkgs.sdl3 - pkgs.freetype - pkgs.zstd - pkgs.cxxopts - pkgs.nlohmann_json - pkgs.xxHash - pkgs.abseil-cpp - pkgs.zlib - pkgs.libpng - pkgs.libjpeg_turbo - pkgs.curl - pkgs.openssl - ] - ++ lib.optionals isDarwin [ - pkgs.apple-sdk_15 - pkgs.libiconv - ] - ++ lib.optionals (!isDarwin) [ - pkgs.libGL - pkgs.libGLU - pkgs.libglvnd - pkgs.vulkan-loader - pkgs.libX11 - pkgs.libxcb - pkgs.libXcursor - pkgs.libxi - pkgs.libxrandr - pkgs.libxscrnsaver - pkgs.libxtst - pkgs.libxinerama - pkgs.libxkbcommon - pkgs.wayland - pkgs.libdecor - pkgs.alsa-lib - pkgs.libpulseaudio - pkgs.pipewire - pkgs.dbus - pkgs.udev - pkgs.libusb1 - pkgs.libunwind - pkgs.gtk3 - ]; - - cmakeBuildType = "RelWithDebInfo"; - ninjaFlags = [ "dusklight" ]; - - cmakeFlags = [ - "-DDUSK_VERSION_OVERRIDE=${versionSuffix}" - "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" - "-DAURORA_DAWN_PROVIDER=package" - "-DAURORA_DAWN_LINKAGE=static" - "-DAURORA_NOD_PROVIDER=package" - "-DAURORA_NOD_LINKAGE=static" - "-DAURORA_SDL3_PROVIDER=system" - ] - ++ lib.mapAttrsToList (key: src: "-DFETCHCONTENT_SOURCE_DIR_${key}=${src}") fetchContentDirs; - - installPhase = - if isDarwin then - '' - runHook preInstall - mkdir -p "$out/Applications" - cp -r Dusklight.app "$out/Applications/Dusklight.app" - runHook postInstall - '' - else - '' - runHook preInstall - install -Dm755 dusklight "$out/bin/dusklight" - cp -r "$src/res" "$out/bin/res" - install -Dm644 "$src/platforms/freedesktop/dev.twilitrealm.dusk.desktop" \ - "$out/share/applications/dev.twilitrealm.dusk.desktop" - for size in 16 32 48 64 128 256 512 1024; do - install -Dm644 "$src/platforms/freedesktop/''${size}x''${size}/apps/dev.twilitrealm.dusk.png" \ - "$out/share/icons/hicolor/''${size}x''${size}/apps/dev.twilitrealm.dusk.png" - done - runHook postInstall + postUnpack = '' + chmod -R u+w "$sourceRoot" + substituteInPlace "$sourceRoot/extern/aurora/CMakeLists.txt" \ + --replace-warn "add_subdirectory(tests)" "" ''; - dontStrip = true; + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.pkg-config + pkgs.python3 + pkgs.python3Packages.markupsafe + ] + ++ lib.optionals (!isDarwin) [ pkgs.autoPatchelfHook ]; - meta = { - description = "Dusklight — native PC port of the Twilight Princess decompilation"; - homepage = "https://github.com/zeldaret/tp"; - platforms = supportedSystems; - mainProgram = "dusklight"; - }; - }; + buildInputs = [ + pkgs.sdl3 + pkgs.freetype + pkgs.zstd + pkgs.cxxopts + pkgs.nlohmann_json + pkgs.xxHash + pkgs.abseil-cpp + pkgs.zlib + pkgs.libpng + pkgs.libjpeg_turbo + pkgs.curl + pkgs.openssl + ] + ++ lib.optionals isDarwin [ + pkgs.apple-sdk_15 + pkgs.libiconv + ] + ++ lib.optionals (!isDarwin) [ + pkgs.libGL + pkgs.libGLU + pkgs.libglvnd + pkgs.vulkan-loader + pkgs.libX11 + pkgs.libxcb + pkgs.libXcursor + pkgs.libxi + pkgs.libxrandr + pkgs.libxscrnsaver + pkgs.libxtst + pkgs.libxinerama + pkgs.libxkbcommon + pkgs.wayland + pkgs.libdecor + pkgs.alsa-lib + pkgs.libpulseaudio + pkgs.pipewire + pkgs.dbus + pkgs.udev + pkgs.libusb1 + pkgs.libunwind + pkgs.gtk3 + ]; + + cmakeBuildType = "RelWithDebInfo"; + ninjaFlags = [ "dusklight" ]; + + cmakeFlags = [ + "-DDUSK_VERSION_OVERRIDE=${versionSuffix}" + "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" + "-DAURORA_DAWN_PROVIDER=package" + "-DAURORA_DAWN_LINKAGE=static" + "-DAURORA_NOD_PROVIDER=package" + "-DAURORA_NOD_LINKAGE=static" + "-DAURORA_SDL3_PROVIDER=system" + "-DBUILD_SHARED_LIBS=OFF" + ] + ++ lib.mapAttrsToList (key: src: "-DFETCHCONTENT_SOURCE_DIR_${key}=${src}") fetchContentDirs; + + installPhase = + if isDarwin then + '' + runHook preInstall + mkdir -p "$out/Applications" + cp -r Dusklight.app "$out/Applications/Dusklight.app" + runHook postInstall + '' + else + '' + runHook preInstall + install -Dm755 dusklight "$out/bin/dusklight" + cp -r "$src/res" "$out/bin/res" + install -Dm644 "$src/platforms/freedesktop/dev.twilitrealm.dusk.desktop" \ + "$out/share/applications/dev.twilitrealm.dusk.desktop" + for size in 16 32 48 64 128 256 512 1024; do + install -Dm644 "$src/platforms/freedesktop/''${size}x''${size}/apps/dev.twilitrealm.dusk.png" \ + "$out/share/icons/hicolor/''${size}x''${size}/apps/dev.twilitrealm.dusk.png" + done + runHook postInstall + ''; + + dontStrip = true; + + meta = { + description = "Dusklight — native PC port of the Twilight Princess decompilation"; + homepage = "https://github.com/zeldaret/tp"; + platforms = supportedSystems; + mainProgram = "dusklight"; + }; + }; # Tooling common to every supported host (Linux and macOS). commonDevTools = [ From 7af51e53bdf61d1202c5c353884f325c98b1f859 Mon Sep 17 00:00:00 2001 From: Reilly Brogan Date: Mon, 1 Jun 2026 21:23:13 -0500 Subject: [PATCH 04/32] Update aurora and adapt for libzstd changes (#1950) * Update aurora and adapt for libzstd changes Signed-off-by: Reilly Brogan * Fix android build failure with zstd Signed-off-by: Reilly Brogan * Another attempt at fixing Android Signed-off-by: Reilly Brogan --------- Signed-off-by: Reilly Brogan --- CMakeLists.txt | 2 +- CMakePresets.json | 8 ++++++++ extern/aurora | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d118d37d5..eaa5bc8202 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,7 +344,7 @@ set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::p aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt Threads::Threads) -list(APPEND GAME_LIBS libzstd_static) +list(APPEND GAME_LIBS zstd::libzstd) if (DUSK_ENABLE_SENTRY_NATIVE) list(APPEND GAME_LIBS sentry) diff --git a/CMakePresets.json b/CMakePresets.json index 6c02a06a26..d83ed045aa 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -335,6 +335,14 @@ "type": "BOOL", "value": false }, + "CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": { + "type": "BOOL", + "value": true + }, + "CMAKE_DISABLE_FIND_PACKAGE_zstd": { + "type": "BOOL", + "value": true + }, "AURORA_SDL3_VERSION": "3.4.8", "AURORA_SDL3_REF": "refs/tags/release-3.4.8" } diff --git a/extern/aurora b/extern/aurora index 839af55c15..49e61d7dad 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 839af55c1588a5c4be5c178c0bb30cfd0a0e4385 +Subproject commit 49e61d7dadfd0b59ba716a9f503225e0d46f707e From 21692d5a789b55a07faf3e591e2cb8a27b1d5fac Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 2 Jun 2026 04:23:28 +0200 Subject: [PATCH 05/32] Fix portable mode Unicode (#1893) * Fix portable mode Unicode Fixes https://github.com/TwilitRealm/dusklight/issues/1839 * Use path_from_utf8 instead Huh yeah sure we have that apparently --- src/dusk/data.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dusk/data.cpp b/src/dusk/data.cpp index dc666dd236..2720651699 100644 --- a/src/dusk/data.cpp +++ b/src/dusk/data.cpp @@ -111,7 +111,7 @@ std::filesystem::path get_pref_path() { Log.fatal("Unable to get PrefPath: {}", SDL_GetError()); } - std::filesystem::path result{reinterpret_cast(prefPath)}; + std::filesystem::path result = path_from_utf8(prefPath); SDL_free(prefPath); return result; } @@ -128,7 +128,7 @@ std::filesystem::path base_path_relative(const std::filesystem::path& path) { if (!basePath) { return path; } - return std::filesystem::path{basePath} / path; + return path_from_utf8(basePath) / path; } std::filesystem::path default_data_path(const std::filesystem::path& prefPath) { From b531936a1f271034cbe85292bf860fa464d2e796 Mon Sep 17 00:00:00 2001 From: Reilly Brogan Date: Mon, 1 Jun 2026 21:24:02 -0500 Subject: [PATCH 06/32] linux: Add metainfo file (#1860) * linux: Add metainfo file Split from https://github.com/TwilitRealm/dusklight/pull/1191 and adjusted for the correct appId and to remove any trademarks. Credit to @Gabantax Signed-off-by: Reilly Brogan * Update metainfo per suggestions Signed-off-by: Reilly Brogan --------- Signed-off-by: Reilly Brogan --- .../dev.twilitrealm.dusk.metainfo.xml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 platforms/freedesktop/dev.twilitrealm.dusk.metainfo.xml diff --git a/platforms/freedesktop/dev.twilitrealm.dusk.metainfo.xml b/platforms/freedesktop/dev.twilitrealm.dusk.metainfo.xml new file mode 100644 index 0000000000..ac99f15ddc --- /dev/null +++ b/platforms/freedesktop/dev.twilitrealm.dusk.metainfo.xml @@ -0,0 +1,38 @@ + + + dev.twilitrealm.dusk + dev.twilitrealm.dusk.desktop + Dusklight + Native port of a classic adventure game + + Twilit Realm + + https://twilitrealm.dev + https://github.com/TwilitRealm/dusklight/issues + CC0-1.0 + CC0-1.0 + + + console + gamepad + + +

+ Dusklight is a reverse-engineered reimplementation of a classic adventure game. + It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience. +

+
+ + + dusklight + dev.twilitrealm.dusk.desktop + + + + + +

Initial Flatpak release.

+
+
+
+
From bd9b81f70050c8697833c8f1f5aa438c9c95f6dd Mon Sep 17 00:00:00 2001 From: Irastris Date: Tue, 2 Jun 2026 01:37:53 -0400 Subject: [PATCH 07/32] Add mouse input option for the third-person camera (#1011) * Untie existing mouse logic from gyro * A bit more mouse cleanup before I start building off it * Rebase and last bit of cleanup * Fix rebase mistake, don't apply invertFirstPerson to gyro or mouse input * Remove the deprecated ImGui toast system * Add Mouse Camera option in preparation for its use * WIP, add mouse controls for the third-person camera * Various helpText revisions * Enable free camera on horseback * Untie mouse camera and free camera options Either being enabled now allows the underlying freecam logic to run * Allow simultaneous C-stick and mouse input * Combine mouse sensitivities for both aim and camera * Add option for inverting mouse Y * Refactor cursor visibility handling * Tighten aim capture condition and constrain cursor to window region * Tidying my trash * Last bit of housekeeping so I'm satisfied * Don't write code while sleep deprived * Fix my sloppy merge and a few helpText updates * Disable control stick aim when mouse aim is active * Use same conditions for cursor grabbing as for capture --- files.cmake | 1 + include/d/actor/d_a_alink.h | 2 +- include/d/d_camera.h | 1 + include/dusk/gyro.h | 5 +- include/dusk/mouse.h | 12 ++ include/dusk/settings.h | 6 +- src/d/actor/d_a_alink_dusk.cpp | 2 +- src/d/actor/d_a_alink_link.inc | 42 +++++-- src/d/d_camera.cpp | 29 ++++- src/dusk/gyro.cpp | 55 +-------- src/dusk/imgui/ImGuiConsole.cpp | 65 ---------- src/dusk/imgui/ImGuiConsole.hpp | 13 -- src/dusk/mouse.cpp | 211 ++++++++++++++++++++++++++++++++ src/dusk/settings.cpp | 12 +- src/dusk/ui/document.cpp | 15 --- src/dusk/ui/document.hpp | 2 - src/dusk/ui/menu_bar.cpp | 2 - src/dusk/ui/prelaunch.cpp | 2 - src/dusk/ui/settings.cpp | 103 ++++++---------- src/m_Do/m_Do_main.cpp | 7 ++ 20 files changed, 349 insertions(+), 238 deletions(-) create mode 100644 include/dusk/mouse.h create mode 100644 src/dusk/mouse.cpp diff --git a/files.cmake b/files.cmake index fe558ba41f..99ccfc23c9 100644 --- a/files.cmake +++ b/files.cmake @@ -1432,6 +1432,7 @@ set(DUSK_FILES src/dusk/game_clock.cpp src/dusk/globals.cpp src/dusk/gyro.cpp + src/dusk/mouse.cpp src/dusk/gamepad_color.cpp src/dusk/autosave.cpp src/dusk/http/http.hpp diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index 9f69900bcb..4fb8abd929 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -4551,7 +4551,7 @@ public: #if TARGET_PC void handleWolfHowl(); void handleQuickTransform(); - bool checkGyroAimContext(); + bool checkAimContext(); void onIronBallChainInterpCallback(); diff --git a/include/d/d_camera.h b/include/d/d_camera.h index 7b12493360..0698bbbe5a 100644 --- a/include/d/d_camera.h +++ b/include/d/d_camera.h @@ -1037,6 +1037,7 @@ public: bool test1Camera(s32); bool test2Camera(s32); #if TARGET_PC + static bool canUseFreeCam(); bool freeCamera(); bool executeDebugFlyCam(); void deactivateDebugFlyCam(); diff --git a/include/dusk/gyro.h b/include/dusk/gyro.h index a206100739..abb56640e5 100644 --- a/include/dusk/gyro.h +++ b/include/dusk/gyro.h @@ -1,5 +1,4 @@ -#ifndef DUSK_GYRO_H -#define DUSK_GYRO_H +#pragma once namespace dusk::gyro { void read(float dt); @@ -14,5 +13,3 @@ bool get_sensor_keep_alive(); void set_sensor_keep_alive(bool value); bool rollgoal_gyro_enabled(); } // namespace dusk::gyro - -#endif diff --git a/include/dusk/mouse.h b/include/dusk/mouse.h new file mode 100644 index 0000000000..514d14534a --- /dev/null +++ b/include/dusk/mouse.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace dusk::mouse { +void read(); +void getAimDeltas(float& out_yaw, float& out_pitch); +void getCameraDeltas(float& out_yaw, float& out_pitch); +void handle_event(const SDL_Event& event) noexcept; +void onFocusLost(); +void onFocusGained(); +} // namespace dusk::mouse diff --git a/include/dusk/settings.h b/include/dusk/settings.h index f48f5862ca..5fd53ce289 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -187,7 +187,6 @@ struct UserSettings { ConfigVar midnasLamentNonStop; // Input - ConfigVar gyroMode; ConfigVar enableGyroAim; ConfigVar enableGyroRollgoal; ConfigVar gyroSensitivityX; @@ -197,6 +196,11 @@ struct UserSettings { ConfigVar gyroDeadband; ConfigVar gyroInvertPitch; ConfigVar gyroInvertYaw; + ConfigVar enableMouseCamera; + ConfigVar enableMouseAim; + ConfigVar mouseAimSensitivity; + ConfigVar mouseCameraSensitivity; + ConfigVar invertMouseY; ConfigVar freeCamera; ConfigVar invertCameraXAxis; ConfigVar invertCameraYAxis; diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 8c1d415ae0..b787eebcaa 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -144,7 +144,7 @@ void daAlink_c::handleQuickTransform() { procCoMetamorphoseInit(); } -bool daAlink_c::checkGyroAimContext() { +bool daAlink_c::checkAimContext() { switch (mProcID) { case PROC_SUBJECTIVITY: case PROC_SWIM_SUBJECTIVITY: diff --git a/src/d/actor/d_a_alink_link.inc b/src/d/actor/d_a_alink_link.inc index 636aabdffe..4d93f39457 100644 --- a/src/d/actor/d_a_alink_link.inc +++ b/src/d/actor/d_a_alink_link.inc @@ -11,8 +11,9 @@ #include "d/actor/d_a_tag_mhint.h" #if TARGET_PC -#include "dusk/gyro.h" #include "dusk/action_bindings.h" +#include "dusk/gyro.h" +#include "dusk/mouse.h" #endif bool daAlink_c::checkNoSubjectModeCamera() { @@ -120,18 +121,28 @@ BOOL daAlink_c::setBodyAngleToCamera() { var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c); } - shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f))); - sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f))); - - if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) { +#if TARGET_PC + if (dusk::getSettings().game.enableMouseAim && checkAimContext()) { sp8 = mBodyAngle.x; + } else +#endif + { + shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f))); + sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f))); + + if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) { + sp8 = mBodyAngle.x; + } } } else { sp8 = mBodyAngle.x; } #if TARGET_PC - if (dusk::getSettings().game.enableGyroAim && checkGyroAimContext()) { + if ((dusk::getSettings().game.enableGyroAim || + dusk::getSettings().game.enableMouseAim) && + checkAimContext()) + { f32 gyro_scale = 1.0f; if (checkWolfEyeUp()) { gyro_scale *= 0.6f; @@ -141,12 +152,21 @@ BOOL daAlink_c::setBodyAngleToCamera() { gyro_scale /= dComIfGp_getCameraZoomScale(field_0x317c); } - f32 gy_yaw = 0.f; - f32 gy_pitch = 0.f; - dusk::gyro::getAimDeltas(gy_yaw, gy_pitch); + f32 final_yaw = 0.f; + f32 final_pitch = 0.f; + if (dusk::getSettings().game.enableMouseAim) { + dusk::mouse::getAimDeltas(final_yaw, final_pitch); + } + if (dusk::getSettings().game.enableGyroAim) { + f32 gyro_yaw = 0.f; + f32 gyro_pitch = 0.f; + dusk::gyro::getAimDeltas(gyro_yaw, gyro_pitch); + final_yaw += gyro_yaw; + final_pitch += gyro_pitch; + } - shape_angle.y = shape_angle.y + cM_rad2s(gy_yaw * gyro_scale); - sp8 = sp8 + cM_rad2s(gy_pitch * gyro_scale); + shape_angle.y = shape_angle.y + cM_rad2s(final_yaw * gyro_scale); + sp8 = sp8 + cM_rad2s(final_pitch * gyro_scale); if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) { sp8 = mBodyAngle.x; diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 8e7e48949a..50e9f073b6 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -32,6 +32,8 @@ #include "dusk/frame_interpolation.h" #include "dusk/logging.h" #include "dusk/action_bindings.h" +#include "dusk/mouse.h" +#include "dusk/settings.h" #include "imgui.h" #endif @@ -7638,12 +7640,16 @@ void dCamera_c::deactivateDebugFlyCam() { mDebugFlyCam.initialized = false; } +bool dCamera_c::canUseFreeCam() { + return dusk::getSettings().game.freeCamera || dusk::getSettings().game.enableMouseCamera; +} + bool dCamera_c::freeCamera() { - if (dusk::getSettings().game.freeCamera && mGear == 1) { + if (canUseFreeCam() && mGear == 1) { mGear = 0; } - if (!dusk::getSettings().game.freeCamera || mCamStyle == 70) + if (!canUseFreeCam() || mCamStyle == 70) { mCamParam.mManualMode = 0; return false; @@ -7669,6 +7675,17 @@ bool dCamera_c::freeCamera() { mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraYSensitivity * 5.0f; } + f32 yaw_rad = 0.0f; + f32 pitch_rad = 0.0f; + dusk::mouse::getCameraDeltas(yaw_rad, pitch_rad); + if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) && + !dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8)) + { + mCamParam.mManualMode = 1; + mCamParam.freeXAngle += MTXRadToDeg(yaw_rad); + mCamParam.freeYAngle += -MTXRadToDeg(pitch_rad); + } + fopAc_ac_c* player = dComIfGp_getPlayer(0); if (!mCamParam.mManualMode || player == nullptr) { return false; @@ -9350,6 +9367,10 @@ bool dCamera_c::rideCamera(s32 param_0) { mStyleSettle.mFinished = true; } +#if TARGET_PC + freeCamera(); +#endif + return true; } @@ -9479,6 +9500,10 @@ bool dCamera_c::rideCamera(s32 param_0) { setFlag(0x400); } +#if TARGET_PC + freeCamera(); +#endif + return true; } diff --git a/src/dusk/gyro.cpp b/src/dusk/gyro.cpp index 680d500631..1e2e379960 100644 --- a/src/dusk/gyro.cpp +++ b/src/dusk/gyro.cpp @@ -2,8 +2,6 @@ #include "dusk/ui/ui.hpp" #include "d/actor/d_a_alink.h" -#include -#include #include namespace dusk::gyro { @@ -16,14 +14,11 @@ constexpr float kGravityEmaAlpha = 0.1f; constexpr float kMinGravityProjection = 0.2f; // Let roll contribute more strongly as the pad approaches an upright posture. constexpr float kRollAimBoostMax = 2.0f; -constexpr float kMousePixelToRad = 0.0025f; bool s_sensor_enabled = false; bool s_accel_enabled = false; bool s_was_aiming = false; bool s_have_gravity_baseline = false; -bool s_mouse_enabled = false; -bool s_mouse_relative = false; float s_smooth_gx = 0.0f; float s_smooth_gy = 0.0f; float s_smooth_gz = 0.0f; @@ -43,7 +38,6 @@ void reset_filter_state() { s_baseline_gravity_y = s_baseline_gravity_z = 0.0f; s_was_aiming = false; s_have_gravity_baseline = false; - s_mouse_enabled = false; s_yaw_rad = s_pitch_rad = s_roll_rad = 0.0f; s_rollgoal_ax = s_rollgoal_az = 0; } @@ -72,7 +66,7 @@ bool get_sensor_keep_alive() { return s_sensor_keep_alive; } void set_sensor_keep_alive(bool value) { s_sensor_keep_alive = value; } bool rollgoal_gyro_enabled() { - return getSettings().game.enableGyroRollgoal && getSettings().game.gyroMode.getValue() != GyroMode::Mouse; + return getSettings().game.enableGyroRollgoal; } bool queryGyroAimContext() { @@ -85,7 +79,7 @@ bool queryGyroAimContext() { return false; } - return link->checkGyroAimContext() && dComIfGp_checkCameraAttentionStatus(link->field_0x317c, 0x10); + return link->checkAimContext() && dComIfGp_checkCameraAttentionStatus(link->field_0x317c, 0x10); } void read(float dt) { @@ -94,26 +88,6 @@ void read(float dt) { const bool aim_just_ended = !aim_active && s_was_aiming; s_was_aiming = aim_active; - const bool mouse_mode = getSettings().game.gyroMode.getValue() == GyroMode::Mouse; - const bool mouse_gyro_active = !ui::any_document_visible() && mouse_mode && (aim_active || s_sensor_keep_alive); - SDL_Window* window = aurora::window::get_sdl_window(); - if (window != nullptr && mouse_gyro_active != s_mouse_relative && - SDL_SetWindowRelativeMouseMode(window, mouse_gyro_active)) - { - s_mouse_relative = mouse_gyro_active; - } - - if (mouse_gyro_active && !s_mouse_enabled && window != nullptr) { - const AuroraWindowSize sz = aurora::window::get_window_size(); - const float cx = static_cast(sz.width) * 0.5f; - const float cy = static_cast(sz.height) * 0.5f; - SDL_WarpMouseInWindow(window, cx, cy); - float discard_x = 0.0f; - float discard_y = 0.0f; - SDL_GetRelativeMouseState(&discard_x, &discard_y); - } - s_mouse_enabled = mouse_gyro_active; - if (!s_sensor_keep_alive && !aim_active) { disable_pad_sensors(); reset_filter_state(); @@ -126,31 +100,6 @@ void read(float dt) { s_have_gravity_baseline = false; } - if (mouse_mode && !mouse_gyro_active) { - s_pitch_rad = 0.0f; - s_yaw_rad = 0.0f; - s_roll_rad = 0.0f; - return; - } - - if (mouse_mode) { - disable_pad_sensors(); - - float mx_rel = 0.0f; - float my_rel = 0.0f; - SDL_GetRelativeMouseState(&mx_rel, &my_rel); - // Convert pixels to radians - s_pitch_rad = my_rel * kMousePixelToRad * getSettings().game.gyroSensitivityY; - s_yaw_rad = -mx_rel * kMousePixelToRad * getSettings().game.gyroSensitivityX; - s_roll_rad = 0.0f; - - s_pitch_rad = getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; - s_yaw_rad = getSettings().game.gyroInvertYaw ? -s_yaw_rad : s_yaw_rad; - s_yaw_rad = getSettings().game.enableMirrorMode ? -s_yaw_rad : s_yaw_rad; - - return; - } - if (!s_sensor_enabled) { if (!PADHasSensor(PAD_CHAN0, PAD_SENSOR_GYRO)) { return; diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index d8b85b2d63..5248bc9d36 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -12,7 +12,6 @@ #include "ImGuiConsole.hpp" #include "ImGuiEngine.hpp" #include "JSystem/JUtility/JUTGamePad.h" -#include "SDL3/SDL_mouse.h" #include "dusk/action_bindings.h" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/config.hpp" @@ -61,10 +60,6 @@ namespace dusk { ImGui::TextUnformatted(text.data(), text.data() + text.size()); } - void DuskToast(std::string_view message, float duration) { - g_imguiConsole.AddToast(message, duration); - } - void ImGuiTextCenter(std::string_view text) { ImGui::NewLine(); float fontSize = ImGui::CalcTextSize( @@ -376,22 +371,6 @@ namespace dusk { m_menuTools.ShowActorSpawner(); } - // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. - if (dusk::getSettings().game.gyroMode.getValue() != GyroMode::Mouse) - { - ImGuiIO& io = ImGui::GetIO(); - if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) { - mouseHideTimer = 0.0f; - ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; // Imgui will re-show cursor. - } else if (mouseHideTimer <= 3.0f) { - mouseHideTimer += ImGui::GetIO().DeltaTime; - } else { - ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; - SDL_HideCursor(); - } - } - - ShowToasts(); } void ImGuiConsole::PostDraw() { @@ -545,50 +524,6 @@ namespace dusk { return false; } - void ImGuiConsole::AddToast(std::string_view message, float duration) { - m_toasts.emplace_back(std::string(message), duration); - } - - void ImGuiConsole::ShowToasts() { - if (m_toasts.empty()) { - return; - } - auto& toast = m_toasts.front(); - const float dt = ImGui::GetIO().DeltaTime; - toast.remain -= dt; - toast.current += dt; - - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - const ImVec2 workPos = viewport->WorkPos; - const ImVec2 workSize = viewport->WorkSize; - constexpr float padding = 10.0f; - const ImVec2 windowPos{workPos.x + workSize.x / 2, workPos.y + workSize.y - padding}; - ImGui::SetNextWindowPos(windowPos, ImGuiCond_Always, ImVec2{0.5f, 1.f}); - - const float alpha = std::min({toast.remain, toast.current, 1.f}); - ImGui::SetNextWindowBgAlpha(alpha * 0.65f); - ImVec4 textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text); - textColor.w *= alpha; - ImVec4 borderColor = ImGui::GetStyleColorVec4(ImGuiCol_Border); - borderColor.w *= alpha; - ImGui::PushStyleColor(ImGuiCol_Text, textColor); - ImGui::PushStyleColor(ImGuiCol_Border, borderColor); - if (ImGui::Begin("Toast", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | - ImGuiWindowFlags_NoSavedSettings | - ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | - ImGuiWindowFlags_NoMove)) - { - ImGuiStringViewText(toast.message); - } - ImGui::End(); - ImGui::PopStyleColor(2); - - if (toast.remain <= 0.f) { - m_toasts.pop_front(); - } - } - void ImGuiConsole::ShowPipelineProgress() { const auto* stats = aurora_get_stats(); const u32 queuedPipelines = stats->queuedPipelines; diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index c1adc427eb..d97f1b00e6 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -24,29 +24,17 @@ public: void PostDraw(); static bool CheckMenuViewToggle(ImGuiKey key, bool& active); - void AddToast(std::string_view message, float duration = 3.f); private: - struct Toast { - std::string message; - float remain; - float current = 0.f; - Toast(std::string message, float duration) noexcept : message(std::move(message)), - remain(duration) {} - }; - - float mouseHideTimer = 0.0f; bool m_isHidden = true; bool m_isLaunchInitialized = false; ImGuiWindow* m_dragScrollWindow = nullptr; ImVec2 m_dragScrollLastMousePos = {}; - std::deque m_toasts; // Keep always last ImGuiMenuTools m_menuTools; - void ShowToasts(); void ShowPipelineProgress(); void UpdateDragScroll(); }; @@ -60,7 +48,6 @@ std::string BytesToString(size_t bytes); void SetOverlayWindowLocation(int corner); bool ShowCornerContextMenu(int& corner, int avoidCorner); void ImGuiStringViewText(std::string_view text); -void DuskToast(std::string_view message, float duration = 3.f); void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); void ImGuiEndGroupPanel(); void ImGuiTextCenter(std::string_view text); diff --git a/src/dusk/mouse.cpp b/src/dusk/mouse.cpp new file mode 100644 index 0000000000..8ebfaf60cb --- /dev/null +++ b/src/dusk/mouse.cpp @@ -0,0 +1,211 @@ +#include "dusk/mouse.h" +#include "dusk/settings.h" +#include "dusk/ui/ui.hpp" +#include "d/actor/d_a_alink.h" +#include "d/d_com_inf_game.h" + +#include +#include +#include +#include + +namespace dusk::mouse { +namespace { +constexpr float kMousePixelToRad = 0.0025f; +constexpr int kIdleHideFrames = 99; // Approx. 3 seconds with 33ms ticks + +float s_aim_yaw_rad = 0.0f; +float s_aim_pitch_rad = 0.0f; +float s_camera_yaw_rad = 0.0f; +float s_camera_pitch_rad = 0.0f; +int s_idle_frames = 0; + +void reset_deltas() { + s_aim_yaw_rad = s_aim_pitch_rad = 0.0f; + s_camera_yaw_rad = s_camera_pitch_rad = 0.0f; +} + +bool queryMouseAimContext() { + if (!getSettings().game.enableMouseAim) { + return false; + } + + daAlink_c* link = daAlink_getAlinkActorClass(); + if (link == nullptr) { + return false; + } + + return link->checkAimContext() && dComIfGp_checkCameraAttentionStatus(link->field_0x317c, 0x10); +} + +bool wantMouseCapture() { + return getSettings().game.enableMouseCamera.getValue() || queryMouseAimContext(); +} + +bool isWindowFocused(SDL_Window* window) { + if (window == nullptr) { + return false; + } + return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0; +} + +bool shouldCaptureMouse(SDL_Window* window) { + if (window == nullptr || ui::any_document_visible()) { + return false; + } + return wantMouseCapture() && isWindowFocused(window); +} + +bool syncCaptureState(SDL_Window* window, bool should_capture) { + if (window == nullptr) { + reset_deltas(); + return false; + } + + const bool was_captured = SDL_GetWindowRelativeMouseMode(window); + if (was_captured != should_capture) { + SDL_SetWindowMouseGrab(window, should_capture); + SDL_SetWindowRelativeMouseMode(window, should_capture); + } + + const bool is_captured = SDL_GetWindowRelativeMouseMode(window); + if (is_captured && !was_captured) { + const AuroraWindowSize sz = aurora::window::get_window_size(); + const float cx = static_cast(sz.width) * 0.5f; + const float cy = static_cast(sz.height) * 0.5f; + SDL_WarpMouseInWindow(window, cx, cy); + float discard_x = 0.0f; + float discard_y = 0.0f; + SDL_GetRelativeMouseState(&discard_x, &discard_y); + } + + if (!is_captured) { + reset_deltas(); + } + + return is_captured; +} + +void accumulateDeltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) { + const auto& game = getSettings().game; + const bool mirror_mode = game.enableMirrorMode.getValue(); + const bool invert_y = game.invertMouseY.getValue(); + + if (aim_active) { + const float aimSens = game.mouseAimSensitivity.getValue(); + s_aim_yaw_rad = -mx_rel * kMousePixelToRad * aimSens; + s_aim_pitch_rad = my_rel * kMousePixelToRad * aimSens; + s_aim_yaw_rad = mirror_mode ? -s_aim_yaw_rad : s_aim_yaw_rad; + s_aim_pitch_rad = invert_y ? -s_aim_pitch_rad : s_aim_pitch_rad; + } else { + s_aim_yaw_rad = s_aim_pitch_rad = 0.0f; + } + + if (camera_active) { + const float camSens = game.mouseCameraSensitivity.getValue(); + s_camera_yaw_rad = -mx_rel * kMousePixelToRad * camSens; + s_camera_pitch_rad = -my_rel * kMousePixelToRad * camSens; + s_camera_yaw_rad = mirror_mode ? -s_camera_yaw_rad : s_camera_yaw_rad; + s_camera_pitch_rad = invert_y ? -s_camera_pitch_rad : s_camera_pitch_rad; + } else { + s_camera_yaw_rad = s_camera_pitch_rad = 0.0f; + } +} + +void set_cursor_visible(bool visible) { + if (visible) { + ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; + SDL_ShowCursor(); + } else { + ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; + SDL_HideCursor(); + } +} + +void update_cursor_visibility(SDL_Window* window, bool captured) { + if (window == nullptr || !isWindowFocused(window)) { + return; + } + + if (captured) { + s_idle_frames = 0; + set_cursor_visible(false); + return; + } + + const ImGuiIO& io = ImGui::GetIO(); + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) { + s_idle_frames = 0; + set_cursor_visible(true); + return; + } + + if (s_idle_frames < kIdleHideFrames) { + ++s_idle_frames; + set_cursor_visible(true); + } else { + set_cursor_visible(false); + } +} +} // namespace + +void read() { + SDL_Window* window = aurora::window::get_sdl_window(); + const bool capture_active = syncCaptureState(window, shouldCaptureMouse(window)); + update_cursor_visibility(window, capture_active); + + if (!capture_active) { + return; + } + + const bool aim_active = capture_active && queryMouseAimContext(); + const bool camera_active = capture_active && getSettings().game.enableMouseCamera; + + float mx_rel = 0.0f; + float my_rel = 0.0f; + SDL_GetRelativeMouseState(&mx_rel, &my_rel); + accumulateDeltas(mx_rel, my_rel, camera_active, aim_active); +} + +void getAimDeltas(float& out_yaw, float& out_pitch) { + out_yaw = s_aim_yaw_rad; + out_pitch = s_aim_pitch_rad; +} + +void getCameraDeltas(float& out_yaw, float& out_pitch) { + out_yaw = 0.0f; + out_pitch = 0.0f; + + if (!getSettings().game.enableMouseCamera) { + return; + } + + out_yaw = s_camera_yaw_rad; + out_pitch = s_camera_pitch_rad; +} + +void handle_event(const SDL_Event& event) noexcept { + switch (event.type) { + case SDL_EVENT_WINDOW_FOCUS_LOST: + onFocusLost(); + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + onFocusGained(); + break; + } +} + +void onFocusLost() { + SDL_Window* window = aurora::window::get_sdl_window(); + if (window != nullptr) { + syncCaptureState(window, false); + } + s_idle_frames = 0; + set_cursor_visible(true); +} + +void onFocusGained() { + SDL_Window* window = aurora::window::get_sdl_window(); + syncCaptureState(window, shouldCaptureMouse(window)); +} +} // namespace dusk::mouse diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 3bea017e2c..3f189f0359 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -75,7 +75,6 @@ UserSettings g_userSettings = { .midnasLamentNonStop {"game.midnasLamentNonStop", false}, // Input - .gyroMode {"game.gyroMode", GyroMode::Sensor}, .enableGyroAim {"game.enableGyroAim", false}, .enableGyroRollgoal {"game.enableGyroRollgoal", false}, .gyroSensitivityX {"game.gyroSensitivityX", 1.0f}, @@ -85,6 +84,11 @@ UserSettings g_userSettings = { .gyroDeadband {"game.gyroDeadband", 0.04f}, .gyroInvertPitch {"game.gyroInvertPitch", false}, .gyroInvertYaw {"game.gyroInvertYaw", false}, + .enableMouseCamera {"game.enableMouseCamera", false}, + .enableMouseAim {"game.enableMouseAim", false}, + .mouseAimSensitivity {"game.mouseAimSensitivity", 1.0f}, + .mouseCameraSensitivity {"game.mouseCameraSensitivity", 1.0f}, + .invertMouseY {"game.invertMouseY", false}, .freeCamera {"game.freeCamera", false}, .invertCameraXAxis {"game.invertCameraXAxis", false}, .invertCameraYAxis {"game.invertCameraYAxis", false}, @@ -281,7 +285,6 @@ void registerSettings() { Register(g_userSettings.game.alwaysGreatspin); Register(g_userSettings.game.invincibleEnemies); Register(g_userSettings.game.enableFrameInterpolation); - Register(g_userSettings.game.gyroMode); Register(g_userSettings.game.enableGyroAim); Register(g_userSettings.game.enableGyroRollgoal); Register(g_userSettings.game.gyroSensitivityX); @@ -291,6 +294,11 @@ void registerSettings() { Register(g_userSettings.game.gyroSmoothing); Register(g_userSettings.game.gyroInvertPitch); Register(g_userSettings.game.gyroInvertYaw); + Register(g_userSettings.game.enableMouseCamera); + Register(g_userSettings.game.enableMouseAim); + Register(g_userSettings.game.mouseAimSensitivity); + Register(g_userSettings.game.mouseCameraSensitivity); + Register(g_userSettings.game.invertMouseY); Register(g_userSettings.game.freeCamera); Register(g_userSettings.game.debugFlyCam); Register(g_userSettings.game.debugFlyCamLockEvents); diff --git a/src/dusk/ui/document.cpp b/src/dusk/ui/document.cpp index 4296ac27d9..a7bcc3f9ed 100644 --- a/src/dusk/ui/document.cpp +++ b/src/dusk/ui/document.cpp @@ -5,7 +5,6 @@ #include "Z2AudioLib/Z2SeMgr.h" #include "m_Do/m_Do_audio.h" -#include namespace dusk::ui { namespace { @@ -107,7 +106,6 @@ bool Document::visible() const { bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (cmd == NavCommand::Menu) { - toggle_cursor_if_gyro(!visible()); mDoAud_seStartMenu(visible() ? kSoundMenuClose : kSoundMenuOpen); toggle(); return true; @@ -115,17 +113,4 @@ bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { return false; } -void Document::toggle_cursor_if_gyro(bool cursor_enabled) { - if (dusk::getSettings().game.gyroMode.getValue() == GyroMode::Mouse) - { - if (cursor_enabled) { - ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; - SDL_ShowCursor(); - } else { - ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; - SDL_HideCursor(); - } - } -} - } // namespace dusk::ui diff --git a/src/dusk/ui/document.hpp b/src/dusk/ui/document.hpp index eed489beb3..d0f4cae841 100644 --- a/src/dusk/ui/document.hpp +++ b/src/dusk/ui/document.hpp @@ -43,8 +43,6 @@ public: bool pending_close() const { return mPendingClose; } bool closed() const { return mClosed; } - void toggle_cursor_if_gyro(bool); - protected: virtual bool handle_nav_command(Rml::Event& event, NavCommand cmd); diff --git a/src/dusk/ui/menu_bar.cpp b/src/dusk/ui/menu_bar.cpp index 1be5c7abb0..068913d592 100644 --- a/src/dusk/ui/menu_bar.cpp +++ b/src/dusk/ui/menu_bar.cpp @@ -45,7 +45,6 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById( mTabBar = std::make_unique(mRoot, TabBar::Props{ .onClose = [this] { - toggle_cursor_if_gyro(false); mDoAud_seStartMenu(kSoundMenuClose); hide(false); }, @@ -219,7 +218,6 @@ bool MenuBar::handle_nav_command(Rml::Event& event, NavCommand cmd) { return true; } if (cmd == NavCommand::Cancel && visible()) { - toggle_cursor_if_gyro(false); mDoAud_seStartMenu(kSoundMenuClose); hide(false); return true; diff --git a/src/dusk/ui/prelaunch.cpp b/src/dusk/ui/prelaunch.cpp index ef6b6e5709..44b73b75ef 100644 --- a/src/dusk/ui/prelaunch.cpp +++ b/src/dusk/ui/prelaunch.cpp @@ -699,8 +699,6 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB return; } - toggle_cursor_if_gyro(false); - mDoAud_seStartMenu(kSoundPlay); show_menu_notification(); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 44fd9e1724..826a87c144 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -383,9 +383,7 @@ int float_setting_percent(ConfigVar& var) { } bool gyro_enabled() { - return getSettings().game.enableGyroAim || - (getSettings().game.enableGyroRollgoal && - getSettings().game.gyroMode.getValue() != GyroMode::Mouse); + return getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal; } struct ConfigBoolProps { @@ -453,7 +451,7 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar
Applies to the control stick only.", + 50, 200, 5, [] { return !getSettings().game.freeCamera; }); config_percent_select(leftPane, rightPane, getSettings().game.freeCameraYSensitivity, - "Free Camera Y Sensitivity", "Adjusts twin-stick camera Y axis sensitivity.", 50, 200, 5, + "Free Camera Y Sensitivity", + "Adjusts vertical free camera sensitivity.

Applies to the control stick only.", + 50, 200, 5, [] { return !getSettings().game.freeCamera; }); + addOption("Invert Camera X Axis", getSettings().game.invertCameraXAxis, + "Invert horizontal camera movement.

Applies to the control stick only."); + addOption("Invert Camera Y Axis", getSettings().game.invertCameraYAxis, + "Invert vertical camera movement.

Applies to the control stick only.", [] { return !getSettings().game.freeCamera; }); addOption("Invert First Person X Axis", getSettings().game.invertFirstPersonXAxis, - "Invert horizontal movement while aiming with items or first person camera. Applies only to the control stick (the gyroscope can be inverted in Input settings)."); + "Invert horizontal movement while aiming with items or first person camera.

Applies to the control stick only."); addOption("Invert First Person Y Axis", getSettings().game.invertFirstPersonYAxis, - "Invert vertical movement while aiming with items or first person camera. Applies only to the control stick (the gyroscope can be inverted in Input settings)."); - addOption("Invert Air/Swim X Axis", getSettings().game.invertAirSwimX, - "Invert horizontal movement while flying or swimming."); - addOption("Invert Air/Swim Y Axis", getSettings().game.invertAirSwimY, - "Invert vertical movement while flying or swimming."); + "Invert vertical movement while aiming with items or first person camera.

Applies to the control stick only."); leftPane.add_section("Gyro"); - leftPane.register_control( - leftPane.add_select_button({ - .key = "Gyro Input Method", - .getValue = - [] { - const auto mode = getSettings().game.gyroMode.getValue(); - const auto idx = static_cast(mode); - return Rml::String{kGyroInputModeLabels[idx]}; - }, - .isModified = - [] { - return getSettings().game.gyroMode.getValue() != - getSettings().game.gyroMode.getDefaultValue(); - }, - }), - rightPane, [](Pane& pane) { - for (size_t i = 0; i < kGyroInputModeLabels.size(); i++) { - pane - .add_button({ - .text = Rml::String{kGyroInputModeLabels[i]}, - .isSelected = - [i] { - return getSettings().game.gyroMode.getValue() == static_cast(i); - }, - }) - .on_pressed([i] { - mDoAud_seStartMenu(kSoundItemChange); - const GyroMode mode = static_cast(i); - getSettings().game.gyroMode.setValue(mode); - config::Save(); - }); - } - pane.add_rml( - "
Sensor reads motion directly from a supported controller's gyro via SDL.
" - "
Mouse treats mouse input as gyro, intended for use with the Steam Deck.
" - "
Mouse input cannot currently be used with Gyro Rollgoal."); - }); addOption("Gyro Aim", getSettings().game.enableGyroAim, "Enables gyro controls while in look mode, aiming a hawk, and aiming " "supported items.

Supported items include the Slingshot, Gale Boomerang, " "Hero's Bow, Clawshot(s), Ball and Chain, and Dominion Rod."); addOption("Gyro Rollgoal", getSettings().game.enableGyroRollgoal, - "Enables gyro controls for Rollgoal in Hena's Cabin.", - [] { return getSettings().game.gyroMode.getValue() == GyroMode::Mouse; }); + "Enables gyro controls for Rollgoal in Hena's Cabin."); config_percent_select(leftPane, rightPane, getSettings().game.gyroSensitivityY, "Gyro Pitch Sensitivity", "Controls vertical gyro aiming sensitivity.", 25, 400, 5, [] { return !gyro_enabled(); }); @@ -1025,10 +982,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { config_percent_select(leftPane, rightPane, getSettings().game.gyroSensitivityRollgoal, "Rollgoal Sensitivity", "Controls how strongly gyro input tilts the Rollgoal table.", 25, 400, 5, - [] { - return !getSettings().game.enableGyroRollgoal || - getSettings().game.gyroMode.getValue() == GyroMode::Mouse; - }); + [] { return !getSettings().game.enableGyroRollgoal; }); config_percent_select(leftPane, rightPane, getSettings().game.gyroDeadband, "Gyro Deadband", "Ignores small gyro movement to reduce drift and jitter.", 0, 50, 1, [] { return !gyro_enabled(); }); @@ -1039,8 +993,29 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { "Invert vertical gyro aiming.", [] { return !gyro_enabled(); }); addOption("Invert Gyro Yaw", getSettings().game.gyroInvertYaw, "Invert horizontal gyro aiming.", [] { return !gyro_enabled(); }); - + + leftPane.add_section("Mouse"); + addOption("Mouse Aim", getSettings().game.enableMouseAim, + "Enables mouse input while in look mode, aiming a hawk, and aiming " + "supported items.

Supported items include the Slingshot, Gale Boomerang, " + "Hero's Bow, Clawshot(s), Ball and Chain, and Dominion Rod."); + addOption("Mouse Camera", getSettings().game.enableMouseCamera, + "Enables mouse input for controlling the third-person camera."); + config_percent_select(leftPane, rightPane, getSettings().game.mouseAimSensitivity, + "Mouse Aim Sensitivity", "Controls mouse aim sensitivity.", 25, 400, 5, + [] { return !getSettings().game.enableMouseAim; }); + config_percent_select(leftPane, rightPane, getSettings().game.mouseCameraSensitivity, + "Mouse Camera Sensitivity", "Controls mouse camera sensitivity.", 25, 400, 5, + [] { return !getSettings().game.enableMouseCamera; }); + addOption("Invert Mouse Y", getSettings().game.invertMouseY, + "Invert vertical mouse control for both aiming and camera.", + [] { return !getSettings().game.enableMouseAim || !getSettings().game.enableMouseCamera; }); + leftPane.add_section("Gameplay"); + addOption("Invert Air/Swim X Axis", getSettings().game.invertAirSwimX, + "Invert horizontal movement while flying or swimming."); + addOption("Invert Air/Swim Y Axis", getSettings().game.invertAirSwimY, + "Invert vertical movement while flying or swimming."); addOption("Swap Direct Select Input", getSettings().game.swapDirectSelect, "Swap the controls for using Direct Select on the item wheel, making Direct Select the default and holding L to scroll the wheel."); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index bf37f964e6..987ae76dba 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -55,6 +55,7 @@ #include "dusk/frame_interpolation.h" #include "dusk/game_clock.h" #include "dusk/gyro.h" +#include "dusk/mouse.h" #include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/imgui/ImGuiEngine.hpp" #include "dusk/iso_validate.hpp" @@ -168,6 +169,7 @@ bool launchUILoop() { while (event != nullptr && event->type != AURORA_NONE) { switch (event->type) { case AURORA_SDL_EVENT: + dusk::mouse::handle_event(event->sdl); dusk::ui::handle_event(event->sdl); dusk::g_imguiConsole.HandleSDLEvent(event->sdl); break; @@ -246,12 +248,15 @@ void main01(void) { goto eventsDone; case AURORA_PAUSED: dusk::audio::SetPaused(true); + dusk::mouse::onFocusLost(); break; case AURORA_UNPAUSED: dusk::audio::SetPaused(false); dusk::game_clock::reset_frame_timer(); + dusk::mouse::onFocusGained(); break; case AURORA_SDL_EVENT: + dusk::mouse::handle_event(event->sdl); dusk::ui::handle_event(event->sdl); dusk::g_imguiConsole.HandleSDLEvent(event->sdl); break; @@ -288,6 +293,7 @@ void main01(void) { for (int sim_tick = 0; sim_tick < pacing.sim_ticks_to_run; ++sim_tick) { dusk::frame_interp::begin_sim_tick(); mDoCPd_c::read(); + dusk::mouse::read(); dusk::gyro::read(pacing.sim_pace); fapGm_Execute(); mDoAud_Execute(); @@ -310,6 +316,7 @@ void main01(void) { // Game Inputs mDoCPd_c::read(); + dusk::mouse::read(); dusk::gyro::read(pacing.presentation_dt_seconds); // EXECUTE GAME LOGIC & RENDER From f8ba14ea8f691ba9d2ddd19d5bf750ab9a53085e Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 3 Jun 2026 07:47:34 +0200 Subject: [PATCH 08/32] Optimize some special kankyo draw packets (housi, snow, odour) (#1970) * Slight dKankyo_housi_Packet documentation * Optimize dKyr_drawHousi (twilight squares) Now a single draw call rather than like 300 * Optimize dKyr_drawSnow Snowpeak stonks rising * Optimize dKyr_odour_draw --- include/d/d_kankyo_wether.h | 3 +- src/d/d_kankyo_rain.cpp | 115 +++++++++++++++++++++++++++--------- src/d/d_kankyo_wether.cpp | 6 +- 3 files changed, 93 insertions(+), 31 deletions(-) diff --git a/include/d/d_kankyo_wether.h b/include/d/d_kankyo_wether.h index 31aa1fd8e3..ff1ce7d9d5 100644 --- a/include/d/d_kankyo_wether.h +++ b/include/d/d_kankyo_wether.h @@ -198,6 +198,7 @@ struct HOUSI_EFF { /* 0x4C */ u16 field_0x4c; }; // Size: 0x50 +// Housi is the rising square particles in Twilight class dKankyo_housi_Packet : public J3DPacket { public: virtual void draw(); @@ -208,7 +209,7 @@ public: /* 0x0020 */ HOUSI_EFF mHousiEff[300]; /* 0x5DE0 */ u8 field_0x5de0[8]; /* 0x5DE8 */ f32 field_0x5de8; - /* 0x5DEC */ s16 field_0x5dec; + /* 0x5DEC */ s16 mHousiCount; }; // Size: 0x5DF0 struct CLOUD_EFF { diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 09e230c9fd..2cdd2ff2d3 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -929,7 +929,7 @@ void dKyr_housi_move() { if (g_env_light.mHousiCount != 0 || (g_env_light.mHousiCount == 0 && housi_packet->field_0x5de8 <= 0.0f)) { - housi_packet->field_0x5dec = g_env_light.mHousiCount; + housi_packet->mHousiCount = g_env_light.mHousiCount; } if (g_env_light.mHousiCount != 0) { @@ -938,7 +938,7 @@ void dKyr_housi_move() { cLib_addCalc(&housi_packet->field_0x5de8, 0.0f, 0.2f, 0.05f, 0.01f); } - if (housi_packet->field_0x5dec == 0) { + if (housi_packet->mHousiCount == 0) { return; } @@ -977,7 +977,7 @@ void dKyr_housi_move() { } } - for (int i = housi_packet->field_0x5dec - 1; i >= 0; i--) { + for (int i = housi_packet->mHousiCount - 1; i >= 0; i--) { f32 var_f26 = 0.4f * housi_packet->field_0x5de8; effect = &housi_packet->mHousiEff[i]; @@ -2025,13 +2025,23 @@ void vrkumo_move() { } } -static void dKr_cullVtx_Set() { +static void dKr_cullVtx_Set(IF_DUSK(bool const vtxColor = false)) { GXSetCullMode(GX_CULL_NONE); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); +#if TARGET_PC + if (vtxColor) { + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + } +#endif GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); +#if TARGET_PC + if (vtxColor) { + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + } +#endif } static void dKyr_draw_rev_moon(Mtx drawMtx, u8** tex) { @@ -3389,10 +3399,10 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { Vec spC4; Vec spB8; - bool var_r28 = 0; - if (housi_packet->field_0x5dec != 0) { + bool isPalaceOfTwilight = 0; + if (housi_packet->mHousiCount != 0) { if (strcmp(dComIfGp_getStartStageName(), "D_MN08") == 0) { - var_r28 = 1; + isPalaceOfTwilight = 1; } if (strcmp(dComIfGp_getStartStageName(), "D_MN08") != 0 || @@ -3419,7 +3429,7 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { color_reg1.b = 0xCA; color_reg1.a = 0xFF; - if (dKy_darkworld_check() == 1 || var_r28 == 1) { + if (dKy_darkworld_check() == 1 || isPalaceOfTwilight == 1) { color_reg0.r = 0; color_reg0.g = 0; color_reg0.b = 0; @@ -3472,17 +3482,22 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { for (int i = 0; i < 1; i++) { dKyr_set_btitex(&spDC, (ResTIMG*)*tex); +#if TARGET_PC + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); +#else GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); +#endif GXSetTevColor(GX_TEVREG1, color_reg1); GXSetNumTexGens(1); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); GXSetNumTevStages(1); - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); - GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_C0, GX_CC_TEXC, GX_CC_ZERO); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, DUSK_IF_ELSE(GX_COLOR0A0, GX_COLOR_NULL)); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, DUSK_IF_ELSE(GX_CC_RASC, GX_CC_C0), GX_CC_TEXC, GX_CC_ZERO); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, DUSK_IF_ELSE(GX_CA_RASA, GX_CA_CA), GX_CA_TEXA, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); @@ -3505,7 +3520,7 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { GXSetClipMode(GX_CLIP_DISABLE); GXSetNumIndStages(0); - dKr_cullVtx_Set(); + dKr_cullVtx_Set(IF_DUSK(true)); rot += 1.2f; MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot)); @@ -3514,7 +3529,13 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { GXLoadPosMtxImm(drawMtx, GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0); - for (int j = 0; j < housi_packet->field_0x5dec; j++) { +#if TARGET_PC + // Dusklight optimization: we submit a single large draw call, rather than hundreds. + u32 vertCount = 4 * housi_packet->mHousiCount; + GXBegin(GX_QUADS, GX_VTXFMT0, vertCount); +#endif + + for (int j = 0; j < housi_packet->mHousiCount; j++) { fopAc_ac_c* player = dComIfGp_getPlayer(0); spD0.x = @@ -3525,6 +3546,10 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { housi_packet->mHousiEff[j].mBasePos.z + housi_packet->mHousiEff[j].mPosition.z; if (i == 1 && j == 0) { +#if TARGET_PC + // Never gets hit I think? + abort(); +#endif color_reg0.r = 0; color_reg0.g = 0; color_reg0.b = 0; @@ -3553,8 +3578,10 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { color_reg0.a = housi_packet->mHousiEff[j].mAlpha * var_f25; block_14: +#if !TARGET_PC // GXLoadTextObj does nothing, TEV colors replaced with vertex colors GXLoadTexObj(&spDC, GX_TEXMAP0); GXSetTevColor(GX_TEVREG0, color_reg0); +#endif f32 var_f27 = housi_packet->mHousiEff[j].field_0x48 * 9.0f; if (g_env_light.field_0xea9 == 1) { @@ -3566,7 +3593,7 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { f32 temp_f30 = (var_f27 * 0.2f) * cM_fcos(housi_packet->mHousiEff[j].mScale.y * 6.0f); - if (dKy_darkworld_check() == 1 || var_r28 == 1) { + if (dKy_darkworld_check() == 1 || isPalaceOfTwilight == 1) { cXyz sp7C[] = { cXyz(-1.0f, -0.5f, 0.0f), cXyz(-1.0f, 1.5f, 0.0f), @@ -3711,24 +3738,34 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { pos[3].z = spD0.z + spB8.z; } - GXBegin(GX_QUADS, GX_VTXFMT0, 4); + IF_NOT_DUSK(GXBegin(GX_QUADS, GX_VTXFMT0, 4)); s16 var_r17 = 0x1FF; - if (dKy_darkworld_check() == true || var_r28 == 1) { + if (dKy_darkworld_check() == true || isPalaceOfTwilight == 1) { var_r17 = 0xFA; } GXPosition3f32(pos[0].x, pos[0].y, pos[0].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0); GXPosition3f32(pos[1].x, pos[1].y, pos[1].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(var_r17, 0); GXPosition3f32(pos[2].x, pos[2].y, pos[2].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(var_r17, var_r17); GXPosition3f32(pos[3].x, pos[3].y, pos[3].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, var_r17); - GXEnd(); + + + IF_NOT_DUSK(GXEnd()); } } + +#if TARGET_PC + GXEnd(); +#endif } GXSetClipMode(GX_CLIP_ENABLE); @@ -3803,23 +3840,30 @@ void dKyr_drawSnow(Mtx drawMtx, u8** tex) { if (tex[0] != NULL) { TGXTexObj spA0; dKyr_set_btitex(&spA0, (ResTIMG*)tex[0]); +#if TARGET_PC + // Dusklight optimization: enable draw call merging + // by using vertex color instead of GX_TEVREG0 + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); +#else GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); +#endif GXSetTevColor(GX_TEVREG1, color_reg1); GXSetNumTexGens(1); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); GXSetNumTevStages(1); - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); - GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_C0, GX_CC_TEXC, GX_CC_ZERO); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, DUSK_IF_ELSE(GX_COLOR0A0, GX_COLOR_NULL)); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, DUSK_IF_ELSE(GX_CC_RASC, GX_CC_C0), GX_CC_TEXC, GX_CC_ZERO); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, DUSK_IF_ELSE(GX_CA_RASA, GX_CA_CA), GX_CA_TEXA, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_COPY); GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_OR, GX_GREATER, 0); GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_DISABLE); GXSetClipMode(GX_CLIP_DISABLE); GXSetNumIndStages(0); - dKr_cullVtx_Set(); + dKr_cullVtx_Set(IF_DUSK(true)); Mtx rotMtx; MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot)); @@ -3896,7 +3940,7 @@ void dKyr_drawSnow(Mtx drawMtx, u8** tex) { } } - GXSetTevColor(GX_TEVREG0, color_reg0); + IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0)); f32 sp38 = 2.0f * (i / 500.0f) * snow_packet->field_0x6d80; f32 sp68 = sp50 * (camera->view.lookat.eye.abs(sp7C) / 1000.0f); if (sp68 > 1.0f) { @@ -3944,19 +3988,23 @@ void dKyr_drawSnow(Mtx drawMtx, u8** tex) { for (int k = 0; k < spC; k++) { GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXPosition3f32(pos[0].x + (temp_f31 * add_table[k].x), pos[0].y + (temp_f31 * add_table[k].y), pos[0].z + (temp_f31 * add_table[k].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0); GXPosition3f32(pos[1].x + (temp_f31 * add_table[k].x), pos[1].y + (temp_f31 * add_table[k].y), pos[1].z + (temp_f31 * add_table[k].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0); GXPosition3f32(pos[2].x + (temp_f31 * add_table[k].x), pos[2].y + (temp_f31 * add_table[k].y), pos[2].z + (temp_f31 * add_table[k].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0xFF); GXPosition3f32(pos[3].x + (temp_f31 * add_table[k].x), pos[3].y + (temp_f31 * add_table[k].y), pos[3].z + (temp_f31 * add_table[k].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0xFF); GXEnd(); } if ((g_env_light.field_0xe90 != 0 && dComIfGp_roomControl_getStayNo() == 0 && sp7C.z < 3000.0f) || dComIfGp_roomControl_getStayNo() == 3 || dComIfGp_roomControl_getStayNo() == 6 || dComIfGp_roomControl_getStayNo() == 9 || dComIfGp_roomControl_getStayNo() == 13) { color_reg0.a = 255.0f * ((0.4f * snow_packet->mSnowEff[i].field_0x30) + temp_f29); - GXSetTevColor(GX_TEVREG0, color_reg0); + IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0)); f32 sp34; f32 sp30; @@ -4012,12 +4060,16 @@ void dKyr_drawSnow(Mtx drawMtx, u8** tex) { GXBegin(GX_QUADS, GX_VTXFMT0, 4); int var_r27 = 0; GXPosition3f32(pos[0].x + (temp_f31 * add_table[var_r27].x), pos[0].y + (temp_f31 * add_table[var_r27].y), pos[0].z + (temp_f31 * add_table[var_r27].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0); GXPosition3f32(pos[1].x + (temp_f31 * add_table[var_r27].x), pos[1].y + (temp_f31 * add_table[var_r27].y), pos[1].z + (temp_f31 * add_table[var_r27].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0); GXPosition3f32(pos[2].x + (temp_f31 * add_table[var_r27].x), pos[2].y + (temp_f31 * add_table[var_r27].y), pos[2].z + (temp_f31 * add_table[var_r27].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0xFF); GXPosition3f32(pos[3].x + (temp_f31 * add_table[var_r27].x), pos[3].y + (temp_f31 * add_table[var_r27].y), pos[3].z + (temp_f31 * add_table[var_r27].z)); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0xFF); GXEnd(); } @@ -5445,18 +5497,23 @@ void dKyr_odour_draw(Mtx drawMtx, u8** tex) { MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot)); MTXConcat(camMtx, rotMtx, camMtx); + // Dusklight opt: enable draw call merging + // by using vertex color instead of GX_TEVREG0 + GXLoadPosMtxImm(drawMtx, GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0); GXLoadTexMtxImm(spF0, GX_TEXMTX0, GX_MTX3x4); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX1, GX_CLR_RGBA, GX_RGBA4, 8); + IF_DUSK(GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0)); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX1, GX_DIRECT); + IF_DUSK(GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT)); GXSetNumChans(1); - GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); + GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, DUSK_IF_ELSE(GX_SRC_VTX, GX_SRC_REG), GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); GXSetTevColor(GX_TEVREG0, color_reg0); GXSetTevColor(GX_TEVREG1, color_reg1); GXSetNumTexGens(2); @@ -5464,14 +5521,14 @@ void dKyr_odour_draw(Mtx drawMtx, u8** tex) { GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, GX_IDENTITY); GXSetNumTevStages(2); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C0, GX_CC_C1); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, DUSK_IF_ELSE(GX_CC_RASC, GX_CC_C0), GX_CC_C1); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_TEXA, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0); GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_CPREV, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV); - GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO); + GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, DUSK_IF_ELSE(GX_CA_RASA, GX_CA_A0), GX_CA_TEXA, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV); GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); @@ -5513,7 +5570,7 @@ void dKyr_odour_draw(Mtx drawMtx, u8** tex) { if (effect->mStatus != 0) { if (!(temp_f29 <= 0.000001f)) { color_reg0.a = 255.0f * temp_f29; - GXSetTevColor(GX_TEVREG0, color_reg0); + IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0)); sp70 = sp4C; @@ -5551,15 +5608,19 @@ void dKyr_odour_draw(Mtx drawMtx, u8** tex) { GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXPosition3f32(pos[0].x, pos[0].y, pos[0].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0); GXTexCoord2s16(0, 0); GXPosition3f32(pos[1].x, pos[1].y, pos[1].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0); GXTexCoord2s16(0xFF, 0); GXPosition3f32(pos[2].x, pos[2].y, pos[2].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0xFF); GXTexCoord2s16(0xFF, 0xFF); GXPosition3f32(pos[3].x, pos[3].y, pos[3].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0xFF); GXTexCoord2s16(0, 0xFF); GXEnd(); diff --git a/src/d/d_kankyo_wether.cpp b/src/d/d_kankyo_wether.cpp index 00a3d6412d..abcc3e33d9 100644 --- a/src/d/d_kankyo_wether.cpp +++ b/src/d/d_kankyo_wether.cpp @@ -79,7 +79,7 @@ SNOW_EFF::~SNOW_EFF() {} SNOW_EFF::SNOW_EFF() {} void dKankyo_snow_Packet::draw() { - dKyr_drawSnow(j3dSys.getViewMtx(), &mpTex); + GX_DEBUG_GROUP(dKyr_drawSnow, j3dSys.getViewMtx(), &mpTex); } STAR_EFF::~STAR_EFF() {} @@ -103,7 +103,7 @@ HOUSI_EFF::~HOUSI_EFF() {} HOUSI_EFF::HOUSI_EFF() {} void dKankyo_housi_Packet::draw() { - dKyr_drawHousi(j3dSys.getViewMtx(), &mpResTex); + GX_DEBUG_GROUP(dKyr_drawHousi, j3dSys.getViewMtx(), &mpResTex); } VRKUMO_EFF::~VRKUMO_EFF() {} @@ -119,7 +119,7 @@ EF_ODOUR_EFF::~EF_ODOUR_EFF() {} EF_ODOUR_EFF::EF_ODOUR_EFF() {} void dKankyo_odour_Packet::draw() { - dKyr_odour_draw(j3dSys.getViewMtx(), &mpResTex); + GX_DEBUG_GROUP(dKyr_odour_draw, j3dSys.getViewMtx(), &mpResTex); } EF_MUD_EFF::~EF_MUD_EFF() {} From 460b96c709049187840bec59a731c5888eb49fec Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 00:01:34 -0600 Subject: [PATCH 09/32] More Tracy zones --- libs/JSystem/src/J2DGraph/J2DGrafContext.cpp | 5 +++++ libs/JSystem/src/JUtility/JUTResFont.cpp | 1 + src/d/actor/d_a_alink_effect.inc | 1 + src/d/actor/d_a_mant.cpp | 1 + src/d/actor/d_a_mirror.cpp | 2 ++ src/d/actor/d_a_obj_flag2.cpp | 1 + src/d/actor/d_a_obj_flag3.cpp | 1 + src/d/actor/d_a_player.cpp | 1 + src/d/actor/d_flower.inc | 1 + src/d/actor/d_grass.inc | 1 + src/d/d_drawlist.cpp | 11 +++++++++++ src/d/d_kankyo_rain.cpp | 9 +++++++++ src/d/d_particle.cpp | 4 ++++ src/m_Do/m_Do_ext.cpp | 10 ++++++++++ 14 files changed, 49 insertions(+) diff --git a/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp b/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp index 3ac3e5d197..7bc9a90780 100644 --- a/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp +++ b/libs/JSystem/src/J2DGraph/J2DGrafContext.cpp @@ -3,6 +3,8 @@ #include "JSystem/J2DGraph/J2DGrafContext.h" #include +#include + J2DGrafContext::J2DGrafContext(f32 x, f32 y, f32 width, f32 height) : mBounds(x, y, x + width, y + height), mScissorBounds(x, y, x + width, y + height) { if (x < 0.0f || y < 0.0f) { @@ -137,6 +139,7 @@ void J2DGrafContext::setLineWidth(u8 lineWidth) { } void J2DGrafContext::fillBox(JGeometry::TBox2 const& box) { + ZoneScoped; GXSetBlendMode((GXBlendMode)mBoxPart.mType, (GXBlendFactor)mBoxPart.mSrcFactor, (GXBlendFactor)mBoxPart.mDstFactor, GX_LO_SET); GXLoadPosMtxImm(mPosMtx, 0); @@ -155,6 +158,7 @@ void J2DGrafContext::fillBox(JGeometry::TBox2 const& box) { } void J2DGrafContext::drawFrame(JGeometry::TBox2 const& box) { + ZoneScoped; GXSetBlendMode((GXBlendMode)mBoxPart.mType, (GXBlendFactor)mBoxPart.mSrcFactor, (GXBlendFactor)mBoxPart.mDstFactor, GX_LO_SET); GXLoadPosMtxImm(mPosMtx, 0); @@ -175,6 +179,7 @@ void J2DGrafContext::drawFrame(JGeometry::TBox2 const& box) { } void J2DGrafContext::line(JGeometry::TVec2 start, JGeometry::TVec2 end) { + ZoneScoped; GXSetBlendMode((GXBlendMode)mLinePart.mType, (GXBlendFactor)mLinePart.mSrcFactor, (GXBlendFactor)mLinePart.mDstFactor, GX_LO_SET); GXLoadPosMtxImm(mPosMtx, 0); diff --git a/libs/JSystem/src/JUtility/JUTResFont.cpp b/libs/JSystem/src/JUtility/JUTResFont.cpp index 3ef83b227e..63afbc29aa 100644 --- a/libs/JSystem/src/JUtility/JUTResFont.cpp +++ b/libs/JSystem/src/JUtility/JUTResFont.cpp @@ -249,6 +249,7 @@ f32 JUTResFont::drawChar_scale(f32 pos_x, f32 pos_y, f32 scale_x, f32 scale_y, i f32 x2; f32 y1; + ZoneScoped; JUT_ASSERT(378, mValid); JUTFont::TWidth width; loadFont(str_int, GX_TEXMAP0, &width FONT_DRAW_CTX_ARG); diff --git a/src/d/actor/d_a_alink_effect.inc b/src/d/actor/d_a_alink_effect.inc index d595cd4293..a5ac1083d7 100644 --- a/src/d/actor/d_a_alink_effect.inc +++ b/src/d/actor/d_a_alink_effect.inc @@ -2028,6 +2028,7 @@ void daAlink_blur_c::traceBlur(cXyz const* param_0, cXyz const* param_1, s16 par } void daAlink_blur_c::draw() { + ZoneScoped; j3dSys.reinitGX(); #ifdef TARGET_PC diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index 48e5554cd2..b8607a2acf 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -305,6 +305,7 @@ static void mant_build_anchor_frame(const cXyz& anchor_a, const cXyz& anchor_b, #endif void daMant_packet_c::draw() { + ZoneScoped; #if TARGET_PC void* image = l_Egnd_mantTEX; void* lut = l_Egnd_mantPAL; diff --git a/src/d/actor/d_a_mirror.cpp b/src/d/actor/d_a_mirror.cpp index 86eaff0a8e..c405645320 100644 --- a/src/d/actor/d_a_mirror.cpp +++ b/src/d/actor/d_a_mirror.cpp @@ -105,6 +105,7 @@ int dMirror_packet_c::entryModel(J3DModel* i_model) { void dMirror_packet_c::mirrorZdraw(f32* param_0, f32* param_1, f32 param_2, f32 param_3, f32 param_4, f32 param_5, f32 param_6, f32 param_7) { + ZoneScoped; GXSetNumChans(1); GXSetChanCtrl(GX_COLOR0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, 0, GX_DF_NONE, GX_AF_NONE); GXSetNumTexGens(0); @@ -265,6 +266,7 @@ void dMirror_packet_c::modelDraw(J3DModel* i_model, Mtx param_1) { } void dMirror_packet_c::mainDraw() { + ZoneScoped; j3dSys.reinitGX(); cXyz sp19C[5]; diff --git a/src/d/actor/d_a_obj_flag2.cpp b/src/d/actor/d_a_obj_flag2.cpp index 1475e3e310..a11287480f 100644 --- a/src/d/actor/d_a_obj_flag2.cpp +++ b/src/d/actor/d_a_obj_flag2.cpp @@ -261,6 +261,7 @@ void FlagCloth_c::execute() { } void FlagCloth_c::draw() { + ZoneScoped; j3dSys.reinitGX(); GXSetNumIndStages(0); dKy_setLight_again(); diff --git a/src/d/actor/d_a_obj_flag3.cpp b/src/d/actor/d_a_obj_flag3.cpp index 5ec6535a5e..094223ddfa 100644 --- a/src/d/actor/d_a_obj_flag3.cpp +++ b/src/d/actor/d_a_obj_flag3.cpp @@ -220,6 +220,7 @@ void FlagCloth2_c::initCcSphere(fopAc_ac_c*) { } inline void FlagCloth2_c::draw() { + ZoneScoped; j3dSys.reinitGX(); GXSetNumIndStages(0); dKy_setLight_again(); diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 6148d23e3a..68e65fed81 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -392,6 +392,7 @@ static const u8* l_sightDL_get() { #endif void daPy_sightPacket_c::draw() { + ZoneScoped; TGXTexObj texObj; j3dSys.reinitGX(); diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 4024d5ad6a..e5f055fb16 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -598,6 +598,7 @@ dFlower_packet_c::dFlower_packet_c() { } void dFlower_packet_c::draw() { + ZoneScoped; dScnKy_env_light_c* kankyo = dKy_getEnvlight(); j3dSys.reinitGX(); diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index 3d67a57007..8b94368a34 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -518,6 +518,7 @@ dGrass_packet_c::dGrass_packet_c() { } void dGrass_packet_c::draw() { + ZoneScoped; dScnKy_env_light_c* kankyo = dKy_getEnvlight(); cXyz spB4; cXyz spA8; diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 1f16b2f655..7725e8e079 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -188,6 +188,7 @@ void dDlst_window_c::setScissor(f32 xOrig, f32 yOrig, f32 width, f32 height) { } void dDlst_2DTri_c::draw() { + ZoneScoped; f32 f4; f32 f5; f32 f2 = cM_scos(field_0xc); @@ -224,6 +225,7 @@ void dDlst_2DTri_c::draw() { } void dDlst_2DQuad_c::draw() { + ZoneScoped; GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); @@ -247,6 +249,7 @@ void dDlst_2DQuad_c::draw() { } void dDlst_2DPoint_c::draw() { + ZoneScoped; GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); @@ -268,6 +271,7 @@ void dDlst_2DPoint_c::draw() { } void dDlst_2DT_c::draw() { + ZoneScoped; static GXColor l_color = {0xFF, 0xFF, 0xFF, 0xE0}; f32 var5 = field_0xe; f32 var6 = field_0x10; @@ -326,6 +330,7 @@ void dDlst_2DT_c::draw() { } void dDlst_2DT2_c::draw() { + ZoneScoped; GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA6, 0); GXClearVtxDesc(); @@ -665,6 +670,7 @@ void dDlst_2DT2_c::init(ResTIMG* i_timg, f32 param_1, f32 param_2, f32 param_3, } void dDlst_2DM_c::draw() { + ZoneScoped; s16 r31 = field_0x22; s16 r30 = field_0x24; int r29 = field_0x22 + 256.0f; @@ -728,6 +734,7 @@ void dDlst_2DM_c::draw() { void dDlst_2Dm_c::draw() { + ZoneScoped; s16 r31 = field_0x48; s16 r30 = field_0x4a; int r29 = field_0x48 + 256.0f; @@ -794,6 +801,7 @@ void dDlst_2Dm_c::draw() { void dDlst_2DMt_c::draw() { + ZoneScoped; GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); @@ -933,6 +941,7 @@ f32 cM_rnd_c::getValue(f32 param_0, f32 param_1) { } void dDlst_effectLine_c::draw() { + ZoneScoped; GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); @@ -1034,6 +1043,7 @@ void dDlst_shadowPoly_c::draw() { return; #endif + ZoneScoped; dDlst_shadowTri_c* tri = getTri(); GXBegin(GX_TRIANGLES, GX_VTXFMT0, mCount * 3); @@ -1610,6 +1620,7 @@ void dDlst_shadowControl_c::imageDraw(Mtx param_0) { } void dDlst_shadowControl_c::draw(Mtx param_0) { + ZoneScoped; static GXTevColorChan l_tevColorChan[4] = { GX_CH_RED, GX_CH_GREEN, diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 2cdd2ff2d3..41f45c8315 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -2045,6 +2045,7 @@ static void dKr_cullVtx_Set(IF_DUSK(bool const vtxColor = false)) { } static void dKyr_draw_rev_moon(Mtx drawMtx, u8** tex) { + ZoneScoped; dKankyo_sun_Packet* sun_packet = g_env_light.mpSunPacket; dKankyo_sunlenz_Packet* lenz_packet = g_env_light.mpSunLenzPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); @@ -2690,6 +2691,7 @@ void dKyr_drawSun(Mtx drawMtx, cXyz* ppos, GXColor& unused, u8** tex) { } void dKyr_drawLenzflare(Mtx drawMtx, cXyz* ppos, GXColor& param_2, u8** tex) { + ZoneScoped; dKankyo_sunlenz_Packet* lenz_packet = g_env_light.mpSunLenzPacket; dKankyo_sun_Packet* sun_packet = g_env_light.mpSunPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); @@ -3388,6 +3390,7 @@ void dKyr_drawSibuki(Mtx drawMtx, u8** tex) { } void dKyr_drawHousi(Mtx drawMtx, u8** tex) { + ZoneScoped; dKankyo_housi_Packet* housi_packet = g_env_light.mpHousiPacket; static f32 rot = 0.0f; @@ -3775,6 +3778,7 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { } void dKyr_drawSnow(Mtx drawMtx, u8** tex) { + ZoneScoped; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); dKankyo_snow_Packet* snow_packet = g_env_light.mpSnowPacket; @@ -4405,6 +4409,7 @@ void dKyr_drawStar(Mtx drawMtx, u8** tex) { } void drawCloudShadow(Mtx drawMtx, u8** tex) { + ZoneScoped; dScnKy_env_light_c* envlight = dKy_getEnvlight(); dKankyo_cloud_Packet* cloud_packet = g_env_light.mpCloudPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); @@ -5393,6 +5398,7 @@ void dKyr_odour_move() { } void dKyr_odour_draw(Mtx drawMtx, u8** tex) { + ZoneScoped; dScnKy_env_light_c* envlight = dKy_getEnvlight(); dKankyo_odour_Packet* odour_packet = envlight->mOdourData.mpOdourPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); @@ -5791,6 +5797,7 @@ void dKyr_mud_move() { } void dKyr_mud_draw(Mtx drawMtx, u8** tex) { + ZoneScoped; dKankyo_mud_Packet* mud_packet = g_env_light.mpMudPacket; dKankyo_sun_Packet* sun_packet = g_env_light.mpSunPacket; @@ -6010,6 +6017,7 @@ void dKyr_evil_move() { } static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { + ZoneScoped; dScnKy_env_light_c* envlight = dKy_getEnvlight(); dKankyo_evil_Packet* evil_packet = envlight->mpEvilPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); @@ -6248,6 +6256,7 @@ static f32 dKyr_near_bosslight_check(cXyz pos) { } void dKyr_evil_draw(Mtx drawMtx, u8** tex) { + ZoneScoped; dScnKy_env_light_c* envlight = dKy_getEnvlight(); dKankyo_evil_Packet* evil_packet = envlight->mpEvilPacket; camera_class* camera = (camera_class*)dComIfGp_getCamera(0); diff --git a/src/d/d_particle.cpp b/src/d/d_particle.cpp index 1c53313826..c3f4e9067f 100644 --- a/src/d/d_particle.cpp +++ b/src/d/d_particle.cpp @@ -1359,6 +1359,7 @@ void dPa_control_c::calcMenu() { } void dPa_control_c::draw(JPADrawInfo* param_0, u8 param_1) { + ZoneScoped; if (mEmitterMng != NULL) { j3dSys.reinitGX(); dKy_setLight_again(); @@ -1957,6 +1958,7 @@ void dPa_gen_d_light8PcallBack::execute(JPABaseEmitter* i_emitter, JPABasePartic } void dPa_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2) { + ZoneScoped; Mtx local_60; Mtx auStack_90; Mtx auStack_c0; @@ -2084,6 +2086,7 @@ void dPa_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2 } void dPa_gen_b_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2) { + ZoneScoped; Mtx local_80; JGeometry::TVec3 local_8c; JGeometry::TVec3 aTStack_98; @@ -2172,6 +2175,7 @@ void dPa_gen_b_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* p } void dPa_gen_d_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2) { + ZoneScoped; Mtx local_60; Mtx auStack_90; Mtx auStack_c0; diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index 16158815cd..ac4e6c740e 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -2369,6 +2369,7 @@ static u8 l_matDL[132] ATTRIBUTE_ALIGN(32) = { }; void mDoExt_3DlineMat0_c::setMaterial() { + ZoneScoped; j3dSys.reinitGX(); GXSetNumIndStages(0); dKy_setLight_again(); @@ -2384,6 +2385,7 @@ void mDoExt_3DlineMat0_c::setMaterial() { } void mDoExt_3DlineMat0_c::draw() { + ZoneScoped; GXSetTevColor(GX_TEVREG2, field_0x8); if (field_0xc != NULL) { @@ -2692,6 +2694,7 @@ static u8 l_mat1DL[141] ATTRIBUTE_ALIGN(32) = { }; void mDoExt_3DlineMat1_c::setMaterial() { + ZoneScoped; j3dSys.reinitGX(); GXSetNumIndStages(0); dKy_setLight_again(); @@ -2709,6 +2712,7 @@ void mDoExt_3DlineMat1_c::setMaterial() { } void mDoExt_3DlineMat1_c::draw() { + ZoneScoped; GXLoadTexObj(&mTextureObject, GX_TEXMAP0); GXSetTexCoordScaleManually(GX_TEXCOORD0, 1, GXGetTexObjWidth(&mTextureObject), GXGetTexObjHeight(&mTextureObject)); GXSetTevColor(GX_TEVREG2, mColor); @@ -2922,6 +2926,7 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 #endif void mDoExt_3DlineMat2_c::setMaterial() { + ZoneScoped; j3dSys.reinitGX(); GXSetNumIndStages(0); GXClearVtxDesc(); @@ -3119,6 +3124,7 @@ mDoExt_cube8pPacket::mDoExt_cube8pPacket(cXyz* i_points, const GXColor& i_color) } void drawCube(MtxP mtx, cXyz* pos, const GXColor& color) { + ZoneScoped; GXSETARRAY(GX_VA_POS, pos, sizeof(cXyz) * 8, sizeof(cXyz), true); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXClearVtxDesc(); @@ -3198,6 +3204,7 @@ mDoExt_quadPacket::mDoExt_quadPacket(cXyz* i_points, const GXColor& i_color, u8 } void mDoExt_quadPacket::draw() { + ZoneScoped; GXSETARRAY(GX_VA_POS, mPoints, sizeof(mPoints), sizeof(cXyz), true); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXClearVtxDesc(); @@ -3248,6 +3255,7 @@ mDoExt_trianglePacket::mDoExt_trianglePacket(cXyz* i_points, const GXColor& i_co } void mDoExt_trianglePacket::draw() { + ZoneScoped; j3dSys.reinitGX(); GXSETARRAY(GX_VA_POS, mPoints, sizeof(mPoints), sizeof(cXyz), true); @@ -3301,6 +3309,7 @@ mDoExt_linePacket::mDoExt_linePacket(cXyz& i_start, cXyz& i_end, const GXColor& } void mDoExt_linePacket::draw() { + ZoneScoped; j3dSys.reinitGX(); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); @@ -3418,6 +3427,7 @@ mDoExt_pointPacket::mDoExt_pointPacket(cXyz& i_position, const GXColor& i_color, } void mDoExt_pointPacket::draw() { + ZoneScoped; j3dSys.reinitGX(); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); From deadde352cdafa001070db17894c12f3b371fdab Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 00:02:47 -0600 Subject: [PATCH 10/32] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 49e61d7dad..59349fb982 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 49e61d7dadfd0b59ba716a9f503225e0d46f707e +Subproject commit 59349fb982892b534fcb96bc23c5042ae140d953 From ef122efccdf5426c47ddf5171e35f2a2850a8364 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 00:56:44 -0600 Subject: [PATCH 11/32] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 59349fb982..417f558669 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 59349fb982892b534fcb96bc23c5042ae140d953 +Subproject commit 417f5586698cdbf99d401a285ce1e16094e2868b From 1a247c2977b181d7cb3d9fba215608f3eb5525ae Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 02:17:46 -0600 Subject: [PATCH 12/32] Pass CMAKE_OSX_* to libjpeg-turbo build --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index eaa5bc8202..a25eb0cfee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,6 +189,8 @@ if (DUSK_MOVIE_SUPPORT) CMAKE_MSVC_RUNTIME_LIBRARY CMAKE_MSVC_DEBUG_INFORMATION_FORMAT CMAKE_OSX_ARCHITECTURES + CMAKE_OSX_DEPLOYMENT_TARGET + CMAKE_OSX_SYSROOT DEPLOYMENT_TARGET ENABLE_ARC ENABLE_BITCODE From 62a26a639dc3ceb548aaf4de73a6b1b21fe1829d Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 02:17:54 -0600 Subject: [PATCH 13/32] Bump CMAKE_OSX_DEPLOYMENT_TARGET to 12.0 --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index d83ed045aa..11512642a0 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -429,7 +429,7 @@ "type": "BOOL", "value": true }, - "CMAKE_OSX_DEPLOYMENT_TARGET": "11.0", + "CMAKE_OSX_DEPLOYMENT_TARGET": "12.0", "CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew" } }, From 5a9bd6f8dca47bc1bc2af2b430bfe8c6ebde68ae Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 02:17:58 -0600 Subject: [PATCH 14/32] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 417f558669..5a3c6d1b74 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 417f5586698cdbf99d401a285ce1e16094e2868b +Subproject commit 5a3c6d1b7451cd8ffb8d80cb4741b6849f703b10 From 2376e0102e912bce50a177911fc397871a5eb44e Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 3 Jun 2026 13:35:51 -0400 Subject: [PATCH 15/32] TPHD Button Fishing (#1949) Co-authored-by: MelonSpeedruns --- include/dusk/settings.h | 1 + src/d/actor/d_a_mg_rod.cpp | 17 +++++++++++++++++ src/dusk/settings.cpp | 2 ++ src/dusk/ui/preset.cpp | 1 + src/dusk/ui/settings.cpp | 2 ++ 5 files changed, 23 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 5fd53ce289..bc1007f8e1 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -153,6 +153,7 @@ struct UserSettings { ConfigVar noMissClimbing; ConfigVar fastTears; ConfigVar no2ndFishForCat; + ConfigVar buttonFishing; ConfigVar instantSaves; ConfigVar instantText; ConfigVar sunsSong; diff --git a/src/d/actor/d_a_mg_rod.cpp b/src/d/actor/d_a_mg_rod.cpp index 5299f57626..271b212a57 100644 --- a/src/d/actor/d_a_mg_rod.cpp +++ b/src/d/actor/d_a_mg_rod.cpp @@ -5755,6 +5755,12 @@ static void play_camera_u(dmg_rod_class* i_this) { } } +#if TARGET_PC +BOOL item_any_fishing_rod(int itemId) { + return itemId == dItemNo_FISHING_ROD_1_e || (itemId >= dItemNo_BEE_ROD_e && itemId <= dItemNo_JEWEL_WORM_ROD_e); +} +#endif + static int dmg_rod_Execute(dmg_rod_class* i_this) { fopAc_ac_c* actor = &i_this->actor; @@ -5821,6 +5827,17 @@ static int dmg_rod_Execute(dmg_rod_class* i_this) { i_this->prev_rod_substick_y = i_this->rod_substick_y; i_this->rod_substick_y = mDoCPd_c::getSubStickY(PAD_1); + #if TARGET_PC + if (dusk::getSettings().game.buttonFishing) { + if ((item_any_fishing_rod(dComIfGp_getSelectItem(0)) && mDoCPd_c::getHoldX(PAD_1)) || + (item_any_fishing_rod(dComIfGp_getSelectItem(1)) && mDoCPd_c::getHoldY(PAD_1))) + { + i_this->rod_stick_y = -1.0f; + i_this->rod_substick_y = -1.0f; + } + } + #endif + i_this->reel_speed = 5.0f; i_this->reel_btn_flags = mDoCPd_c::getHoldB(PAD_1) | mDoCPd_c::getHoldDown(PAD_1); if (mDoCPd_c::getHoldDown(PAD_1)) { diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 3f189f0359..402001a1dc 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -41,6 +41,7 @@ UserSettings g_userSettings = { .noMissClimbing {"game.noMissClimbing", false}, .fastTears {"game.fastTears", false}, .no2ndFishForCat {"game.no2ndFishForCat", false}, + .buttonFishing {"game.buttonFishing", false}, .instantSaves {"game.instantSaves", false}, .instantText {"game.instantText", false}, .sunsSong {"game.sunsSong", false}, @@ -223,6 +224,7 @@ void registerSettings() { Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastTears); Register(g_userSettings.game.no2ndFishForCat); + Register(g_userSettings.game.buttonFishing); Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.instantText); Register(g_userSettings.game.sunsSong); diff --git a/src/dusk/ui/preset.cpp b/src/dusk/ui/preset.cpp index 4d5950f1f4..5d1bbcdd28 100644 --- a/src/dusk/ui/preset.cpp +++ b/src/dusk/ui/preset.cpp @@ -37,6 +37,7 @@ void applyPresetDusk() { s.game.invertCameraXAxis.setValue(true); s.game.invertFirstPersonYAxis.setValue(true); s.game.no2ndFishForCat.setValue(true); + s.game.buttonFishing.setValue(true); s.game.enableAchievementToasts.setValue(true); s.game.enableControllerToasts.setValue(true); s.game.enableQuickTransform.setValue(true); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 826a87c144..b11875f48c 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1173,6 +1173,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { "Link will not recoil when his sword hits walls."); addOption("No 2nd Fish for Cat", getSettings().game.no2ndFishForCat, "Skip needing to catch a second fish for Sera's cat."); + addOption("Button Fishing", getSettings().game.buttonFishing, + "Allow fishing with the Fishing Rod using the button the item is assigned to."); addOption("Show Poe Count on Map", getSettings().game.enhancedMapMenus, "Displays collected/total number of Poe Souls for a region on the map."); addSpeedrunDisabledOption("Sun's Song (R+X)", getSettings().game.sunsSong, From e99b604dd271322cd5ca2094d920588b6e4b7d86 Mon Sep 17 00:00:00 2001 From: Joshua Trees Date: Thu, 4 Jun 2026 03:29:41 +0100 Subject: [PATCH 16/32] Fix flake.nix for systems where nod must build from source (#1987) This should actually be fixed upstream, but until then... See here for more details: https://github.com/NixOS/nixpkgs/issues/144170 Co-authored-by: Joshua Trees --- fix-cmake-paths.patch | 32 ++++++++++++++++++++++++++++++++ flake.nix | 5 +++-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 fix-cmake-paths.patch diff --git a/fix-cmake-paths.patch b/fix-cmake-paths.patch new file mode 100644 index 0000000000..202a42fbd6 --- /dev/null +++ b/fix-cmake-paths.patch @@ -0,0 +1,32 @@ +From f69d29614644f9963f5cb3f828b58575d60a1c5a Mon Sep 17 00:00:00 2001 +From: Joshua Trees +Date: Thu, 4 Jun 2026 01:04:04 +0100 +Subject: [PATCH] fix cmake paths + +--- + cmake/nodConfig.cmake.in | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/cmake/nodConfig.cmake.in b/cmake/nodConfig.cmake.in +index 0969382..2a24a88 100644 +--- a/cmake/nodConfig.cmake.in ++++ b/cmake/nodConfig.cmake.in +@@ -1,12 +1,12 @@ + @PACKAGE_INIT@ + +-set(_nod_libdir "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@") +-set(_nod_incdir "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") ++set(_nod_libdir "@CMAKE_INSTALL_FULL_LIBDIR@") ++set(_nod_incdir "@CMAKE_INSTALL_FULL_INCLUDEDIR@") + + if (NOT TARGET nod::nod_shared AND NOT TARGET nod::nod_static) + # Shared library + if (WIN32) +- set(_nod_dll "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_BINDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}nod${CMAKE_SHARED_LIBRARY_SUFFIX}") ++ set(_nod_dll "@CMAKE_INSTALL_FULL_BINDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}nod${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(_nod_implib "${_nod_libdir}/${CMAKE_IMPORT_LIBRARY_PREFIX}nod${CMAKE_IMPORT_LIBRARY_SUFFIX}") + if (EXISTS "${_nod_dll}") + add_library(nod::nod_shared SHARED IMPORTED) +-- +2.53.0 + diff --git a/flake.nix b/flake.nix index 713acef074..99fcd49f94 100644 --- a/flake.nix +++ b/flake.nix @@ -96,6 +96,7 @@ rev = nodVersion; hash = "sha256-+zrtVzjo0+X/6uMcNUn1+FaSR+jOhrcQSDNBFjw0NDs="; }; + patches = [ ./fix-cmake-paths.patch ]; cargoDeps = pkgs.rustPlatform.importCargoLock { lockFile = "${finalAttrs.src}/Cargo.lock"; }; @@ -229,6 +230,7 @@ pkgs.libusb1 pkgs.libunwind pkgs.gtk3 + nod ]; cmakeBuildType = "RelWithDebInfo"; @@ -239,8 +241,7 @@ "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" "-DAURORA_DAWN_PROVIDER=package" "-DAURORA_DAWN_LINKAGE=static" - "-DAURORA_NOD_PROVIDER=package" - "-DAURORA_NOD_LINKAGE=static" + "-DAURORA_NOD_PROVIDER=system" "-DAURORA_SDL3_PROVIDER=system" "-DBUILD_SHARED_LIBS=OFF" ] From b7d32918bd4b5a5a9f98441b61cb9b0cb64b9b42 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 4 Jun 2026 04:29:54 +0200 Subject: [PATCH 17/32] Fix a warning (#1985) Lol --- src/d/actor/d_a_npc_ks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/actor/d_a_npc_ks.cpp b/src/d/actor/d_a_npc_ks.cpp index e84d4b7bad..71eeb16335 100644 --- a/src/d/actor/d_a_npc_ks.cpp +++ b/src/d/actor/d_a_npc_ks.cpp @@ -178,7 +178,7 @@ static void anm_init(npc_ks_class* i_this, int param_2, f32 i_morf, u8 i_attr, f param_2 = 42; } else { // bug: developers meant to set equal to 44? - param_2 == 44; + IF_NOT_DUSK(param_2 == 44); dComIfGs_shake_kandelaar(); } } From 74f20c38e0c87c6f825ce8210ee6ff25121ccc57 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 4 Jun 2026 04:58:35 +0200 Subject: [PATCH 18/32] Don't send debug groups to Aurora if not enabled (#1984) Intended together with https://github.com/encounter/aurora/pull/221 --- CMakeLists.txt | 12 ++++++++++++ include/dusk/gx_helper.h | 8 ++++++++ src/d/d_drawlist.cpp | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a25eb0cfee..f36987ad96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,11 +137,18 @@ target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1) add_subdirectory(libs/freeverb) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(DUSK_GFX_DEBUG_GROUPS_DEFAULT ON) +else () + set(DUSK_GFX_DEBUG_GROUPS_DEFAULT OFF) +endif () + option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)") option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.") option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON) option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON) option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF) +option(DUSK_GFX_DEBUG_GROUPS "Report debug groups to the native graphics API" ${DUSK_GFX_DEBUG_GROUPS_DEFAULT}) set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN") set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment") @@ -418,6 +425,11 @@ if(ANDROID) list(APPEND GAME_COMPILE_DEFS TARGET_ANDROID=1) endif () +if (DUSK_GFX_DEBUG_GROUPS) + list(APPEND GAME_COMPILE_DEFS DUSK_GFX_DEBUG_GROUPS=1) + target_compile_definitions(aurora_gx PRIVATE AURORA_GFX_DEBUG_GROUPS) +endif () + # game_debug is for game code files that we know work when compiled with DEBUG=1 # Of course, if building a release build, this distinction is irrelevant set(GAME_DEBUG_FILES diff --git a/include/dusk/gx_helper.h b/include/dusk/gx_helper.h index 8f71cbdf26..8ed97e917a 100644 --- a/include/dusk/gx_helper.h +++ b/include/dusk/gx_helper.h @@ -7,12 +7,16 @@ #include #include "tracy/Tracy.hpp" +#if DUSK_GFX_DEBUG_GROUPS #define GX_DEBUG_GROUP(name, ...) \ do { \ GXPushDebugGroup(#name); \ name(__VA_ARGS__); \ GXPopDebugGroup(); \ } while (0) +#else +#define GX_DEBUG_GROUP(name, ...) name(__VA_ARGS__) +#endif #ifdef TARGET_PC class GXTexObjRAII : public GXTexObj { @@ -45,10 +49,14 @@ typedef GXTexObj TGXTexObj; struct GXScopedDebugGroup { explicit GXScopedDebugGroup(const char* text) { +#if DUSK_GFX_DEBUG_GROUPS GXPushDebugGroup(text); +#endif } ~GXScopedDebugGroup() { +#if DUSK_GFX_DEBUG_GROUPS GXPopDebugGroup(); +#endif } }; diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 7725e8e079..8387047252 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -1996,7 +1996,7 @@ int dDlst_list_c::set(dDlst_base_c**& p_start, dDlst_base_c**& p_end, dDlst_base return 1; } -#if TARGET_PC && (TRACY_ENABLE || PARTIAL_DEBUG) +#if DUSK_GFX_DEBUG_GROUPS static absl::flat_hash_map typeDrawNames; static const char* getTypeDrawName(dDlst_base_c* dlst) { @@ -2019,7 +2019,7 @@ void dDlst_list_c::draw(dDlst_base_c** p_start, dDlst_base_c** p_end) { for (; p_start < p_end; p_start++) { dDlst_base_c* dlst = *p_start; -#if TARGET_PC && (TRACY_ENABLE || PARTIAL_DEBUG) +#if DUSK_GFX_DEBUG_GROUPS const auto name = getTypeDrawName(dlst); GXScopedDebugGroup scope(name); #endif From 08c4442fdf52d1c314ce13e97738baadcd880d6e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 3 Jun 2026 21:01:39 -0600 Subject: [PATCH 19/32] Update aurora --- CMakePresets.json | 4 +--- extern/aurora | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 11512642a0..90970138f6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -342,9 +342,7 @@ "CMAKE_DISABLE_FIND_PACKAGE_zstd": { "type": "BOOL", "value": true - }, - "AURORA_SDL3_VERSION": "3.4.8", - "AURORA_SDL3_REF": "refs/tags/release-3.4.8" + } } }, { diff --git a/extern/aurora b/extern/aurora index 5a3c6d1b74..04cd3b3ac7 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 5a3c6d1b7451cd8ffb8d80cb4741b6849f703b10 +Subproject commit 04cd3b3ac7eac46a7df384ff7b6f355012610388 From b00b7f8f1b91bb05303fdd42b4a0432a91d19ff5 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 4 Jun 2026 01:21:40 -0600 Subject: [PATCH 20/32] More texture caching --- include/d/actor/d_a_alink.h | 4 + include/d/actor/d_a_player.h | 4 + include/dusk/gx_helper.h | 17 ++++ include/m_Do/m_Do_lib.h | 2 +- src/d/actor/d_a_alink_effect.inc | 18 +++- src/d/actor/d_a_mant.cpp | 30 +++++- src/d/actor/d_a_player.cpp | 16 ++++ src/d/d_drawlist.cpp | 8 +- src/d/d_kankyo_rain.cpp | 153 ++++++++++++++++++++++++++++++- src/m_Do/m_Do_lib.cpp | 5 +- 10 files changed, 240 insertions(+), 17 deletions(-) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index 4fb8abd929..1c2963b8e8 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -88,6 +88,10 @@ public: /* 0x02C */ cXyz field_0x2c; /* 0x038 */ cXyz field_0x38[60]; /* 0x308 */ cXyz field_0x308[60]; +#if TARGET_PC + TGXTexObj mBlurTexObj; + ResTIMG* mpCachedBlurTex = nullptr; +#endif }; // Size = 0x5D8 class dAlink_bottleWaterPcallBack_c : public JPAParticleCallBack { diff --git a/include/d/actor/d_a_player.h b/include/d/actor/d_a_player.h index 698e3b03cd..1dfbec8783 100644 --- a/include/d/actor/d_a_player.h +++ b/include/d/actor/d_a_player.h @@ -50,6 +50,10 @@ public: /* 0x14 */ Mtx mProjMtx; /* 0x44 */ ResTIMG* mpImg; /* 0x48 */ u8* mpData; +#if TARGET_PC + TGXTexObj mTexObj; + ResTIMG* mpCachedImg = nullptr; +#endif }; class daPy_boomerangMove_c { diff --git a/include/dusk/gx_helper.h b/include/dusk/gx_helper.h index 8ed97e917a..bf5f3c4d3a 100644 --- a/include/dusk/gx_helper.h +++ b/include/dusk/gx_helper.h @@ -43,8 +43,25 @@ public: static_assert(sizeof(GXTexObjRAII) == sizeof(GXTexObj), "GXTexObjRAII should have the same size as GXTexObj"); typedef GXTexObjRAII TGXTexObj; + +class GXTlutObjRAII : public GXTlutObj { +public: + GXTlutObjRAII() : GXTlutObj() {} + ~GXTlutObjRAII() { GXDestroyTlutObj(this); } + + void reset() { GXDestroyTlutObj(this); } + + GXTlutObjRAII(const GXTlutObjRAII&) = delete; + GXTlutObjRAII& operator=(const GXTlutObjRAII&) = delete; + GXTlutObjRAII(GXTlutObjRAII&&) = delete; + GXTlutObjRAII& operator=(GXTlutObjRAII&&) = delete; +}; +static_assert(sizeof(GXTlutObjRAII) == sizeof(GXTlutObj), + "GXTlutObjRAII should have the same size as GXTlutObj"); +typedef GXTlutObjRAII TGXTlutObj; #else typedef GXTexObj TGXTexObj; +typedef GXTlutObj TGXTlutObj; #endif struct GXScopedDebugGroup { diff --git a/include/m_Do/m_Do_lib.h b/include/m_Do/m_Do_lib.h index 14e57ddf5a..f194a4591b 100644 --- a/include/m_Do/m_Do_lib.h +++ b/include/m_Do/m_Do_lib.h @@ -44,7 +44,7 @@ struct mDoLib_clipper { void mDoLib_project(Vec* src, Vec* dst); u32 mDoLib_setResTimgObj(ResTIMG const* res, TGXTexObj* o_texObj, u32 tlut_name, - GXTlutObj* o_tlutObj); + TGXTlutObj* o_tlutObj); void mDoLib_pos2camera(Vec* src, Vec* dst); #if PLATFORM_WII diff --git a/src/d/actor/d_a_alink_effect.inc b/src/d/actor/d_a_alink_effect.inc index a5ac1083d7..3461568f19 100644 --- a/src/d/actor/d_a_alink_effect.inc +++ b/src/d/actor/d_a_alink_effect.inc @@ -2031,9 +2031,7 @@ void daAlink_blur_c::draw() { ZoneScoped; j3dSys.reinitGX(); -#ifdef TARGET_PC - TGXTexObj texObj; -#else +#if !TARGET_PC static TGXTexObj texObj; #endif static GXColor nColor0 = {0xFF, 0xFF, 0xFF, 0x14}; @@ -2041,11 +2039,25 @@ void daAlink_blur_c::draw() { GXSetNumIndStages(0); nColor0.a = field_0x20; +#if TARGET_PC + if (mpCachedBlurTex != m_blurTex) { + mBlurTexObj.reset(); + GXInitTexObj(&mBlurTexObj, + reinterpret_cast( + reinterpret_cast(m_blurTex) + m_blurTex->imageOffset), + 16, 4, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + GXInitTexObjLOD( + &mBlurTexObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); + mpCachedBlurTex = m_blurTex; + } + GXLoadTexObj(&mBlurTexObj, GX_TEXMAP0); +#else GXInitTexObj(&texObj, (void*)((uintptr_t)m_blurTex + m_blurTex->imageOffset), 16, 4, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&texObj, GX_TEXMAP0); +#endif GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); GXClearVtxDesc(); diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index b8607a2acf..a308ad4209 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -419,15 +419,36 @@ void daMant_packet_c::draw() { GXSetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K3_A); GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_OR, GX_GREATER, 0); +#if TARGET_PC + static bool textureObjsInitialized = false; + static TGXTlutObj tlutObj; + static TGXTexObj mainTexObj; + static TGXTexObj undersideTexObj; + if (!textureObjsInitialized) { + GXInitTlutObj(&tlutObj, lut, GX_TL_RGB5A3, 0x100); + GXInitTexObjCI(&mainTexObj, image, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0); + GXInitTexObjLOD(&mainTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); + GXInitTexObjCI( + &undersideTexObj, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0); + GXInitTexObjLOD(&undersideTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); + textureObjsInitialized = true; + } +#else GXTlutObj GStack_80; GXInitTlutObj(&GStack_80, lut, GX_TL_RGB5A3, 0x100); TGXTexObj GStack_74; GXInitTexObjCI(&GStack_74, image, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0); GXInitTexObjLOD(&GStack_74, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); +#endif - GXLoadTlut(&GStack_80, 0); +#if TARGET_PC + GXLoadTlut(&tlutObj, GX_TLUT0); + GXLoadTexObj(&mainTexObj, GX_TEXMAP0); +#else + GXLoadTlut(&GStack_80, GX_TLUT0); GXLoadTexObj(&GStack_74, GX_TEXMAP0); +#endif GXSetCullMode(GX_CULL_BACK); @@ -443,12 +464,13 @@ void daMant_packet_c::draw() { GXLoadNrmMtxImm(MStack_54, GX_PNMTX0); GXCallDisplayList(l_Egnd_mantDL, 0x3e0); -#ifdef TARGET_PC - GStack_74.reset(); -#endif +#if TARGET_PC + GXLoadTexObj(&undersideTexObj, GX_TEXMAP0); +#else GXInitTexObjCI(&GStack_74, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0); GXInitTexObjLOD(&GStack_74, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); GXLoadTexObj(&GStack_74, GX_TEXMAP0); +#endif GXSetTevColor(GX_TEVREG0, COMPOUND_LITERAL(GXColor){0, 0, 0, 0}); GXSetTevKColor(GX_KCOLOR0, COMPOUND_LITERAL(GXColor){0, 0, 0, 0}); diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 68e65fed81..e2cb035811 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -393,7 +393,9 @@ static const u8* l_sightDL_get() { void daPy_sightPacket_c::draw() { ZoneScoped; +#if !TARGET_PC TGXTexObj texObj; +#endif j3dSys.reinitGX(); GXSetNumIndStages(0); @@ -408,10 +410,24 @@ void daPy_sightPacket_c::draw() { GXSetTevColor(GX_TEVREG0, reg0); GXSetTevColor(GX_TEVREG1, reg1); +#if TARGET_PC + if (mpCachedImg != mpImg) { + mTexObj.reset(); + GXInitTexObj(&mTexObj, mpData, mpImg->width, mpImg->height, + static_cast(mpImg->format), static_cast(mpImg->wrapS), + static_cast(mpImg->wrapT), + mpImg->mipmapCount > 1 ? GX_ENABLE : GX_DISABLE); + GXInitTexObjLOD( + &mTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, GX_FALSE, GX_FALSE, GX_ANISO_1); + mpCachedImg = mpImg; + } + GXLoadTexObj(&mTexObj, GX_TEXMAP0); +#else GXInitTexObj(&texObj, mpData, mpImg->width, mpImg->height, (GXTexFmt)mpImg->format, (GXTexWrapMode)mpImg->wrapS, (GXTexWrapMode)mpImg->wrapT, mpImg->mipmapCount > 1 ? GX_ENABLE : GX_DISABLE); GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&texObj, GX_TEXMAP0); +#endif GXLoadPosMtxImm(mProjMtx, GX_PNMTX0); GXSetCurrentMtx(0); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 8387047252..b3c685092f 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -41,12 +41,12 @@ public: /* 0x14 */ GXColor field_0x14; /* 0x18 */ GXColor field_0x18; /* 0x1C */ TGXTexObj field_0x1c; - /* 0x3C */ GXTlutObj field_0x3c; + /* 0x3C */ TGXTlutObj field_0x3c; /* 0x48 */ s16 field_0x48; /* 0x4A */ s16 field_0x4a; /* 0x4C */ u8 field_0x4c; /* 0x50 */ TGXTexObj field_0x50; - /* 0x70 */ GXTlutObj field_0x70; + /* 0x70 */ TGXTlutObj field_0x70; /* 0x7C */ s16 field_0x7c; /* 0x7E */ s16 field_0x7e; /* 0x80 */ u8 field_0x80; @@ -100,7 +100,7 @@ public: u8 check() { return field_0x0; } int getCI() { return mCI; } TGXTexObj* getTexObj() { return &mTexObj; } - GXTlutObj* getTlutObj() { return &mTlutObj; } + TGXTlutObj* getTlutObj() { return &mTlutObj; } GXColor* getColor() { return &mColor; } f32 getS() { return mS; } f32 getT() { return mT; } @@ -110,7 +110,7 @@ public: /* 0x00 */ u8 field_0x0; /* 0x01 */ u8 mCI; /* 0x04 */ TGXTexObj mTexObj; - /* 0x24 */ GXTlutObj mTlutObj; + /* 0x24 */ TGXTlutObj mTlutObj; /* 0x30 */ GXColor mColor; /* 0x34 */ f32 mS; /* 0x38 */ f32 mT; diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 41f45c8315..bcc8b228e6 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -94,6 +94,39 @@ static void dKyr_set_btitex(TGXTexObj* i_obj, ResTIMG* i_img) { dKyr_set_btitex_common(i_obj, i_img, GX_TEXMAP0); } +#if TARGET_PC +template +struct CachedTexObjs { + TGXTexObj texObj[N]; + ResTIMG* timg[N] = {}; +}; + +template +static GXTexObj* load_cached_tex(CachedTexObjs& cache, ResTIMG* img, GXTexMapID mapID) { + for (int i = 0; i < N; i++) { + if (img != nullptr && cache.timg[i] == img) { + GXLoadTexObj(&cache.texObj[i], mapID); + return &cache.texObj[i]; + } + } + + int slot = 0; + for (int i = 0; i < N; i++) { + if (cache.timg[i] == nullptr) { + slot = i; + break; + } + } + + if (cache.timg[slot] != nullptr) { + cache.texObj[slot].reset(); + } + cache.timg[slot] = img; + dKyr_set_btitex_common(&cache.texObj[slot], img, mapID); + return &cache.texObj[slot]; +} +#endif + void dKyr_lenzflare_move() { dKankyo_sun_Packet* sun_packet = g_env_light.mpSunPacket; dKankyo_sunlenz_Packet* lenz_packet = g_env_light.mpSunLenzPacket; @@ -2133,10 +2166,17 @@ static void dKyr_draw_rev_moon(Mtx drawMtx, u8** tex) { return; } +#if TARGET_PC + static CachedTexObjs<8> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); + load_cached_tex(texobj, (ResTIMG*)tex[1], GX_TEXMAP1); + load_cached_tex(texobj, (ResTIMG*)tex[texidx + 2], GX_TEXMAP2); +#else TGXTexObj texobj; dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[0], GX_TEXMAP0); dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[1], GX_TEXMAP1); dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[texidx + 2], GX_TEXMAP2); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); @@ -2216,7 +2256,11 @@ static void dKyr_draw_rev_moon(Mtx drawMtx, u8** tex) { for (int i = 0; i < 2; i++) { if (i == 1) { +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)lenz_packet->mpResBall, GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)lenz_packet->mpResBall); +#endif GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); @@ -2481,10 +2525,17 @@ void dKyr_drawSun(Mtx drawMtx, cXyz* ppos, GXColor& unused, u8** tex) { return; } +#if TARGET_PC + static CachedTexObjs<8> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); + load_cached_tex(texobj, (ResTIMG*)tex[1], GX_TEXMAP1); + load_cached_tex(texobj, (ResTIMG*)tex[texidx + 2], GX_TEXMAP2); +#else TGXTexObj texobj; dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[0], GX_TEXMAP0); dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[1], GX_TEXMAP1); dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[texidx + 2], GX_TEXMAP2); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); @@ -2578,7 +2629,11 @@ void dKyr_drawSun(Mtx drawMtx, cXyz* ppos, GXColor& unused, u8** tex) { for (int i = 0; i < 2; i++) { if (i == 1) { +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)lenz_packet->mpResBall, GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)lenz_packet->mpResBall); +#endif GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); @@ -2742,8 +2797,13 @@ void dKyr_drawLenzflare(Mtx drawMtx, cXyz* ppos, GXColor& param_2, u8** tex) { j3dSys.reinitGX(); +#if TARGET_PC + static CachedTexObjs<3> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); GXSetTevColor(GX_TEVREG1, color_reg1); @@ -3048,11 +3108,23 @@ void dKyr_drawLenzflare(Mtx drawMtx, cXyz* ppos, GXColor& param_2, u8** tex) { } if (i == 1) { +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)tex[2], GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)tex[2]); +#endif } else if (i == 2) { +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)tex[3], GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)tex[3]); +#endif } else { +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif } spE4.x = -var_f31; @@ -3143,8 +3215,13 @@ void dKyr_drawRain(Mtx drawMtx, u8** tex) { return; } +#if TARGET_PC + static CachedTexObjs<1> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); GXSetNumTexGens(1); @@ -3308,8 +3385,13 @@ void dKyr_drawSibuki(Mtx drawMtx, u8** tex) { color.b = 0xC8; color.a = rain_packet->mSibukiAlpha * alphaFade; +#if TARGET_PC + static CachedTexObjs<1> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[1], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[1]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color); GXSetTevColor(GX_TEVREG1, color); @@ -3397,7 +3479,11 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { Mtx camMtx; Mtx rotMtx; cXyz pos[4]; +#if TARGET_PC + static CachedTexObjs<1> texobj; +#else TGXTexObj spDC; +#endif cXyz spD0; Vec spC4; Vec spB8; @@ -3484,7 +3570,11 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { f32 temp_f24 = 6.5f; for (int i = 0; i < 1; i++) { - dKyr_set_btitex(&spDC, (ResTIMG*)*tex); +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)*tex, GX_TEXMAP0); +#else + dKyr_set_btitex(&texobj, (ResTIMG*)*tex); +#endif #if TARGET_PC GXSetNumChans(1); GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); @@ -3582,7 +3672,7 @@ void dKyr_drawHousi(Mtx drawMtx, u8** tex) { block_14: #if !TARGET_PC // GXLoadTextObj does nothing, TEV colors replaced with vertex colors - GXLoadTexObj(&spDC, GX_TEXMAP0); + GXLoadTexObj(&texobj, GX_TEXMAP0); GXSetTevColor(GX_TEVREG0, color_reg0); #endif @@ -3842,8 +3932,13 @@ void dKyr_drawSnow(Mtx drawMtx, u8** tex) { } if (tex[0] != NULL) { - TGXTexObj spA0; - dKyr_set_btitex(&spA0, (ResTIMG*)tex[0]); +#if TARGET_PC + static CachedTexObjs<1> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else + TGXTexObj texobj; + dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif #if TARGET_PC // Dusklight optimization: enable draw call merging // by using vertex color instead of GX_TEVREG0 @@ -4445,7 +4540,12 @@ void drawCloudShadow(Mtx drawMtx, u8** tex) { GXSetClipMode(GX_CLIP_DISABLE); +#if TARGET_PC + static CachedTexObjs<1> texobj; + TGXTexObj fb_texobj; +#else TGXTexObj texobj, fb_texobj; +#endif if (g_env_light.mMoyaMode < 50) { dKy_ParticleColor_get_bg(&camera->view.lookat.eye, NULL, &sp48, &sp44, &sp40, &sp3C, 0.0f); f32 temp_f30 = 0.4f; @@ -4458,7 +4558,11 @@ void drawCloudShadow(Mtx drawMtx, u8** tex) { color_reg1.g = (0.45f * sp38.g) + (0.55f * sp44.g); color_reg1.b = (0.45f * sp38.b) + (0.55f * sp44.b); +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); GXSetTevColor(GX_TEVREG1, color_reg1); @@ -4503,7 +4607,11 @@ void drawCloudShadow(Mtx drawMtx, u8** tex) { color_reg1.b = 0; color_reg1.a = 0xFF; +#if TARGET_PC + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP1); +#else dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[0], GX_TEXMAP1); +#endif ResTIMG* fb_timg = mDoGph_gInf_c::getFrameBufferTimg(); dDlst_window_c* window = dComIfGp_getWindow(0); @@ -4650,7 +4758,11 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { Mtx camMtx; Mtx rotMtx; +#if TARGET_PC + static CachedTexObjs<3> texobj; +#else TGXTexObj texobj; +#endif cXyz proj; f32 rot; @@ -4760,7 +4872,11 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { color_reg1.r = 0; color_reg1.g = 0; color_reg1.b = 0; +#if TARGET_PC + auto* loaded_texobj = load_cached_tex(texobj, (ResTIMG*)tex[j], GX_TEXMAP0); +#else dKyr_set_btitex(&texobj, (ResTIMG*)tex[j]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color); @@ -4865,7 +4981,11 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { } if (!(vrkumo_packet->mVrkumoEff[k].mAlpha <= 0.000001f)) { +#if TARGET_PC + GXLoadTexObj(loaded_texobj, GX_TEXMAP0); +#else GXLoadTexObj(&texobj, GX_TEXMAP0); +#endif GXSetTevColor(GX_TEVREG0, color); sp60 = sp68 * (0.2f + (0.2f * (k / 100.0f))); @@ -5487,8 +5607,14 @@ void dKyr_odour_draw(Mtx drawMtx, u8** tex) { break; } +#if TARGET_PC + static CachedTexObjs<1> texobj; + TGXTexObj fb_texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP1); +#else TGXTexObj texobj, fb_texobj; dKyr_set_btitex_common(&texobj, (ResTIMG*)tex[0], GX_TEXMAP1); +#endif ResTIMG* fb_timg = mDoGph_gInf_c::getFrameBufferTimg(); dDlst_window_c* window = dComIfGp_getWindow(0); @@ -5891,8 +6017,13 @@ void dKyr_mud_draw(Mtx drawMtx, u8** tex) { if (g_env_light.camera_water_in_status == 0) { for (int i = 0; i < 1; i++) { +#if TARGET_PC + static CachedTexObjs<1> texobj_cache; + auto* texobj = load_cached_tex(texobj_cache, (ResTIMG*)tex[0], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif GXSetNumChans(0); GXSetTevColor(GX_TEVREG0, color_reg0); @@ -5932,7 +6063,11 @@ void dKyr_mud_draw(Mtx drawMtx, u8** tex) { color_reg0.a = mud_packet->mEffect[j].field_0x38 * var_f31; +#if TARGET_PC + GXLoadTexObj(texobj, GX_TEXMAP0); +#else GXLoadTexObj(&texobj, GX_TEXMAP0); +#endif GXSetTevColor(GX_TEVREG0, color_reg0); f32 sp30 = 1.0f; @@ -6054,8 +6189,13 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { color_reg0.b = 0x87; color_reg0.a = 0xFF; +#if TARGET_PC + static CachedTexObjs<1> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[1], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[1]); +#endif #if TARGET_PC if (dusk::frame_interp::get_ui_tick_pending()) @@ -6293,8 +6433,13 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { color_reg1.b = 10; color_reg1.a = 255; +#if TARGET_PC + static CachedTexObjs<1> texobj; + load_cached_tex(texobj, (ResTIMG*)tex[0], GX_TEXMAP0); +#else TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); +#endif #if TARGET_PC if (dusk::frame_interp::get_ui_tick_pending()) diff --git a/src/m_Do/m_Do_lib.cpp b/src/m_Do/m_Do_lib.cpp index 3a32c4c342..b46527b11c 100644 --- a/src/m_Do/m_Do_lib.cpp +++ b/src/m_Do/m_Do_lib.cpp @@ -11,12 +11,15 @@ #include u32 mDoLib_setResTimgObj(ResTIMG const* i_img, TGXTexObj* o_texObj, u32 tlut_name, - GXTlutObj* o_tlutObj) { + TGXTlutObj* o_tlutObj) { #ifdef TARGET_PC o_texObj->reset(); #endif if (i_img->indexTexture) { JUT_ASSERT(44, o_tlutObj != NULL); +#ifdef TARGET_PC + o_tlutObj->reset(); +#endif GXInitTlutObj(o_tlutObj, (void*)((u8*)i_img + i_img->paletteOffset), (GXTlutFmt)i_img->colorFormat, (u16)i_img->numColors); GXInitTexObjCI(o_texObj, (void*)((u8*)i_img + i_img->imageOffset), i_img->width, i_img->height, From 09361154834a54be19cc94866e657641be180b05 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 4 Jun 2026 23:27:30 -0600 Subject: [PATCH 21/32] Optimize display lists in J3DShapeDraw This is a stop-gap until DL optimization is upstreamed to Aurora. --- .../JSystem/J3DGraphBase/J3DShapeDraw.h | 4 + .../JSystem/src/J3DGraphBase/J3DShapeDraw.cpp | 343 +++++++++++++++++- .../src/J3DGraphLoader/J3DShapeFactory.cpp | 7 +- 3 files changed, 349 insertions(+), 5 deletions(-) diff --git a/libs/JSystem/include/JSystem/J3DGraphBase/J3DShapeDraw.h b/libs/JSystem/include/JSystem/J3DGraphBase/J3DShapeDraw.h index e6e8d61786..feff2b4991 100644 --- a/libs/JSystem/include/JSystem/J3DGraphBase/J3DShapeDraw.h +++ b/libs/JSystem/include/JSystem/J3DGraphBase/J3DShapeDraw.h @@ -1,6 +1,7 @@ #ifndef J3DSHAPEDRAW_H #define J3DSHAPEDRAW_H +#include #include /** @@ -12,6 +13,9 @@ public: u32 countVertex(u32); void addTexMtxIndexInDL(u32, u32, u32); J3DShapeDraw(u8 const*, u32); +#if TARGET_PC + J3DShapeDraw(u8 const*, u32, const GXVtxDescList*); +#endif void draw() const; virtual ~J3DShapeDraw(); diff --git a/libs/JSystem/src/J3DGraphBase/J3DShapeDraw.cpp b/libs/JSystem/src/J3DGraphBase/J3DShapeDraw.cpp index a1bd69438c..b40f577d79 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DShapeDraw.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DShapeDraw.cpp @@ -1,15 +1,310 @@ -#include "JSystem/JSystem.h" // IWYU pragma: keep +#include "JSystem/JSystem.h" // IWYU pragma: keep +#include +#include +#include #include "JSystem/J3DGraphBase/J3DShapeDraw.h" #include "JSystem/JKernel/JKRHeap.h" -#include -#include -#include + +#if TARGET_PC +#include +#include +#include +#include "dusk/logging.h" + +namespace { + +u16 read_be16(const u8* data) { + return (u16(data[0]) << 8) | data[1]; +} + +void append_be16(std::vector& out, u16 value) { + out.push_back(value >> 8); + out.push_back(value & 0xFF); +} + +void append_bytes(std::vector& out, const u8* data, u32 size) { + out.insert(out.end(), data, data + size); +} + +bool is_matrix_idx_attr(GXAttr attr) { + return attr >= GX_VA_PNMTXIDX && attr <= GX_VA_TEX7MTXIDX; +} + +bool is_draw_opcode(u8 opcode) { + return opcode == GX_QUADS || opcode == GX_TRIANGLES || opcode == GX_TRIANGLESTRIP || + opcode == GX_TRIANGLEFAN || opcode == GX_LINES || opcode == GX_LINESTRIP || + opcode == GX_POINTS; +} + +bool is_mergeable_draw_opcode(u8 opcode) { + return opcode == GX_QUADS || opcode == GX_TRIANGLES || opcode == GX_TRIANGLESTRIP || + opcode == GX_TRIANGLEFAN; +} + +bool calc_vtx_stride(const GXVtxDescList* vtxDesc, u32& stride) { + stride = 0; + for (; vtxDesc->attr != GX_VA_NULL; vtxDesc++) { + switch (vtxDesc->type) { + case GX_NONE: + break; + case GX_DIRECT: + if (!is_matrix_idx_attr(vtxDesc->attr)) { + return false; + } + stride += 1; + break; + case GX_INDEX8: + stride += 1; + break; + case GX_INDEX16: + stride += 2; + break; + default: + return false; + } + } + return stride != 0; +} + +bool get_command_size(const u8* dlStart, u32 dlSize, u32 offset, u32 stride, u32& cmdSize) { + if (offset >= dlSize) { + return false; + } + + const u8 cmd = dlStart[offset]; + const u8 opcode = cmd & GX_OPCODE_MASK; + switch (opcode) { + case GX_NOP: + case GX_CMD_INVL_VC: + cmdSize = 1; + return true; + case (GX_LOAD_BP_REG & GX_OPCODE_MASK): + cmdSize = 5; + return offset + cmdSize <= dlSize; + case GX_LOAD_CP_REG: + cmdSize = 6; + return offset + cmdSize <= dlSize; + case GX_LOAD_XF_REG: { + if (offset + 5 > dlSize) { + return false; + } + const u16 count = read_be16(dlStart + offset + 1) + 1; + cmdSize = 5 + count * 4; + return offset + cmdSize <= dlSize; + } + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + cmdSize = 5; + return offset + cmdSize <= dlSize; + case GX_CMD_CALL_DL: + cmdSize = 9; + return offset + cmdSize <= dlSize; + default: + if (is_draw_opcode(opcode)) { + if (offset + 3 > dlSize) { + return false; + } + const u16 vtxCount = read_be16(dlStart + offset + 1); + cmdSize = 3 + vtxCount * stride; + return offset + cmdSize <= dlSize; + } + return false; + } +} + +struct MergeRun { + u8 cmd = 0; + u16 vtxCount = 0; + std::vector vertices; +}; + +void flush_merge_run(std::vector& out, MergeRun& run) { + if (run.vtxCount == 0) { + return; + } + + out.push_back(run.cmd); + append_be16(out, run.vtxCount); + append_bytes(out, run.vertices.data(), run.vertices.size()); + run.vertices.clear(); + run.vtxCount = 0; +} + +void append_vertex(std::vector& out, const u8* vertices, u32 stride, u16 idx) { + append_bytes(out, vertices + idx * stride, stride); +} + +bool triangulate_draw( + std::vector& out, u8 opcode, const u8* vertices, u32 stride, u16 vtxCount) { + switch (opcode) { + case GX_TRIANGLES: + append_bytes(out, vertices, vtxCount * stride); + return true; + case GX_TRIANGLEFAN: + if (vtxCount < 3) { + return false; + } + for (u16 v = 2; v < vtxCount; v++) { + append_vertex(out, vertices, stride, 0); + append_vertex(out, vertices, stride, v - 1); + append_vertex(out, vertices, stride, v); + } + return true; + case GX_TRIANGLESTRIP: + if (vtxCount < 3) { + return false; + } + for (u16 v = 2; v < vtxCount; v++) { + if ((v & 1) == 0) { + append_vertex(out, vertices, stride, v - 2); + append_vertex(out, vertices, stride, v - 1); + } else { + append_vertex(out, vertices, stride, v - 1); + append_vertex(out, vertices, stride, v - 2); + } + append_vertex(out, vertices, stride, v); + } + return true; + case GX_QUADS: + if ((vtxCount & 3) != 0) { + return false; + } + for (u16 v = 0; v < vtxCount; v += 4) { + append_vertex(out, vertices, stride, v); + append_vertex(out, vertices, stride, v + 1); + append_vertex(out, vertices, stride, v + 2); + append_vertex(out, vertices, stride, v + 2); + append_vertex(out, vertices, stride, v + 3); + append_vertex(out, vertices, stride, v); + } + return true; + default: + return false; + } +} + +void append_triangles_to_run( + std::vector& out, MergeRun& run, u8 cmd, const std::vector& vertices, u32 stride) { + u32 offset = 0; + u32 remaining = vertices.size() / stride; + while (remaining != 0) { + if (run.vtxCount != 0 && run.cmd != cmd) { + flush_merge_run(out, run); + } + + if (run.vtxCount == 0) { + run.cmd = cmd; + } + + u32 available = 0xFFFF - run.vtxCount; + if (available == 0) { + flush_merge_run(out, run); + continue; + } + + u32 toCopy = std::min(remaining, available); + append_bytes(run.vertices, vertices.data() + offset * stride, toCopy * stride); + run.vtxCount += toCopy; + offset += toCopy; + remaining -= toCopy; + + if (run.vtxCount == 0xFFFF) { + flush_merge_run(out, run); + } + } +} + +bool optimize_display_list(const u8* dlStart, u32 dlSize, u32 stride, std::vector& out) { + MergeRun run; + out.reserve(dlSize); + + for (u32 offset = 0; offset < dlSize;) { + u32 cmdSize = 0; + if (!get_command_size(dlStart, dlSize, offset, stride, cmdSize)) { + return false; + } + + const u8 cmd = dlStart[offset]; + const u8 opcode = cmd & GX_OPCODE_MASK; + if (opcode == GX_NOP) { + offset += cmdSize; + continue; + } + + if (!is_draw_opcode(opcode)) { + flush_merge_run(out, run); + append_bytes(out, dlStart + offset, cmdSize); + offset += cmdSize; + continue; + } + + if (!is_mergeable_draw_opcode(opcode)) { + flush_merge_run(out, run); + append_bytes(out, dlStart + offset, cmdSize); + offset += cmdSize; + continue; + } + + const u16 vtxCount = read_be16(dlStart + offset + 1); + const u8* vertices = dlStart + offset + 3; + std::vector triangles; + if (!triangulate_draw(triangles, opcode, vertices, stride, vtxCount)) { + flush_merge_run(out, run); + append_bytes(out, dlStart + offset, cmdSize); + offset += cmdSize; + continue; + } + + append_triangles_to_run(out, run, (GX_TRIANGLES | (cmd & GX_VAT_MASK)), triangles, stride); + offset += cmdSize; + } + + flush_merge_run(out, run); + return true; +} + +void set_display_list_copy(void*& displayList, u32& displayListSize, const u8* data, u32 size) { + const u32 alignedSize = ALIGN_NEXT(size, 0x20); + u8* newDL = JKR_NEW_ARRAY_ARGS(u8, alignedSize, 0x20); + if (size != 0) { + std::memcpy(newDL, data, size); + } + for (u32 i = size; i < alignedSize; i++) { + newDL[i] = 0; + } + + displayList = newDL; + displayListSize = alignedSize; + DCStoreRange(newDL, displayListSize); +} + +} // namespace +#endif u32 J3DShapeDraw::countVertex(u32 stride) { u32 count = 0; u8* dlStart = (u8*)getDisplayList(); +#if TARGET_PC + for (u32 offset = 0; offset < getDisplayListSize();) { + u8 cmd = dlStart[offset]; + u8 opcode = cmd & GX_OPCODE_MASK; + u32 cmdSize = 0; + if (!get_command_size(dlStart, getDisplayListSize(), offset, stride, cmdSize)) { + break; + } + if (!is_draw_opcode(opcode)) { + offset += cmdSize; + continue; + } + int vtxNum = be16(*reinterpret_cast(dlStart + offset + 1)); + count += vtxNum; + offset += 3 + stride * vtxNum; + } +#else for (u8* dl = dlStart; (dl - dlStart) < getDisplayListSize();) { u8 cmd = *(u8*)dl; dl++; @@ -20,6 +315,7 @@ u32 J3DShapeDraw::countVertex(u32 stride) { count += vtxNum; dl = (u8*)dl + stride * vtxNum; } +#endif return count; } @@ -34,13 +330,32 @@ void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) { u8* newDL = newDLStart; for (; (oldDL - oldDLStart) < mDisplayListSize;) { +#if TARGET_PC + u32 oldOffset = oldDL - oldDLStart; + u32 cmdSize = 0; + if (!get_command_size(oldDLStart, mDisplayListSize, oldOffset, stride, cmdSize)) { + memcpy(newDL, oldDL, mDisplayListSize - oldOffset); + newDL += mDisplayListSize - oldOffset; + break; + } +#endif // Copy command u8 cmd = *(u8*)oldDL; oldDL++; *newDL++ = cmd; +#if TARGET_PC + u8 opcode = cmd & GX_OPCODE_MASK; + if (!is_draw_opcode(opcode)) { + memcpy(newDL, oldDL, cmdSize - 1); + oldDL += cmdSize - 1; + newDL += cmdSize - 1; + continue; + } +#else if (cmd != GX_TRIANGLEFAN && cmd != GX_TRIANGLESTRIP) break; +#endif // Copy count int vtxNum = *(u16*)oldDL; @@ -71,11 +386,31 @@ void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) { } J3DShapeDraw::J3DShapeDraw(const u8* displayList, u32 displayListSize) { +#if TARGET_PC + set_display_list_copy(mDisplayList, mDisplayListSize, displayList, displayListSize); +#else mDisplayList = (void*)displayList; mDisplayListSize = displayListSize; +#endif } +#if TARGET_PC +J3DShapeDraw::J3DShapeDraw( + const u8* displayList, u32 displayListSize, const GXVtxDescList* vtxDesc) { + u32 stride = 0; + std::vector optimized; + if (calc_vtx_stride(vtxDesc, stride) && + optimize_display_list(displayList, displayListSize, stride, optimized)) + { + set_display_list_copy(mDisplayList, mDisplayListSize, optimized.data(), optimized.size()); + } else { + set_display_list_copy(mDisplayList, mDisplayListSize, displayList, displayListSize); + } +} +#endif + void J3DShapeDraw::draw() const { + ZoneScoped; GXCallDisplayList(mDisplayList, mDisplayListSize); } diff --git a/libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp b/libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp index f283cb8932..b8b3b14c36 100644 --- a/libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp +++ b/libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp @@ -132,7 +132,12 @@ J3DShapeDraw* J3DShapeFactory::newShapeDraw(int shapeNo, int mtxGroupNo) const { const J3DShapeInitData& shapeInitData = mShapeInitData[mIndexTable[shapeNo]]; const J3DShapeDrawInitData& drawInitData = (&mDrawInitData[shapeInitData.mDrawInitDataIndex])[mtxGroupNo]; +#if TARGET_PC + shapeDraw = JKR_NEW J3DShapeDraw(&mDisplayListData[drawInitData.mDisplayListIndex], drawInitData.mDisplayListSize, + getVtxDescList(shapeNo)); +#else shapeDraw = JKR_NEW J3DShapeDraw(&mDisplayListData[drawInitData.mDisplayListIndex], drawInitData.mDisplayListSize); +#endif J3D_ASSERT_ALLOCMEM(193, shapeDraw); return shapeDraw; } @@ -154,7 +159,7 @@ s32 J3DShapeFactory::calcSize(int shapeNo, u32 flag) { for (u32 i = 0; i < mtxGroupNo; i++) { size += calcSizeShapeMtx(flag, shapeNo, i); - size += 0x0C; + size += sizeof(J3DShapeDraw); } return size; From e484a100180a24ed9d4fac9ed3cc5792e0ddfe1a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 4 Jun 2026 23:28:44 -0600 Subject: [PATCH 22/32] tvOS fixes --- CMakePresets.json | 15 ++++++--------- src/dusk/crash_handler.cpp | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 90970138f6..2a6285443f 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -292,24 +292,21 @@ "type": "BOOL", "value": false }, + "ENABLE_ARC": { + "type": "BOOL", + "value": false + }, "Rust_CARGO_TARGET": "aarch64-apple-tvos", "Rust_TOOLCHAIN": "nightly", "BUILD_SHARED_LIBS": { "type": "BOOL", "value": false }, - "CMAKE_DISABLE_FIND_PACKAGE_BZip2": { + "CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": { "type": "BOOL", "value": true }, - "CMAKE_DISABLE_FIND_PACKAGE_LibLZMA": { - "type": "BOOL", - "value": true - }, - "CMAKE_DISABLE_FIND_PACKAGE_zstd": { - "type": "BOOL", - "value": true - } + "CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew" }, "vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { diff --git a/src/dusk/crash_handler.cpp b/src/dusk/crash_handler.cpp index 8562d5f14b..b520a6ff29 100644 --- a/src/dusk/crash_handler.cpp +++ b/src/dusk/crash_handler.cpp @@ -34,6 +34,7 @@ #if defined(__APPLE__) #include #include +#include #else #include #include @@ -929,7 +930,7 @@ void install() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); #endif g_prevFilter = SetUnhandledExceptionFilter(&windowsHandler); -#else +#elif !defined(__APPLE__) || !TARGET_OS_TV Dl_info moduleInfo; if (dladdr(reinterpret_cast(&install), &moduleInfo) != 0) { g_ctx.moduleBase = reinterpret_cast(moduleInfo.dli_fbase); From 358de645704d9d79059c61d7985b50123b8febd4 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 4 Jun 2026 23:30:30 -0600 Subject: [PATCH 23/32] ci: Use mold linker on Linux --- .github/workflows/build.yml | 2 +- CMakePresets.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88e20dcdf8..80257624c5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get -y install ninja-build clang lld openssl libcurl4-openssl-dev \ + sudo apt-get -y install ninja-build clang lld mold openssl libcurl4-openssl-dev \ zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \ libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev libfreetype-dev \ libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev libssl-dev \ diff --git a/CMakePresets.json b/CMakePresets.json index 2a6285443f..88c5aee56a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -395,7 +395,8 @@ "ci" ], "cacheVariables": { - "AURORA_SDL3_PROVIDER": "vendor" + "AURORA_SDL3_PROVIDER": "vendor", + "CMAKE_LINKER_TYPE": "MOLD" } }, { From 7f306fe1ec4d3ca71e40107fa46849767d75b085 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 5 Jun 2026 00:03:29 -0600 Subject: [PATCH 24/32] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 04cd3b3ac7..c31d6dadcb 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 04cd3b3ac7eac46a7df384ff7b6f355012610388 +Subproject commit c31d6dadcbe8d6131b90ea30b756553d8ee5ae6e From da3ac9f5467b3700354e096491fb8959f711c6d6 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 5 Jun 2026 00:03:43 -0600 Subject: [PATCH 25/32] ci: Build with shared vcruntime --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 88c5aee56a..292055a756 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -19,7 +19,7 @@ "hidden": true, "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo", - "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded" + "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDLL" } }, { From eefa69b53dba28d760061301df72bfe6163b0daa Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Fri, 5 Jun 2026 02:05:20 -0400 Subject: [PATCH 26/32] Re-enable JParticle interpolation and fix emitter direction issue (#1968) * Re-enable JParticle interpolation * Ensure emitter direction is valid for JPA interp Fixes #618. * Don't `calcWorkData` if we don't need to --- libs/JSystem/src/JParticle/JPAParticle.cpp | 3 +-- libs/JSystem/src/JParticle/JPAResource.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libs/JSystem/src/JParticle/JPAParticle.cpp b/libs/JSystem/src/JParticle/JPAParticle.cpp index d3490ab294..eb2395e346 100644 --- a/libs/JSystem/src/JParticle/JPAParticle.cpp +++ b/libs/JSystem/src/JParticle/JPAParticle.cpp @@ -206,8 +206,7 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent) #if TARGET_PC void JPABaseParticle::interp(JPAEmitterWorkData* work, void const* drawFunc) { - static bool enable = false; - if (!enable) + if (!dusk::frame_interp::is_enabled()) return; // don't interpolate the first frame diff --git a/libs/JSystem/src/JParticle/JPAResource.cpp b/libs/JSystem/src/JParticle/JPAResource.cpp index 2ae4709fc3..59e679d449 100644 --- a/libs/JSystem/src/JParticle/JPAResource.cpp +++ b/libs/JSystem/src/JParticle/JPAResource.cpp @@ -761,6 +761,15 @@ bool JPAResource::calc(JPAEmitterWorkData* work, JPABaseEmitter* emtr) { } } +#ifdef TARGET_PC + if (((pBsp && pBsp->getDirType() == 3) || (pCsp && pCsp->getDirType() == 3)) && + dusk::frame_interp::is_enabled()) + { + // ensure mGlobalEmtrDir is valid + calcWorkData_d(work); + } +#endif + JPANode* next = NULL; for (JPANode* node = emtr->mAlivePtclBase.getFirst(); node != emtr->mAlivePtclBase.getEnd(); node = next) { next = node->getNext(); From 24ca190029f510a3eb3728e5a2c5844bfddf6e42 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Fri, 5 Jun 2026 02:05:47 -0400 Subject: [PATCH 27/32] Adjust Total Achievement Count (#1924) - Don't count the glitched achievements towards the total so that they appear over 100% --- src/dusk/ui/achievements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/ui/achievements.cpp b/src/dusk/ui/achievements.cpp index b631d444f5..9d25f1d82a 100644 --- a/src/dusk/ui/achievements.cpp +++ b/src/dusk/ui/achievements.cpp @@ -217,7 +217,7 @@ void AchievementsWindow::updateTotal() { return; } const auto all = AchievementSystem::get().getAchievements(); - int total = static_cast(all.size()); + const int total = std::count_if(all.begin(), all.end(), [](const Achievement& achievement){ return achievement.category != AchievementCategory::Glitched;}); int unlocked = 0; for (const auto& a : all) { if (a.unlocked) { From 1b42c4ecac4a9d45335ef91e291371e8984fe77d Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 5 Jun 2026 00:09:07 -0600 Subject: [PATCH 28/32] ci: Build Android w/ release & LTO --- CMakePresets.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 292055a756..6c3a2c46ef 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -22,6 +22,18 @@ "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDLL" } }, + { + "name": "release", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDLL", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": { + "type": "BOOL", + "value": true + } + } + }, { "name": "ci", "hidden": true, @@ -367,7 +379,8 @@ "hidden": true, "inherits": [ "android-base", - "ci" + "ci", + "release" ], "cacheVariables": { "DUSK_ENABLE_SENTRY_NATIVE": { From 8705e75b9d5084c64012a69e97c3a5f590500db7 Mon Sep 17 00:00:00 2001 From: Kevin Lema Date: Fri, 5 Jun 2026 08:14:09 +0200 Subject: [PATCH 29/32] Add HUD scale setting (#1387) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add HUD scale setting Adds a "HUD Scale" preference (50%–200%) that scales the gameplay HUD (hearts, magic/lantern meter, light drops, rupees/keys, action buttons and the mini-map) without affecting dialog boxes or menus. Each HUD group is scaled around its own pane origin and nudged toward its anchor corner (via dApplyHudCorner) so it stays put against the screen edge instead of drifting toward the centre when shrunk. The mini-map is scaled and shifted in d_meter_map so its bottom-left corner stays anchored. The setting is clamped to a safe range and is a no-op on non-PC targets. It is disabled in the menu while Minimal HUD is enabled. Signed-off-by: kevin Lema * Scale remaining gameplay HUD elements with HUD scale Extends the HUD Scale setting to the item ammo counters, the lantern oil gauge and the small-key counter, and gives the oil/magic meter a reduced horizontal anchor pull so it stays on-screen at small scales. Signed-off-by: kevin Lema * Update settings.cpp Signed-off-by: kevin Lema --------- Signed-off-by: kevin Lema --- include/dusk/settings.h | 1 + src/d/d_meter2_draw.cpp | 161 +++++++++++++++++++++++++++++++++++++++ src/d/d_meter_map.cpp | 16 +++- src/dusk/settings.cpp | 2 + src/dusk/ui/settings.cpp | 5 ++ 5 files changed, 183 insertions(+), 2 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index bc1007f8e1..30138b0042 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -163,6 +163,7 @@ struct UserSettings { // Preferences ConfigVar enableMirrorMode; ConfigVar minimalHUD; + ConfigVar hudScale; ConfigVar pauseOnFocusLost; ConfigVar enableLinkDollRotation; ConfigVar enableAchievementToasts; diff --git a/src/d/d_meter2_draw.cpp b/src/d/d_meter2_draw.cpp index 3c342ea7d4..900367d7f3 100644 --- a/src/d/d_meter2_draw.cpp +++ b/src/d/d_meter2_draw.cpp @@ -23,6 +23,39 @@ #include "dusk/frame_interpolation.h" #include +#if TARGET_PC +#include "dusk/settings.h" +#include + +namespace { + +// Reads the user HUD scale setting, clamped to a safe range. +f32 dGetUserHudScale() { + return std::clamp(dusk::getSettings().game.hudScale.getValue(), 0.5f, 2.0f); +} + +// The screen corner each HUD group is anchored to. A pane scales around its own origin, +// so without correction it drifts away from the screen edge; this names the corner that +// must stay put. +enum class HudCorner { TopLeft, TopRight, BottomLeft, BottomRight }; + +// Adds the paneTrans offset that keeps i_corner pinned in place while the user HUD scale +// grows or shrinks the pane. The shift is half the change in size pushed toward the +// anchor corner, so it depends only on the pane's size (not its on-screen position) and +// works whether the HUD is scaled down or up. i_pull < 1 applies a partial horizontal +// push for a pane whose content sits inset from its box edge (the heart row). +void dAnchorHudScale(CPaneMgr* i_pane, HudCorner i_corner, f32* io_x, f32* io_y, f32 i_pull = 1.0f) { + const f32 half = (1.0f - dGetUserHudScale()) * 0.5f; + const f32 dirX = + (i_corner == HudCorner::TopRight || i_corner == HudCorner::BottomRight) ? 1.0f : -1.0f; + const f32 dirY = + (i_corner == HudCorner::BottomLeft || i_corner == HudCorner::BottomRight) ? 1.0f : -1.0f; + *io_x += dirX * i_pane->getInitSizeX() * half * i_pull; + *io_y += dirY * i_pane->getInitSizeY() * half; +} + +} // namespace +#endif dMeter2Draw_c::dMeter2Draw_c(JKRExpHeap* mp_heap) { OS_REPORT("enter dMeter2Draw_c::dMeter2Draw_c(JKRExpHeap *mp_heap)\n"); @@ -536,6 +569,12 @@ void dMeter2Draw_c::init() { } void dMeter2Draw_c::exec(u32 i_status) { +#if TARGET_PC + // n_all keeps the vanilla scale. Scaling the root pane shrinks every child toward + // its centred origin; per-child scaling in each drawXxx() path keeps each HUD group + // anchored to its own pane origin and also pulls it toward the screen corner. + const f32 userHudScale = dGetUserHudScale(); +#endif if (mParentScale != g_drawHIO.mParentScale) { mParentScale = g_drawHIO.mParentScale; mpParent->scale(g_drawHIO.mParentScale, g_drawHIO.mParentScale); @@ -546,6 +585,39 @@ void dMeter2Draw_c::exec(u32 i_status) { mpParent->setAlphaRate(g_drawHIO.mParentAlpha); } +#if TARGET_PC + if (i_status & 0x1000000) { + f32 ringPosX = g_drawHIO.mRingHUDButtonsPosX; + f32 ringPosY = g_drawHIO.mRingHUDButtonsPosY; + dAnchorHudScale(mpButtonParent, HudCorner::TopRight, &ringPosX, &ringPosY); + if (mButtonsPosX != ringPosX || mButtonsPosY != ringPosY) { + mButtonsPosX = ringPosX; + mButtonsPosY = ringPosY; + mpButtonParent->paneTrans(ringPosX, ringPosY); + } + + const f32 ringButtonsScale = g_drawHIO.mRingHUDButtonsScale * userHudScale; + if (mButtonsScale != ringButtonsScale) { + mButtonsScale = ringButtonsScale; + mpButtonParent->scale(ringButtonsScale, ringButtonsScale); + } + } else { + f32 mainPosX = g_drawHIO.mMainHUDButtonsPosX; + f32 mainPosY = g_drawHIO.mMainHUDButtonsPosY; + dAnchorHudScale(mpButtonParent, HudCorner::TopRight, &mainPosX, &mainPosY); + if (mButtonsPosX != mainPosX || mButtonsPosY != mainPosY) { + mButtonsPosX = mainPosX; + mButtonsPosY = mainPosY; + mpButtonParent->paneTrans(mainPosX, mainPosY); + } + + const f32 mainButtonsScale = g_drawHIO.mMainHUDButtonsScale * userHudScale; + if (mButtonsScale != mainButtonsScale) { + mButtonsScale = mainButtonsScale; + mpButtonParent->scale(mainButtonsScale, mainButtonsScale); + } + } +#else if (i_status & 0x1000000) { if (mButtonsPosX != g_drawHIO.mRingHUDButtonsPosX || mButtonsPosY != g_drawHIO.mRingHUDButtonsPosY) @@ -574,6 +646,7 @@ void dMeter2Draw_c::exec(u32 i_status) { mpButtonParent->scale(g_drawHIO.mMainHUDButtonsScale, g_drawHIO.mMainHUDButtonsScale); } } +#endif } void dMeter2Draw_c::draw() { @@ -588,6 +661,9 @@ void dMeter2Draw_c::draw() { if (mpItemXY[i] != NULL) { for (int j = 0; j < 3; j++) { f32 temp_f30 = mItemParams[i].num_scale * 16.0f; +#if TARGET_PC + temp_f30 *= dGetUserHudScale(); +#endif Vec vtx0 = mpItemXY[i]->getPanePtr()->getGlbVtx(0); Vec vtx3 = mpItemXY[i]->getPanePtr()->getGlbVtx(3); @@ -1478,7 +1554,12 @@ void dMeter2Draw_c::drawLife(s16 i_maxLife, s16 i_life, f32 i_posX, f32 i_posY) } } +#if TARGET_PC + const f32 lifeParentScale = g_drawHIO.mLifeParentScale * dGetUserHudScale(); + mpLifeParent->scale(lifeParentScale, lifeParentScale); +#else mpLifeParent->scale(g_drawHIO.mLifeParentScale, g_drawHIO.mLifeParentScale); +#endif for (int i = 0; i < 20; i++) { mpHeartMark[i]->scale(g_drawHIO.mHeartMarkScale, g_drawHIO.mHeartMarkScale); @@ -1488,7 +1569,16 @@ void dMeter2Draw_c::drawLife(s16 i_maxLife, s16 i_life, f32 i_posX, f32 i_posY) mpBigHeart->scale(g_drawHIO.mBigHeartScale, g_drawHIO.mBigHeartScale); } +#if TARGET_PC + f32 lifePosX = i_posX; + f32 lifePosY = i_posY; + // The heart row sits inset from its box's left edge, so use a partial horizontal pull + // to keep it from jamming against the screen edge. + dAnchorHudScale(mpLifeParent, HudCorner::TopLeft, &lifePosX, &lifePosY, 0.6f); + mpLifeParent->paneTrans(lifePosX, lifePosY); +#else mpLifeParent->paneTrans(i_posX, i_posY); +#endif } void dMeter2Draw_c::setAlphaLifeChange(bool param_0) { @@ -1601,9 +1691,22 @@ void dMeter2Draw_c::drawKanteraScreen(u8 i_meterType) { mpMagicMeter->resize(field_0x584[i_meterType], field_0x590[i_meterType]); mpMagicFrameR->move(field_0x59c[i_meterType], field_0x5a8[i_meterType]); mpMagicBase->resize(field_0x5b4[i_meterType], field_0x5c0[i_meterType]); +#if TARGET_PC + const f32 magicUserScale = dGetUserHudScale(); + mpMagicParent->scale(field_0x5cc[i_meterType] * magicUserScale, + field_0x5d8[i_meterType] * magicUserScale); + + f32 magicPosX = field_0x5e4[i_meterType]; + f32 magicPosY = field_0x5f0[i_meterType]; + // The oil/magic bar sits inset within its pane box, so use a reduced horizontal pull + // (like the heart row) to keep it from overshooting off the left edge when shrunk. + dAnchorHudScale(mpMagicParent, HudCorner::TopLeft, &magicPosX, &magicPosY, 0.3f); + mpMagicParent->paneTrans(magicPosX, magicPosY); +#else mpMagicParent->scale(field_0x5cc[i_meterType], field_0x5d8[i_meterType]); mpMagicParent->paneTrans(field_0x5e4[i_meterType], field_0x5f0[i_meterType]); +#endif mpKanteraScreen->draw(0.0f, 0.0f, graf_ctx); } @@ -1867,10 +1970,21 @@ void dMeter2Draw_c::drawLightDrop(u8 i_num, u8 i_needNum, f32 i_posX, f32 i_posY field_0x6fc = param_5; mLightDropVesselScale = i_vesselScale; +#if TARGET_PC + const f32 lightDropUserScale = dGetUserHudScale(); + const f32 lightDropScale = mLightDropVesselScale * field_0x6f8 * lightDropUserScale; + mpLightDropParent->scale(lightDropScale, lightDropScale); + + f32 lightDropPosX = i_posX; + f32 lightDropPosY = i_posY; + dAnchorHudScale(mpLightDropParent, HudCorner::TopRight, &lightDropPosX, &lightDropPosY); + mpLightDropParent->paneTrans(lightDropPosX, lightDropPosY); +#else mpLightDropParent->scale(mLightDropVesselScale * field_0x6f8, mLightDropVesselScale * field_0x6f8); mpLightDropParent->paneTrans(i_posX, i_posY); +#endif } void dMeter2Draw_c::setAlphaLightDropChange(bool unused) {} @@ -1943,8 +2057,13 @@ void dMeter2Draw_c::setAlphaLightDropAnimeMax() { field_0x6f8 = 1.0f; } +#if TARGET_PC + const f32 dropAnimScale = mLightDropVesselScale * field_0x6f8 * dGetUserHudScale(); + mpLightDropParent->scale(dropAnimScale, dropAnimScale); +#else mpLightDropParent->scale(mLightDropVesselScale * field_0x6f8, mLightDropVesselScale * field_0x6f8); +#endif if (g_drawHIO.mLightDrop.mDropGetScaleAnimFrameNum == mpLightDropParent->getAlphaTimer()) { dMeter2Info_setLightDropGetFlag(dComIfGp_getStartStageDarkArea(), 0xFF); @@ -2015,10 +2134,22 @@ void dMeter2Draw_c::drawRupee(s16 i_rupeeNum) { static_cast(mpRupeeTexture[0][0]->getPanePtr())->changeTexture(timg, 0); static_cast(mpRupeeTexture[0][1]->getPanePtr())->changeTexture(timg, 0); +#if TARGET_PC + const f32 rupeeKeyUserScale = dGetUserHudScale(); + const f32 rupeeKeyScale = g_drawHIO.mRupeeKeyScale * field_0x718 * rupeeKeyUserScale; + mpRupeeKeyParent->scale(rupeeKeyScale, rupeeKeyScale); + + f32 rupeeKeyPosX = g_drawHIO.mRupeeKeyPosX; + f32 rupeeKeyPosY = g_drawHIO.mRupeeKeyPosY; + // Rupees/keys read better anchored to the bottom-right corner than the top-right. + dAnchorHudScale(mpRupeeKeyParent, HudCorner::BottomRight, &rupeeKeyPosX, &rupeeKeyPosY); + mpRupeeKeyParent->paneTrans(rupeeKeyPosX, rupeeKeyPosY); +#else mpRupeeKeyParent->scale(g_drawHIO.mRupeeKeyScale * field_0x718, g_drawHIO.mRupeeKeyScale * field_0x718); mpRupeeKeyParent->paneTrans(g_drawHIO.mRupeeKeyPosX, g_drawHIO.mRupeeKeyPosY); +#endif mpRupeeParent[0]->scale(g_drawHIO.mRupeeScale, g_drawHIO.mRupeeScale); mpRupeeParent[0]->paneTrans(g_drawHIO.mRupeePosX, g_drawHIO.mRupeePosY); @@ -2137,8 +2268,18 @@ void dMeter2Draw_c::drawKey(s16 i_keyNum) { } } +#if TARGET_PC + const f32 keyScale = g_drawHIO.mKeyScale * dGetUserHudScale(); + mpKeyParent->scale(keyScale, keyScale); + + f32 keyPosX = g_drawHIO.mKeyPosX; + f32 keyPosY = g_drawHIO.mKeyPosY; + dAnchorHudScale(mpKeyParent, HudCorner::BottomRight, &keyPosX, &keyPosY); + mpKeyParent->paneTrans(keyPosX, keyPosY); +#else mpKeyParent->scale(g_drawHIO.mKeyScale, g_drawHIO.mKeyScale); mpKeyParent->paneTrans(g_drawHIO.mKeyPosX, g_drawHIO.mKeyPosY); +#endif } void dMeter2Draw_c::setAlphaKeyChange(bool param_0) { @@ -2596,11 +2737,24 @@ f32 dMeter2Draw_c::getButtonCrossParentInitTransY() { } void dMeter2Draw_c::drawButtonCross(f32 i_posX, f32 i_posY) { +#if TARGET_PC + const f32 buttonCrossUserScale = dGetUserHudScale(); + const f32 buttonCrossScale = g_drawHIO.mButtonCrossScale * buttonCrossUserScale; + mpButtonCrossParent->scale(buttonCrossScale, buttonCrossScale); +#else mpButtonCrossParent->scale(g_drawHIO.mButtonCrossScale, g_drawHIO.mButtonCrossScale); +#endif mpTextI->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); mpTextM->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); +#if TARGET_PC + f32 buttonCrossPosX = i_posX; + f32 buttonCrossPosY = i_posY; + dAnchorHudScale(mpButtonCrossParent, HudCorner::TopLeft, &buttonCrossPosX, &buttonCrossPosY); + mpButtonCrossParent->paneTrans(buttonCrossPosX, buttonCrossPosY); +#else mpButtonCrossParent->paneTrans(i_posX, i_posY); +#endif } void dMeter2Draw_c::setAlphaButtonCrossAnimeMin() { @@ -3505,9 +3659,16 @@ void dMeter2Draw_c::drawKanteraMeter(u8 i_button, f32 i_alphaRate) { Vec vtx0 = pane->getPanePtr()->getGlbVtx(0); Vec vtx3 = pane->getPanePtr()->getGlbVtx(3); +#if TARGET_PC + const f32 oilUserScale = dGetUserHudScale(); + mpKanteraMeter[i_button]->setPos(((vtx0.x + vtx3.x) * 0.5f) + 9.0f * oilUserScale + sp10[i_button], + vtx3.y + sp8[i_button]); + mpKanteraMeter[i_button]->setScale(0.6f * oilUserScale, 0.6f * oilUserScale); +#else mpKanteraMeter[i_button]->setPos(((vtx0.x + vtx3.x) * 0.5f) + 9.0f + sp10[i_button], vtx3.y + sp8[i_button]); mpKanteraMeter[i_button]->setScale(0.6f, 0.6f); +#endif mpKanteraMeter[i_button]->setNowGauge(dComIfGs_getMaxOil(), dComIfGs_getOil()); mpKanteraMeter[i_button]->setAlphaRate(i_alphaRate); } diff --git a/src/d/d_meter_map.cpp b/src/d/d_meter_map.cpp index 419235c970..c03214b963 100644 --- a/src/d/d_meter_map.cpp +++ b/src/d/d_meter_map.cpp @@ -16,6 +16,10 @@ #include "f_op/f_op_overlap_mng.h" #include "m_Do/m_Do_controller_pad.h" #include "d/d_camera.h" +#if TARGET_PC +#include "dusk/settings.h" +#include +#endif #include #if (PLATFORM_WII || PLATFORM_SHIELD) @@ -621,8 +625,16 @@ void dMeterMap_c::draw() { mMapJ2DPicture->setAlpha(alpha); #if TARGET_PC - mMapJ2DPicture->draw(mDoGph_gInf_c::ScaleHUDXLeft(drawPosX), drawPosY, sizeX, sizeY, false, - false, false); + // Scale the minimap with the user HUD scale and shift down so its bottom-left + // corner stays anchored to the same screen position as at scale 1.0. + const f32 userHudScale = + std::clamp(dusk::getSettings().game.hudScale.getValue(), 0.5f, 2.0f); + const f32 scaledSizeX = sizeX * userHudScale; + const f32 scaledSizeY = sizeY * userHudScale; + const f32 mapBottomShift = sizeY - scaledSizeY; + mMapJ2DPicture->draw(mDoGph_gInf_c::ScaleHUDXLeft(drawPosX), + drawPosY + mapBottomShift, scaledSizeX, scaledSizeY, + false, false, false); #else mMapJ2DPicture->draw(drawPosX, drawPosY, sizeX, sizeY, false, false, false); #endif diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 402001a1dc..7a34264f48 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -51,6 +51,7 @@ UserSettings g_userSettings = { // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, .minimalHUD {"game.minimalHUD", false}, + .hudScale {"game.hudScale", 1.0f}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, .enableLinkDollRotation {"game.enableLinkDollRotation", false}, .enableAchievementToasts {"game.enableAchievementToasts", true}, @@ -240,6 +241,7 @@ void registerSettings() { Register(g_userSettings.game.freeCameraXSensitivity); Register(g_userSettings.game.freeCameraYSensitivity); Register(g_userSettings.game.minimalHUD); + Register(g_userSettings.game.hudScale); Register(g_userSettings.game.pauseOnFocusLost); Register(g_userSettings.game.enableDiscordPresence); Register(g_userSettings.game.bloomMode); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index b11875f48c..d65cab3370 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1113,6 +1113,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { addOption("Minimal HUD", getSettings().game.minimalHUD, "Disables the elements of the main HUD of the game.
Useful for a more immersive " "experience."); + config_percent_select(leftPane, rightPane, getSettings().game.hudScale, + "HUD Scale", + "Scales the size of the gameplay HUD (hearts, buttons, mini-map, etc.). Does not affect dialog boxes or menus.", + 50, 200, 5, + [] { return getSettings().game.minimalHUD.getValue(); }); addOption("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches, "Restores patched glitches from Wii USA 1.0, the first released version."); addOption("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation, From d9d9966f8f325472ee486235401b4fd366a25643 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 5 Jun 2026 02:17:06 -0400 Subject: [PATCH 30/32] Time Freezing Camera (#1787) Thanks to @bkd89 for the idea! Co-authored-by: MelonSpeedruns --- src/dusk/imgui/ImGuiCameraOverlay.cpp | 4 ++-- src/f_op/f_op_camera.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index 0d2168924c..8963b88ede 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -75,12 +75,12 @@ namespace dusk { if (!getSettings().game.debugFlyCam) { ImGui::BeginDisabled(); } - config::ImGuiCheckbox("Lock Events", getSettings().game.debugFlyCamLockEvents); + config::ImGuiCheckbox("Freeze Time", getSettings().game.debugFlyCamLockEvents); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { if (!getSettings().game.debugFlyCam) { ImGui::SetTooltip("Enable Fly Mode first."); } else { - ImGui::SetTooltip("Freeze game events while flying."); + ImGui::SetTooltip("Freezes the game while flying."); } } if (!getSettings().game.debugFlyCam) { diff --git a/src/f_op/f_op_camera.cpp b/src/f_op/f_op_camera.cpp index 48045aeae7..567f80904f 100644 --- a/src/f_op/f_op_camera.cpp +++ b/src/f_op/f_op_camera.cpp @@ -36,9 +36,20 @@ static int fopCam_Execute(camera_class* i_this) { fapGm_HIO_c::startCpuTimer(); #endif + #if TARGET_PC + if (dusk::getSettings().game.debugFlyCam && dusk::getSettings().game.debugFlyCamLockEvents) { + dScnPly_c::setPauseTimer(1); + ret = fpcMtd_Execute((process_method_class*)i_this->submethod, i_this); + } else { + if (!dComIfGp_isPauseFlag() && !dScnPly_c::isPause()) { + ret = fpcMtd_Execute((process_method_class*)i_this->submethod, i_this); + } + } + #else if (!dComIfGp_isPauseFlag() && !dScnPly_c::isPause()) { ret = fpcMtd_Execute((process_method_class*)i_this->submethod, i_this); } + #endif #if DEBUG fapGm_HIO_c::stopCpuTimer("カメラ(計算処理)"); // Camera (computational processing) From 7a900471bf257dbe0d73d8683554e0a8876e6ae2 Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:05:54 -0400 Subject: [PATCH 31/32] Clamp flycam FOV (#1996) --- src/dusk/imgui/ImGuiCameraOverlay.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index 8963b88ede..320c41ec92 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -49,7 +49,9 @@ namespace dusk { dCam->Reset(center, eye); } - ImGui::InputFloat("Camera FOV", &dCam->mFovy); + if (ImGui::InputFloat("Camera FOV", &dCam->mFovy)) { + dCam->mFovy = std::clamp(dCam->mFovy, 0.1f, 179.9f); + } ImGui::SeparatorText("Options"); From 08e0f4a2ee70dc93107f7de193c372621da9180a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 6 Jun 2026 09:41:07 -0600 Subject: [PATCH 32/32] Update aurora & remove old pipeline cache handling --- extern/aurora | 2 +- src/dusk/data.cpp | 100 ---------------------------------------------- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/extern/aurora b/extern/aurora index c31d6dadcb..19479a53e4 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit c31d6dadcbe8d6131b90ea30b756553d8ee5ae6e +Subproject commit 19479a53e4e82c58fb1b4fe07498383b89688713 diff --git a/src/dusk/data.cpp b/src/dusk/data.cpp index 2720651699..c1eb333399 100644 --- a/src/dusk/data.cpp +++ b/src/dusk/data.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -28,8 +27,6 @@ namespace { aurora::Module Log{"dusk::data"}; constexpr auto kLocationDescriptorName = "data_location.json"; -constexpr auto kPipelineCacheName = "pipeline_cache.db"; -constexpr auto kInitialPipelineCacheName = "initial_pipeline_cache.db"; constexpr std::array kUserDataDirectories = { "texture_replacements", @@ -888,102 +885,6 @@ void ensure_data_directory(const std::filesystem::path& dataPath) { } } -SDL_IOStream* open_initial_pipeline_cache_source(std::string& sourcePathString) { - const auto basePath = base_path_relative(kInitialPipelineCacheName); - sourcePathString = io::fs_path_to_string(basePath); - auto* source = SDL_IOFromFile(sourcePathString.c_str(), "rb"); - if (source != nullptr) { - return source; - } - - sourcePathString = std::string{kInitialPipelineCacheName}; - return SDL_IOFromFile(sourcePathString.c_str(), "rb"); -} - -void ensure_initial_pipeline_cache(const std::filesystem::path& configDir) { - if (configDir.empty()) { - return; - } - - std::error_code ec; - std::filesystem::create_directories(configDir, ec); - if (ec) { - Log.warn("Failed to create config directory '{}' for pipeline cache: {}", - io::fs_path_to_string(configDir), ec.message()); - return; - } - - const auto pipelineCachePath = configDir / kPipelineCacheName; - if (std::filesystem::exists(pipelineCachePath, ec)) { - return; - } - - std::string sourcePathString; - SDL_IOStream* source = open_initial_pipeline_cache_source(sourcePathString); - if (source == nullptr) { - Log.info("No bundled initial pipeline cache found"); - return; - } - - const auto pipelineCacheString = io::fs_path_to_string(pipelineCachePath); - SDL_IOStream* destination = SDL_IOFromFile(pipelineCacheString.c_str(), "wb"); - if (destination == nullptr) { - Log.warn("Failed to open '{}' for seeded pipeline cache: {}", pipelineCacheString, - SDL_GetError()); - SDL_CloseIO(source); - return; - } - - bool copied = true; - std::array buffer{}; - while (true) { - const size_t bytesRead = SDL_ReadIO(source, buffer.data(), buffer.size()); - if (bytesRead > 0) { - size_t bytesWritten = 0; - while (bytesWritten < bytesRead) { - const size_t written = SDL_WriteIO( - destination, buffer.data() + bytesWritten, bytesRead - bytesWritten); - if (written == 0) { - Log.warn("Failed to write seeded pipeline cache '{}': {}", pipelineCacheString, - SDL_GetError()); - copied = false; - break; - } - bytesWritten += written; - } - } - - if (!copied) { - break; - } - - if (bytesRead < buffer.size()) { - if (SDL_GetIOStatus(source) == SDL_IO_STATUS_EOF) { - break; - } - - Log.warn( - "Failed to read bundled pipeline cache '{}': {}", sourcePathString, SDL_GetError()); - copied = false; - break; - } - } - - if (!SDL_CloseIO(destination)) { - Log.warn( - "Failed to close seeded pipeline cache '{}': {}", pipelineCacheString, SDL_GetError()); - copied = false; - } - SDL_CloseIO(source); - - if (!copied) { - std::filesystem::remove(pipelineCachePath, ec); - return; - } - - Log.info("Seeded pipeline cache from '{}'", sourcePathString); -} - } // namespace bool open_data_path() { @@ -1096,7 +997,6 @@ Paths initialize_data() { migrate_data(prefPath, dataPath, descriptor ? &descriptor->descriptor : nullptr); ensure_data_directory(dataPath); ensure_data_directory(prefPath); - ensure_initial_pipeline_cache(prefPath); return Paths{ .userPath = dataPath,